mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2025-01-18 17:15:13 +01:00
Create reroll functions
Still need to make them functional
This commit is contained in:
parent
c9cea4f22c
commit
e3fe6e9d7b
2
app/classes/exceptions/autherrors.py
Normal file
2
app/classes/exceptions/autherrors.py
Normal file
@ -0,0 +1,2 @@
|
||||
class AuthError(Exception):
|
||||
pass
|
@ -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,
|
||||
|
@ -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,9 +132,10 @@ class ApiAuthLoginHandler(BaseApiHandler):
|
||||
valid_backup_code = code
|
||||
break
|
||||
try:
|
||||
self.controller.totp.remove_recovery_code(
|
||||
user_data.user_id, valid_backup_code
|
||||
)
|
||||
if valid_backup_code:
|
||||
self.controller.totp.remove_recovery_code(
|
||||
user_data.user_id, valid_backup_code
|
||||
)
|
||||
except RuntimeError:
|
||||
self.finish_json(
|
||||
401,
|
||||
@ -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",
|
||||
|
@ -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}},
|
||||
)
|
||||
|
@ -55,7 +55,11 @@
|
||||
<h4 class="card-title"><i class="fas fa-key"></i> {{ 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>
|
||||
{{
|
||||
translate('otp', 'renewRecovery', data['lang']) }}</button> <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) {
|
||||
|
@ -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 {
|
||||
// Redirect immediately if no warning
|
||||
location.href = responseData.data.page;
|
||||
}
|
||||
} else {
|
||||
$("#error-field").html(responseData.error);
|
||||
$("#error-field").html(responseData.error_data);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
@ -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": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user