add /api/alias/options

This commit is contained in:
Son NK 2019-12-03 23:48:30 +00:00
parent c58d9052e7
commit ab4f5bf329
6 changed files with 186 additions and 2 deletions

View File

@ -74,4 +74,36 @@ response_type=id_token code
return `id_token` in addition to `authorization_code` in /authorization endpoint
## API endpoints for extension
```
GET /alias/options hostname?="www.groupon.com"
recommendation?:
alias: www_groupon_com@simplelogin.co
hostname: www.groupon.com
custom?:
suggestion: www_groupon_com
suffix: [@my_domain.com, .abcde@simplelogin.co]
can_create_custom: true
can_create_random: true
existing:
[email1, email2, ...]
POST /alias/custom/new
prefix: www_groupon_com
suffix: @my_domain.com
201 -> OK {alias: "www_groupon_com@my_domain.com"}
409 -> duplicated
POST /alias/random/new
201 -> OK {alias: "random_word@simplelogin.co"}
```

View File

@ -1 +1 @@
from .views import index
from .views import index, alias_options

View File

@ -1,3 +1,30 @@
from flask import Blueprint
from functools import wraps
import arrow
from flask import Blueprint, request, jsonify, g
from app.extensions import db
from app.models import ApiKey
api_bp = Blueprint(name="api", import_name=__name__, url_prefix="/api")
def verify_api_key(f):
@wraps(f)
def decorated(*args, **kwargs):
api_code = request.headers.get("Authentication")
api_key = ApiKey.get_by(code=api_code)
if not api_key:
return jsonify(error="Wrong api key"), 401
# Update api key stats
api_key.last_used = arrow.now()
api_key.times += 1
db.session.commit()
g.user = api_key.user
return f(*args, **kwargs)
return decorated

View File

@ -0,0 +1,70 @@
from flask import jsonify, request, g
from flask_cors import cross_origin
from app.api.base import api_bp, verify_api_key
from app.config import EMAIL_DOMAIN
from app.extensions import db
from app.log import LOG
from app.models import AliasUsedOn, GenEmail, User
from app.utils import random_string
@api_bp.route("/alias/options")
@cross_origin()
@verify_api_key
def options():
"""
Return what options user has when creating new alias.
Input:
a valid api-key in "Authentication" header and
optional "hostname" in args
Output: cf README
optional recommendation:
optional custom
can_create_custom: boolean
can_create_random: boolean
existing: array of existing aliases
"""
user = g.user
hostname = request.args.get("hostname")
ret = {
"existing": [ge.email for ge in GenEmail.query.filter_by(user_id=user.id)],
"can_create_custom": user.can_create_new_custom_alias(),
"can_create_random": user.can_create_new_random_alias(),
}
# recommendation alias if exist
if hostname:
q = db.session.query(AliasUsedOn, GenEmail, User).filter(
AliasUsedOn.gen_email_id == GenEmail.id,
GenEmail.user_id == user.id,
AliasUsedOn.hostname == hostname,
)
r = q.first()
if r:
_, alias, _ = r
LOG.d("found alias %s %s %s", alias, hostname, user)
ret["recommendation"] = {"alias": alias.email, "hostname": hostname}
# custom alias suggestion and suffix
if user.can_create_new_custom_alias():
ret["custom"] = {}
if hostname:
ret["custom"]["suggestion"] = hostname.replace(".", "_")
else:
ret["custom"]["suggestion"] = ""
# maybe better to make sure the suffix is never used before
# but this is ok as there's a check when creating a new custom alias
ret["custom"]["suffixes"] = [f".{random_string(6)}@{EMAIL_DOMAIN}"]
for custom_domain in user.verified_custom_domains():
ret["custom"]["suffixes"].append("@" + custom_domain.domain)
# custom domain should be put first
ret["custom"]["suffixes"] = list(reversed(ret["custom"]["suffixes"]))
return jsonify(ret)

0
tests/api/__init__.py Normal file
View File

View File

@ -0,0 +1,55 @@
from flask import url_for
from app.extensions import db
from app.models import User, ApiKey, AliasUsedOn, GenEmail
def test_different_scenarios(flask_client):
"""Start with a blank database."""
# create user, user is not activated
user = User.create(email="a@b.c", password="password", name="Test User")
db.session.commit()
# create api_key
api_key = ApiKey.create(user.id, "for test")
db.session.commit()
# <<< without hostname >>>
r = flask_client.get(
url_for("api.options"), headers={"Authentication": api_key.code}
)
# {
# "can_create_custom": True,
# "can_create_random": True,
# "custom": {"suffix": ["azdwbw@sl.local"], "suggestion": ""},
# "existing": ["cat_cat_cat@sl.local"],
# }
assert r.status_code == 200
assert r.json["can_create_custom"]
assert r.json["can_create_random"]
assert len(r.json["existing"]) == 1
assert r.json["custom"]["suffix"]
assert r.json["custom"]["suggestion"] == "" # no hostname => no suggestion
# <<< with hostname >>>
r = flask_client.get(
url_for("api.options", hostname="www.test.com"),
headers={"Authentication": api_key.code},
)
assert r.json["custom"]["suggestion"] == "www_test_com"
# <<< with recommendation >>>
alias = GenEmail.create_new_gen_email(user.id)
db.session.commit()
AliasUsedOn.create(gen_email_id=alias.id, hostname="www.test.com")
db.session.commit()
r = flask_client.get(
url_for("api.options", hostname="www.test.com"),
headers={"Authentication": api_key.code},
)
assert r.json["recommendation"]["alias"] == alias.email
assert r.json["recommendation"]["hostname"] == "www.test.com"