def create_user(**kwargs): """Create user in Caliopen instance.""" from caliopen_main.user.core import User from caliopen_main.user.parameters import NewUser from caliopen_main.contact.parameters import NewContact from caliopen_main.contact.parameters import NewEmail # Fill core registry from caliopen_main.message.objects.message import Message param = NewUser() param.name = kwargs['email'] if '@' in param.name: username, domain = param.name.split('@') param.name = username # Monkey patch configuration local_domain with provided value conf = Configuration('global').configuration conf['default_domain'] = domain param.password = kwargs['password'] param.recovery_email = u'{}@caliopen.local'.format(param.name) contact = NewContact() contact.given_name = kwargs.get('given_name') contact.family_name = kwargs.get('family_name') email = NewEmail() email.address = param.recovery_email contact.emails = [email] param.contact = contact user = User.create(param) log.info('User %s (%s) created' % (user.user_id, user.name))
def create_user(**kwargs): """Create user in Caliopen instance.""" from caliopen_main.user.core import User from caliopen_main.user.parameters import NewUser from caliopen_main.contact.parameters import NewContact from caliopen_main.contact.parameters import NewEmail # Fill core registry from caliopen_main.message.objects.message import Message param = NewUser() param.name = kwargs['email'] if '@' in param.name: username, domain = param.name.split('@') param.name = username # Monkey patch configuration local_domain with provided value conf = Configuration('global').configuration conf['default_domain'] = domain param.password = kwargs['password'] param.recovery_email = u'{}@recovery-caliopen.local'.format(param.name) contact = NewContact() contact.given_name = kwargs.get('given_name') contact.family_name = kwargs.get('family_name') email = NewEmail() email.address = param.recovery_email contact.emails = [email] param.contact = contact user = User.create(param) log.info('User %s (%s) created' % (user.user_id, user.name))
def collection_post(self): """Create a new user.""" contact = self.request.swagger_data['user']['contact'] settings = Settings() settings.import_data(self.request.swagger_data['user']['settings']) settings.validate() param = NewUser({'name': self.request.swagger_data['user']['username'], 'password': self.request.swagger_data['user'][ 'password'], 'recovery_email': self.request.swagger_data['user'][ 'recovery_email'], 'contact': contact, 'settings': settings, }) if self.request.swagger_data['user']['contact'] is not None: param.contact = self.request.swagger_data['user']['contact'] else: c = NewContact() c.given_name = param.name email = NewEmail() email.address = param.recovery_email c.emails = [email] param.contact = c try: user = User.create(param) except Exception as exc: raise AuthenticationError(exc.message) # why this class of error ? log.info('Created user {} with name {}'. format(user.user_id, user.name)) user_url = self.request.route_path('User', user_id=user.user_id) self.request.response.location = user_url.encode('utf-8') return {'location': user_url}
def __build_email(self, param): email = NewEmail() email.address = param.value if 'TYPE' in param.params: email_type = param.params['TYPE'][0].lower() if email_type in EMAIL_TYPES: email.type = email_type if 'PREF' in param.params: email.is_primary = True return email
def collection_post(self): """Create a new user.""" settings = Settings() settings.import_data(self.request.swagger_data['user']['settings']) try: settings.validate() except Exception as exc: raise Unprocessable(detail=exc.message) param = NewUser({ 'name': self.request.swagger_data['user']['username'], 'password': self.request.swagger_data['user']['password'], 'recovery_email': self.request.swagger_data['user']['recovery_email'], 'settings': settings, }) if self.request.swagger_data['user']['contact'] is not None: param.contact = self.request.swagger_data['user']['contact'] else: c = NewContact() c.given_name = param.name c.family_name = "" # can't guess it ! email = NewEmail() email.address = param.recovery_email c.emails = [email] param.contact = c try: user = User.create(param) except Exception as exc: log.exception('Error during user creation {0}'.format(exc)) raise NotAcceptable(detail=exc.message) log.info('Created user {} with name {}'.format(user.user_id, user.name)) # default device management in_device = self.request.swagger_data['user']['device'] if in_device: try: in_device['name'] = 'default' device = Device.create_from_parameter(user, in_device, self.request.headers) log.info('Device %r created' % device.device_id) except Exception as exc: log.exception('Error during default device creation %r' % exc) else: log.warn('Missing default device parameter') user_url = self.request.route_path('User', user_id=user.user_id) self.request.response.location = user_url.encode('utf-8') return {'location': user_url}
def collection_post(self): """Create a new user.""" settings = Settings() settings.import_data(self.request.swagger_data['user']['settings']) try: settings.validate() except Exception as exc: raise Unprocessable(detail=exc.message) param = NewUser({ 'name': self.request.swagger_data['user']['username'], 'password': self.request.swagger_data['user']['password'], 'recovery_email': self.request.swagger_data['user']['recovery_email'], 'settings': settings, }) if self.request.swagger_data['user']['contact'] is not None: param.contact = self.request.swagger_data['user']['contact'] else: c = NewContact() c.given_name = param.name c.family_name = "" # can't guess it ! email = NewEmail() email.address = param.recovery_email c.emails = [email] param.contact = c try: user = User.create(param) except Exception as exc: raise NotAcceptable(detail=exc.message) log.info('Created user {} with name {}'.format(user.user_id, user.name)) user_url = self.request.route_path('User', user_id=user.user_id) self.request.response.location = user_url.encode('utf-8') return {'location': user_url}
def import_email(email, import_path, format, contact_probability, **kwargs): """Import emails for an user.""" from caliopen_main.user.core import User from caliopen_main.contact.core import Contact, ContactLookup from caliopen_main.message.parsers.mail import MailMessage from caliopen_main.contact.parameters import NewContact, NewEmail from caliopen_nats.delivery import UserMessageDelivery from caliopen_main.message.core import RawMessage from caliopen_storage.config import Configuration max_size = int(Configuration("global").get("object_store.db_size_limit")) if format == 'maildir': emails = Maildir(import_path, factory=message_from_file) mode = 'maildir' else: if os.path.isdir(import_path): mode = 'mbox_directory' emails = {} files = [ f for f in os.listdir(import_path) if os.path.isfile(os.path.join(import_path, f)) ] for f in files: try: log.debug('Importing mail from file {}'.format(f)) with open('%s/%s' % (import_path, f)) as fh: emails[f] = message_from_file(fh) except Exception as exc: log.error('Error importing email {}'.format(exc)) else: mode = 'mbox' emails = mbox(import_path) user = User.by_local_identity(email) log.info("Processing mode %s" % mode) for key, data in emails.iteritems(): # Prevent creating message too large to fit in db. # (should use inject cmd for large messages) size = len(data.as_string()) if size > max_size: log.warn("Message too large to fit into db. \ Please, use 'inject' cmd for importing large emails.") continue raw = RawMessage.create(data.as_string()) log.debug('Created raw message {}'.format(raw.raw_msg_id)) message = MailMessage(data.as_string()) dice = random() if dice <= contact_probability: for participant in message.participants: try: ContactLookup.get(user, participant.address) except NotFound: log.info('Creating contact %s' % participant.address) name, domain = participant.address.split('@') contact_param = NewContact() contact_param.family_name = name if participant.address: e_mail = NewEmail() e_mail.address = participant.address contact_param.emails = [e_mail] Contact.create(user, contact_param) log.info('No contact associated to raw {} '.format(raw.raw_msg_id)) processor = UserMessageDelivery(user) obj_message = processor.process_raw(raw.raw_msg_id) log.info('Created message {}'.format(obj_message.message_id))
def import_email(email, import_path, format, contact_probability, **kwargs): """Import emails for an user.""" from caliopen_main.user.core import User from caliopen_main.contact.core import Contact, ContactLookup from caliopen_main.message.parsers.mail import MailMessage from caliopen_main.contact.parameters import NewContact, NewEmail from caliopen_nats.delivery import UserMailDelivery from caliopen_main.message.core import RawMessage from caliopen_storage.config import Configuration max_size = int(Configuration("global").get("object_store.db_size_limit")) if 'to' in kwargs and kwargs['to']: dest_email = kwargs['to'] else: dest_email = email if format == 'maildir': if dest_email != email: raise Exception('Cannot change To email using maildir format') emails = Maildir(import_path, factory=message_from_file) mode = 'maildir' else: if os.path.isdir(import_path): mode = 'mbox_directory' emails = {} files = [ f for f in os.listdir(import_path) if os.path.isfile(os.path.join(import_path, f)) ] for f in files: try: log.debug('Importing mail from file {}'.format(f)) with open('%s/%s' % (import_path, f)) as fh: data = fh.read() data = re.sub('^To: (.*)', 'To: %s' % dest_email, data, flags=re.MULTILINE) emails[f] = message_from_string(data) except Exception as exc: log.error('Error importing email {}'.format(exc)) else: mode = 'mbox' emails = mbox(import_path) user = User.by_local_identifier(dest_email, 'email') log.info("Processing mode %s" % mode) for key, data in emails.iteritems(): # Prevent creating message too large to fit in db. # (should use inject cmd for large messages) size = len(data.as_string()) if size > max_size: log.warn("Message too large to fit into db. \ Please, use 'inject' cmd for importing large emails.") continue raw = RawMessage.create(data.as_string()) log.debug('Created raw message {}'.format(raw.raw_msg_id)) message = MailMessage(data.as_string()) dice = random() if dice <= contact_probability: for participant in message.participants: try: ContactLookup.get(user, participant.address) except NotFound: log.info('Creating contact %s' % participant.address) name, domain = participant.address.split('@') contact_param = NewContact() contact_param.family_name = name if participant.address: e_mail = NewEmail() e_mail.address = participant.address contact_param.emails = [e_mail] Contact.create(user, contact_param) else: log.info('No contact associated to raw {} '.format(raw.raw_msg_id)) processor = UserMailDelivery( user, user.local_identities[0]) # assume one local identity try: obj_message = processor.process_raw(raw.raw_msg_id) except Exception as exc: if isinstance(exc, DuplicateMessage): log.info('duplicate message {}, not imported'.format( raw.raw_msg_id)) else: log.exception(exc) else: log.info('Created message {}'.format(obj_message.message_id))
def collection_post(self): """Create a new user.""" settings = Settings() settings.import_data(self.request.swagger_data['user']['settings']) try: settings.validate() except Exception as exc: raise Unprocessable(detail=exc.message) param = NewUser({'name': self.request.swagger_data['user']['username'], 'password': self.request.swagger_data['user'][ 'password'], 'recovery_email': self.request.swagger_data['user'][ 'recovery_email'], 'settings': settings, }) if self.request.swagger_data['user']['contact'] is not None: param.contact = self.request.swagger_data['user']['contact'] else: c = NewContact() c.given_name = param.name c.family_name = "" # can't guess it ! email = NewEmail() email.address = param.recovery_email c.emails = [email] param.contact = c try: user = User.create(param) except Exception as exc: log.exception('Error during user creation {0}'.format(exc)) raise NotAcceptable(detail=exc.message) log.info('Created user {} with name {}'. format(user.user_id, user.name)) # default device management in_device = self.request.swagger_data['user']['device'] if in_device: try: in_device['name'] = 'default' device = Device.create_from_parameter(user, in_device, self.request.headers) log.info('Device %r created' % device.device_id) except Exception as exc: log.exception('Error during default device creation %r' % exc) else: log.warn('Missing default device parameter') user_url = self.request.route_path('User', user_id=user.user_id) self.request.response.location = user_url.encode('utf-8') # send notification to apiv2 to trigger post-registration actions config = Configuration('global').get("message_queue") try: tornado.ioloop.IOLoop.current().run_sync( lambda: notify_new_user(user, config), timeout=5) except Exception as exc: log.exception( 'Error when sending new_user notification on NATS : {0}'. format(exc)) return {'location': user_url}
def create(cls, new_user): """Create a new user. @param: new_user is a parameters/user.py.NewUser object # 1.check username regex # 2.check username is not in reserved_name table # 3.check recovery email validity (TODO : check if email is not within # the current Caliopen's instance) # 4.check username availability # 5.add username to user cassa user_name table (to block the # availability) # 6.check password strength (and regex?) # then # create user and linked contact """ def rollback_username_storage(username): UserName.get(username).delete() # 0. check for user email white list and max number of users cls._check_whitelistes(new_user) cls._check_max_users() # 1. try: validators.is_valid_username(new_user.name) except SyntaxError: raise ValueError("Malformed username") # 2. try: ReservedName.get(new_user.name) raise ValueError('Reserved user name') except NotFound: pass user_id = uuid.uuid4() # 3. if not new_user.recovery_email: raise ValueError("Missing recovery email") try: cls.validate_recovery_email(new_user.recovery_email) except Exception as exc: log.info("recovery email failed validation : {}".format(exc)) raise ValueError(exc) # 4. & 5. if User.is_username_available(new_user.name.lower()): # save username immediately to prevent concurrent creation UserName.create(name=new_user.name.lower(), user_id=user_id) # NB : need to rollback this username creation if the below # User creation failed for any reason else: raise ValueError("Username already exist") # 6. try: user_inputs = [ new_user.name.encode("utf-8"), new_user.recovery_email.encode("utf-8") ] # TODO: add contact inputs if any password_strength = zxcvbn(new_user.password, user_inputs=user_inputs) privacy_features = { "password_strength": str(password_strength["score"]) } passwd = new_user.password.encode('utf-8') new_user.password = bcrypt.hashpw(passwd, bcrypt.gensalt()) except Exception as exc: log.exception(exc) rollback_username_storage(new_user.name) raise exc try: new_user.validate() # schematic model validation except Exception as exc: rollback_username_storage(new_user.name) log.info("schematics validation error: {}".format(exc)) raise ValueError("new user malformed") try: recovery = new_user.recovery_email if hasattr(new_user, "contact"): family_name = new_user.contact.family_name given_name = new_user.contact.given_name else: family_name = "" given_name = "" # XXX PI compute pi = PIModel() pi.technic = 0 pi.comportment = 0 pi.context = 0 pi.version = 0 shard_id = allocate_user_shard(user_id) core = super(User, cls).create( user_id=user_id, name=new_user.name, password=new_user.password, recovery_email=recovery, params=new_user.params, date_insert=datetime.datetime.now(tz=pytz.utc), privacy_features=privacy_features, pi=pi, family_name=family_name, given_name=given_name, shard_id=shard_id) except Exception as exc: log.info(exc) rollback_username_storage(new_user.name) raise exc # **** operations below do not raise fatal error and rollback **** # # Setup index setup_index(core) # Setup others entities related to user setup_system_tags(core) setup_settings(core, new_user.settings) UserRecoveryEmail.create(recovery_email=recovery, user_id=user_id) # Add a default local identity on a default configured domain default_domain = Configuration('global').get('default_domain') default_local_id = '{}@{}'.format(core.name, default_domain) if not core.add_local_identity(default_local_id): log.warn('Impossible to create default local identity {}'.format( default_local_id)) # save and index linked contact if hasattr(new_user, "contact"): # add local email to contact local_mail = NewEmail() local_mail.address = default_local_id new_user.contact.emails.append(local_mail) # create default contact for user contact = CoreContact.create(core, new_user.contact) core.model.contact_id = contact.contact_id log.info("contact id {} for new user {}".format( contact.contact_id, core.user_id)) else: log.error("missing contact in new_user params for user {}. " "Can't create related tables".format(core.user_id)) core.save() return core
def parse_vcard(vcard): """Parse a vcard input and produce a ``NewContact``.""" new_contact = NewContact() n = False for parcours in vcard.contents: if parcours == 'n': n = True if n: new_contact.family_name = vcard.contents['n'][0].value.family new_contact.given_name = vcard.contents['n'][0].value.given if vcard.contents['n'][0].value.additional: for a in vcard.contents['n'][0].value.additional: if len(a) == 1: tmp = vcard.contents['n'][0].value.additional new_contact.additional_name = tmp else: liste = vcard.contents['n'][0].value.additional new_contact.additional_name = liste[0] new_contact.name_prefix = vcard.contents['n'][0].value.prefix if vcard.contents['n'][0].value.suffix: for a in vcard.contents['n'][0].value.suffix: if len(a) == 1: tmp = vcard.contents['n'][0].value.suffix new_contact.additional_name = tmp else: liste = vcard.contents['n'][0].value.suffix new_contact.name_suffix = liste[0] else: for v in vcard.contents: if v == 'sn': for sn in vcard.contents['sn']: new_contact.family_name = sn.value elif v == 'cn': for cn in vcard.contents['cn']: ind = 0 prems = False for a in cn.value: if a != ' ' and not prems: ind += 1 else: prems = True new_contact.given_name = cn.value[:ind] new_contact.family_name = cn.value[ind + 1:] elif v == 'name': for name in vcard.contents['name']: ind = 0 prems = False for a in name.value: if a == ' ' and not prems: ind += 1 else: prems = True new_contact.given_name = name.value[ind + 1:] new_contact.family_name = name.value[:ind] elif v == 'fn': for fn in vcard.contents['fn']: ind = 0 prems = False for a in fn.value: if a != ' ' and not prems: ind += 1 else: prems = True new_contact.given_name = fn.value[:ind] new_contact.family_name = fn.value[ind + 1:] for v in vcard.contents: if v == 'adr': for ad in vcard.contents['adr']: add = NewPostalAddress() add.city = ad.value.city if ad.value.country != "": add.country = ad.value.country add.is_primary = False add.postal_code = ad.value.code add.region = ad.value.region add.street = ad.value.street for i in ADDRESS_TYPES: if i == ad.type_param: add.type = ad.type_param if not add.type: add.type = ADDRESS_TYPES[2] new_contact.addresses.append(add) elif v == 'email': for mail in vcard.contents['email']: email_tmp = NewEmail() try: ad = validate_email(mail.value) email_tmp.address = ad email_tmp.is_primary = False if mail.params: if mail.params.get('TYPE')[0]: for i in EMAIL_TYPES: if i == mail.params.get('TYPE')[0]: email_tmp.type = i new_contact.emails.append(email_tmp) except: pass elif v == 'impp': for i in vcard.contents['impp']: impp = NewIM() try: impp_tmp = validate_email(i.value) impp.address = impp_tmp impp.is_primary = False if i.params: for j in IM_TYPES: if j == i.params.get('TYPE')[0]: impp.type = j new_contact.ims.append(impp) except: pass elif v == 'org': for o in vcard.contents['org']: for orga in o.value: org = NewOrganization() org.is_primary = False org.label = orga org.name = orga new_contact.organizations.append(org) elif v == 'key': test = False for key in vcard.contents['key']: ke = NewPublicKey() if key.params: if key.params.get('ENCODING'): test = False else: test = True if test: ke.key = vcard.contents['key'][0].value if "1024" in key.value: ke.size = 1024 elif "2048" in key.value: ke.size = 2048 elif "4096" in key.value: ke.size = 4096 if (key.params): for j in KEY_CHOICES: if j == 'gpg': j = 'pgp' j = j.upper() if j == key.params.get('TYPE'): j = j.lower() if j == 'pgp': j = 'gpg' ke.type = j ke.name = ('key{}{}'.format(ke.type, ke.size)) new_contact.public_keys.append(ke) elif v == 'tel': for tel in vcard.contents['tel']: phone = NewPhone() phone.is_primary = False try: func = PhoneNumberType.validate_phone phone.number = func(PhoneNumberType(), tel.value) new_contact.phones.append(phone) except: pass return new_contact
def import_email(email, import_path, format, contact_probability, **kwargs): """Import emails for an user.""" from caliopen_main.user.core import User, UserIdentity from caliopen_main.contact.core import Contact, ContactLookup from caliopen_main.message.parsers.mail import MailMessage from caliopen_main.contact.parameters import NewContact, NewEmail from caliopen_nats.delivery import UserMailDelivery from caliopen_main.message.core import RawMessage from caliopen_storage.config import Configuration max_size = int(Configuration("global").get("object_store.db_size_limit")) if 'to' in kwargs and kwargs['to']: dest_email = kwargs['to'] else: dest_email = email if format == 'maildir': if dest_email != email: raise Exception('Cannot change To email using maildir format') emails = Maildir(import_path, factory=message_from_file) mode = 'maildir' else: if os.path.isdir(import_path): mode = 'mbox_directory' emails = {} files = [f for f in os.listdir(import_path) if os.path.isfile(os.path.join(import_path, f))] for f in files: try: log.debug('Importing mail from file {}'.format(f)) with open('%s/%s' % (import_path, f)) as fh: data = fh.read() data = re.sub('^To: (.*)', 'To: %s' % dest_email, data, flags=re.MULTILINE) emails[f] = message_from_string(data) except Exception as exc: log.error('Error importing email {}'.format(exc)) else: mode = 'mbox' emails = mbox(import_path) user = User.by_local_identifier(dest_email, 'email') log.info("Processing mode %s" % mode) for key, data in emails.iteritems(): # Prevent creating message too large to fit in db. # (should use inject cmd for large messages) size = len(data.as_string()) if size > max_size: log.warn("Message too large to fit into db. \ Please, use 'inject' cmd for importing large emails.") continue raw = RawMessage.create(data.as_string()) log.debug('Created raw message {}'.format(raw.raw_msg_id)) message = MailMessage(data.as_string()) dice = random() if dice <= contact_probability: for participant in message.participants: try: ContactLookup.get(user, participant.address) except NotFound: log.info('Creating contact %s' % participant.address) name, domain = participant.address.split('@') contact_param = NewContact() contact_param.family_name = name if participant.address: e_mail = NewEmail() e_mail.address = participant.address contact_param.emails = [e_mail] Contact.create(user, contact_param) log.info('No contact associated to raw {} '.format(raw.raw_msg_id)) processor = UserMailDelivery(user, user.local_identities[0]) # assume one local identity try: obj_message = processor.process_raw(raw.raw_msg_id) except Exception as exc: log.exception(exc) else: log.info('Created message {}'.format(obj_message.message_id))