From 02d26df292ec1fc1ef2c71dba97a6535e5e057f4 Mon Sep 17 00:00:00 2001 From: Son NK Date: Thu, 27 Feb 2020 22:57:24 +0700 Subject: [PATCH] add /api/auth/facebook --- README.md | 15 +++++++++ app/api/views/auth_login.py | 61 +++++++++++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b2cfdc0c..0158eb65 100644 --- a/README.md +++ b/README.md @@ -738,6 +738,21 @@ Output: The `api_key` is used in all subsequent requests. It's empty if MFA is enabled. If user hasn't enabled MFA, `mfa_key` is empty. +#### POST /api/auth/facebook + +Input: +- facebook_token: Facebook access token +- device: device name. Used to create the API Key. Should be humanly readable so user can manage later on the "API Key" page. + +Output: Same output as for `/api/auth/login` endpoint +- name: user name, could be an empty string +- mfa_enabled: boolean +- mfa_key: only useful when user enables MFA. In this case, user needs to enter their OTP token in order to login. +- api_key: if MFA is not enabled, the `api key` is returned right away. + +The `api_key` is used in all subsequent requests. It's empty if MFA is enabled. +If user hasn't enabled MFA, `mfa_key` is empty. + #### GET /api/aliases Get user aliases. diff --git a/app/api/views/auth_login.py b/app/api/views/auth_login.py index 59e78c1c..9fb4fb88 100644 --- a/app/api/views/auth_login.py +++ b/app/api/views/auth_login.py @@ -3,12 +3,20 @@ from flask import jsonify, request from flask_cors import cross_origin from itsdangerous import Signer +from app import email_utils from app.api.base import api_bp, verify_api_key -from app.config import EMAIL_DOMAIN, MAX_NB_EMAIL_FREE_PLAN, FLASK_SECRET +from app.config import ( + EMAIL_DOMAIN, + MAX_NB_EMAIL_FREE_PLAN, + FLASK_SECRET, + DISABLE_REGISTRATION, +) +from app.email_utils import can_be_used_as_personal_email, email_already_used from app.extensions import db from app.log import LOG -from app.models import GenEmail, AliasUsedOn, User, ApiKey +from app.models import GenEmail, AliasUsedOn, User, ApiKey, SocialAuth from app.utils import convert_to_id +import facebook @api_bp.route("/auth/login", methods=["POST"]) @@ -48,6 +56,55 @@ def auth_login(): return jsonify(**auth_payload(user, device)), 200 +@api_bp.route("/auth/facebook", methods=["POST"]) +@cross_origin() +def auth_facebook(): + """ + Authenticate user with Facebook + Input: + facebook_token: facebook access token + device: to create an ApiKey associated with this device + Output: + 200 and user info containing: + { + name: "John Wick", + mfa_enabled: true, + mfa_key: "a long string", + api_key: "a long string" + } + + """ + data = request.get_json() + if not data: + return jsonify(error="request body cannot be empty"), 400 + + facebook_token = data.get("facebook_token") + device = data.get("device") + + graph = facebook.GraphAPI(access_token=facebook_token) + user_info = graph.get_object("me", fields="email,name") + email = user_info.get("email") + + user = User.get_by(email=email) + + if not user: + if DISABLE_REGISTRATION: + return jsonify(error="registration is closed"), 400 + if not can_be_used_as_personal_email(email) or email_already_used(email): + return jsonify(error=f"cannot use {email} as personal inbox"), 400 + + LOG.d("create facebook user with %s", user_info) + user = User.create(email=email.lower(), name=user_info["name"], activated=True) + db.session.commit() + email_utils.send_welcome_email(user) + + if not SocialAuth.get_by(user_id=user.id, social="facebook"): + SocialAuth.create(user_id=user.id, social="facebook") + db.session.commit() + + return jsonify(**auth_payload(user, device)), 200 + + def auth_payload(user, device) -> dict: ret = { "name": user.name,