PKCE support

This commit is contained in:
Tracker-Friendly 2024-03-31 12:38:29 +01:00
parent 5d41541921
commit 127fcfa964
2 changed files with 35 additions and 4 deletions

35
main
View File

@ -1,4 +1,6 @@
#!/usr/bin/python3 #!/usr/bin/python3
import hashlib
import base64
import jwt import jwt
import os import os
import sqlite3 import sqlite3
@ -31,6 +33,12 @@ if SECRET_KEY == "supersecretkey" or SECRET_KEY == "placeholder":
app = Quart(__name__) app = Quart(__name__)
app.config["SECRET_KEY"] = SECRET_KEY app.config["SECRET_KEY"] = SECRET_KEY
# Hash creation function
def sha256_base64(s: str) -> str:
hashed = hashlib.sha256(s.encode()).digest()
encoded = base64.urlsafe_b64encode(hashed).rstrip(b'=').decode()
return encoded
# Database functions # Database functions
def get_db_connection(): def get_db_connection():
conn = sqlite3.connect("database.db") conn = sqlite3.connect("database.db")
@ -246,6 +254,8 @@ async def apiauthenticate():
data = await request.get_json() data = await request.get_json()
secretKey = data["secretKey"] secretKey = data["secretKey"]
appId = data["appId"] appId = data["appId"]
code = data["code"]
codemethod = data["codemethod"]
userCookie = get_session(secretKey) userCookie = get_session(secretKey)
user = get_user(userCookie["id"]) user = get_user(userCookie["id"])
@ -282,8 +292,8 @@ async def apiauthenticate():
nextjwt_token = jwt.encode(datatemplate2, SECRET_KEY, algorithm='HS256') nextjwt_token = jwt.encode(datatemplate2, SECRET_KEY, algorithm='HS256')
conn.execute("INSERT INTO logins (appId, secret, nextsecret, code, nextcode, creator, openid, nextopenid) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", conn.execute("INSERT INTO logins (appId, secret, nextsecret, code, nextcode, creator, openid, nextopenid, pkce, pkcemethod) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
(str(appId), str(secretkey), str(secrets.token_hex(512)), str(secrets.token_hex(512)), str(secrets.token_hex(512)), int(user["id"]), str(jwt_token), str(nextjwt_token))) (str(appId), str(secretkey), str(secrets.token_hex(512)), str(secrets.token_hex(512)), str(secrets.token_hex(512)), int(user["id"]), str(jwt_token), str(nextjwt_token), str(code), str(codemethod)))
conn.commit() conn.commit()
conn.close() conn.close()
@ -301,13 +311,32 @@ async def apitokenexchange():
appId = data["client_id"] appId = data["client_id"]
code = data["code"] code = data["code"]
if "code_verifier" in data:
code_verify = data["code_verifier"]
verifycode = true
else:
verifycode = false
conn = get_db_connection() conn = get_db_connection()
# Fetch required data in a single query # Fetch required data in a single query
oauth_data = conn.execute("SELECT appId, secret FROM oauth WHERE appId = ?", (str(appId),)).fetchone() oauth_data = conn.execute("SELECT appId, secret, pkce, pkcemethod FROM oauth WHERE appId = ?", (str(appId),)).fetchone()
if not oauth_data or oauth_data["appId"] != appId or oauth_data["secret"] != secret: if not oauth_data or oauth_data["appId"] != appId or oauth_data["secret"] != secret:
return {}, 401 return {}, 401
if verifycode:
if str(oauth_data["pkce"]) == "none":
return 400
else:
if str(oauth_data["pkcemethod"]) == "S256":
if str(sha256_base64(code_verify)) != str(oauth_data["code"]):
return 403
elif str(oauth_data["pkcemethod"]) == "plain":
if str(code_verify) != str(oauth_data["code"]):
return 403
else:
return 501
newkey = str(secrets.token_hex(512)) newkey = str(secrets.token_hex(512))
conn.execute("UPDATE logins SET secret = ?, nextsecret = ? WHERE appId = ? AND secret = ?", (str(newkey), str(secrets.token_hex(512)), str(appId), str(secret))) conn.execute("UPDATE logins SET secret = ?, nextsecret = ? WHERE appId = ? AND secret = ?", (str(newkey), str(secrets.token_hex(512)), str(appId), str(secret)))

View File

@ -31,7 +31,9 @@ CREATE TABLE logins (
code TEXT NOT NULL, code TEXT NOT NULL,
nextcode TEXT NOT NULL, nextcode TEXT NOT NULL,
creator INTEGER NOT NULL, creator INTEGER NOT NULL,
openid TEXT NOT NULL openid TEXT NOT NULL,
pkce TEXT NOT NULL,
pkcemethod TEXT NOT NULL
); );
CREATE TABLE oauth ( CREATE TABLE oauth (