OAuth2 build working

This commit is contained in:
Tracker-Friendly 2024-05-14 01:23:03 +01:00
parent 060df3b740
commit 64818f1e6e
3 changed files with 154 additions and 8 deletions

View File

@ -1,6 +1,6 @@
[config] [config]
PORT = 8080 PORT = 8083
SECRET_KEY = placeholder SECRET_KEY = illaaaaaaaaaaaaaaaaaaaaaaaaaaoewhoihowheowheowheow
UPLOAD_FOLDER = uploads UPLOAD_FOLDER = uploads
PASSWORD_REQUIREMENT = 12 PASSWORD_REQUIREMENT = 8
UPLOAD_LIMIT = 12 UPLOAD_LIMIT = 8

12
main
View File

@ -388,13 +388,15 @@ async def apilogin():
}, 400 }, 400
@app.route("/api/oauth", methods=("GET", "POST")) @app.route("/api/oauth", methods=("GET", "POST"))
async def apilogin(): async def apioauth():
if request.method == "POST": if request.method == "POST":
data = await request.get_json() data = await request.get_json()
username = data["username"] username = data["username"]
password = data["access_token"] password = data["access_token"]
response = requests.post("https://auth.hectabit.org/api/loggedin", {"access_token": password}) conn = get_db_connection()
subdata = '{"access_token":"' + password + '"}'
response = requests.post("https://auth.hectabit.org/api/loggedin", subdata)
if response.status_code == 200: if response.status_code == 200:
userID = check_username_taken(username) userID = check_username_taken(username)
user = get_user(userID) user = get_user(userID)
@ -402,11 +404,10 @@ async def apilogin():
conn.execute("INSERT INTO users (username, password, created, htmldescription) VALUES (?, ?, ?, ?)", conn.execute("INSERT INTO users (username, password, created, htmldescription) VALUES (?, ?, ?, ?)",
(username, "OAUTH2", str(time.time()), "")) (username, "OAUTH2", str(time.time()), ""))
else: else:
return {"error": "oauth2 token error"}, response.status_code return {"error": response.json()["error"]}, response.status_code
randomCharacters = secrets.token_hex(512) randomCharacters = secrets.token_hex(512)
conn = get_db_connection()
conn.execute("INSERT INTO sessions (session, id) VALUES (?, ?)", conn.execute("INSERT INTO sessions (session, id) VALUES (?, ?)",
(randomCharacters, userID)) (randomCharacters, userID))
conn.commit() conn.commit()
@ -625,6 +626,9 @@ async def login():
else: else:
return await render_template("login.html") return await render_template("login.html")
@app.route("/oauth", methods=("GET", "POST"))
async def oauth():
return await render_template("oauth.html")
@app.route("/settings", methods=("GET", "POST")) @app.route("/settings", methods=("GET", "POST"))
async def settings(): async def settings():

142
templates/oauth.html Normal file
View File

@ -0,0 +1,142 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OAuth2 Test</title>
</head>
<body>
<h1 id="text">Login using OAuth2</h1>
<button onclick="authorize()">Authorize</button>
<script>
// Configuration
const clientId = 'jT89GqLCqobN3pb6Rgkk0klDyicUbdjY';
const redirectUri = 'https://cat.hectabit.org/oauth';
const authorizationEndpoint = 'https://auth.hectabit.org/login';
const tokenEndpoint = 'https://auth.hectabit.org/api/tokenauth';
const userinfoEndpoint = 'https://auth.hectabit.org/userinfo'; // Added userinfo endpoint
// Generate a random code verifier
function generateCodeVerifier() {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~";
const length = 128;
return Array.from(crypto.getRandomValues(new Uint8Array(length)))
.map((x) => charset[x % charset.length])
.join("");
}
// Create a code challenge from the code verifier using SHA-256
async function createCodeChallenge(codeVerifier) {
const buffer = new TextEncoder().encode(codeVerifier);
const hashArrayBuffer = await crypto.subtle.digest('SHA-256', buffer);
const hashBase64 = btoa(String.fromCharCode(...new Uint8Array(hashArrayBuffer)))
.replace(/=/g, '')
.replace(/\+/g, '-')
.replace(/\//g, '_');
return hashBase64;
}
// Authorization function with PKCE
function authorize() {
const codeVerifier = generateCodeVerifier();
localStorage.setItem('codeVerifier', codeVerifier); // Store code verifier
createCodeChallenge(codeVerifier)
.then((codeChallenge) => {
const authorizationUrl = `${authorizationEndpoint}?response_type=code&client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&code_challenge=${codeChallenge}&code_challenge_method=S256`;
window.location.href = authorizationUrl;
})
.catch((error) => {
console.error('Error generating code challenge:', error);
});
}
// Parse the authorization code from the URL
function parseCodeFromUrl() {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get('code');
}
// Exchange authorization code for access token
async function exchangeCodeForToken(code) {
const codeVerifier = localStorage.getItem('codeVerifier'); // Retrieve code verifier
const formData = new URLSearchParams();
formData.append('client_id', String(clientId));
formData.append('code', String(code));
formData.append('redirect_uri', String(redirectUri));
formData.append('grant_type', 'authorization_code');
formData.append('code_verifier', String(codeVerifier));
const response = await fetch(tokenEndpoint, {
method: 'POST',
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: formData
});
const data = await response.json();
const accessToken = data.access_token;
const idToken = data.id_token;
// Request userinfo with id_token in bearer format
fetch(userinfoEndpoint, {
headers: {
"Authorization": `Bearer ${idToken}`
}
})
.then((response) => {
async function doStuff() {
if (response.status == 200) {
const userinfoData = await response.json();
console.log("User:", userinfoData.name)
console.log("Sub:", userinfoData.sub);
document.getElementById("text").innerText = "Authenticating, " + userinfoData.name;
fetch("https://cat.hectabit.org/api/oauth", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
username: userinfoData.name,
access_token: data.access_token
})
})
.then((response) => {
async function doStuff2() {
let key = await response.json()
if (response.status == 200) {
document.cookie = "session_DO_NOT_SHARE" + "=" + (key["key"] || "") + "; expires=Session" + "; path=/" + "; samesite=Strict";
window.location.replace("/")
} else {
document.getElementById("text").innerText = "Failed: " + key["error"]
}
}
doStuff2()
});
localStorage.setItem("user", userinfoData.name)
localStorage.setItem("sub", userinfoData.sub)
} else {
document.getElementById("text").innerText = "Authentication failed"
}
}
doStuff()
});
}
// Main function to handle OAuth2 flow
async function main() {
if (localStorage.getItem("user") !== null) {
document.getElementById("text").innerText = "Welcome back, " + localStorage.getItem("user")
}
const code = parseCodeFromUrl();
if (code) {
await exchangeCodeForToken(code);
}
}
// Call the main function on page load
main();
</script>
</body>
</html>