Add /api/v4/alias/options

This commit is contained in:
Son NK 2020-05-02 16:21:18 +02:00
parent 56967e7a38
commit 72e9b52b29
3 changed files with 128 additions and 10 deletions

View File

@ -659,7 +659,7 @@ Output: if api key is correct, return a json with user name and whether user is
If api key is incorrect, return 401. If api key is incorrect, return 401.
#### GET /api/v3/alias/options #### GET /api/v4/alias/options
User alias info and suggestion. Used by the first extension screen when user opens the extension. User alias info and suggestion. Used by the first extension screen when user opens the extension.
@ -669,7 +669,7 @@ Input:
Output: a json with the following field: Output: a json with the following field:
- can_create: boolean. Whether user can create new alias - can_create: boolean. Whether user can create new alias
- suffixes: list of string. List of alias `suffix` that user can use. If user doesn't have custom domain, this list has a single element which is the alias default domain (simplelogin.co). - suffixes: list of `[suffix, signed-suffix]`. List of alias `suffix` that user can use. The `signed-suffix` is necessary to avoid request tampering.
- prefix_suggestion: string. Suggestion for the `alias prefix`. Usually this is the website name extracted from `hostname`. If no `hostname`, then the `prefix_suggestion` is empty. - prefix_suggestion: string. Suggestion for the `alias prefix`. Usually this is the website name extracted from `hostname`. If no `hostname`, then the `prefix_suggestion` is empty.
- recommendation: optional field, dictionary. If an alias is already used for this website, the recommendation will be returned. There are 2 subfields in `recommendation`: `alias` which is the recommended alias and `hostname` is the website on which this alias is used before. - recommendation: optional field, dictionary. If an alias is already used for this website, the recommendation will be returned. There are 2 subfields in `recommendation`: `alias` which is the recommended alias and `hostname` is the website on which this alias is used before.
@ -677,15 +677,16 @@ For ex:
```json ```json
{ {
"can_create": true, "can_create": true,
"prefix_suggestion": "test", "prefix_suggestion": "",
"recommendation": {
"alias": "e1.cat@sl.local",
"hostname": "www.test.com"
},
"suffixes": [ "suffixes": [
"@very-long-domain.com.net.org", [
"@ab.cd", "@ab.cd",
".cat@sl.local" "@ab.cd.Xq2BOA.zBebBB-QYikFkbPZ9CPKGpJ2-PU"
],
[
".yeah@local1.localhost",
".yeah@local1.localhost.Xq2BOA.dM9gyHyHcSXuJ8ps4i3wpJZ_Frw"
]
] ]
} }
``` ```

View File

@ -4,6 +4,7 @@ from sqlalchemy import desc
from app.api.base import api_bp, require_api_auth from app.api.base import api_bp, require_api_auth
from app.config import ALIAS_DOMAINS, DISABLE_ALIAS_SUFFIX from app.config import ALIAS_DOMAINS, DISABLE_ALIAS_SUFFIX
from app.dashboard.views.custom_alias import available_suffixes
from app.extensions import db from app.extensions import db
from app.log import LOG from app.log import LOG
from app.models import AliasUsedOn, Alias, User from app.models import AliasUsedOn, Alias, User
@ -239,3 +240,71 @@ def options_v3():
ret["suffixes"] = list(reversed(ret["suffixes"])) ret["suffixes"] = list(reversed(ret["suffixes"]))
return jsonify(ret) return jsonify(ret)
@api_bp.route("/v4/alias/options")
@cross_origin()
@require_api_auth
def options_v4():
"""
Return what options user has when creating new alias.
Same as v3 but return time-based signed-suffix in addition to suffix. To be used with /v2/alias/custom/new
Input:
a valid api-key in "Authentication" header and
optional "hostname" in args
Output: cf README
can_create: bool
suffixes: [[suffix, signed_suffix]]
prefix_suggestion: str
recommendation: Optional dict
alias: str
hostname: str
"""
user = g.user
hostname = request.args.get("hostname")
ret = {
"can_create": user.can_create_new_alias(),
"suffixes": [],
"prefix_suggestion": "",
}
# recommendation alias if exist
if hostname:
# put the latest used alias first
q = (
db.session.query(AliasUsedOn, Alias, User)
.filter(
AliasUsedOn.alias_id == Alias.id,
Alias.user_id == user.id,
AliasUsedOn.hostname == hostname,
)
.order_by(desc(AliasUsedOn.created_at))
)
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 hostname:
# keep only the domain name of hostname, ignore TLD and subdomain
# for ex www.groupon.com -> groupon
domain_name = hostname
if "." in hostname:
parts = hostname.split(".")
domain_name = parts[-2]
domain_name = convert_to_id(domain_name)
ret["prefix_suggestion"] = domain_name
# List of (is_custom_domain, alias-suffix, time-signed alias-suffix)
suffixes = available_suffixes(user)
# custom domain should be put first
ret["suffixes"] = list([suffix[1], suffix[2]] for suffix in suffixes)
return jsonify(ret)

View File

@ -143,3 +143,51 @@ def test_different_scenarios_v3(flask_client):
) )
assert r.json["recommendation"]["alias"] == alias.email assert r.json["recommendation"]["alias"] == alias.email
assert r.json["recommendation"]["hostname"] == "www.test.com" assert r.json["recommendation"]["hostname"] == "www.test.com"
def test_different_scenarios_v4(flask_client):
user = User.create(
email="a@b.c", password="password", name="Test User", activated=True
)
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_v4"), headers={"Authentication": api_key.code}
)
assert r.status_code == 200
assert r.json["can_create"]
assert r.json["suffixes"]
assert r.json["prefix_suggestion"] == "" # no hostname => no suggestion
for (suffix, signed_suffix) in r.json["suffixes"]:
assert signed_suffix.startswith(suffix)
# <<< with hostname >>>
r = flask_client.get(
url_for("api.options_v4", hostname="www.test.com"),
headers={"Authentication": api_key.code},
)
assert r.json["prefix_suggestion"] == "test"
# <<< with recommendation >>>
alias = Alias.create_new(user, prefix="test")
db.session.commit()
AliasUsedOn.create(
alias_id=alias.id, hostname="www.test.com", user_id=alias.user_id
)
db.session.commit()
r = flask_client.get(
url_for("api.options_v4", hostname="www.test.com"),
headers={"Authentication": api_key.code},
)
assert r.json["recommendation"]["alias"] == alias.email
assert r.json["recommendation"]["hostname"] == "www.test.com"