def return_to_parent_directory(update, context): """ Moving user back to parent directory of current directory """ current_directory = Directory.objects.get( name=context.chat_data.get('current_directory'), user_id=Directory.encrypt_user_id(update.effective_user.id)) parent_directory = Directory.objects.get( contains_directories=current_directory, user_id=Directory.encrypt_user_id(update.effective_user.id)) def __handle_successfully_switched(): context.chat_data['current_directory'] = parent_directory.name update.message.reply_text( f"You now switched to directory {parent_directory.name}") def __handle_dir_with_no_parents(): if current_directory.name != ROOT_DIRECTORY: context.chat_data['current_directory'] = ROOT_DIRECTORY logger.error( f"Unexpected accident: directory {current_directory.name} " f"doesn't have a parent directory. User were redirected to root directory" ) update.message.reply_text(f"You now in the root directory") if parent_directory: __handle_successfully_switched() else: __handle_dir_with_no_parents()
def directory(): dirs = Directory.query.filter_by(user_id=current_user.id).all() new_dir_form = NewDirForm() if request.method == "POST": if request.form.get("form-name") == "delete": dir_id = request.form.get("dir-id") dir = Directory.get(dir_id) if not dir: flash("Unknown error. Refresh the page", "warning") return redirect(url_for("dashboard.directory")) elif dir.user_id != current_user.id: flash("You cannot delete this directory", "warning") return redirect(url_for("dashboard.directory")) name = dir.name Directory.delete(dir_id) db.session.commit() flash(f"Directory {name} has been deleted", "success") return redirect(url_for("dashboard.directory")) elif request.form.get("form-name") == "create": if not current_user.is_premium(): flash("Only premium plan can add directory", "warning") return redirect(url_for("dashboard.directory")) if new_dir_form.validate(): new_dir_name = new_dir_form.name.data.lower() if Directory.get_by(name=new_dir_name): flash(f"{new_dir_name} already added", "warning") elif new_dir_name == "reply": flash( "directory name cannot be *reply*, please choose another name", "warning", ) else: new_dir = Directory.create(name=new_dir_name, user_id=current_user.id) db.session.commit() flash(f"Directory {new_dir.name} is created", "success") return redirect(url_for("dashboard.directory")) return render_template( "dashboard/directory.html", dirs=dirs, new_dir_form=new_dir_form, EMAIL_DOMAIN=EMAIL_DOMAIN, ALIAS_DOMAINS=ALIAS_DOMAINS, )
def test_delete_directory(flask_client): """cannot add domain if user personal email uses this domain""" user = login(flask_client) directory = Directory.create(name="test", user_id=user.id, commit=True) r = flask_client.post( url_for("dashboard.directory"), data={"form-name": "delete", "dir-id": directory.id}, follow_redirects=True, ) assert r.status_code == 200 assert f"Directory test has been deleted" in r.data.decode() assert Directory.get_by(name="test") is None
def start(update, context): logger.info('New user joined') root_directory = Directory.objects.get( name=ROOT_DIRECTORY, user_id=Directory.encrypt_user_id(update.effective_user.id)) if root_directory: pass else: Directory(name=ROOT_DIRECTORY, user_id=update.effective_user.id).save() update.message.reply_text( 'Welcome to Telegram Cloud bot. I will help you to store an manage your photos. ' 'Now you are in a root directory. ' 'You can upload your photos here, or create you on directories to ' 'store your files im more manageable way')
def edit_album(id): ''' Edit album ''' form = EditAlbumForm(prefix='form1') directory_form = AddDirectoryForm(prefix='form2') album = Album.query.get_or_404(id) if form.submit.data and form.validate_on_submit(): album.title = form.title.data album.description = form.description.data album.hidden = form.hidden.data db.session.add(album) db.session.commit() flash(gettext('\'%(album)s\' album edited', album=album.title)) return redirect(url_for('.album', id=album.id)) if directory_form.submit.data and directory_form.validate_on_submit(): directory = Directory(album=album, path=directory_form.path.data) db.session.add(directory) db.session.commit() flash(gettext('\'%(directory)s\' directory added to \'%(album)s\'', directory=directory.path, album=album.title)) return redirect(url_for('.edit_album', id=album.id)) form.title.data = album.title form.description.data = album.description form.hidden.data = album.hidden return render_template('edit_album.html', album=album, form=form, directory_form = directory_form)
def test_create_directory_out_of_quota(flask_client): user = login(flask_client) for i in range(MAX_NB_DIRECTORY): Directory.create(name=f"test{i}", user_id=user.id, commit=True) assert Directory.count() == MAX_NB_DIRECTORY flask_client.post( url_for("dashboard.directory"), data={"form-name": "create", "name": "test"}, follow_redirects=True, ) # no new directory is created assert Directory.count() == MAX_NB_DIRECTORY
def projects(user_id: int = None, username: str = None) -> Tuple[Any, int]: user = get_user( user_id if user_id else username.lower() if username else None) if not user: return make_resp(NOT_FOUND) if request.method == "GET": return jsonify(data=project_schema.dump(Project.query.filter( Project.user_id == user.id).all(), many=True)), 200 elif request.method == "POST": if get_user() is None: return make_resp(UNAUTHORIZED) if not request.is_json: return make_resp(NO_JSON) try: project = project_schema.load(request.get_json()) project.user = get_user() project.root_directory = Directory(name="root") project.root_directory.block_files = [ BlockFile(name="app.py", block_xml="") ] project.last_modified = datetime.datetime.utcnow() except ValidationError as errors: return errors.messages, 422 db.session.add(project) db.session.commit() return jsonify(data=project_schema.dump(project)), 200
def try_auto_create_directory(address: str) -> Optional[Alias]: """ Try to create an alias with directory """ # check if alias belongs to a directory, ie having directory/anything@EMAIL_DOMAIN format if email_belongs_to_alias_domains(address): # if there's no directory separator in the alias, no way to auto-create it if "/" not in address and "+" not in address and "#" not in address: return None # alias contains one of the 3 special directory separator: "/", "+" or "#" if "/" in address: sep = "/" elif "+" in address: sep = "+" else: sep = "#" directory_name = address[:address.find(sep)] LOG.d("directory_name %s", directory_name) directory = Directory.get_by(name=directory_name) if not directory: return None dir_user: User = directory.user if not dir_user.can_create_new_alias(): send_cannot_create_directory_alias(dir_user, address, directory_name) return None try: LOG.d("create alias %s for directory %s", address, directory) mailboxes = directory.mailboxes alias = Alias.create( email=address, user_id=directory.user_id, directory_id=directory.id, mailbox_id=mailboxes[0].id, ) db.session.flush() for i in range(1, len(mailboxes)): AliasMailbox.create( alias_id=alias.id, mailbox_id=mailboxes[i].id, ) db.session.commit() return alias except AliasInTrashError: LOG.warning( "Alias %s was deleted before, cannot auto-create using directory %s, user %s", address, directory_name, dir_user, ) return None
def process_keyboard(update, context): """ A callback for go_to_directory() and remove_directory() methods, that perform directory change to selected one """ query = update.callback_query action, directory = query.data.split(',') current_directory = Directory.objects.get( name=context.chat_data.get('current_directory'), user_id=Directory.encrypt_user_id(update.effective_user.id)) def _goto_handler(directory_name): if current_directory.has_subdirectory( directory_name, Directory.encrypt_user_id(update.effective_user.id)): context.chat_data['current_directory'] = directory_name query.answer() query.edit_message_text( text=f"You now switched to directory {directory_name}") else: context.chat_data['current_directory'] = ROOT_DIRECTORY logger.error( f"Unexpected accident: <directory.has_subdirectory> returned False for directory " f"{directory_name}. current_directory={current_directory}, action={action}, " f"directory={directory_name}. User were redirected to root directory" ) query.edit_message_text( f"Wow, you've broke me somehow..\nSo i switched you to root directory" ) def _delete_handler(directory_name): if current_directory.has_subdirectory( directory_name, Directory.encrypt_user_id(update.effective_user.id)): subdirectory = Directory.objects.get( name=directory_name, user_id=Directory.encrypt_user_id( update.effective_user.id)) subdirectory.delete() query.edit_message_text( f"The directory '{directory_name}' and it's files are successfully deleted from current " f"{current_directory.name} directory") else: query.edit_message_text( f"Seems, the directory '{directory_name}' is already deleted" ) if directory == CANCEL_BUTTON: query.edit_message_text(text=f"Operation were canceled") else: action_map = { DIRECTORY_ACTIONS['goto']: _goto_handler, DIRECTORY_ACTIONS['delete']: _delete_handler, } handler = action_map[action] handler(directory)
def _delete_handler(directory_name): if current_directory.has_subdirectory( directory_name, Directory.encrypt_user_id(update.effective_user.id)): subdirectory = Directory.objects.get( name=directory_name, user_id=Directory.encrypt_user_id( update.effective_user.id)) subdirectory.delete() query.edit_message_text( f"The directory '{directory_name}' and it's files are successfully deleted from current " f"{current_directory.name} directory") else: query.edit_message_text( f"Seems, the directory '{directory_name}' is already deleted" )
def create_directory(update, context, name): """ Create new directory in the current one :param update: Telegram chat data :param context: Telegram chat data :param name: name of a directory to be created """ name = name[0] # check if directory exists if Directory.exists( name, Directory.encrypt_user_id(update.effective_user.id)): update.message.reply_text(f"The directory '{name}' already exists") else: # create new directory new_directory = Directory(name=name, user_id=update.effective_user.id) new_directory.save() # add new directory as a sub directory to current_directory current_directory = Directory.objects.get( name=context.chat_data.get('current_directory'), user_id=Directory.encrypt_user_id(update.effective_user.id)) current_directory.update( add_to_set__contains_directories=new_directory) current_directory.save() update.message.reply_text( f"The directory '{name}' is successfully created and saved in {current_directory.name} directory" )
def compute_metric2() -> Metric2: now = arrow.now() _24h_ago = now.shift(days=-1) nb_referred_user_paid = 0 for user in User.filter(User.referral_id.isnot(None)): if user.is_paid(): nb_referred_user_paid += 1 return Metric2.create( date=now, # user stats nb_user=User.count(), nb_activated_user=User.filter_by(activated=True).count(), # subscription stats nb_premium=Subscription.filter( Subscription.cancelled.is_(False)).count(), nb_cancelled_premium=Subscription.filter( Subscription.cancelled.is_(True)).count(), # todo: filter by expires_date > now nb_apple_premium=AppleSubscription.count(), nb_manual_premium=ManualSubscription.filter( ManualSubscription.end_at > now, ManualSubscription.is_giveaway.is_(False), ).count(), nb_coinbase_premium=CoinbaseSubscription.filter( CoinbaseSubscription.end_at > now).count(), # referral stats nb_referred_user=User.filter(User.referral_id.isnot(None)).count(), nb_referred_user_paid=nb_referred_user_paid, nb_alias=Alias.count(), # email log stats nb_forward_last_24h=EmailLog.filter( EmailLog.created_at > _24h_ago).filter_by(bounced=False, is_spam=False, is_reply=False, blocked=False).count(), nb_bounced_last_24h=EmailLog.filter( EmailLog.created_at > _24h_ago).filter_by(bounced=True).count(), nb_total_bounced_last_24h=Bounce.filter( Bounce.created_at > _24h_ago).count(), nb_reply_last_24h=EmailLog.filter( EmailLog.created_at > _24h_ago).filter_by(is_reply=True).count(), nb_block_last_24h=EmailLog.filter( EmailLog.created_at > _24h_ago).filter_by(blocked=True).count(), # other stats nb_verified_custom_domain=CustomDomain.filter_by( verified=True).count(), nb_subdomain=CustomDomain.filter_by(is_sl_subdomain=True).count(), nb_directory=Directory.count(), nb_deleted_directory=DeletedDirectory.count(), nb_deleted_subdomain=DeletedSubdomain.count(), nb_app=Client.count(), commit=True, )
def test_create_directory(flask_client): login(flask_client) r = flask_client.post( url_for("dashboard.directory"), data={"form-name": "create", "name": "test"}, follow_redirects=True, ) assert r.status_code == 200 assert f"Directory test is created" in r.data.decode() assert Directory.get_by(name="test") is not None
def test_create_directory_in_trash(flask_client): user = login(flask_client) directory = Directory.create(name="test", user_id=user.id, commit=True) # delete the directory r = flask_client.post( url_for("dashboard.directory"), data={"form-name": "delete", "dir-id": directory.id}, follow_redirects=True, ) assert Directory.get_by(name="test") is None # try to recreate the directory r = flask_client.post( url_for("dashboard.directory"), data={"form-name": "create", "name": "test"}, follow_redirects=True, ) assert r.status_code == 200 assert "test has been used before and cannot be reused" in r.data.decode()
def folder(page=1): parent_id = 0 top = 0 success = True if request.method == 'POST': sub_folder = request.form.get('folder') parent_directory = request.form.get('parent_directory', '') # 验证目录 if sub_folder is None: return custom_response(False, gettext("Directory name isn't empty!")) sub_folder = parse.unquote(sub_folder) if not re.match(r'^[0-9a-zA-Z_]+$', sub_folder): return custom_response( False, gettext("Directory name only character or underline!")) if Directory.query.filter_by(site_id=Site.master_site_id(current_user), name=sub_folder).first(): return custom_response(False, gettext("Directory name is already exist!")) if parent_directory != '': directories = parent_directory.split('/') # pop last item last_directory_name = directories.pop() last_directory = Directory.query.filter_by( site_id=Site.master_site_id(current_user), name=last_directory_name).first() parent_id = last_directory.id top = 1 try: directory = Directory(name=sub_folder, master_uid=Master.master_uid(), site_id=Site.master_site_id(current_user), user_id=current_user.id, parent_id=parent_id, top=top) db.session.add(directory) db.session.commit() except Exception as ex: success = False return status_response(success)
def try_auto_create_directory(alias: str) -> Optional[GenEmail]: """ Try to create an alias with directory """ # check if alias belongs to a directory, ie having directory/anything@EMAIL_DOMAIN format if email_belongs_to_alias_domains(alias): # if there's no directory separator in the alias, no way to auto-create it if "/" not in alias and "+" not in alias and "#" not in alias: return None # alias contains one of the 3 special directory separator: "/", "+" or "#" if "/" in alias: sep = "/" elif "+" in alias: sep = "+" else: sep = "#" directory_name = alias[: alias.find(sep)] LOG.d("directory_name %s", directory_name) directory = Directory.get_by(name=directory_name) if not directory: return None dir_user: User = directory.user if not dir_user.can_create_new_alias(): send_cannot_create_directory_alias(dir_user, alias, directory_name) return None # if alias has been deleted before, do not auto-create it if DeletedAlias.get_by(email=alias, user_id=directory.user_id): LOG.warning( "Alias %s was deleted before, cannot auto-create using directory %s, user %s", alias, directory_name, dir_user, ) return None LOG.d("create alias %s for directory %s", alias, directory) gen_email = GenEmail.create( email=alias, user_id=directory.user_id, directory_id=directory.id, mailbox_id=dir_user.default_mailbox_id, ) db.session.commit() return gen_email
def save_photo(update, context): """ Add given photo to current directory """ # create new record about the file in the DB photo = File(telegram_id=update.message.message_id) photo.save() # attach new file to current directory directory = Directory.objects.get( name=context.chat_data.get('current_directory'), user_id=Directory.encrypt_user_id(update.effective_user.id)) directory.update(add_to_set__contains_files=photo) directory.save() update.message.reply_text( f'Your file now live in directory {directory.name}')
def go_to_directory(update, context): """ Create a buttons template. Buttons are names of subdirectories, that current directory contains. By clicking on one of buttons user will be redirected to selected directory """ current_directory = Directory.objects.get( name=context.chat_data.get('current_directory'), user_id=Directory.encrypt_user_id(update.effective_user.id)) if current_directory.contains_directories: keyboard = FileSystemHandlers.__create_subdirectories_keyboard( current_directory, DIRECTORY_ACTIONS['goto']) update.message.reply_text( 'Choose the folder, that you want go to', reply_markup=InlineKeyboardMarkup(keyboard)) else: update.message.reply_text( f"There are no subdirectories in the directory {context.chat_data.get('current_directory')}" )
def _goto_handler(directory_name): if current_directory.has_subdirectory( directory_name, Directory.encrypt_user_id(update.effective_user.id)): context.chat_data['current_directory'] = directory_name query.answer() query.edit_message_text( text=f"You now switched to directory {directory_name}") else: context.chat_data['current_directory'] = ROOT_DIRECTORY logger.error( f"Unexpected accident: <directory.has_subdirectory> returned False for directory " f"{directory_name}. current_directory={current_directory}, action={action}, " f"directory={directory_name}. User were redirected to root directory" ) query.edit_message_text( f"Wow, you've broke me somehow..\nSo i switched you to root directory" )
def show_subdirectories(update, context): """ Show subdirectories of current directory :param update: Telegram chat data :param context: Telegram chat data """ current_directory = Directory.objects.get( name=context.chat_data.get('current_directory'), user_id=Directory.encrypt_user_id(update.effective_user.id)) if current_directory.contains_directories: subdirectories = reduce( lambda res, directory: f"{res} {directory.name}", current_directory.contains_directories, "") update.message.reply_text( f"Current directory {context.chat_data.get('current_directory')} " f"contains the following subdirectories: {subdirectories}") else: update.message.reply_text( f"There are no subdirectories in the directory {context.chat_data.get('current_directory')}" )
def remove_directory(update, context): """ Remove selected subdirectory :param update: Telegram chat data :param context: Telegram chat data """ current_directory = Directory.objects.get( name=context.chat_data.get('current_directory'), user_id=Directory.encrypt_user_id(update.effective_user.id)) if current_directory.contains_directories: keyboard = FileSystemHandlers.__create_subdirectories_keyboard( current_directory, DIRECTORY_ACTIONS['delete']) update.message.reply_text( 'Choose the folder, that you want to delete', reply_markup=InlineKeyboardMarkup(keyboard)) else: update.message.reply_text( f"There are no subdirectories in the directory {context.chat_data.get('current_directory')}" )
def show_photo(update, context): """ Send all photos from current directory """ directory = Directory.objects.get( name=context.chat_data.get('current_directory'), user_id=Directory.encrypt_user_id(update.effective_user.id)) if not directory.contains_files: update.message.reply_text( 'There are no photos stored in current directory') else: for photo in directory.contains_files: try: context.bot.forward_message( chat_id=update.effective_chat.id, from_chat_id=update.effective_chat.id, message_id=File.prepare_telegram_id(photo.telegram_id)) except BadRequest as bad_request: no_message = 'Message to forward not found' if str(bad_request) == no_message: continue else: raise
def fake_data(): LOG.d("create fake data") # Remove db if exist if os.path.exists("db.sqlite"): LOG.d("remove existing db file") os.remove("db.sqlite") # Create all tables db.create_all() # Create a user user = User.create( email="*****@*****.**", name="John Wick", password="******", activated=True, is_admin=True, enable_otp=False, otp_secret="base32secret3232", intro_shown=True, fido_uuid=None, ) user.include_sender_in_reverse_alias = None db.session.commit() user.trial_end = None LifetimeCoupon.create(code="coupon", nb_used=10, commit=True) # Create a subscription for user # Subscription.create( # user_id=user.id, # cancel_url="https://checkout.paddle.com/subscription/cancel?user=1234", # update_url="https://checkout.paddle.com/subscription/update?user=1234", # subscription_id="123", # event_time=arrow.now(), # next_bill_date=arrow.now().shift(days=10).date(), # plan=PlanEnum.monthly, # ) # db.session.commit() CoinbaseSubscription.create(user_id=user.id, end_at=arrow.now().shift(days=10), commit=True) api_key = ApiKey.create(user_id=user.id, name="Chrome") api_key.code = "code" api_key = ApiKey.create(user_id=user.id, name="Firefox") api_key.code = "codeFF" pgp_public_key = open(get_abs_path("local_data/public-pgp.asc")).read() m1 = Mailbox.create( user_id=user.id, email="*****@*****.**", verified=True, pgp_public_key=pgp_public_key, ) m1.pgp_finger_print = load_public_key(pgp_public_key) db.session.commit() for i in range(3): if i % 2 == 0: a = Alias.create(email=f"e{i}@{FIRST_ALIAS_DOMAIN}", user_id=user.id, mailbox_id=m1.id) else: a = Alias.create( email=f"e{i}@{FIRST_ALIAS_DOMAIN}", user_id=user.id, mailbox_id=user.default_mailbox_id, ) db.session.commit() if i % 5 == 0: if i % 2 == 0: AliasMailbox.create(alias_id=a.id, mailbox_id=user.default_mailbox_id) else: AliasMailbox.create(alias_id=a.id, mailbox_id=m1.id) db.session.commit() # some aliases don't have any activity # if i % 3 != 0: # contact = Contact.create( # user_id=user.id, # alias_id=a.id, # website_email=f"contact{i}@example.com", # reply_email=f"rep{i}@sl.local", # ) # db.session.commit() # for _ in range(3): # EmailLog.create(user_id=user.id, contact_id=contact.id) # db.session.commit() # have some disabled alias if i % 5 == 0: a.enabled = False db.session.commit() CustomDomain.create(user_id=user.id, domain="ab.cd", verified=True) CustomDomain.create(user_id=user.id, domain="very-long-domain.com.net.org", verified=True) db.session.commit() Directory.create(user_id=user.id, name="abcd") Directory.create(user_id=user.id, name="xyzt") db.session.commit() # Create a client client1 = Client.create_new(name="Demo", user_id=user.id) client1.oauth_client_id = "client-id" client1.oauth_client_secret = "client-secret" client1.published = True db.session.commit() RedirectUri.create(client_id=client1.id, uri="https://ab.com") client2 = Client.create_new(name="Demo 2", user_id=user.id) client2.oauth_client_id = "client-id2" client2.oauth_client_secret = "client-secret2" client2.published = True db.session.commit() ClientUser.create(user_id=user.id, client_id=client1.id, name="Fake Name") referral = Referral.create(user_id=user.id, code="REFCODE", name="First referral") db.session.commit() for i in range(6): Notification.create(user_id=user.id, message=f"""Hey hey <b>{i}</b> """ * 10) db.session.commit() User.create( email="*****@*****.**", password="******", activated=True, referral_id=referral.id, ) db.session.commit()
def fake_data(): LOG.d("create fake data") # Remove db if exist if os.path.exists("db.sqlite"): LOG.d("remove existing db file") os.remove("db.sqlite") # Create all tables db.create_all() # Create a user user = User.create( email="*****@*****.**", name="John Wick", password="******", activated=True, is_admin=True, # enable_otp=True, otp_secret="base32secret3232", intro_shown=True, fido_uuid=None, ) user.trial_end = None db.session.commit() # add a profile picture file_path = "profile_pic.svg" s3.upload_from_bytesio( file_path, open(os.path.join(ROOT_DIR, "static", "default-icon.svg"), "rb"), content_type="image/svg", ) file = File.create(user_id=user.id, path=file_path, commit=True) user.profile_picture_id = file.id db.session.commit() # create a bounced email alias = Alias.create_new_random(user) db.session.commit() bounce_email_file_path = "bounce.eml" s3.upload_email_from_bytesio( bounce_email_file_path, open(os.path.join(ROOT_DIR, "local_data", "email_tests", "2.eml"), "rb"), "download.eml", ) refused_email = RefusedEmail.create( path=bounce_email_file_path, full_report_path=bounce_email_file_path, user_id=user.id, commit=True, ) contact = Contact.create( user_id=user.id, alias_id=alias.id, website_email="*****@*****.**", reply_email="*****@*****.**", commit=True, ) EmailLog.create( user_id=user.id, contact_id=contact.id, refused_email_id=refused_email.id, bounced=True, commit=True, ) LifetimeCoupon.create(code="coupon", nb_used=10, commit=True) # Create a subscription for user Subscription.create( user_id=user.id, cancel_url="https://checkout.paddle.com/subscription/cancel?user=1234", update_url="https://checkout.paddle.com/subscription/update?user=1234", subscription_id="123", event_time=arrow.now(), next_bill_date=arrow.now().shift(days=10).date(), plan=PlanEnum.monthly, commit=True, ) CoinbaseSubscription.create( user_id=user.id, end_at=arrow.now().shift(days=10), commit=True ) api_key = ApiKey.create(user_id=user.id, name="Chrome") api_key.code = "code" api_key = ApiKey.create(user_id=user.id, name="Firefox") api_key.code = "codeFF" pgp_public_key = open(get_abs_path("local_data/public-pgp.asc")).read() m1 = Mailbox.create( user_id=user.id, email="*****@*****.**", verified=True, pgp_public_key=pgp_public_key, ) m1.pgp_finger_print = load_public_key(pgp_public_key) db.session.commit() for i in range(3): if i % 2 == 0: a = Alias.create( email=f"e{i}@{FIRST_ALIAS_DOMAIN}", user_id=user.id, mailbox_id=m1.id ) else: a = Alias.create( email=f"e{i}@{FIRST_ALIAS_DOMAIN}", user_id=user.id, mailbox_id=user.default_mailbox_id, ) db.session.commit() if i % 5 == 0: if i % 2 == 0: AliasMailbox.create(alias_id=a.id, mailbox_id=user.default_mailbox_id) else: AliasMailbox.create(alias_id=a.id, mailbox_id=m1.id) db.session.commit() # some aliases don't have any activity # if i % 3 != 0: # contact = Contact.create( # user_id=user.id, # alias_id=a.id, # website_email=f"contact{i}@example.com", # reply_email=f"rep{i}@sl.local", # ) # db.session.commit() # for _ in range(3): # EmailLog.create(user_id=user.id, contact_id=contact.id) # db.session.commit() # have some disabled alias if i % 5 == 0: a.enabled = False db.session.commit() CustomDomain.create(user_id=user.id, domain="ab.cd", verified=True) CustomDomain.create( user_id=user.id, domain="very-long-domain.com.net.org", verified=True ) db.session.commit() Directory.create(user_id=user.id, name="abcd") Directory.create(user_id=user.id, name="xyzt") db.session.commit() # Create a client client1 = Client.create_new(name="Demo", user_id=user.id) client1.oauth_client_id = "client-id" client1.oauth_client_secret = "client-secret" client1.published = True db.session.commit() RedirectUri.create(client_id=client1.id, uri="https://ab.com") client2 = Client.create_new(name="Demo 2", user_id=user.id) client2.oauth_client_id = "client-id2" client2.oauth_client_secret = "client-secret2" client2.published = True db.session.commit() ClientUser.create(user_id=user.id, client_id=client1.id, name="Fake Name") referral = Referral.create(user_id=user.id, code="REFCODE", name="First referral") db.session.commit() for i in range(6): Notification.create(user_id=user.id, message=f"""Hey hey <b>{i}</b> """ * 10) db.session.commit() user2 = User.create( email="*****@*****.**", password="******", activated=True, referral_id=referral.id, ) Mailbox.create(user_id=user2.id, email="*****@*****.**", verified=True) db.session.commit() ManualSubscription.create( user_id=user2.id, end_at=arrow.now().shift(years=1, days=1), commit=True )
def handle_forward(self, envelope, smtp: SMTP, msg: Message) -> str: """return *status_code message*""" alias = envelope.rcpt_tos[0].lower() # alias@SL gen_email = GenEmail.get_by(email=alias) if not gen_email: LOG.d( "alias %s not exist. Try to see if it can be created on the fly", alias) # try to see if alias could be created on-the-fly on_the_fly = False # check if alias belongs to a directory, ie having directory/anything@EMAIL_DOMAIN format if email_belongs_to_alias_domains(alias): if "/" in alias or "+" in alias or "#" in alias: if "/" in alias: sep = "/" elif "+" in alias: sep = "+" else: sep = "#" directory_name = alias[:alias.find(sep)] LOG.d("directory_name %s", directory_name) directory = Directory.get_by(name=directory_name) # Only premium user can use the directory feature if directory: dir_user = directory.user if dir_user.is_premium(): LOG.d("create alias %s for directory %s", alias, directory) on_the_fly = True gen_email = GenEmail.create( email=alias, user_id=directory.user_id, directory_id=directory.id, ) db.session.commit() else: LOG.error( "User %s is not premium anymore and cannot create alias with directory", dir_user, ) send_cannot_create_directory_alias( dir_user, alias, directory_name) # try to create alias on-the-fly with custom-domain catch-all feature # check if alias is custom-domain alias and if the custom-domain has catch-all enabled if not on_the_fly: alias_domain = get_email_domain_part(alias) custom_domain = CustomDomain.get_by(domain=alias_domain) # Only premium user can continue using the catch-all feature if custom_domain and custom_domain.catch_all: domain_user = custom_domain.user if domain_user.is_premium(): LOG.d("create alias %s for domain %s", alias, custom_domain) on_the_fly = True gen_email = GenEmail.create( email=alias, user_id=custom_domain.user_id, custom_domain_id=custom_domain.id, automatic_creation=True, ) db.session.commit() else: LOG.error( "User %s is not premium anymore and cannot create alias with domain %s", domain_user, alias_domain, ) send_cannot_create_domain_alias( domain_user, alias, alias_domain) if not on_the_fly: LOG.d("alias %s cannot be created on-the-fly, return 510", alias) return "510 Email not exist" user_email = gen_email.user.email website_email = get_email_part(msg["From"]) forward_email = ForwardEmail.get_by(gen_email_id=gen_email.id, website_email=website_email) if not forward_email: LOG.debug( "create forward email for alias %s and website email %s", alias, website_email, ) # generate a reply_email, make sure it is unique # not use while to avoid infinite loop for _ in range(1000): reply_email = f"reply+{random_string(30)}@{EMAIL_DOMAIN}" if not ForwardEmail.get_by(reply_email=reply_email): break forward_email = ForwardEmail.create( gen_email_id=gen_email.id, website_email=website_email, website_from=msg["From"], reply_email=reply_email, ) db.session.commit() forward_log = ForwardEmailLog.create(forward_id=forward_email.id) if gen_email.enabled: # add custom header add_or_replace_header(msg, "X-SimpleLogin-Type", "Forward") # remove reply-to header if present delete_header(msg, "Reply-To") # change the from header so the sender comes from @SL # so it can pass DMARC check # replace the email part in from: header from_header = (get_email_name(msg["From"]) + " - " + website_email.replace("@", " at ") + f" <{forward_email.reply_email}>") msg.replace_header("From", from_header) LOG.d("new from header:%s", from_header) # add List-Unsubscribe header unsubscribe_link = f"{URL}/dashboard/unsubscribe/{gen_email.id}" add_or_replace_header(msg, "List-Unsubscribe", f"<{unsubscribe_link}>") add_or_replace_header(msg, "List-Unsubscribe-Post", "List-Unsubscribe=One-Click") add_dkim_signature(msg, EMAIL_DOMAIN) LOG.d( "Forward mail from %s to %s, mail_options %s, rcpt_options %s ", website_email, user_email, envelope.mail_options, envelope.rcpt_options, ) # smtp.send_message has UnicodeEncodeErroremail issue # encode message raw directly instead msg_raw = msg.as_string().encode() smtp.sendmail( forward_email.reply_email, user_email, msg_raw, envelope.mail_options, envelope.rcpt_options, ) else: LOG.d("%s is disabled, do not forward", gen_email) forward_log.blocked = True db.session.commit() return "250 Message accepted for delivery"
def directory(): dirs = (Directory.query.filter_by(user_id=current_user.id).order_by( Directory.created_at.desc()).all()) mailboxes = current_user.mailboxes() new_dir_form = NewDirForm() if request.method == "POST": if request.form.get("form-name") == "delete": dir_id = request.form.get("dir-id") dir = Directory.get(dir_id) if not dir: flash("Unknown error. Refresh the page", "warning") return redirect(url_for("dashboard.directory")) elif dir.user_id != current_user.id: flash("You cannot delete this directory", "warning") return redirect(url_for("dashboard.directory")) name = dir.name Directory.delete(dir_id) db.session.commit() flash(f"Directory {name} has been deleted", "success") return redirect(url_for("dashboard.directory")) if request.form.get("form-name") == "toggle-directory": dir_id = request.form.get("dir-id") dir = Directory.get(dir_id) if not dir or dir.user_id != current_user.id: flash("Unknown error. Refresh the page", "warning") return redirect(url_for("dashboard.directory")) if request.form.get("dir-status") == "on": dir.disabled = False flash(f"On-the-fly is enabled for {dir.name}", "success") else: dir.disabled = True flash(f"On-the-fly is disabled for {dir.name}", "warning") db.session.commit() return redirect(url_for("dashboard.directory")) elif request.form.get("form-name") == "update": dir_id = request.form.get("dir-id") dir = Directory.get(dir_id) if not dir or dir.user_id != current_user.id: flash("Unknown error. Refresh the page", "warning") return redirect(url_for("dashboard.directory")) mailbox_ids = request.form.getlist("mailbox_ids") # check if mailbox is not tempered with mailboxes = [] for mailbox_id in mailbox_ids: mailbox = Mailbox.get(mailbox_id) if (not mailbox or mailbox.user_id != current_user.id or not mailbox.verified): flash("Something went wrong, please retry", "warning") return redirect(url_for("dashboard.directory")) mailboxes.append(mailbox) if not mailboxes: flash("You must select at least 1 mailbox", "warning") return redirect(url_for("dashboard.directory")) # first remove all existing directory-mailboxes links DirectoryMailbox.query.filter_by(directory_id=dir.id).delete() db.session.flush() for mailbox in mailboxes: DirectoryMailbox.create(directory_id=dir.id, mailbox_id=mailbox.id) db.session.commit() flash(f"Directory {dir.name} has been updated", "success") return redirect(url_for("dashboard.directory")) elif request.form.get("form-name") == "create": if not current_user.is_premium(): flash("Only premium plan can add directory", "warning") return redirect(url_for("dashboard.directory")) if current_user.nb_directory() >= MAX_NB_DIRECTORY: flash( f"You cannot have more than {MAX_NB_DIRECTORY} directories", "warning", ) return redirect(url_for("dashboard.directory")) if new_dir_form.validate(): new_dir_name = new_dir_form.name.data.lower() if Directory.get_by(name=new_dir_name): flash(f"{new_dir_name} already used", "warning") elif new_dir_name in ( "reply", "ra", "bounces", "bounce", "transactional", BOUNCE_PREFIX_FOR_REPLY_PHASE, ): flash( "this directory name is reserved, please choose another name", "warning", ) else: new_dir = Directory.create(name=new_dir_name, user_id=current_user.id) db.session.commit() mailbox_ids = request.form.getlist("mailbox_ids") if mailbox_ids: # check if mailbox is not tempered with mailboxes = [] for mailbox_id in mailbox_ids: mailbox = Mailbox.get(mailbox_id) if (not mailbox or mailbox.user_id != current_user.id or not mailbox.verified): flash("Something went wrong, please retry", "warning") return redirect(url_for("dashboard.directory")) mailboxes.append(mailbox) for mailbox in mailboxes: DirectoryMailbox.create(directory_id=new_dir.id, mailbox_id=mailbox.id) db.session.commit() flash(f"Directory {new_dir.name} is created", "success") return redirect(url_for("dashboard.directory")) return render_template( "dashboard/directory.html", dirs=dirs, new_dir_form=new_dir_form, mailboxes=mailboxes, EMAIL_DOMAIN=EMAIL_DOMAIN, ALIAS_DOMAINS=ALIAS_DOMAINS, )
def fake_data(): LOG.d("create fake data") # Create a user user = User.create( email="*****@*****.**", name="John Wick", password="******", activated=True, is_admin=True, # enable_otp=True, otp_secret="base32secret3232", intro_shown=True, fido_uuid=None, ) user.trial_end = None Session.commit() # add a profile picture file_path = "profile_pic.svg" s3.upload_from_bytesio( file_path, open(os.path.join(ROOT_DIR, "static", "default-icon.svg"), "rb"), content_type="image/svg", ) file = File.create(user_id=user.id, path=file_path, commit=True) user.profile_picture_id = file.id Session.commit() # create a bounced email alias = Alias.create_new_random(user) Session.commit() bounce_email_file_path = "bounce.eml" s3.upload_email_from_bytesio( bounce_email_file_path, open(os.path.join(ROOT_DIR, "local_data", "email_tests", "2.eml"), "rb"), "download.eml", ) refused_email = RefusedEmail.create( path=bounce_email_file_path, full_report_path=bounce_email_file_path, user_id=user.id, commit=True, ) contact = Contact.create( user_id=user.id, alias_id=alias.id, website_email="*****@*****.**", reply_email="*****@*****.**", commit=True, ) EmailLog.create( user_id=user.id, contact_id=contact.id, alias_id=contact.alias_id, refused_email_id=refused_email.id, bounced=True, commit=True, ) LifetimeCoupon.create(code="lifetime-coupon", nb_used=10, commit=True) Coupon.create(code="coupon", commit=True) # Create a subscription for user Subscription.create( user_id=user.id, cancel_url="https://checkout.paddle.com/subscription/cancel?user=1234", update_url="https://checkout.paddle.com/subscription/update?user=1234", subscription_id="123", event_time=arrow.now(), next_bill_date=arrow.now().shift(days=10).date(), plan=PlanEnum.monthly, commit=True, ) CoinbaseSubscription.create(user_id=user.id, end_at=arrow.now().shift(days=10), commit=True) api_key = ApiKey.create(user_id=user.id, name="Chrome") api_key.code = "code" api_key = ApiKey.create(user_id=user.id, name="Firefox") api_key.code = "codeFF" pgp_public_key = open(get_abs_path("local_data/public-pgp.asc")).read() m1 = Mailbox.create( user_id=user.id, email="*****@*****.**", verified=True, pgp_public_key=pgp_public_key, ) m1.pgp_finger_print = load_public_key(pgp_public_key) Session.commit() # [email protected] is in a LOT of data breaches Alias.create(email="*****@*****.**", user_id=user.id, mailbox_id=m1.id) for i in range(3): if i % 2 == 0: a = Alias.create(email=f"e{i}@{FIRST_ALIAS_DOMAIN}", user_id=user.id, mailbox_id=m1.id) else: a = Alias.create( email=f"e{i}@{FIRST_ALIAS_DOMAIN}", user_id=user.id, mailbox_id=user.default_mailbox_id, ) Session.commit() if i % 5 == 0: if i % 2 == 0: AliasMailbox.create(alias_id=a.id, mailbox_id=user.default_mailbox_id) else: AliasMailbox.create(alias_id=a.id, mailbox_id=m1.id) Session.commit() # some aliases don't have any activity # if i % 3 != 0: # contact = Contact.create( # user_id=user.id, # alias_id=a.id, # website_email=f"contact{i}@example.com", # reply_email=f"rep{i}@sl.local", # ) # Session.commit() # for _ in range(3): # EmailLog.create(user_id=user.id, contact_id=contact.id, alias_id=contact.alias_id) # Session.commit() # have some disabled alias if i % 5 == 0: a.enabled = False Session.commit() custom_domain1 = CustomDomain.create(user_id=user.id, domain="ab.cd", verified=True) Session.commit() Alias.create( user_id=user.id, email="*****@*****.**", mailbox_id=user.default_mailbox_id, custom_domain_id=custom_domain1.id, commit=True, ) Alias.create( user_id=user.id, email="*****@*****.**", mailbox_id=user.default_mailbox_id, custom_domain_id=custom_domain1.id, commit=True, ) Directory.create(user_id=user.id, name="abcd") Directory.create(user_id=user.id, name="xyzt") Session.commit() # Create a client client1 = Client.create_new(name="Demo", user_id=user.id) client1.oauth_client_id = "client-id" client1.oauth_client_secret = "client-secret" Session.commit() RedirectUri.create(client_id=client1.id, uri="https://your-website.com/oauth-callback") client2 = Client.create_new(name="Demo 2", user_id=user.id) client2.oauth_client_id = "client-id2" client2.oauth_client_secret = "client-secret2" Session.commit() ClientUser.create(user_id=user.id, client_id=client1.id, name="Fake Name") referral = Referral.create(user_id=user.id, code="Website", name="First referral") Referral.create(user_id=user.id, code="Podcast", name="First referral") Payout.create(user_id=user.id, amount=1000, number_upgraded_account=100, payment_method="BTC") Payout.create( user_id=user.id, amount=5000, number_upgraded_account=200, payment_method="PayPal", ) Session.commit() for i in range(6): Notification.create(user_id=user.id, message=f"""Hey hey <b>{i}</b> """ * 10) Session.commit() user2 = User.create( email="*****@*****.**", password="******", activated=True, referral_id=referral.id, ) Mailbox.create(user_id=user2.id, email="*****@*****.**", verified=True) Session.commit() ManualSubscription.create( user_id=user2.id, end_at=arrow.now().shift(years=1, days=1), comment="Local manual", commit=True, ) SLDomain.create(domain="premium.com", premium_only=True, commit=True) hibp1 = Hibp.create(name="first breach", description="breach description", commit=True) hibp2 = Hibp.create(name="second breach", description="breach description", commit=True) breached_alias1 = Alias.create(email="*****@*****.**", user_id=user.id, mailbox_id=m1.id, commit=True) breached_alias2 = Alias.create(email="*****@*****.**", user_id=user.id, mailbox_id=m1.id, commit=True) AliasHibp.create(hibp_id=hibp1.id, alias_id=breached_alias1.id) AliasHibp.create(hibp_id=hibp2.id, alias_id=breached_alias2.id) # old domain will have ownership_verified=True CustomDomain.create(user_id=user.id, domain="old.com", verified=True, ownership_verified=True)
def fake_data(): LOG.d("create fake data") # Remove db if exist if os.path.exists("db.sqlite"): LOG.d("remove existing db file") os.remove("db.sqlite") # Create all tables db.create_all() # Create a user user = User.create( email="*****@*****.**", name="John Wick", password="******", activated=True, is_admin=True, otp_secret="base32secret3232", ) db.session.commit() LifetimeCoupon.create(code="coupon", nb_used=10) db.session.commit() # Create a subscription for user Subscription.create( user_id=user.id, cancel_url="https://checkout.paddle.com/subscription/cancel?user=1234", update_url="https://checkout.paddle.com/subscription/update?user=1234", subscription_id="123", event_time=arrow.now(), next_bill_date=arrow.now().shift(days=10).date(), plan=PlanEnum.monthly, ) db.session.commit() api_key = ApiKey.create(user_id=user.id, name="Chrome") api_key.code = "code" GenEmail.create_new(user.id, "e1@") GenEmail.create_new(user.id, "e2@") GenEmail.create_new(user.id, "e3@") CustomDomain.create(user_id=user.id, domain="ab.cd", verified=True) CustomDomain.create(user_id=user.id, domain="very-long-domain.com.net.org", verified=True) db.session.commit() Directory.create(user_id=user.id, name="abcd") Directory.create(user_id=user.id, name="xyzt") db.session.commit() # Create a client client1 = Client.create_new(name="Demo", user_id=user.id) client1.oauth_client_id = "client-id" client1.oauth_client_secret = "client-secret" client1.published = True db.session.commit() RedirectUri.create(client_id=client1.id, uri="https://ab.com") client2 = Client.create_new(name="Demo 2", user_id=user.id) client2.oauth_client_id = "client-id2" client2.oauth_client_secret = "client-secret2" client2.published = True db.session.commit() db.session.commit()
def try_auto_create_directory(address: str) -> Optional[Alias]: """ Try to create an alias with directory """ # check if alias belongs to a directory, ie having directory/anything@EMAIL_DOMAIN format if can_create_directory_for_address(address): # if there's no directory separator in the alias, no way to auto-create it if "/" not in address and "+" not in address and "#" not in address: return None # alias contains one of the 3 special directory separator: "/", "+" or "#" if "/" in address: sep = "/" elif "+" in address: sep = "+" else: sep = "#" directory_name = address[:address.find(sep)] LOG.d("directory_name %s", directory_name) directory = Directory.get_by(name=directory_name) if not directory: return None user: User = directory.user if not user.can_create_new_alias(): send_cannot_create_directory_alias(user, address, directory_name) return None if directory.disabled: send_cannot_create_directory_alias_disabled( user, address, directory_name) return None try: LOG.d("create alias %s for directory %s", address, directory) mailboxes = directory.mailboxes alias = Alias.create( email=address, user_id=directory.user_id, directory_id=directory.id, mailbox_id=mailboxes[0].id, ) if not user.disable_automatic_alias_note: alias.note = f"Created by directory {directory.name}" Session.flush() for i in range(1, len(mailboxes)): AliasMailbox.create( alias_id=alias.id, mailbox_id=mailboxes[i].id, ) Session.commit() return alias except AliasInTrashError: LOG.w( "Alias %s was deleted before, cannot auto-create using directory %s, user %s", address, directory_name, user, ) return None except IntegrityError: LOG.w("Alias %s already exists", address) Session.rollback() alias = Alias.get_by(email=address) return alias