add /api/alias/options
This commit is contained in:
parent
c58d9052e7
commit
ab4f5bf329
32
README.md
32
README.md
|
@ -74,4 +74,36 @@ response_type=id_token code
|
||||||
return `id_token` in addition to `authorization_code` in /authorization endpoint
|
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"}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
from .views import index
|
from .views import index, alias_options
|
||||||
|
|
|
@ -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")
|
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
|
||||||
|
|
|
@ -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,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"
|
Loading…
Reference in New Issue