mirror of
https://github.com/hubHarmony/servii-backend.git
synced 2024-11-17 21:40:31 +00:00
[+] Added super-secure-token authentication
Now uses firebase complete tokens; it verifies the signature and integrity of the token, the origin of the project the token was issued for, the secret key, and finally the sub before verifying the account.
This commit is contained in:
parent
18acd1e08d
commit
9ad1bdaff9
@ -107,6 +107,8 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const uploadForm = document.getElementById('uploadForm');
|
||||
const messageDiv = document.getElementById('message');
|
||||
const token = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImUwM2E2ODg3YWU3ZjNkMTAyNzNjNjRiMDU3ZTY1MzE1MWUyOTBiNzIiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiSXR6IFNlbiIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS9BQ2c4b2NLOElVZHlzcW5kZkxxNFc5ZWlRNlpjTFpkbUVDX29UNXBVaURGQ2gzY2VDZTZXSGxvWD1zOTYtYyIsImlzcyI6Imh0dHBzOi8vc2VjdXJldG9rZW4uZ29vZ2xlLmNvbS9zZXJ2aS1lNjcwNSIsImF1ZCI6InNlcnZpLWU2NzA1IiwiYXV0aF90aW1lIjoxNzI2ODM5NTUwLCJ1c2VyX2lkIjoiTXBrYkRNT084UFFkZFFnQjVWZ0JRZFRNV0Y1MyIsInN1YiI6Ik1wa2JETU9POFBRZGRRZ0I1VmdCUWRUTVdGNTMiLCJpYXQiOjE3MjY4Mzk1NTAsImV4cCI6MTcyNjg0MzE1MCwiZW1haWwiOiJ0ZWNobm9wcm9kMjU0NTg1NjVAZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZ29vZ2xlLmNvbSI6WyIxMTQ0Mzk0NjEyOTM5OTE1NzU5MTgiXSwiZW1haWwiOlsidGVjaG5vcHJvZDI1NDU4NTY1QGdtYWlsLmNvbSJdfSwic2lnbl9pbl9wcm92aWRlciI6Imdvb2dsZS5jb20ifX0.Aa3mdAmOzYET_QsGk2-QKxLGhxtXGfyAcTRnnM6cPGx0UJeSoQ-EhMIgK7HDiLVni_eMHbnwMSeEXDHEpsCWosm6e3e96zwMU3GXI1nowcnZ3CYTDH8jDCs2-6_ODomZtT2S1Lp3fD7IoSD4tDGFdo9kZNyuFGApTHhFHNAyHvfBqGL_c0c71Gfh-6ywl5C8nc07YPVbYGJu6GrS28L1vOjRSkl89Xm7o6atf38YWYWwg84QsrugRlF7Nz6yZJf7cjRY5x2guilqxrWVCWhlLiCMqFhe4oIW3BL7s3AfUC6U7DvlTyGwZJoN3fUr7V1Q5xloqSz7dcexRe1YkXXrCA";
|
||||
|
||||
|
||||
// File Upload functionality
|
||||
uploadForm.addEventListener('submit', async event => {
|
||||
@ -129,6 +131,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
try {
|
||||
const response = await fetch('http://localhost:3000/Upload', {
|
||||
method: 'POST',
|
||||
headers: {'SST': token},
|
||||
body: formData
|
||||
});
|
||||
|
||||
@ -157,7 +160,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
button.addEventListener('click', async event => {
|
||||
event.preventDefault();
|
||||
const action = button.dataset.action;
|
||||
const token = "MpkbDMOO8PQddQgB5VgBQdTMWF53";
|
||||
//const token = "dhmNGJYaVzNkKWgMAEOoAjaPWdc2";
|
||||
const token = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImUwM2E2ODg3YWU3ZjNkMTAyNzNjNjRiMDU3ZTY1MzE1MWUyOTBiNzIiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiSXR6IFNlbiIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS9BQ2c4b2NLOElVZHlzcW5kZkxxNFc5ZWlRNlpjTFpkbUVDX29UNXBVaURGQ2gzY2VDZTZXSGxvWD1zOTYtYyIsImlzcyI6Imh0dHBzOi8vc2VjdXJldG9rZW4uZ29vZ2xlLmNvbS9zZXJ2aS1lNjcwNSIsImF1ZCI6InNlcnZpLWU2NzA1IiwiYXV0aF90aW1lIjoxNzI2ODM5NTUwLCJ1c2VyX2lkIjoiTXBrYkRNT084UFFkZFFnQjVWZ0JRZFRNV0Y1MyIsInN1YiI6Ik1wa2JETU9POFBRZGRRZ0I1VmdCUWRUTVdGNTMiLCJpYXQiOjE3MjY4Mzk1NTAsImV4cCI6MTcyNjg0MzE1MCwiZW1haWwiOiJ0ZWNobm9wcm9kMjU0NTg1NjVAZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZ29vZ2xlLmNvbSI6WyIxMTQ0Mzk0NjEyOTM5OTE1NzU5MTgiXSwiZW1haWwiOlsidGVjaG5vcHJvZDI1NDU4NTY1QGdtYWlsLmNvbSJdfSwic2lnbl9pbl9wcm92aWRlciI6Imdvb2dsZS5jb20ifX0.Aa3mdAmOzYET_QsGk2-QKxLGhxtXGfyAcTRnnM6cPGx0UJeSoQ-EhMIgK7HDiLVni_eMHbnwMSeEXDHEpsCWosm6e3e96zwMU3GXI1nowcnZ3CYTDH8jDCs2-6_ODomZtT2S1Lp3fD7IoSD4tDGFdo9kZNyuFGApTHhFHNAyHvfBqGL_c0c71Gfh-6ywl5C8nc07YPVbYGJu6GrS28L1vOjRSkl89Xm7o6atf38YWYWwg84QsrugRlF7Nz6yZJf7cjRY5x2guilqxrWVCWhlLiCMqFhe4oIW3BL7s3AfUC6U7DvlTyGwZJoN3fUr7V1Q5xloqSz7dcexRe1YkXXrCA";
|
||||
const framework = document.getElementById('serverFramework').value;
|
||||
const subdomain = document.getElementById('subdomain').value;
|
||||
const email = document.getElementById('accountEmail').value;
|
||||
@ -172,58 +176,59 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
switch(action) {
|
||||
case 'FetchServers':
|
||||
data = {token};
|
||||
data = {};
|
||||
break;
|
||||
case 'FetchLogs':
|
||||
data = {token, name};
|
||||
data = {name};
|
||||
break;
|
||||
case 'FetchPlayersStatus':
|
||||
data = {token, name};
|
||||
data = { name};
|
||||
break;
|
||||
case 'FetchDirContent':
|
||||
data = {token, name};
|
||||
data = { name};
|
||||
break;
|
||||
case 'AccountCreate':
|
||||
data = {email, port, token};
|
||||
data = {email, port, };
|
||||
break;
|
||||
case 'AccountDelete':
|
||||
data = {subdomain, port, token};
|
||||
data = {subdomain, port, };
|
||||
break;
|
||||
case 'ServerCreate':
|
||||
data = {port, name, version, token, framework};
|
||||
data = {port, name, version, framework};
|
||||
break;
|
||||
case 'ServerDelete':
|
||||
data = {port, name, token};
|
||||
data = {port, name, };
|
||||
break;
|
||||
case 'ServerRun':
|
||||
data = {port, name, token};
|
||||
data = {port, name, };
|
||||
break;
|
||||
case 'ServerStop':
|
||||
data = {port, name, token};
|
||||
data = {port, name, };
|
||||
break;
|
||||
case 'UpdateProperties':
|
||||
data = {port, name, props, value, token};
|
||||
data = {port, name, props, value, };
|
||||
break;
|
||||
case 'Command':
|
||||
data = {port, name, command, token};
|
||||
data = {port, name, command, };
|
||||
break;
|
||||
case 'SetSubdomain':
|
||||
data = {token, subdomain};
|
||||
data = {subdomain};
|
||||
break;
|
||||
}
|
||||
|
||||
sendRequest(action, data)
|
||||
sendRequest(action, data, token)
|
||||
.then(response => response.text())
|
||||
.then(data => alert(`Response: ${data}`))
|
||||
.catch(error => console.error('Error:', error));
|
||||
});
|
||||
});
|
||||
|
||||
function sendRequest(endpoint, payload) {
|
||||
function sendRequest(endpoint, payload, token) {
|
||||
return fetch(`http://localhost:3000/${endpoint}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
'SST': token,
|
||||
},
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
37
app.py
37
app.py
@ -55,28 +55,25 @@ TODO : replace 53 by the given statement.
|
||||
'''
|
||||
|
||||
|
||||
def authenticate_request(data: dict):
|
||||
if 'token' not in data:
|
||||
raise Exception("Missing 'token' in request body. The API doesn't support anonymous access anymore.")
|
||||
def authenticate_request(token: str):
|
||||
valid, user_id = firebase_manager.verify_jwt_token(token)
|
||||
if not valid:
|
||||
raise Exception("Invalid JWT token.")
|
||||
else:
|
||||
valid, user_id = True, data['token']
|
||||
if not valid:
|
||||
raise Exception("Invalid JWT token.")
|
||||
else:
|
||||
user = firebase_manager.get_user_from_id(user_id)
|
||||
if not user:
|
||||
raise Exception("User not found.")
|
||||
if not user.email_verified:
|
||||
raise Exception("Your google account isn't verified yet.")
|
||||
user = firebase_manager.get_user_from_id(user_id)
|
||||
if not user:
|
||||
raise Exception("User not found.")
|
||||
if not user.email_verified:
|
||||
raise Exception("Your google account isn't verified yet.")
|
||||
return user
|
||||
|
||||
|
||||
def parse_and_validate_request(parameters: list[str]) -> Union[list[str], None]:
|
||||
def parse_and_validate_request(parameters: list[str], token: str) -> Union[list[str], None]:
|
||||
fn_args = []
|
||||
data = request.get_json()
|
||||
if not data:
|
||||
raise Exception("Empty request body.")
|
||||
user = authenticate_request(data)
|
||||
user = authenticate_request(token)
|
||||
data['user'] = user
|
||||
for name in parameters:
|
||||
if name not in data:
|
||||
@ -115,7 +112,10 @@ def dynamic_route_handler(path):
|
||||
for param in sig.parameters.values():
|
||||
parameters.append(param.name)
|
||||
try:
|
||||
mapped_parameters = parse_and_validate_request(parameters)
|
||||
token: str or None = request.headers.get('SST')
|
||||
if not token:
|
||||
return generic_response_maker(http.HTTPStatus.BAD_REQUEST, "No provided token.")
|
||||
mapped_parameters = parse_and_validate_request(parameters, token)
|
||||
if mapped_parameters is None:
|
||||
return generic_response_maker(http.HTTPStatus.BAD_REQUEST)
|
||||
status, message = route_fn(*mapped_parameters)
|
||||
@ -130,7 +130,7 @@ def dynamic_route_handler(path):
|
||||
@apiBP.route('/Upload', methods=['POST'])
|
||||
def upload():
|
||||
form = request.form
|
||||
token: str or None = form.get('token')
|
||||
token: str or None = request.headers.get('SST')
|
||||
name: str or None = form.get('name')
|
||||
files: ImmutableMultiDict[str, FileStorage] = request.files
|
||||
|
||||
@ -144,8 +144,7 @@ def upload():
|
||||
if not name:
|
||||
raise KeyError('name')
|
||||
|
||||
data: dict = {'token': token}
|
||||
user: UserRecord = authenticate_request(data)
|
||||
user: UserRecord = authenticate_request(token)
|
||||
user_id: str = user.uid
|
||||
|
||||
for _, file in files.items():
|
||||
@ -200,4 +199,4 @@ if __name__ == '__main__':
|
||||
scheduler.start()
|
||||
|
||||
run_simple('0.0.0.0', 3000, app, use_debugger=False, use_reloader=False)
|
||||
api_cleanup()
|
||||
#api_cleanup()
|
@ -22,13 +22,16 @@ def get_user_from_id(user_id):
|
||||
|
||||
def verify_jwt_token(token):
|
||||
try:
|
||||
decoded_token = jwt.decode(token, options={"verify_signature": False})
|
||||
decoded_token = auth.verify_id_token(token, app=app, check_revoked=True)
|
||||
user_id = decoded_token.get('sub')
|
||||
return True, user_id
|
||||
except jwt.ExpiredSignatureError:
|
||||
return False, None
|
||||
except jwt.InvalidTokenError:
|
||||
return False, None
|
||||
except Exception as e:
|
||||
log_exception_to_firestore(e, None, {"user": None, "error-step": "auth"})
|
||||
return False, None
|
||||
|
||||
|
||||
def fetch_port() -> Union[int, None]:
|
||||
|
@ -2,6 +2,9 @@ import os
|
||||
import shutil
|
||||
from typing import Callable, Union
|
||||
|
||||
from firebase_admin import auth
|
||||
from jwt.api_jws import decode_complete
|
||||
|
||||
import firebase_manager
|
||||
import server_mc_manager
|
||||
from generic_executor import mc_manager
|
||||
@ -41,4 +44,7 @@ if __name__ == '__main__':
|
||||
listdir("/home/hapso/Desktop/Personal/servii-backend/servers/paper"),
|
||||
"/home/hapso/Desktop/Personal/servii-backend/servers/paper")
|
||||
'''
|
||||
token: str = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImUwM2E2ODg3YWU3ZjNkMTAyNzNjNjRiMDU3ZTY1MzE1MWUyOTBiNzIiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiSXR6IFNlbiIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS9BQ2c4b2NLOElVZHlzcW5kZkxxNFc5ZWlRNlpjTFpkbUVDX29UNXBVaURGQ2gzY2VDZTZXSGxvWD1zOTYtYyIsImlzcyI6Imh0dHBzOi8vc2VjdXJldG9rZW4uZ29vZ2xlLmNvbS9zZXJ2aS1lNjcwNSIsImF1ZCI6InNlcnZpLWU2NzA1IiwiYXV0aF90aW1lIjoxNzI2ODI1ODEzLCJ1c2VyX2lkIjoiTXBrYkRNT084UFFkZFFnQjVWZ0JRZFRNV0Y1MyIsInN1YiI6Ik1wa2JETU9POFBRZGRRZ0I1VmdCUWRUTVdGNTMiLCJpYXQiOjE3MjY4MjU4MTMsImV4cCI6MTcyNjgyOTQxMywiZW1haWwiOiJ0ZWNobm9wcm9kMjU0NTg1NjVAZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZ29vZ2xlLmNvbSI6WyIxMTQ0Mzk0NjEyOTM5OTE1NzU5MTgiXSwiZW1haWwiOlsidGVjaG5vcHJvZDI1NDU4NTY1QGdtYWlsLmNvbSJdfSwic2lnbl9pbl9wcm92aWRlciI6Imdvb2dsZS5jb20ifX0.K1xpVX3S83b8AIUShE33bcTcN0XaxA1Uh4oe-sjVE51BGbrpHWw5SNhMzBAiaadPf_mET6-85WdmTYTFcXoDhiC5YhXDfu4fsyQq3K-zwi0ZDNOB0A3Xa7kdsCTwYSxb1DAq3zUZSLH6OHq6af1mGFfsH1WmQ9FT34ULgiBV4W1IHH4PtuYIc1kszgNAxU2lJehi2YsCYB2OZ47VohtOpfYtisJzA9er-L9WmtrMKokxTuCXAuhKIZwb0xAr_ZkZSDx8J1uhGPnPPMeID-7cXXg_tcvCv_WSlTXioQ20hG8J4Lq8Xz1ldQmbcdXl_owqty5m3MdIDiDvP8C9Oc_yLg"
|
||||
decoded = auth.verify_id_token(token, app=firebase_manager.app, check_revoked=True)
|
||||
print(decoded)
|
||||
pass
|
||||
|
Loading…
Reference in New Issue
Block a user