126 lines
3.5 KiB
Python
126 lines
3.5 KiB
Python
from datetime import timedelta
|
|
import random
|
|
import string
|
|
import urllib.parse
|
|
from flask import Blueprint, abort, make_response, redirect, request, url_for
|
|
import requests
|
|
from spectree import Response
|
|
from spec import spec
|
|
import models
|
|
from app_db import db
|
|
from models.auth_session import AuthSession
|
|
from models.player import Player, PlayerSchema
|
|
from middleware import requires_authentication
|
|
import sys
|
|
|
|
api_login = Blueprint("login", __name__, url_prefix="/login")
|
|
|
|
STEAM_OPENID_URL = "https://steamcommunity.com/openid/login"
|
|
|
|
@api_login.get("/")
|
|
def index():
|
|
return "test"
|
|
|
|
@api_login.get("/get-user")
|
|
@spec.validate(
|
|
resp=Response(
|
|
HTTP_200=PlayerSchema,
|
|
HTTP_401=None,
|
|
),
|
|
operation_id="get_user"
|
|
)
|
|
@requires_authentication
|
|
def get_user(player: Player, auth_session: AuthSession):
|
|
return PlayerSchema.from_model(player).dict(by_alias=True)
|
|
|
|
@api_login.post("/authenticate")
|
|
def steam_authenticate():
|
|
params = request.get_json()
|
|
params["openid.mode"] = "check_authentication"
|
|
|
|
steam_params = params
|
|
if "username" in steam_params:
|
|
del steam_params["username"]
|
|
|
|
response = requests.post(STEAM_OPENID_URL, data=steam_params)
|
|
print("response text = ", file=sys.stderr)
|
|
print(response.text, file=sys.stderr)
|
|
|
|
# check if authentication was successful
|
|
if "is_valid:true" in response.text:
|
|
claimed_id = params["openid.claimed_id"]
|
|
steam_id = int(extract_steam_id_from_response(claimed_id))
|
|
print("User logged in as", steam_id)
|
|
|
|
player = db.session.query(
|
|
Player
|
|
).where(
|
|
Player.steam_id == steam_id
|
|
).one_or_none()
|
|
|
|
is_registering = False
|
|
if not player:
|
|
# we are registering, so create user
|
|
player = Player()
|
|
player.username = str(steam_id)
|
|
player.steam_id = steam_id
|
|
is_registering = True
|
|
db.session.add(player)
|
|
|
|
auth_session = create_auth_session_for_player(player)
|
|
|
|
resp = make_response({
|
|
"message": "Logged in",
|
|
"steamId": player.steam_id,
|
|
"username": player.username,
|
|
"isRegistering": is_registering,
|
|
})
|
|
|
|
# TODO: secure=True in production
|
|
resp.set_cookie(
|
|
"auth",
|
|
auth_session.key,
|
|
httponly=True,
|
|
max_age=timedelta(days=30),
|
|
)
|
|
return resp
|
|
return abort(401)
|
|
|
|
@api_login.delete("/")
|
|
@requires_authentication
|
|
def logout(**kwargs):
|
|
auth_session: AuthSession = kwargs["auth_session"]
|
|
db.session.delete(auth_session)
|
|
response = make_response(200)
|
|
response.delete_cookie("auth")
|
|
return response
|
|
|
|
def create_or_get_user_from_steam_id(steam_id: int, username: str) -> Player:
|
|
statement = db.select(Player).filter_by(steam_id=steam_id)
|
|
player = db.session.execute(statement).scalar_one_or_none()
|
|
if not player:
|
|
player = Player()
|
|
player.steam_id = steam_id
|
|
player.username = username
|
|
db.session.add(player)
|
|
db.session.commit()
|
|
return player
|
|
|
|
def generate_base36(length):
|
|
alphabet = string.digits + string.ascii_uppercase
|
|
return "".join(random.choice(alphabet) for _ in range(length))
|
|
|
|
def create_auth_session_for_player(player: Player):
|
|
session = AuthSession()
|
|
session.player = player
|
|
|
|
random_key = generate_base36(31)
|
|
session.key = random_key
|
|
|
|
player.auth_sessions.append(session)
|
|
db.session.commit()
|
|
return session
|
|
|
|
def extract_steam_id_from_response(claimed_id_url):
|
|
return claimed_id_url.split("/")[-1]
|