def get_aliases_v2(): """ Get aliases Input: page_id: in query pinned: in query Output: - aliases: list of alias: - id - email - creation_date - creation_timestamp - nb_forward - nb_block - nb_reply - note - mailbox - mailboxes - support_pgp - disable_pgp - latest_activity: null if no activity. - timestamp - action: forward|reply|block|bounced - contact: - email - name - reverse_alias """ user = g.user try: page_id = int(request.args.get("page_id")) except (ValueError, TypeError): return jsonify(error="page_id must be provided in request query"), 400 pinned = "pinned" in request.args query = None data = request.get_json(silent=True) if data: query = data.get("query") alias_infos: [AliasInfo] = get_alias_infos_with_pagination_v3( user, page_id=page_id, query=query, alias_filter="pinned" if pinned else None) return ( jsonify(aliases=[ serialize_alias_info_v2(alias_info) for alias_info in alias_infos ]), 200, )
def get_alias(alias_id): """ Get alias Input: alias_id: in url Output: Alias info, same as in get_aliases """ user = g.user alias: Alias = Alias.get(alias_id) if alias.user_id != user.id: return jsonify(error="Forbidden"), 403 return jsonify(**serialize_alias_info_v2(get_alias_info_v2(alias))), 200
def new_random_alias(): """ Create a new random alias Input: (Optional) note Output: 201 if success """ user = g.user if not user.can_create_new_alias(): LOG.d("user %s cannot create new random alias", user) return ( jsonify( error=f"You have reached the limitation of a free account with the maximum of " f"{MAX_NB_EMAIL_FREE_PLAN} aliases, please upgrade your plan to create more aliases" ), 400, ) note = None data = request.get_json(silent=True) if data: note = data.get("note") scheme = user.alias_generator mode = request.args.get("mode") if mode: if mode == "word": scheme = AliasGeneratorEnum.word.value elif mode == "uuid": scheme = AliasGeneratorEnum.uuid.value else: return jsonify(error=f"{mode} must be either word or alias"), 400 alias = Alias.create_new_random(user=user, scheme=scheme, note=note) db.session.commit() hostname = request.args.get("hostname") if hostname: AliasUsedOn.create(alias_id=alias.id, hostname=hostname, user_id=alias.user_id) db.session.commit() return ( jsonify(alias=alias.email, **serialize_alias_info_v2(get_alias_info_v2(alias))), 201, )
def new_custom_alias_v3(): """ Create a new custom alias Same as v2 but accept a list of mailboxes as input Input: alias_prefix, for ex "www_groupon_com" signed_suffix, either [email protected] or @my-domain.com mailbox_ids: list of int optional "hostname" in args optional "note" optional "name" Output: 201 if success 409 if the alias already exists """ user: User = g.user if not user.can_create_new_alias(): LOG.d("user %s cannot create any custom alias", user) return ( jsonify( error= "You have reached the limitation of a free account with the maximum of " f"{MAX_NB_EMAIL_FREE_PLAN} aliases, please upgrade your plan to create more aliases" ), 400, ) hostname = request.args.get("hostname") data = request.get_json() if not data: return jsonify(error="request body cannot be empty"), 400 alias_prefix = data.get("alias_prefix", "").strip().lower().replace(" ", "") signed_suffix = data.get("signed_suffix", "").strip() mailbox_ids = data.get("mailbox_ids") note = data.get("note") name = data.get("name") if name: name = name.replace("\n", "") alias_prefix = convert_to_id(alias_prefix) if not check_alias_prefix(alias_prefix): return jsonify(error="alias prefix invalid format or too long"), 400 # 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 != user.id or not mailbox.verified: return jsonify(error="Errors with Mailbox"), 400 mailboxes.append(mailbox) if not mailboxes: return jsonify(error="At least one mailbox must be selected"), 400 # hypothesis: user will click on the button in the 600 secs try: alias_suffix = signer.unsign(signed_suffix, max_age=600).decode() except SignatureExpired: LOG.warning("Alias creation time expired for %s", user) return jsonify( error="Alias creation time is expired, please retry"), 412 except Exception: LOG.warning("Alias suffix is tampered, user %s", user) return jsonify(error="Tampered suffix"), 400 if not verify_prefix_suffix(user, alias_prefix, alias_suffix): return jsonify(error="wrong alias prefix or suffix"), 400 full_alias = alias_prefix + alias_suffix if (Alias.get_by(email=full_alias) or DeletedAlias.get_by(email=full_alias) or DomainDeletedAlias.get_by(email=full_alias)): LOG.d("full alias already used %s", full_alias) return jsonify(error=f"alias {full_alias} already exists"), 409 custom_domain_id = None if alias_suffix.startswith("@"): alias_domain = alias_suffix[1:] domain = CustomDomain.get_by(domain=alias_domain) if domain: custom_domain_id = domain.id alias = Alias.create( user_id=user.id, email=full_alias, note=note, name=name or None, mailbox_id=mailboxes[0].id, custom_domain_id=custom_domain_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() if hostname: AliasUsedOn.create(alias_id=alias.id, hostname=hostname, user_id=alias.user_id) db.session.commit() return ( jsonify(alias=full_alias, **serialize_alias_info_v2(get_alias_info_v2(alias))), 201, )
def new_custom_alias_v2(): """ Create a new custom alias Same as v1 but signed_suffix is actually the suffix with signature, e.g. [email protected] Input: alias_prefix, for ex "www_groupon_com" signed_suffix, either [email protected] or @my-domain.com optional "hostname" in args optional "note" Output: 201 if success 409 if the alias already exists """ user: User = g.user if not user.can_create_new_alias(): LOG.d("user %s cannot create any custom alias", user) return ( jsonify( error= "You have reached the limitation of a free account with the maximum of " f"{MAX_NB_EMAIL_FREE_PLAN} aliases, please upgrade your plan to create more aliases" ), 400, ) hostname = request.args.get("hostname") data = request.get_json() if not data: return jsonify(error="request body cannot be empty"), 400 alias_prefix = data.get("alias_prefix", "").strip().lower().replace(" ", "") signed_suffix = data.get("signed_suffix", "").strip() note = data.get("note") alias_prefix = convert_to_id(alias_prefix) # hypothesis: user will click on the button in the 600 secs try: alias_suffix = signer.unsign(signed_suffix, max_age=600).decode() except SignatureExpired: LOG.warning("Alias creation time expired for %s", user) return jsonify( error="Alias creation time is expired, please retry"), 412 except Exception: LOG.warning("Alias suffix is tampered, user %s", user) return jsonify(error="Tampered suffix"), 400 if not verify_prefix_suffix(user, alias_prefix, alias_suffix): return jsonify(error="wrong alias prefix or suffix"), 400 full_alias = alias_prefix + alias_suffix if (Alias.get_by(email=full_alias) or DeletedAlias.get_by(email=full_alias) or DomainDeletedAlias.get_by(email=full_alias)): LOG.d("full alias already used %s", full_alias) return jsonify(error=f"alias {full_alias} already exists"), 409 custom_domain_id = None if alias_suffix.startswith("@"): alias_domain = alias_suffix[1:] domain = CustomDomain.get_by(domain=alias_domain) # check if the alias is currently in the domain trash if domain and DomainDeletedAlias.get_by(domain_id=domain.id, email=full_alias): LOG.d( f"Alias {full_alias} is currently in the {domain.domain} trash. " ) return jsonify(error=f"alias {full_alias} in domain trash"), 409 if domain: custom_domain_id = domain.id alias = Alias.create( user_id=user.id, email=full_alias, mailbox_id=user.default_mailbox_id, note=note, custom_domain_id=custom_domain_id, ) db.session.commit() if hostname: AliasUsedOn.create(alias_id=alias.id, hostname=hostname, user_id=alias.user_id) db.session.commit() return ( jsonify(alias=full_alias, **serialize_alias_info_v2(get_alias_info_v2(alias))), 201, )
def new_random_alias(): """ Create a new random alias Input: (Optional) note Output: 201 if success """ user = g.user if not user.can_create_new_alias(): LOG.d("user %s cannot create new random alias", user) return ( jsonify( error= f"You have reached the limitation of a free account with the maximum of " f"{MAX_NB_EMAIL_FREE_PLAN} aliases, please upgrade your plan to create more aliases" ), 400, ) note = None data = request.get_json(silent=True) if data: note = data.get("note") alias = None # custom alias suggestion and suffix hostname = request.args.get("hostname") if hostname and user.include_website_in_one_click_alias: LOG.d("Use %s to create new alias", hostname) # keep only the domain name of hostname, ignore TLD and subdomain # for ex www.groupon.com -> groupon ext = tldextract.extract(hostname) prefix_suggestion = ext.domain prefix_suggestion = convert_to_id(prefix_suggestion) suffixes = get_available_suffixes(user) # use the first suffix suggested_alias = prefix_suggestion + suffixes[0].suffix alias = Alias.get_by(email=suggested_alias) # cannot use this alias as it belongs to another user if alias and not alias.user_id == user.id: LOG.d("%s belongs to another user", alias) alias = None elif alias and alias.user_id == user.id: # make sure alias was created for this website if AliasUsedOn.get_by(alias_id=alias.id, hostname=hostname, user_id=alias.user_id): LOG.d("Use existing alias %s", alias) else: LOG.d("%s wasn't created for this website %s", alias, hostname) alias = None elif not alias: LOG.d("create new alias %s", suggested_alias) try: alias = Alias.create( user_id=user.id, email=suggested_alias, note=note, mailbox_id=user.default_mailbox_id, commit=True, ) except AliasInTrashError: LOG.i("Alias %s is in trash", suggested_alias) alias = None if not alias: scheme = user.alias_generator mode = request.args.get("mode") if mode: if mode == "word": scheme = AliasGeneratorEnum.word.value elif mode == "uuid": scheme = AliasGeneratorEnum.uuid.value else: return jsonify( error=f"{mode} must be either word or uuid"), 400 alias = Alias.create_new_random(user=user, scheme=scheme, note=note) Session.commit() if hostname and not AliasUsedOn.get_by(alias_id=alias.id, hostname=hostname): AliasUsedOn.create(alias_id=alias.id, hostname=hostname, user_id=alias.user_id) Session.commit() return ( jsonify(alias=alias.email, **serialize_alias_info_v2(get_alias_info_v2(alias))), 201, )