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', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const uploadForm = document.getElementById('uploadForm');
|
const uploadForm = document.getElementById('uploadForm');
|
||||||
const messageDiv = document.getElementById('message');
|
const messageDiv = document.getElementById('message');
|
||||||
|
const token = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImUwM2E2ODg3YWU3ZjNkMTAyNzNjNjRiMDU3ZTY1MzE1MWUyOTBiNzIiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiSXR6IFNlbiIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS9BQ2c4b2NLOElVZHlzcW5kZkxxNFc5ZWlRNlpjTFpkbUVDX29UNXBVaURGQ2gzY2VDZTZXSGxvWD1zOTYtYyIsImlzcyI6Imh0dHBzOi8vc2VjdXJldG9rZW4uZ29vZ2xlLmNvbS9zZXJ2aS1lNjcwNSIsImF1ZCI6InNlcnZpLWU2NzA1IiwiYXV0aF90aW1lIjoxNzI2ODM5NTUwLCJ1c2VyX2lkIjoiTXBrYkRNT084UFFkZFFnQjVWZ0JRZFRNV0Y1MyIsInN1YiI6Ik1wa2JETU9POFBRZGRRZ0I1VmdCUWRUTVdGNTMiLCJpYXQiOjE3MjY4Mzk1NTAsImV4cCI6MTcyNjg0MzE1MCwiZW1haWwiOiJ0ZWNobm9wcm9kMjU0NTg1NjVAZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZ29vZ2xlLmNvbSI6WyIxMTQ0Mzk0NjEyOTM5OTE1NzU5MTgiXSwiZW1haWwiOlsidGVjaG5vcHJvZDI1NDU4NTY1QGdtYWlsLmNvbSJdfSwic2lnbl9pbl9wcm92aWRlciI6Imdvb2dsZS5jb20ifX0.Aa3mdAmOzYET_QsGk2-QKxLGhxtXGfyAcTRnnM6cPGx0UJeSoQ-EhMIgK7HDiLVni_eMHbnwMSeEXDHEpsCWosm6e3e96zwMU3GXI1nowcnZ3CYTDH8jDCs2-6_ODomZtT2S1Lp3fD7IoSD4tDGFdo9kZNyuFGApTHhFHNAyHvfBqGL_c0c71Gfh-6ywl5C8nc07YPVbYGJu6GrS28L1vOjRSkl89Xm7o6atf38YWYWwg84QsrugRlF7Nz6yZJf7cjRY5x2guilqxrWVCWhlLiCMqFhe4oIW3BL7s3AfUC6U7DvlTyGwZJoN3fUr7V1Q5xloqSz7dcexRe1YkXXrCA";
|
||||||
|
|
||||||
|
|
||||||
// File Upload functionality
|
// File Upload functionality
|
||||||
uploadForm.addEventListener('submit', async event => {
|
uploadForm.addEventListener('submit', async event => {
|
||||||
@ -129,6 +131,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
try {
|
try {
|
||||||
const response = await fetch('http://localhost:3000/Upload', {
|
const response = await fetch('http://localhost:3000/Upload', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
headers: {'SST': token},
|
||||||
body: formData
|
body: formData
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -157,7 +160,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
button.addEventListener('click', async event => {
|
button.addEventListener('click', async event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const action = button.dataset.action;
|
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 framework = document.getElementById('serverFramework').value;
|
||||||
const subdomain = document.getElementById('subdomain').value;
|
const subdomain = document.getElementById('subdomain').value;
|
||||||
const email = document.getElementById('accountEmail').value;
|
const email = document.getElementById('accountEmail').value;
|
||||||
@ -172,58 +176,59 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
switch(action) {
|
switch(action) {
|
||||||
case 'FetchServers':
|
case 'FetchServers':
|
||||||
data = {token};
|
data = {};
|
||||||
break;
|
break;
|
||||||
case 'FetchLogs':
|
case 'FetchLogs':
|
||||||
data = {token, name};
|
data = {name};
|
||||||
break;
|
break;
|
||||||
case 'FetchPlayersStatus':
|
case 'FetchPlayersStatus':
|
||||||
data = {token, name};
|
data = { name};
|
||||||
break;
|
break;
|
||||||
case 'FetchDirContent':
|
case 'FetchDirContent':
|
||||||
data = {token, name};
|
data = { name};
|
||||||
break;
|
break;
|
||||||
case 'AccountCreate':
|
case 'AccountCreate':
|
||||||
data = {email, port, token};
|
data = {email, port, };
|
||||||
break;
|
break;
|
||||||
case 'AccountDelete':
|
case 'AccountDelete':
|
||||||
data = {subdomain, port, token};
|
data = {subdomain, port, };
|
||||||
break;
|
break;
|
||||||
case 'ServerCreate':
|
case 'ServerCreate':
|
||||||
data = {port, name, version, token, framework};
|
data = {port, name, version, framework};
|
||||||
break;
|
break;
|
||||||
case 'ServerDelete':
|
case 'ServerDelete':
|
||||||
data = {port, name, token};
|
data = {port, name, };
|
||||||
break;
|
break;
|
||||||
case 'ServerRun':
|
case 'ServerRun':
|
||||||
data = {port, name, token};
|
data = {port, name, };
|
||||||
break;
|
break;
|
||||||
case 'ServerStop':
|
case 'ServerStop':
|
||||||
data = {port, name, token};
|
data = {port, name, };
|
||||||
break;
|
break;
|
||||||
case 'UpdateProperties':
|
case 'UpdateProperties':
|
||||||
data = {port, name, props, value, token};
|
data = {port, name, props, value, };
|
||||||
break;
|
break;
|
||||||
case 'Command':
|
case 'Command':
|
||||||
data = {port, name, command, token};
|
data = {port, name, command, };
|
||||||
break;
|
break;
|
||||||
case 'SetSubdomain':
|
case 'SetSubdomain':
|
||||||
data = {token, subdomain};
|
data = {subdomain};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendRequest(action, data)
|
sendRequest(action, data, token)
|
||||||
.then(response => response.text())
|
.then(response => response.text())
|
||||||
.then(data => alert(`Response: ${data}`))
|
.then(data => alert(`Response: ${data}`))
|
||||||
.catch(error => console.error('Error:', error));
|
.catch(error => console.error('Error:', error));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function sendRequest(endpoint, payload) {
|
function sendRequest(endpoint, payload, token) {
|
||||||
return fetch(`http://localhost:3000/${endpoint}`, {
|
return fetch(`http://localhost:3000/${endpoint}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json',
|
||||||
|
'SST': token,
|
||||||
},
|
},
|
||||||
body: JSON.stringify(payload)
|
body: JSON.stringify(payload)
|
||||||
});
|
});
|
||||||
|
23
app.py
23
app.py
@ -55,11 +55,8 @@ TODO : replace 53 by the given statement.
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
def authenticate_request(data: dict):
|
def authenticate_request(token: str):
|
||||||
if 'token' not in data:
|
valid, user_id = firebase_manager.verify_jwt_token(token)
|
||||||
raise Exception("Missing 'token' in request body. The API doesn't support anonymous access anymore.")
|
|
||||||
else:
|
|
||||||
valid, user_id = True, data['token']
|
|
||||||
if not valid:
|
if not valid:
|
||||||
raise Exception("Invalid JWT token.")
|
raise Exception("Invalid JWT token.")
|
||||||
else:
|
else:
|
||||||
@ -71,12 +68,12 @@ def authenticate_request(data: dict):
|
|||||||
return user
|
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 = []
|
fn_args = []
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
if not data:
|
if not data:
|
||||||
raise Exception("Empty request body.")
|
raise Exception("Empty request body.")
|
||||||
user = authenticate_request(data)
|
user = authenticate_request(token)
|
||||||
data['user'] = user
|
data['user'] = user
|
||||||
for name in parameters:
|
for name in parameters:
|
||||||
if name not in data:
|
if name not in data:
|
||||||
@ -115,7 +112,10 @@ def dynamic_route_handler(path):
|
|||||||
for param in sig.parameters.values():
|
for param in sig.parameters.values():
|
||||||
parameters.append(param.name)
|
parameters.append(param.name)
|
||||||
try:
|
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:
|
if mapped_parameters is None:
|
||||||
return generic_response_maker(http.HTTPStatus.BAD_REQUEST)
|
return generic_response_maker(http.HTTPStatus.BAD_REQUEST)
|
||||||
status, message = route_fn(*mapped_parameters)
|
status, message = route_fn(*mapped_parameters)
|
||||||
@ -130,7 +130,7 @@ def dynamic_route_handler(path):
|
|||||||
@apiBP.route('/Upload', methods=['POST'])
|
@apiBP.route('/Upload', methods=['POST'])
|
||||||
def upload():
|
def upload():
|
||||||
form = request.form
|
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')
|
name: str or None = form.get('name')
|
||||||
files: ImmutableMultiDict[str, FileStorage] = request.files
|
files: ImmutableMultiDict[str, FileStorage] = request.files
|
||||||
|
|
||||||
@ -144,8 +144,7 @@ def upload():
|
|||||||
if not name:
|
if not name:
|
||||||
raise KeyError('name')
|
raise KeyError('name')
|
||||||
|
|
||||||
data: dict = {'token': token}
|
user: UserRecord = authenticate_request(token)
|
||||||
user: UserRecord = authenticate_request(data)
|
|
||||||
user_id: str = user.uid
|
user_id: str = user.uid
|
||||||
|
|
||||||
for _, file in files.items():
|
for _, file in files.items():
|
||||||
@ -200,4 +199,4 @@ if __name__ == '__main__':
|
|||||||
scheduler.start()
|
scheduler.start()
|
||||||
|
|
||||||
run_simple('0.0.0.0', 3000, app, use_debugger=False, use_reloader=False)
|
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):
|
def verify_jwt_token(token):
|
||||||
try:
|
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')
|
user_id = decoded_token.get('sub')
|
||||||
return True, user_id
|
return True, user_id
|
||||||
except jwt.ExpiredSignatureError:
|
except jwt.ExpiredSignatureError:
|
||||||
return False, None
|
return False, None
|
||||||
except jwt.InvalidTokenError:
|
except jwt.InvalidTokenError:
|
||||||
return False, None
|
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]:
|
def fetch_port() -> Union[int, None]:
|
||||||
|
@ -2,6 +2,9 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
from typing import Callable, Union
|
from typing import Callable, Union
|
||||||
|
|
||||||
|
from firebase_admin import auth
|
||||||
|
from jwt.api_jws import decode_complete
|
||||||
|
|
||||||
import firebase_manager
|
import firebase_manager
|
||||||
import server_mc_manager
|
import server_mc_manager
|
||||||
from generic_executor import mc_manager
|
from generic_executor import mc_manager
|
||||||
@ -41,4 +44,7 @@ if __name__ == '__main__':
|
|||||||
listdir("/home/hapso/Desktop/Personal/servii-backend/servers/paper"),
|
listdir("/home/hapso/Desktop/Personal/servii-backend/servers/paper"),
|
||||||
"/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
|
pass
|
||||||
|
Loading…
Reference in New Issue
Block a user