Create reroll functions

Still need to make them functional
This commit is contained in:
= 2025-01-12 19:25:48 -05:00
parent c9cea4f22c
commit e3fe6e9d7b
7 changed files with 128 additions and 9 deletions

View File

@ -0,0 +1,2 @@
class AuthError(Exception):
pass

View File

@ -67,6 +67,7 @@ from app.classes.web.routes.api.users.user.permissions import (
from app.classes.web.routes.api.users.user.otp import (
APIUsersTOTPHandler,
APIUsersTOTPIndexHandler,
APIUsersTOTPRecovery,
)
from app.classes.web.routes.api.users.user.api import ApiUsersUserKeyHandler
from app.classes.web.routes.api.users.user.pfp import ApiUsersUserPfpHandler
@ -172,6 +173,16 @@ def api_handlers(handler_args):
ApiUsersUserIndexHandler,
handler_args,
),
(
r"/api/v2/users/(@me)/totp/recovery/renew/?",
APIUsersTOTPRecovery,
handler_args,
),
(
r"/api/v2/users/([0-9]+)/totp/recovery/renew/?",
APIUsersTOTPRecovery,
handler_args,
),
(
r"/api/v2/users/([0-9]+)/totp/?",
APIUsersTOTPIndexHandler,

View File

@ -118,6 +118,7 @@ class ApiAuthLoginHandler(BaseApiHandler):
totp_enabled = len(list(user_data.totp_user)) > 0
# Check if user has TOTP and if we got any type of TOTP data in the login
# payload
valid_backup_code = False
if totp_enabled and not totp and backup_code:
# Check for backup code
lowered_backup_code = str(backup_code).replace("-", "").lower()
@ -131,6 +132,7 @@ class ApiAuthLoginHandler(BaseApiHandler):
valid_backup_code = code
break
try:
if valid_backup_code:
self.controller.totp.remove_recovery_code(
user_data.user_id, valid_backup_code
)
@ -152,7 +154,7 @@ class ApiAuthLoginHandler(BaseApiHandler):
)
# Check if both password auth and totp auth passed
login_result = pass_login_result is True and totp_login_result is True
elif not totp_enabled and not totp:
elif (not totp_enabled and not totp) and (not totp_enabled and not backup_code):
# If the user doesn't have TOTP enabled and they didn't send a TOTP code
# We'll pass them through
login_result = pass_login_result
@ -178,7 +180,27 @@ class ApiAuthLoginHandler(BaseApiHandler):
)
token = self.controller.authentication.generate(user_data.user_id)
self.set_current_user(user_data.user_id, token)
self.finish_json(
if valid_backup_code:
return self.finish_json(
200,
{
"status": "ok",
"data": {
"token": token,
"user_id": str(user_data.user_id),
"page": "/panel/dashboard",
"warning": self.helper.translation.translate(
"login",
"burnedBackupCode",
self.controller.users.get_user_lang_by_id(
user_data.user_id
),
),
},
},
)
return self.finish_json(
200,
{
"status": "ok",

View File

@ -251,3 +251,50 @@ class APIUsersTOTPHandler(BaseApiHandler):
200,
{"status": "ok"},
)
class APIUsersTOTPRecovery(BaseApiHandler):
def get(self, user_id: str, totp_id=None):
auth_data = self.authenticate_user()
if not auth_data:
return
(
_,
exec_user_crafty_permissions,
_,
_,
user,
_,
) = auth_data
if totp_id:
return
if user_id in ["@me", user["user_id"]]:
user_id = user["user_id"]
res_user = self.controller.users.get_user_object(user_id)
elif EnumPermissionsCrafty.USER_CONFIG not in exec_user_crafty_permissions:
return self.finish_json(
400,
{
"status": "error",
"error": "NOT_AUTHORIZED",
},
)
else:
# has User_Config permission and isn't viewing self
res_user = self.controller.users.get_user_object(user_id)
if not res_user:
return self.finish_json(
404,
{
"status": "error",
"error": "USER_NOT_FOUND",
},
)
user_totp = list(res_user.recovery_user)
self.finish_json(
200,
{"status": "ok", "data": {"backup_codes": user_totp}},
)

View File

@ -55,7 +55,11 @@
<h4 class="card-title"><i class="fas fa-key"></i>&nbsp;{{ translate('otp',
'otpTitle',
data['lang']) }}</h4>
<div><button class="btn btn-primary" id="createButton" data-backup-codes="{{
<div><button class="btn btn-primary" id="renewCodes"><i
class="fas fa-plus-circle"></i>
&nbsp; {{
translate('otp', 'renewRecovery', data['lang']) }}</button>&nbsp;<button
class="btn btn-primary" id="createButton" data-backup-codes="{{
translate('otp', 'backupCodes', data['lang']) }}" data-backup-codes-max="{{
translate('otp', 'backupCodesMax', data['lang']) }}"><i
class="fas fa-plus-circle"></i>
@ -129,6 +133,26 @@
correctLevel: QRCode.CorrectLevel.L
});
}
$("#renewCodes").click(async function () {
let res = await fetch(`/api/v2/users/${userId}/totp/recovery/renew/`, {
method: 'GET',
headers: {
'X-XSRFToken': token
},
});
let responseData = await res.json();
let backupcodes = `<ul class="list-group">`;
responseData["backup_codes"].forEach(element => {
backupcodes += `<li class="list-group-item">${element}</li>`;
});
backupcodes += `</ul>`
if (data["backup_codes"].length == 0) {
backupcodes = `<div style="text-align: center; color: grey;">
${$("#createButton").data("backup-codes-max")}
</div>`
}
bootbox.alert(backupcodes);
});
// Function to create the modal response content
function createResponseDiv(data) {

View File

@ -223,10 +223,21 @@
});
let responseData = await res.json();
if (responseData.status === "ok") {
console.log("OK")
location.href = `/panel/dashboard`
if (responseData.data.warning) {
bootbox.alert({
message: responseData.data.warning,
callback: function () {
console.log("message answered");
// Redirect after the alert is acknowledged
location.href = responseData.data.page;
}
});
} else {
$("#error-field").html(responseData.error);
// Redirect immediately if no warning
location.href = responseData.data.page;
}
} else {
$("#error-field").html(responseData.error_data);
}
});
</script>

View File

@ -222,6 +222,7 @@
"2faRecovery": "Recover 2FA",
"backupCodeTitle": "Backup Code",
"backupCode": "Enter Backup Code",
"burnedBackupCode": "You have burned one of your backup codes. Please reroll your backup codes to avoid being locked out",
"cancel": "Cancel",
"defaultPath": "The password you entered is the default credential path, not the password. Please find the default password in that location.",
"disabled": "User account disabled. Please contact your system administrator for more info.",
@ -267,6 +268,7 @@
"saveWarn": "Make sure to save these backup codes or you could lose access",
"confirm2FA": "Please Confirm Authenticator Code",
"otpTitle": "2FA Methods",
"renewRecovery": "Renew Recovery Codes",
"newOTP": "Add New 2 Factor Auth"
},
"panelConfig": {