def db_create_identityaccessrequest_notifications(session, tid, itip, rtip, iar): users = session.query(models.User).filter(models.User.role == u'custodian', models.User.notification == True) for user in users: node = db_admin_serialize_node(session, tid, user.language) context = session.query(models.Context).filter(models.Context.id == itip.context_id, models.Context.tid == tid).one() data = { 'type': 'identity_access_request' } data['user'] = user_serialize_user(session, user, user.language) data['tip'] = serialize_rtip(session, rtip, itip, user.language) data['context'] = admin_serialize_context(session, context, user.language) data['iar'] = serialize_identityaccessrequest(session, iar) data['node'] = db_admin_serialize_node(session, tid, user.language) if data['node']['mode'] != u'whistleblowing.it': data['notification'] = db_get_notification(session, tid, user.language) else: data['notification'] = db_get_notification(session, 1, user.language) subject, body = Templating().get_mail_subject_and_body(data) session.add(models.Mail({ 'address': data['user']['mail_address'], 'subject': subject, 'body': body, 'tid': tid }))
def signup(session, state, tid, request, language): node = config.ConfigFactory(session, 1, 'node') if not node.get_val(u'enable_signup'): raise errors.ForbiddenOperation request['activation_token'] = generateRandomKey(32) request['language'] = language tenant_id = db_preallocate_tenant(session, { 'label': request['subdomain'], 'subdomain': request['subdomain'] }).id signup = models.Signup(request) signup.tid = tenant_id session.add(signup) # We need to send two emails # # The first one is sent to the platform owner with the activation email. # # The second goes to the instance administrators notifying them that a new # platform has been added. signup_dict = serialize_signup(signup) # Email 1 - Activation Link template_vars = { 'type': 'signup', 'node': db_admin_serialize_node(session, 1, language), 'notification': db_get_notification(session, 1, language), 'signup': signup_dict } state.format_and_send_mail(session, 1, {'mail_address': signup.email}, template_vars) # Email 2 - Admin Notification for user_desc in db_get_admin_users(session, 1): template_vars = { 'type': 'admin_signup_alert', 'signup': serialize_signup(signup), 'node': db_admin_serialize_node(session, 1, user_desc['language']), 'notification': db_get_notification(session, 1, user_desc['language']), 'user': user_desc, 'signup': signup_dict } state.format_and_send_mail(session, 1, user_desc, template_vars)
def signup(session, state, tid, request, language): config = ConfigFactory(session, 1) if not config.get_val(u'enable_signup'): raise errors.ForbiddenOperation request['activation_token'] = generateRandomKey(32) request['language'] = language tenant_id = db_preallocate_tenant(session, {'label': request['subdomain'], 'subdomain': request['subdomain']}).id signup = models.Signup(request) signup.tid = tenant_id session.add(signup) # We need to send two emails # # The first one is sent to the platform owner with the activation email. # # The second goes to the instance administrators notifying them that a new # platform has been added. signup_dict = serialize_signup(signup) # Email 1 - Activation Link template_vars = { 'type': 'signup', 'node': db_admin_serialize_node(session, 1, language), 'notification': db_get_notification(session, 1, language), 'signup': signup_dict } state.format_and_send_mail(session, 1, {'mail_address': signup.email}, template_vars) # Email 2 - Admin Notification for user_desc in db_get_admin_users(session, 1): template_vars = { 'type': 'admin_signup_alert', 'node': db_admin_serialize_node(session, 1, user_desc['language']), 'notification': db_get_notification(session, 1, user_desc['language']), 'user': user_desc, 'signup': signup_dict } state.format_and_send_mail(session, 1, user_desc, template_vars)
def get_tip_export(store, user_id, rtip_id): rtip = db_access_rtip(store, user_id, rtip_id) files = [] for rf in store.find(models.ReceiverFile, models.ReceiverFile.receivertip_id == rtip_id): rf.downloads += 1 file_dict = serialize_receiver_file(rf) file_dict['name'] = 'files/' + file_dict['name'] files.append(copy.deepcopy(file_dict)) receiver = rtip.receiver user_language = receiver.user.language export_dict = { 'type': u'export_template', 'node': db_admin_serialize_node(store, user_language), 'notification': db_get_notification(store, user_language), 'tip': serialize_rtip(store, rtip, user_language), 'context': admin_serialize_context(store, rtip.internaltip.context, user_language), 'receiver': admin_serialize_receiver(receiver, user_language), 'comments': db_get_comment_list(rtip), 'messages': db_get_message_list(rtip), 'files': [] } export_template = Templating().format_template(export_dict['notification']['export_template'], export_dict).encode('utf-8') export_dict['files'].append({'buf': export_template, 'name': "data.txt"}) return export_dict
def check_for_expiring_submissions(self, store): threshold = datetime_now() - timedelta( GLSettings.memory_copy.tip_expiration_threshold) for itip in store.find(models.InternalTip, models.InternalTip.expiration_date < threshold): for rtip in itip.receivertips: user = rtip.receiver.user language = user.language node_desc = db_admin_serialize_node(store, language) notification_desc = db_get_notification(store, language) context_desc = admin_serialize_context( store, rtip.internaltip.context, language) receiver_desc = admin_serialize_receiver( rtip.receiver, language) tip_desc = serialize_rtip(store, rtip, user.language) data = { 'type': u'tip_expiration', 'node': node_desc, 'context': context_desc, 'receiver': receiver_desc, 'notification': notification_desc, 'tip': tip_desc } subject, body = Templating().get_mail_subject_and_body(data) mail = models.Mail({ 'address': data['receiver']['mail_address'], 'subject': subject, 'body': body }) store.add(mail)
def get_tip_export(store, user_id, rtip_id, language): rtip = db_access_rtip(store, user_id, rtip_id) receiver = rtip.receiver export_dict = { 'type': u'export_template', 'node': db_admin_serialize_node(store, language), 'notification': db_get_notification(store, language), 'tip': serialize_rtip(store, rtip, language), 'context': admin_serialize_context(store, rtip.internaltip.context, language), 'receiver': admin_serialize_receiver(receiver, language), 'comments': db_get_comment_list(rtip), 'messages': db_get_message_list(rtip), 'files': [] } export_template = Templating().format_template(export_dict['notification']['export_template'], export_dict).encode('utf-8') export_dict['files'].append({'buf': export_template, 'name': "data.txt"}) for rf in store.find(models.ReceiverFile, models.ReceiverFile.receivertip_id == rtip_id): rf.downloads += 1 file_dict = serialize_receiver_file(rf) file_dict['name'] = 'files/' + file_dict['name'] export_dict['files'].append(copy.deepcopy(file_dict)) return export_dict
def evaluate_update_notification(session, state, latest_version): priv_fact = ConfigFactory(session, 1) stored_latest = priv_fact.get_val('latest_version') # Check if the running version is lower than the latest version if parse_version(stored_latest) >= parse_version(latest_version): return Cache.invalidate() priv_fact.set_val('latest_version', latest_version) # Check to reduce number of email notifications of new updates if parse_version(__version__) != parse_version(stored_latest): return for user_desc in db_get_users(session, 1, 'admin'): if not user_desc['notification']: continue lang = user_desc['language'] template_vars = { 'type': 'software_update_available', 'latest_version': latest_version, 'node': db_admin_serialize_node(session, 1, lang), 'notification': db_get_notification(session, 1, lang), 'user': user_desc, } state.format_and_send_mail(session, 1, user_desc, template_vars)
def check_for_expiring_submissions(self, store): threshold = datetime_now() + timedelta(GLSettings.memory_copy.notif.tip_expiration_threshold) for rtip in store.find(models.ReceiverTip, models.ReceiverTip.internaltip_id == models.InternalTip.id, models.InternalTip.expiration_date < threshold): user = rtip.receiver.user language = user.language node_desc = db_admin_serialize_node(store, language) notification_desc = db_get_notification(store, language) context_desc = admin_serialize_context(store, rtip.internaltip.context, language) receiver_desc = admin_serialize_receiver(rtip.receiver, language) tip_desc = serialize_rtip(store, rtip, user.language) data = { 'type': u'tip_expiration', 'node': node_desc, 'context': context_desc, 'receiver': receiver_desc, 'notification': notification_desc, 'tip': tip_desc } subject, body = Templating().get_mail_subject_and_body(data) mail = models.Mail({ 'address': data['receiver']['mail_address'], 'subject': subject, 'body': body }) store.add(mail)
def certificate_mail_creation(self, store, expiration_date): for user_desc in db_get_admin_users(store): lang = user_desc['language'] template_vars = { 'type': 'https_certificate_expiration', 'expiration_date': expiration_date, 'node': db_admin_serialize_node(store, lang), 'notification': db_get_notification(store, lang) } subject, body = Templating().get_mail_subject_and_body( template_vars) # encrypt the notification if the admin has configured the issue. pub_key = user_desc['pgp_key_public'] if len(pub_key) > 0: body = encrypt_pgp_message(pub_key, user_desc['pgp_key_fingerprint'], body) store.add( models.Mail({ 'address': user_desc['mail_address'], 'subject': subject, 'body': body }))
def signup(session, state, tid, request, language): node = config.ConfigFactory(session, 1, 'node') if not node.get_val(u'enable_signup'): raise errors.ForbiddenOperation request['activation_token'] = generateRandomKey(32) request['language'] = language signup = models.Signup(request) session.add(signup) ret = { 'signup': serialize_signup(signup), 'activation_url': 'https://%s/#/activation?token=%s' % (node.get_val(u'rootdomain'), signup.activation_token), 'expiration_date': datetime_to_ISO8601(signup.registration_date + timedelta(days=7)) } template_vars = copy.deepcopy(ret) template_vars.update({ 'type': 'signup', 'node': db_admin_serialize_node(session, 1, language), 'notification': db_get_notification(session, 1, language), }) state.format_and_send_mail(session, 1, {'mail_address': signup.email}, template_vars) return ret
def generate_password_reset_token(session, state, tid, username_or_email, allow_admin_reset=False): from globaleaks.handlers.admin.notification import db_get_notification from globaleaks.handlers.admin.node import db_admin_serialize_node from globaleaks.handlers.user import user_serialize_user users = session.query(models.User).filter( or_(models.User.username == username_or_email, models.User.mail_address == username_or_email), models.UserTenant.user_id == models.User.id, models.UserTenant.tenant_id == tid ).distinct() for user in users: if not allow_admin_reset and user.role == u'admin': continue user.reset_password_token = generateRandomKey(32) user.reset_password_date = datetime_now() user_desc = user_serialize_user(session, user, user.language) template_vars = { 'type': 'password_reset_validation', 'user': user_desc, 'reset_token': user.reset_password_token, 'node': db_admin_serialize_node(session, 1, user.language), 'notification': db_get_notification(session, tid, user.language) } state.format_and_send_mail(session, tid, user_desc, template_vars)
def db_user_update_user(session, state, tid, user_id, request): """ Updates the specified user. This version of the function is specific for users that with comparison with admins can change only few things: - real name - email address - preferred language - the password (with old password check) - pgp key raises: globaleaks.errors.ResourceNotFound` if the receiver does not exist. """ from globaleaks.handlers.admin.notification import db_get_notification from globaleaks.handlers.admin.node import db_admin_serialize_node user = models.db_get(session, models.User, models.User.id == user_id) user.language = request.get('language', State.tenant_cache[tid].default_language) user.name = request['name'] new_password = request['password'] old_password = request['old_password'] if new_password: if user.password_change_needed: user.password_change_needed = False else: if not check_password(old_password, user.salt, user.password): raise errors.InvalidOldPassword user.password = hash_password(new_password, user.salt) user.password_change_date = datetime_now() # If the email address changed, send a validation email if request['mail_address'] != user.mail_address: user.change_email_address = request['mail_address'] user.change_email_date = datetime_now() user.change_email_token = generateRandomKey(32) user_desc = user_serialize_user(session, user, user.language) template_vars = { 'type': 'email_validation', 'user': user_desc, 'new_email_address': request['mail_address'], 'validation_token': user.change_email_token, 'node': db_admin_serialize_node(session, 1, user.language), 'notification': db_get_notification(session, tid, user.language) } state.format_and_send_mail(session, tid, user_desc, template_vars) # If the platform allows users to change PGP keys, process it if State.tenant_cache[tid]['enable_user_pgp_key_upload'] is True: parse_pgp_options(state, user, request) return user
def db_generate_password_reset_token(session, state, tid, username_or_email, allow_admin_reset=False): from globaleaks.handlers.admin.notification import db_get_notification from globaleaks.handlers.admin.node import db_admin_serialize_node from globaleaks.handlers.user import user_serialize_user users = session.query(models.User).filter( or_(models.User.username == username_or_email, models.User.mail_address == username_or_email), models.UserTenant.user_id == models.User.id, models.UserTenant.tenant_id == tid).distinct() for user in users: if not allow_admin_reset and user.role == u'admin': continue user.reset_password_token = generateRandomKey(32) user.reset_password_date = datetime_now() user_desc = user_serialize_user(session, user, user.language) template_vars = { 'type': 'password_reset_validation', 'user': user_desc, 'reset_token': user.reset_password_token, 'node': db_admin_serialize_node(session, 1, user.language), 'notification': db_get_notification(session, tid, user.language) } state.format_and_send_mail(session, tid, user_desc, template_vars)
def generate_password_reset_token(session, state, tid, username_or_email): from globaleaks.handlers.admin.notification import db_get_notification from globaleaks.handlers.admin.node import db_admin_serialize_node from globaleaks.handlers.user import user_serialize_user users = session.query(models.User).filter( or_(models.User.username == username_or_email, models.User.mail_address == username_or_email), models.User.tid == tid).distinct() for user in users: user.reset_password_token = generateRandomKey(32) user.reset_password_date = datetime_now() user_desc = user_serialize_user(session, user, user.language) template_vars = { 'type': 'password_reset_validation', 'user': user_desc, 'reset_token': user.reset_password_token, 'node': db_admin_serialize_node(session, tid, user.language), 'notification': db_get_notification(session, tid, user.language) } state.format_and_send_mail(session, tid, user_desc, template_vars) return {'redirect': '/login/passwordreset/requested'}
def db_generate_password_reset_token(session, user): """ Transaction for issuing password reset tokens :param session: An ORM session :param user: The user for which issuing a password reset token """ user.reset_password_token = generateRandomKey() user.reset_password_date = datetime_now() if user.last_login > datetime_null(): template = 'password_reset_validation' else: template = 'account_activation' user_desc = user_serialize_user(session, user, user.language) template_vars = { 'type': template, 'user': user_desc, 'reset_token': user.reset_password_token, 'node': db_admin_serialize_node(session, user.tid, user.language), 'notification': db_get_notification(session, user.tid, user.language) } State.format_and_send_mail(session, user.tid, user_desc, template_vars)
def process_mail_creation(self, store, data): # https://github.com/globaleaks/GlobaLeaks/issues/798 # TODO: the current solution is global and configurable only by the admin receiver_id = data['receiver']['id'] sent_emails = GLSettings.get_mail_counter(receiver_id) if sent_emails >= GLSettings.memory_copy.notification_threshold_per_hour: log.debug( "Discarding emails for receiver %s due to threshold already exceeded for the current hour" % receiver_id) return GLSettings.increment_mail_counter(receiver_id) if sent_emails >= GLSettings.memory_copy.notification_threshold_per_hour: log.info( "Reached threshold of %d emails with limit of %d for receiver %s" % (sent_emails, GLSettings.memory_copy.notification_threshold_per_hour, receiver_id)) # simply changing the type of the notification causes # to send the notification_limit_reached data['type'] = u'receiver_notification_limit_reached' data['notification'] = db_get_notification( store, data['receiver']['language']) data['node'] = db_admin_serialize_node(store, data['receiver']['language']) if not data['node']['allow_unencrypted'] and data['receiver'][ 'pgp_key_status'] != u'enabled': return subject, body = Templating().get_mail_subject_and_body(data) # If the receiver has encryption enabled encrypt the mail body if data['receiver']['pgp_key_status'] == u'enabled': gpob = GLBPGP() try: gpob.load_key(data['receiver']['pgp_key_public']) body = gpob.encrypt_message( data['receiver']['pgp_key_fingerprint'], body) except Exception as excep: log.err( "Error in PGP interface object (for %s: %s)! (notification+encryption)" % (data['receiver']['username'], str(excep))) return finally: # the finally statement is always called also if # except contains a return or a raise gpob.destroy_environment() mail = models.Mail({ 'address': data['receiver']['mail_address'], 'subject': subject, 'body': body }) store.add(mail)
def process_mail_creation(self, store, data): receiver_id = data['receiver']['id'] # Do not spool emails if the receiver has opted out of ntfns for this tip. if not data['tip']['enable_notifications']: log.debug("Discarding emails for %s due to receiver's preference." % receiver_id) return # https://github.com/globaleaks/GlobaLeaks/issues/798 # TODO: the current solution is global and configurable only by the admin sent_emails = GLSettings.get_mail_counter(receiver_id) if sent_emails >= GLSettings.memory_copy.notification_threshold_per_hour: log.debug("Discarding emails for receiver %s due to threshold already exceeded for the current hour" % receiver_id) return GLSettings.increment_mail_counter(receiver_id) if sent_emails >= GLSettings.memory_copy.notification_threshold_per_hour: log.info("Reached threshold of %d emails with limit of %d for receiver %s" % ( sent_emails, GLSettings.memory_copy.notification_threshold_per_hour, receiver_id) ) # simply changing the type of the notification causes # to send the notification_limit_reached data['type'] = u'receiver_notification_limit_reached' data['notification'] = db_get_notification(store, data['receiver']['language']) data['node'] = db_admin_serialize_node(store, data['receiver']['language']) if not data['node']['allow_unencrypted'] and data['receiver']['pgp_key_status'] != u'enabled': return subject, body = Templating().get_mail_subject_and_body(data) # If the receiver has encryption enabled encrypt the mail body if data['receiver']['pgp_key_status'] == u'enabled': gpob = GLBPGP() try: gpob.load_key(data['receiver']['pgp_key_public']) body = gpob.encrypt_message(data['receiver']['pgp_key_fingerprint'], body) except Exception as excep: log.err("Error in PGP interface object (for %s: %s)! (notification+encryption)" % (data['receiver']['username'], str(excep))) return finally: # the finally statement is always called also if # except contains a return or a raise gpob.destroy_environment() mail = models.Mail({ 'address': data['receiver']['mail_address'], 'subject': subject, 'body': body }) store.add(mail)
def signup_activation(session, state, tid, token, language): node = config.ConfigFactory(session, 1, 'node') if not node.get_val(u'enable_signup'): raise errors.ForbiddenOperation signup = session.query(models.Signup).filter( models.Signup.activation_token == token).one_or_none() if signup is None: return {} if not session.query( models.Config).filter(models.Config.tid == signup.tid).count(): tenant = session.query( models.Tenant).filter(models.Tenant.id == signup.tid).one() mode = node.get_val('mode') db_initialize_tenant(session, tenant, mode) password_admin = generateRandomKey(16) password_recipient = generateRandomKey(16) node_name = signup.organization_name if signup.organization_name else signup.subdomain wizard = { 'node_language': signup.language, 'node_name': node_name, 'admin_name': signup.name + ' ' + signup.surname, 'admin_password': password_admin, 'admin_mail_address': signup.email, 'receiver_name': signup.name + ' ' + signup.surname, 'receiver_password': password_recipient, 'receiver_mail_address': signup.email, 'profile': 'default', 'enable_developers_exception_notification': True } db_wizard(session, state, signup.tid, wizard, False, language) ids = [ r[0] for r in session.query(models.User.id).filter( models.UserTenant.user_id == models.User.id, models.UserTenant.tenant_id == signup.tid) ] template_vars = { 'type': 'activation', 'node': db_admin_serialize_node(session, 1, language), 'notification': db_get_notification(session, 1, language), 'signup': serialize_signup(signup), 'password_admin': password_admin, 'password_recipient': password_recipient } state.format_and_send_mail(session, 1, {'mail_address': signup.email}, template_vars) db_refresh_memory_variables(session, [1])
def get_tip_export(session, tid, user_id, rtip_id, language): rtip, itip = db_access_rtip(session, tid, user_id, rtip_id) user, context = session.query(models.User, models.Context) \ .filter(models.User.id == rtip.receiver_id, models.Context.id == models.InternalTip.context_id, models.InternalTip.id == rtip.internaltip_id, models.User.tid == tid).one() rtip_dict = serialize_rtip(session, rtip, itip, language) export_dict = { 'type': 'export_template', 'node': db_admin_serialize_node(session, tid, language), 'notification': db_get_notification(session, tid, language), 'tip': rtip_dict, 'crypto_tip_prv_key': rtip.crypto_tip_prv_key, 'user': user_serialize_user(session, user, language), 'context': admin_serialize_context(session, context, language), 'comments': rtip_dict['comments'], 'messages': rtip_dict['messages'], 'files': [], 'submission_statuses': db_retrieve_all_submission_statuses(session, tid, language) } for rfile in session.query(models.ReceiverFile).filter( models.ReceiverFile.receivertip_id == rtip_id): rfile.last_access = datetime_now() rfile.downloads += 1 file_dict = models.serializers.serialize_rfile(session, tid, rfile) file_dict['name'] = 'files/' + file_dict['name'] file_dict['path'] = os.path.join(Settings.attachments_path, file_dict['filename']) file_dict['forged'] = False export_dict['files'].append(file_dict) for wf in session.query(models.WhistleblowerFile).filter( models.WhistleblowerFile.receivertip_id == models.ReceiverTip.id, models.ReceiverTip.internaltip_id == rtip.internaltip_id, models.InternalTip.id == rtip.internaltip_id): file_dict = models.serializers.serialize_wbfile(session, tid, wf) file_dict['name'] = 'files_from_recipients/' + file_dict['name'] file_dict['path'] = os.path.join(Settings.attachments_path, file_dict['filename']) file_dict[ 'forged'] = True # To be removed as soon it will be encrypted export_dict['files'].append(file_dict) return export_dict
def db_user_update_user(session, state, tid, user_id, request): """ Updates the specified user. This version of the function is specific for users that with comparison with admins can change only few things: - real name - email address - preferred language - the password (with old password check) - pgp key raises: globaleaks.errors.ResourceNotFound` if the receiver does not exist. """ from globaleaks.handlers.admin.notification import db_get_notification from globaleaks.handlers.admin.node import db_admin_serialize_node from globaleaks.handlers.admin.user import get_user user = models.db_get(session, models.User, models.User.id == user_id, models.User.tid == tid) user.language = request.get('language', State.tenant_cache[tid].default_language) user.name = request['name'] new_password = request['password'] old_password = request['old_password'] if new_password and old_password: user.password = change_password(user.password, old_password, new_password, user.salt) if user.password_change_needed: user.password_change_needed = False user.password_change_date = datetime_now() # If the email address changed, send a validation email if request['mail_address'] != user.mail_address: user.change_email_address = request['mail_address'] user.change_email_date = datetime_now() user.change_email_token = generateRandomKey(32) user_desc = user_serialize_user(session, user, user.language) template_vars = { 'type': 'email_validation', 'user': user_desc, 'new_email_address': request['mail_address'], 'validation_token': user.change_email_token, 'node': db_admin_serialize_node(session, 1, user.language), 'notification': db_get_notification(session, tid, user.language) } state.format_and_send_mail(session, tid, user_desc, template_vars) # We don't directly change user email addresses, if a user # The various options related in manage PGP keys are used here. parse_pgp_options(state, user, request) return user
def db_create_identity_access_reply_notifications(session, itip, rtip, iar): """ Transaction for the creation of notifications related to identity access replies :param session: An ORM session :param itip: A itip ID of the tip involved in the request :param iar: A identity access request model """ from globaleaks.handlers.rtip import serialize_rtip for user in session.query(models.User) \ .filter(models.User.id == rtip.receiver_id, models.User.notification.is_(True)): context = session.query( models.Context).filter(models.Context.id == itip.context_id).one() data = { 'type': 'identity_access_authorized' if iar.reply == 'authorized' else 'identity_access_denied' } data['user'] = user_serialize_user(session, user, user.language) data['tip'] = serialize_rtip(session, rtip, itip, user.language) data['context'] = admin_serialize_context(session, context, user.language) data['iar'] = serialize_identityaccessrequest(session, iar) data['node'] = db_admin_serialize_node(session, user.tid, user.language) if data['node']['mode'] == 'default': data['notification'] = db_get_notification(session, user.tid, user.language) else: data['notification'] = db_get_notification(session, 1, user.language) subject, body = Templating().get_mail_subject_and_body(data) session.add( models.Mail({ 'address': data['user']['mail_address'], 'subject': subject, 'body': body, 'tid': user.tid }))
def db_user_update_user(session, tid, user_session, request): """ Transaction for updating an existing user :param session: An ORM session :param tid: A tenant ID :param user_session: A session of the user invoking the transaction :param request: A user request data :return: A user model """ from globaleaks.handlers.admin.notification import db_get_notification from globaleaks.handlers.admin.node import db_admin_serialize_node user = models.db_get(session, models.User, models.User.id == user_session.user_id) user.language = request.get('language', State.tenant_cache[tid].default_language) user.name = request['name'] user.public_name = request['public_name'] if request[ 'public_name'] else request['name'] if request['password']: if user.password_change_needed: user.password_change_needed = False else: if not GCE.check_password(user.hash_alg, request['old_password'], user.salt, user.password): raise errors.InvalidOldPassword user_session.cc = set_user_password(tid, user, request['password'], user_session.cc) # If the email address changed, send a validation email if request['mail_address'] != user.mail_address: user.change_email_address = request['mail_address'] user.change_email_date = datetime_now() user.change_email_token = generateRandomKey() user_desc = user_serialize_user(session, user, user.language) user_desc['mail_address'] = request['mail_address'] template_vars = { 'type': 'email_validation', 'user': user_desc, 'new_email_address': request['mail_address'], 'validation_token': user.change_email_token, 'node': db_admin_serialize_node(session, tid, user.language), 'notification': db_get_notification(session, tid, user.language) } State.format_and_send_mail(session, tid, user_desc, template_vars) parse_pgp_options(user, request) return user
def login(session, tid, username, password, authcode, client_using_tor, client_ip): """ login returns a session """ user = None users = session.query(User).filter(User.username == username, User.state != u'disabled', UserTenant.user_id == User.id, UserTenant.tenant_id == tid).distinct() for u in users: if GCE.check_password(u.hash_alg, password, u.salt, u.password): user = u break if user is None: log.debug("Login: Invalid credentials") Settings.failed_login_attempts += 1 raise errors.InvalidAuthentication connection_check(client_ip, tid, user.role, client_using_tor) if State.tenant_cache[ 1].two_factor_auth and user.last_login != datetime_null(): token = TwoFactorTokens.get(user.id) if token is not None and authcode != '': if token.token == authcode: TwoFactorTokens.revoke(user.id) else: raise errors.InvalidTwoFactorAuthCode elif token is None and authcode == '': token = TwoFactorTokens.new(user.id) data = {'type': '2fa', 'authcode': str(token.token)} data['node'] = db_admin_serialize_node(session, tid, user.language) data['notification'] = db_get_notification(session, tid, user.language) subject, body = Templating().get_mail_subject_and_body(data) State.sendmail(1, user.mail_address, subject, body) raise errors.TwoFactorAuthCodeRequired else: raise errors.TwoFactorAuthCodeRequired user.last_login = datetime_now() crypto_prv_key = '' if State.tenant_cache[1].encryption and user.crypto_prv_key: user_key = GCE.derive_key(password.encode('utf-8'), user.salt) crypto_prv_key = GCE.symmetric_decrypt(user_key, user.crypto_prv_key) return Sessions.new(tid, user.id, user.role, user.password_change_needed, crypto_prv_key)
def get_tip_export(session, tid, user_id, rtip_id, language): rtip, itip = db_access_rtip(session, tid, user_id, rtip_id) user, context = session.query(models.User, models.Context) \ .filter(models.User.id == rtip.receiver_id, models.Context.id == models.InternalTip.context_id, models.InternalTip.id == rtip.internaltip_id, models.UserTenant.user_id == models.User.id, models.UserTenant.tenant_id == tid).one() rtip_dict = serialize_rtip(session, rtip, itip, language) export_dict = { 'type': u'export_template', 'node': db_admin_serialize_node(session, tid, language), 'notification': db_get_notification(session, tid, language), 'tip': rtip_dict, 'user': user_serialize_user(session, user, language), 'context': admin_serialize_context(session, context, language), 'comments': rtip_dict['comments'], 'messages': rtip_dict['messages'], 'files': [] } export_template = Templating().format_template( export_dict['notification']['export_template'], export_dict).encode('utf-8') export_template = msdos_encode(text_type(export_template, 'utf-8')).encode('utf-8') export_dict['files'].append({ 'fo': BytesIO(export_template), 'name': "data.txt" }) for rfile in session.query(models.ReceiverFile).filter( models.ReceiverFile.receivertip_id == rtip_id): rfile.last_access = datetime_now() rfile.downloads += 1 file_dict = models.serializers.serialize_rfile(session, tid, rfile) file_dict['name'] = 'files/' + file_dict['name'] file_dict['path'] = os.path.join(Settings.attachments_path, file_dict['filename']) export_dict['files'].append(file_dict) for wf in session.query(models.WhistleblowerFile).filter( models.WhistleblowerFile.receivertip_id == models.ReceiverTip.id, models.ReceiverTip.internaltip_id == rtip.internaltip_id, models.InternalTip.id == rtip.internaltip_id): file_dict = models.serializers.serialize_wbfile(session, tid, wf) file_dict['name'] = 'files_from_recipients/' + file_dict['name'] file_dict['path'] = os.path.join(Settings.attachments_path, file_dict['filename']) export_dict['files'].append(file_dict) return export_dict
def db_create_identityaccessrequest_notifications(session, tid, itip, rtip, iar): """ Transaction for the creation of notifications related to identity access requests :param session: An ORM session :param tid: A tenant ID on which the request is issued :param itip: A itip ID of the tip involved in the request :param rtip: A rtip ID of the rtip involved in the request :param iar: A identity access request model """ for user in session.query(models.User).filter( models.User.role == 'custodian', models.User.tid == tid, models.User.notification.is_(True)): context = session.query(models.Context).filter( models.Context.id == itip.context_id, models.Context.tid == tid).one() data = {'type': 'identity_access_request'} data['user'] = user_serialize_user(session, user, user.language) data['tip'] = serialize_rtip(session, rtip, itip, user.language) data['context'] = admin_serialize_context(session, context, user.language) data['iar'] = serialize_identityaccessrequest(session, iar) data['node'] = db_admin_serialize_node(session, tid, user.language) if data['node']['mode'] == 'default': data['notification'] = db_get_notification(session, tid, user.language) else: data['notification'] = db_get_notification(session, 1, user.language) subject, body = Templating().get_mail_subject_and_body(data) session.add( models.Mail({ 'address': data['user']['mail_address'], 'subject': subject, 'body': body, 'tid': tid }))
def signup_activation(session, state, tid, token, language): node = config.ConfigFactory(session, 1, 'node') if not node.get_val(u'enable_signup'): raise errors.ForbiddenOperation signup = session.query(models.Signup).filter(models.Signup.activation_token == token).one_or_none() if signup is None: return {} if signup.tid is None: signup.tid = db_create_tenant(session, {'label': signup.subdomain, 'subdomain': signup.subdomain}).id wizard = { 'node_name': signup.subdomain, 'admin_name': signup.name + ' ' + signup.surname, 'admin_password': '', 'admin_mail_address': signup.email, 'receiver_name': signup.name + ' ' + signup.surname, 'receiver_mail_address': signup.email, 'profile': 'default', 'enable_developers_exception_notification': True } db_wizard(session, state, signup.tid, wizard, False, language) template_vars = { 'type': 'activation', 'node': db_admin_serialize_node(session, 1, language), 'notification': db_get_notification(session, 1, language), 'signup': serialize_signup(signup), 'activation_url': '', 'expiration_date': datetime_to_ISO8601(signup.registration_date + timedelta(days=7)) } state.format_and_send_mail(session, 1, {'mail_address': signup.email}, template_vars) if session.query(models.Tenant).filter(models.Tenant.id == signup.tid).one_or_none() is not None: admin = session.query(models.User).filter(models.User.tid == signup.tid, models.User.role == u'admin').one() admin.password_change_needed = False recipient = session.query(models.User).filter(models.User.tid == signup.tid, models.User.role == u'receiver').one() recipient.password_change_needed = False return { 'platform_url': 'https://%s.%s' % (signup.subdomain, node.get_val(u'rootdomain')), 'login_url': 'https://%s.%s/#/login' % (signup.subdomain, node.get_val(u'rootdomain')), 'admin_login_url': 'https://%s.%s/#/login?token=%s' % (signup.subdomain, node.get_val(u'rootdomain'), admin.auth_token), 'recipient_login_url': 'https://%s.%s/#/login?token=%s' % (signup.subdomain, node.get_val(u'rootdomain'), recipient.auth_token), 'expiration_date': datetime_to_ISO8601(signup.registration_date + timedelta(days=7)) } else: return {}
def prepare_user_pgp_alerts(self, store, user_desc): user_language = user_desc['language'] data = { 'address': user_desc['mail_address'], 'type': u'pgp_alert', 'node': db_admin_serialize_node(store, user_language), 'notification': db_get_notification(store, user_language), 'user': user_desc } Templating().db_prepare_mail(store, data)
def serialize_config(self, store, key, language): cache_key = key + '-' + language if cache_key not in self.cache: if key == 'node': cache_obj = db_admin_serialize_node(store, language) elif key == 'notification': cache_obj = db_get_notification(store, language) self.cache[cache_key] = cache_obj return self.cache[cache_key]
def certificate_mail_creation(self, store, expiration_date): for user_desc in db_get_admin_users(store): lang = user_desc['language'] template_vars = { 'type': 'https_certificate_expiration', 'expiration_date': expiration_date, 'node': db_admin_serialize_node(store, lang), 'notification': db_get_notification(store, lang) } format_and_send(store, user_desc, template_vars)
def get_tip_export(store, user_id, rtip_id, language): rtip = db_access_rtip(store, user_id, rtip_id) receiver = rtip.receiver rtip_dict = serialize_rtip(store, rtip, language) export_dict = { 'type': u'export_template', 'node': db_admin_serialize_node(store, language), 'notification': db_get_notification(store, language), 'tip': serialize_rtip(store, rtip, language), 'context': admin_serialize_context(store, rtip.internaltip.context, language), 'receiver': admin_serialize_receiver(store, receiver, language), 'comments': rtip_dict['comments'], 'messages': rtip_dict['messages'], 'files': [] } export_template = Templating().format_template( export_dict['notification']['export_template'], export_dict).encode('utf-8') export_template = msdos_encode(export_template) export_dict['files'].append({'buf': export_template, 'name': "data.txt"}) for rf in store.find(models.ReceiverFile, models.ReceiverFile.receivertip_id == rtip_id): rf.downloads += 1 file_dict = models.serializers.serialize_rfile(rf) file_dict['name'] = 'files/' + file_dict['name'] export_dict['files'].append(file_dict) rtips_ids = [rt.id for rt in rtip.internaltip.receivertips] wfs = store.find(models.WhistleblowerFile, In(models.WhistleblowerFile.receivertip_id, rtips_ids)) for wf in wfs: file_dict = models.serializers.serialize_wbfile(wf) file_dict['name'] = 'files_from_recipients/' + file_dict['name'] export_dict['files'].append(file_dict) return export_dict
def signup_activation(session, state, tid, token, language): config = ConfigFactory(session, 1) if not config.get_val(u'enable_signup'): raise errors.ForbiddenOperation signup = session.query(models.Signup).filter(models.Signup.activation_token == token).one_or_none() if signup is None: return {} if not session.query(models.Config).filter(models.Config.tid == signup.tid).count(): tenant = session.query(models.Tenant).filter(models.Tenant.id == signup.tid).one() mode = config.get_val('mode') db_initialize_tenant(session, tenant, mode) password_admin = generateRandomKey(16) password_recipient = generateRandomKey(16) node_name = signup.organization_name if signup.organization_name else signup.subdomain wizard = { 'node_language': signup.language, 'node_name': node_name, 'admin_name': signup.name + ' ' + signup.surname, 'admin_password': password_admin, 'admin_mail_address': signup.email, 'receiver_name': signup.name + ' ' + signup.surname, 'receiver_password': password_recipient, 'receiver_mail_address': signup.email, 'profile': 'default', 'enable_developers_exception_notification': True } db_wizard(session, signup.tid, wizard, False, language) ids = [r[0] for r in session.query(models.User.id).filter(models.UserTenant.user_id == models.User.id, models.UserTenant.tenant_id == signup.tid)] template_vars = { 'type': 'activation', 'node': db_admin_serialize_node(session, 1, language), 'notification': db_get_notification(session, 1, language), 'signup': serialize_signup(signup), 'password_admin': password_admin, 'password_recipient': password_recipient } state.format_and_send_mail(session, 1, {'mail_address': signup.email}, template_vars) db_refresh_memory_variables(session, [1])
def serialize_config(self, session, key, tid, language): cache_key = gen_cache_key(key, tid, language) cache_obj = None if cache_key not in self.cache: if key == 'node': cache_obj = db_admin_serialize_node(session, tid, language) elif key == 'notification': cache_obj = db_get_notification(session, tid, language) self.cache[cache_key] = cache_obj return self.cache[cache_key]
def _generate_admin_alert_mail(store, alert): for user_desc in db_get_admin_users(store): user_language = user_desc['language'] data = { 'address': user_desc['mail_address'], 'type': u'admin_anomaly', 'node': db_admin_serialize_node(store, user_language), 'notification': db_get_notification(store, user_language), 'alert': alert } Templating().db_prepare_mail(store, data)
def prepare_user_pgp_alerts(self, store, user_desc): user_language = user_desc['language'] data = { 'type': u'pgp_alert', 'node': db_admin_serialize_node(store, user_language), 'notification': db_get_notification(store, user_language), 'user': user_desc } subject, body = Templating().get_mail_subject_and_body(data) db_schedule_email(store, user_desc['mail_address'], subject, body)
def prepare_user_pgp_alerts(self, session, tid, user_desc): user_language = user_desc['language'] data = { 'type': u'pgp_alert', 'node': db_admin_serialize_node(session, tid, user_language), 'notification': db_get_notification(session, tid, user_language), 'user': user_desc } subject, body = Templating().get_mail_subject_and_body(data) db_schedule_email(session, tid, user_desc['mail_address'], subject, body)
def certificate_mail_creation(self, session, mail_type, tid, expiration_date): for user_desc in db_get_admin_users(session, tid): lang = user_desc['language'] template_vars = { 'type': mail_type, 'node': db_admin_serialize_node(session, tid, lang), 'notification': db_get_notification(session, tid, lang), 'expiration_date': expiration_date, 'user': user_desc, } self.state.format_and_send_mail(session, tid, user_desc, template_vars)
def prepare_admin_pgp_alerts(self, store, expired_or_expiring): for user_desc in db_get_admin_users(store): user_language = user_desc['language'] data = { 'address': user_desc['mail_address'], 'type': u'admin_pgp_alert', 'node': db_admin_serialize_node(store, user_language), 'notification': db_get_notification(store, user_language), 'users': expired_or_expiring } Templating().db_prepare_mail(store, data)
def generate_admin_alert_mail(session, tid, alert): for user_desc in db_get_admin_users(session, tid): user_language = user_desc['language'] data = { 'type': u'admin_anomaly', 'node': db_admin_serialize_node(session, tid, user_language), 'notification': db_get_notification(session, tid, user_language), 'alert': alert, 'user': user_desc, } subject, body = Templating().get_mail_subject_and_body(data) db_schedule_email(session, tid, user_desc['mail_address'], subject, body)
def get_tip_export(store, user_id, rtip_id, language): rtip = db_access_rtip(store, user_id, rtip_id) receiver = rtip.receiver rtip_dict = serialize_rtip(store, rtip, language) export_dict = { 'type': u'export_template', 'node': db_admin_serialize_node(store, language), 'notification': db_get_notification(store, language), 'tip': serialize_rtip(store, rtip, language), 'context': admin_serialize_context(store, rtip.internaltip.context, language), 'receiver': admin_serialize_receiver(receiver, language), 'comments': rtip_dict['comments'], 'messages': rtip_dict['messages'], 'files': [] } export_template = Templating().format_template(export_dict['notification']['export_template'], export_dict).encode('utf-8') export_template = msdos_encode(export_template) export_dict['files'].append({'buf': export_template, 'name': "data.txt"}) for rf in store.find(models.ReceiverFile, models.ReceiverFile.receivertip_id == rtip_id): rf.downloads += 1 file_dict = models.serializers.serialize_rfile(rf) file_dict['name'] = 'files/' + file_dict['name'] export_dict['files'].append(copy.deepcopy(file_dict)) rtips_ids = [rt.id for rt in rtip.internaltip.receivertips] wfs = store.find(models.WhistleblowerFile, In(models.WhistleblowerFile.receivertip_id, rtips_ids)) for wf in wfs: file_dict = models.serializers.serialize_wbfile(wf) file_dict['name'] = 'files_from_recipients/' + file_dict['name'] export_dict['files'].append(copy.deepcopy(file_dict)) return export_dict
def evaluate_update_notification(session, state, latest_version): priv_fact = ConfigFactory(session, 1) stored_latest = priv_fact.get_val(u'latest_version') if V(stored_latest) < V(latest_version): priv_fact.set_val(u'latest_version', latest_version) if V(__version__) == V(latest_version): return for user_desc in db_get_admin_users(session, 1): lang = user_desc['language'] template_vars = { 'type': 'software_update_available', 'latest_version': latest_version, 'node': db_admin_serialize_node(session, 1, lang), 'notification': db_get_notification(session, 1, lang), 'user': user_desc, } state.format_and_send_mail(session, 1, user_desc, template_vars)
def db_check_for_expiring_submissions(self, session): for tid in self.state.tenant_state: threshold = datetime_now() + timedelta(hours=self.state.tenant_cache[tid].notification.tip_expiration_threshold) for user in session.query(models.User).filter(models.User.role == u'receiver', models.UserTenant.user_id == models.User.id, models.UserTenant.tenant_id == tid): itip_ids = [id[0] for id in session.query(models.InternalTip.id) .filter(models.InternalTip.tid == tid, models.ReceiverTip.internaltip_id == models.InternalTip.id, models.InternalTip.expiration_date < threshold, models.ReceiverTip.receiver_id == user.id)] if not len(itip_ids): continue earliest_expiration_date = session.query(func.min(models.InternalTip.expiration_date)) \ .filter(models.InternalTip.id.in_(itip_ids)).one()[0] user_desc = user_serialize_user(session, user, user.language) data = { 'type': u'tip_expiration_summary', 'node': db_admin_serialize_node(session, tid, user.language), 'notification': db_get_notification(session, tid, user.language), 'user': user_desc, 'expiring_submission_count': len(itip_ids), 'earliest_expiration_date': datetime_to_ISO8601(earliest_expiration_date) } subject, body = Templating().get_mail_subject_and_body(data) session.add(models.Mail({ 'tid': tid, 'address': user_desc['mail_address'], 'subject': subject, 'body': body }))
def get_file_collection(store, user_id, rtip_id): rtip = db_access_rtip(store, user_id, rtip_id) archive_dict = {'files': [], 'file_counter': 0, 'total_size': 0} file_list = [] for rf in store.find(models.ReceiverFile, models.ReceiverFile.receivertip_id == rtip_id): rf.downloads += 1 file_list.append(serialize_receiver_file(rf)) archive_dict['file_counter'] += 1 archive_dict['total_size'] += rf.size archive_dict['files'].append(serialize_receiver_file(rf)) receiver = rtip.receiver user_language = receiver.user.language data = { 'type': u'archive_description', 'node': db_admin_serialize_node(store, user_language), 'notification': db_get_notification(store, user_language), 'tip': serialize_rtip(store, rtip, user_language), 'context': admin_serialize_context(store, rtip.internaltip.context, user_language), 'receiver': admin_serialize_receiver(receiver, user_language), 'archive': archive_dict } archive_description = Templating().format_template(data['notification']['archive_description'], data).encode('utf-8') file_list.append( { 'buf': archive_description, 'name': "COLLECTION_INFO.txt" } ) return file_list
def db_user_update_user(session, tid, user_session, request): """ Updates the specified user. This version of the function is specific for users that with comparison with admins can change only few things: - real name - email address - preferred language - the password (with old password check) - pgp key raises: globaleaks.errors.ResourceNotFound` if the receiver does not exist. """ from globaleaks.handlers.admin.notification import db_get_notification from globaleaks.handlers.admin.node import db_admin_serialize_node user = models.db_get(session, models.User, models.User.id == user_session.user_id) user.language = request.get('language', State.tenant_cache[tid].default_language) user.name = request['name'] new_password = request['password'] old_password = request['old_password'] if new_password: if user.password_change_needed: user.password_change_needed = False else: if not GCE.check_password(user.hash_alg, old_password, user.salt, user.password): raise errors.InvalidOldPassword user.hash_alg = GCE.HASH user.salt = GCE.generate_salt() user.password = GCE.hash_password(new_password, user.salt) user.password_change_date = datetime_now() if State.tenant_cache[1].encryption: enc_key = GCE.derive_key(request['password'].encode(), user.salt) if not user_session.cc: user_session.cc, user.crypto_pub_key = GCE.generate_keypair() user.crypto_prv_key = GCE.symmetric_encrypt(enc_key, user_session.cc) # If the email address changed, send a validation email if request['mail_address'] != user.mail_address: user.change_email_address = request['mail_address'] user.change_email_date = datetime_now() user.change_email_token = generateRandomKey(32) user_desc = user_serialize_user(session, user, user.language) template_vars = { 'type': 'email_validation', 'user': user_desc, 'new_email_address': request['mail_address'], 'validation_token': user.change_email_token, 'node': db_admin_serialize_node(session, 1, user.language), 'notification': db_get_notification(session, tid, user.language) } State.format_and_send_mail(session, tid, user_desc, template_vars) # If the platform allows users to change PGP keys, process it if State.tenant_cache[tid]['enable_user_pgp_key_upload'] is True: parse_pgp_options(user, request) return user
def login(session, tid, username, password, authcode, client_using_tor, client_ip): """ login returns a session """ user = None users = session.query(User).filter(User.username == username, User.state != u'disabled', UserTenant.user_id == User.id, UserTenant.tenant_id == tid).distinct() for u in users: if GCE.check_password(u.hash_alg, password, u.salt, u.password): user = u break # Fix for issue: https://github.com/globaleaks/GlobaLeaks/issues/2563 if State.tenant_cache[1].creation_date < datetime.timestamp(datetime(2019, 5, 3, 0, 0)): u_password = '******'' + u.password + '\'' if GCE.check_password(u.hash_alg, password, u.salt, u_password): user = u break if user is None: log.debug("Login: Invalid credentials") Settings.failed_login_attempts += 1 raise errors.InvalidAuthentication connection_check(client_ip, tid, user.role, client_using_tor) if State.tenant_cache[1].two_factor_auth and user.last_login != datetime_null(): token = TwoFactorTokens.get(user.id) if token is not None and authcode != '': if token.token == authcode: TwoFactorTokens.revoke(user.id) else: raise errors.InvalidTwoFactorAuthCode elif token is None and authcode == '': token = TwoFactorTokens.new(user.id) data = { 'type': '2fa', 'authcode': str(token.token) } data['node'] = db_admin_serialize_node(session, tid, user.language) data['notification'] = db_get_notification(session, tid, user.language) subject, body = Templating().get_mail_subject_and_body(data) State.sendmail(1, user.mail_address, subject, body) raise errors.TwoFactorAuthCodeRequired else: raise errors.TwoFactorAuthCodeRequired user.last_login = datetime_now() crypto_prv_key = '' if State.tenant_cache[1].encryption and user.crypto_prv_key: user_key = GCE.derive_key(password.encode('utf-8'), user.salt) crypto_prv_key = GCE.symmetric_decrypt(user_key, user.crypto_prv_key) return Sessions.new(tid, user.id, user.role, user.password_change_needed, crypto_prv_key)