diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py index 301780282e7..3ad3b3db5b0 100644 --- a/addons/base_calendar/base_calendar.py +++ b/addons/base_calendar/base_calendar.py @@ -410,6 +410,8 @@ property or property parameter."), return res cal = vobject.iCalendar() event = cal.add('vevent') + if not event_obj.date_deadline or not event_obj.date: + raise osv.except_osv(_('Warning !'),_("Couldn't Invite because date is not specified!")) event.add('created').value = ics_datetime(time.strftime('%Y-%m-%d %H:%M:%S')) event.add('dtstart').value = ics_datetime(event_obj.date) event.add('dtend').value = ics_datetime(event_obj.date_deadline) @@ -461,7 +463,6 @@ property or property parameter."), attendee_add.params['ROLE'] = [str(attendee.role)] attendee_add.params['RSVP'] = [str(attendee.rsvp)] attendee_add.value = 'MAILTO:' + (attendee.email or '') - res = cal.serialize() return res diff --git a/addons/base_calendar/base_calendar_view.xml b/addons/base_calendar/base_calendar_view.xml index 6fcb8f72f82..d536ef02824 100644 --- a/addons/base_calendar/base_calendar_view.xml +++ b/addons/base_calendar/base_calendar_view.xml @@ -77,6 +77,7 @@ + diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py old mode 100755 new mode 100644 index 98c36744ef1..9f437ace9fc --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -37,14 +37,14 @@ # USA. from random import seed, sample -from string import letters, digits +from string import ascii_letters, digits from osv import fields,osv import pooler from tools.translate import _ magic_md5 = '$1$' -def gen_salt( length=8, symbols=letters + digits ): +def gen_salt( length=8, symbols=ascii_letters + digits ): seed() return ''.join( sample( symbols, length ) ) @@ -64,15 +64,16 @@ def gen_salt( length=8, symbols=letters + digits ): # * # * Poul-Henning Kamp -from sys import version_info -if version_info < (2,5): - from md5 import md5 -else: - from hashlib import md5 + +#TODO: py>=2.6: from hashlib import md5 +import hashlib def encrypt_md5( raw_pw, salt, magic=magic_md5 ): - hash = md5( raw_pw + magic + salt ) - stretch = md5( raw_pw + salt + raw_pw).digest() + hash = hashlib.md5() + hash.update( raw_pw + magic + salt ) + st = hashlib.md5() + st.update( raw_pw + salt + raw_pw) + stretch = st.digest() for i in range( 0, len( raw_pw ) ): hash.update( stretch[i % 16] ) @@ -89,7 +90,7 @@ def encrypt_md5( raw_pw, salt, magic=magic_md5 ): saltedmd5 = hash.digest() for i in range( 1000 ): - hash = md5() + hash = hashlib.md5() if i & 1: hash.update( raw_pw ) @@ -166,19 +167,37 @@ class users(osv.osv): } def login(self, db, login, password): - cr = pooler.get_db(db).cursor() - cr.execute('select password, id from res_users where login=%s', - (login.encode('utf-8'),)) - stored_pw = id = cr.fetchone() - - if stored_pw: - stored_pw = stored_pw[0] - id = id[1] - else: - # Return early if there is no such login. + if not password: return False + if db is False: + raise RuntimeError("Cannot authenticate to False db!") + cr = None + try: + cr = pooler.get_db(db).cursor() + return self._login(cr, db, login, password) + except Exception: + import logging + logging.getLogger('netsvc').exception('Could not authenticate') + return Exception('Access Denied') + finally: + if cr is not None: + cr.close() + def _login(self, cr, db, login, password): + cr.execute( 'SELECT password, id FROM res_users WHERE login=%s', + (login.encode('utf-8'),)) + + if cr.rowcount: + stored_pw, id = cr.fetchone() + else: + # Return early if no one has a login name like that. + return False + stored_pw = self.maybe_encrypt(cr, stored_pw, id) + + if not stored_pw: + # means couldn't encrypt or user is not active! + return False # Calculate an encrypted password from the user-provided # password. @@ -187,12 +206,14 @@ class users(osv.osv): obj._salt_cache = {} salt = obj._salt_cache[id] = stored_pw[len(magic_md5):11] encrypted_pw = encrypt_md5(password, salt) - + # Check if the encrypted password matches against the one in the db. - cr.execute('select id from res_users where id=%s and password=%s and active', (int(id), encrypted_pw.encode('utf-8'))) + cr.execute('UPDATE res_users SET date=now() ' \ + 'WHERE id=%s AND password=%s AND active RETURNING id', + (int(id), encrypted_pw.encode('utf-8'))) res = cr.fetchone() - cr.close() - + cr.commit() + if res: return res[0] else: @@ -210,22 +231,28 @@ class users(osv.osv): return True cr = pooler.get_db(db).cursor() - if uid not in obj._salt_cache: - cr.execute('select login from res_users where id=%s', (int(uid),)) - stored_login = cr.fetchone() - if stored_login: - stored_login = stored_login[0] + try: + if uid not in self._salt_cache.get(db, {}): + # If we don't have cache, we have to repeat the procedure + # through the login function. + cr.execute( 'SELECT login FROM res_users WHERE id=%s', (uid,) ) + stored_login = cr.fetchone() + if stored_login: + stored_login = stored_login[0] + + res = self._login(cr, db, stored_login, passwd) + if not res: + raise security.ExceptionNoTb('AccessDenied') + else: + salt = self._salt_cache[db][uid] + cr.execute('SELECT COUNT(*) FROM res_users WHERE id=%s AND password=%s', + (int(uid), encrypt_md5(passwd, salt))) + res = cr.fetchone()[0] + finally: + cr.close() - if not self.login(db,stored_login,passwd): - return False - - salt = obj._salt_cache[uid] - cr.execute('select count(id) from res_users where id=%s and password=%s', - (int(uid), encrypt_md5(passwd, salt))) - res = cr.fetchone()[0] - cr.close() if not bool(res): - raise Exception('AccessDenied') + raise security.ExceptionNoTb('AccessDenied') if res: if self._uid_cache.has_key(db): @@ -234,20 +261,24 @@ class users(osv.osv): else: self._uid_cache[db] = {uid: passwd} return bool(res) - + def maybe_encrypt(self, cr, pw, id): - # If the password 'pw' is not encrypted, then encrypt all passwords - # in the db. Returns the (possibly newly) encrypted password for 'id'. + """ Return the password 'pw', making sure it is encrypted. + + If the password 'pw' is not encrypted, then encrypt all active passwords + in the db. Returns the (possibly newly) encrypted password for 'id'. + """ if not pw.startswith(magic_md5): - cr.execute('select id, password from res_users') + cr.execute("SELECT id, password FROM res_users " \ + "WHERE active=true AND password NOT LIKE '$%'") + # Note that we skip all passwords like $.., in anticipation for + # more than md5 magic prefixes. res = cr.fetchall() for i, p in res: - encrypted = p - if p and not p.startswith(magic_md5): - encrypted = encrypt_md5(p, gen_salt()) - cr.execute('update res_users set password=%s where id=%s', - (encrypted.encode('utf-8'), int(i))) + encrypted = encrypt_md5(p, gen_salt()) + cr.execute('UPDATE res_users SET password=%s where id=%s', + (encrypted, i)) if i == id: encrypted_res = encrypted cr.commit() diff --git a/addons/base_crypt/i18n/el.po b/addons/base_crypt/i18n/el.po new file mode 100644 index 00000000000..b9aaac39501 --- /dev/null +++ b/addons/base_crypt/i18n/el.po @@ -0,0 +1,27 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * base_crypt +# +# Copyright (C) 2008,2009 P. Christeas +# <> <>, 2009. +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 5.0.0\n" +"Report-Msgid-Bugs-To: support@openerp.com\n" +"POT-Creation-Date: 2009-05-30 15:14:08+0000\n" +"PO-Revision-Date: 2009-03-27 14:30+0200\n" +"Last-Translator: <> <>\n" +"Language-Team: <>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#~ msgid "Module for password encryption." +#~ msgstr "Άρθρωμα για κρυπτογράφηση κωδικών." + +#~ msgid "Invalid XML for View Architecture!" +#~ msgstr "Άκυρο XML για αρχιτεκτονική προβολής!" + +#~ msgid "Password" +#~ msgstr "Κωδικός" diff --git a/addons/base_setup/__init__.py b/addons/base_setup/__init__.py index 85d01779842..9ed5ec84535 100644 --- a/addons/base_setup/__init__.py +++ b/addons/base_setup/__init__.py @@ -45,9 +45,15 @@ class base_setup_config_choice(osv.osv_memory): def get_users(self, cr, uid, context=None): user_obj = self.pool.get('res.users') user_ids = user_obj.search(cr, uid, []) - users = user_obj.browse(cr, uid, user_ids, context=context) - user_str = '\n'.join(map(lambda x: ' - %s :\n\t\tLogin : %s \n\t\tPassword : %s' % (x.name, x.login, x.password), users)) - return _('The following users have been installed : \n')+ user_str + user_list = [] + user_tmpl_nopass = _(' - %s :\n\t\tLogin : %s') + user_tmpl_pass = _(' - %s :\n\t\tLogin : %s \n\t\tPassword : %s') + for user in user_obj.browse(cr, uid, user_ids, context=context): + if user.password and not user.password.startswith('$'): + user_list.append(user_tmpl_pass % (user.name, user.login, user.password)) + else: + user_list.append(user_tmpl_nopass % (user.name, user.login)) + return _('The following users have been installed : \n')+ '\n'.join(user_list) _columns = { 'installed_users':fields.text('Installed Users', readonly=True), diff --git a/addons/crm/wizard/crm_opportunity_to_phonecall.py b/addons/crm/wizard/crm_opportunity_to_phonecall.py index 0b68d7f37ba..8fc7ffb310d 100644 --- a/addons/crm/wizard/crm_opportunity_to_phonecall.py +++ b/addons/crm/wizard/crm_opportunity_to_phonecall.py @@ -137,7 +137,7 @@ class crm_opportunity2phonecall(osv.osv_memory): 'view_mode': 'tree,form', 'res_model': 'crm.phonecall', 'res_id' : new_case, - 'views': [(id3, 'form'), (id2, 'tree'), (False, 'calendar'), (False, 'graph')], + 'views': [(id3, 'form'), (id2, 'tree'), (False, 'calendar')], 'type': 'ir.actions.act_window', 'search_view_id': res['res_id'] } diff --git a/addons/crm_claim/crm_claim_view.xml b/addons/crm_claim/crm_claim_view.xml index c489152565e..696c8ed3a84 100644 --- a/addons/crm_claim/crm_claim_view.xml +++ b/addons/crm_claim/crm_claim_view.xml @@ -53,6 +53,8 @@ + +