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 (
|
from app.classes.web.routes.api.users.user.otp import (
|
||||||
APIUsersTOTPHandler,
|
APIUsersTOTPHandler,
|
||||||
APIUsersTOTPIndexHandler,
|
APIUsersTOTPIndexHandler,
|
||||||
|
APIUsersTOTPRecovery,
|
||||||
)
|
)
|
||||||
from app.classes.web.routes.api.users.user.api import ApiUsersUserKeyHandler
|
from app.classes.web.routes.api.users.user.api import ApiUsersUserKeyHandler
|
||||||
from app.classes.web.routes.api.users.user.pfp import ApiUsersUserPfpHandler
|
from app.classes.web.routes.api.users.user.pfp import ApiUsersUserPfpHandler
|
||||||
@ -172,6 +173,16 @@ def api_handlers(handler_args):
|
|||||||
ApiUsersUserIndexHandler,
|
ApiUsersUserIndexHandler,
|
||||||
handler_args,
|
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/?",
|
r"/api/v2/users/([0-9]+)/totp/?",
|
||||||
APIUsersTOTPIndexHandler,
|
APIUsersTOTPIndexHandler,
|
||||||
|
@ -118,6 +118,7 @@ class ApiAuthLoginHandler(BaseApiHandler):
|
|||||||
totp_enabled = len(list(user_data.totp_user)) > 0
|
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
|
# Check if user has TOTP and if we got any type of TOTP data in the login
|
||||||
# payload
|
# payload
|
||||||
|
valid_backup_code = False
|
||||||
if totp_enabled and not totp and backup_code:
|
if totp_enabled and not totp and backup_code:
|
||||||
# Check for backup code
|
# Check for backup code
|
||||||
lowered_backup_code = str(backup_code).replace("-", "").lower()
|
lowered_backup_code = str(backup_code).replace("-", "").lower()
|
||||||
@ -131,6 +132,7 @@ class ApiAuthLoginHandler(BaseApiHandler):
|
|||||||
valid_backup_code = code
|
valid_backup_code = code
|
||||||
break
|
break
|
||||||
try:
|
try:
|
||||||
|
if valid_backup_code:
|
||||||
self.controller.totp.remove_recovery_code(
|
self.controller.totp.remove_recovery_code(
|
||||||
user_data.user_id, valid_backup_code
|
user_data.user_id, valid_backup_code
|
||||||
)
|
)
|
||||||
@ -152,7 +154,7 @@ class ApiAuthLoginHandler(BaseApiHandler):
|
|||||||
)
|
)
|
||||||
# Check if both password auth and totp auth passed
|
# Check if both password auth and totp auth passed
|
||||||
login_result = pass_login_result is True and totp_login_result is True
|
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
|
# If the user doesn't have TOTP enabled and they didn't send a TOTP code
|
||||||
# We'll pass them through
|
# We'll pass them through
|
||||||
login_result = pass_login_result
|
login_result = pass_login_result
|
||||||
@ -178,7 +180,27 @@ class ApiAuthLoginHandler(BaseApiHandler):
|
|||||||
)
|
)
|
||||||
token = self.controller.authentication.generate(user_data.user_id)
|
token = self.controller.authentication.generate(user_data.user_id)
|
||||||
self.set_current_user(user_data.user_id, token)
|
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,
|
200,
|
||||||
{
|
{
|
||||||
"status": "ok",
|
"status": "ok",
|
||||||
|
@ -251,3 +251,50 @@ class APIUsersTOTPHandler(BaseApiHandler):
|
|||||||
200,
|
200,
|
||||||
{"status": "ok"},
|
{"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',
|
<h4 class="card-title"><i class="fas fa-key"></i> {{ translate('otp',
|
||||||
'otpTitle',
|
'otpTitle',
|
||||||
data['lang']) }}</h4>
|
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', 'backupCodes', data['lang']) }}" data-backup-codes-max="{{
|
||||||
translate('otp', 'backupCodesMax', data['lang']) }}"><i
|
translate('otp', 'backupCodesMax', data['lang']) }}"><i
|
||||||
class="fas fa-plus-circle"></i>
|
class="fas fa-plus-circle"></i>
|
||||||
@ -129,6 +133,26 @@
|
|||||||
correctLevel: QRCode.CorrectLevel.L
|
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 to create the modal response content
|
||||||
function createResponseDiv(data) {
|
function createResponseDiv(data) {
|
||||||
|
@ -223,10 +223,21 @@
|
|||||||
});
|
});
|
||||||
let responseData = await res.json();
|
let responseData = await res.json();
|
||||||
if (responseData.status === "ok") {
|
if (responseData.status === "ok") {
|
||||||
console.log("OK")
|
if (responseData.data.warning) {
|
||||||
location.href = `/panel/dashboard`
|
bootbox.alert({
|
||||||
|
message: responseData.data.warning,
|
||||||
|
callback: function () {
|
||||||
|
console.log("message answered");
|
||||||
|
// Redirect after the alert is acknowledged
|
||||||
|
location.href = responseData.data.page;
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
$("#error-field").html(responseData.error);
|
// Redirect immediately if no warning
|
||||||
|
location.href = responseData.data.page;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$("#error-field").html(responseData.error_data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -222,6 +222,7 @@
|
|||||||
"2faRecovery": "Recover 2FA",
|
"2faRecovery": "Recover 2FA",
|
||||||
"backupCodeTitle": "Backup Code",
|
"backupCodeTitle": "Backup Code",
|
||||||
"backupCode": "Enter 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",
|
"cancel": "Cancel",
|
||||||
"defaultPath": "The password you entered is the default credential path, not the password. Please find the default password in that location.",
|
"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.",
|
"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",
|
"saveWarn": "Make sure to save these backup codes or you could lose access",
|
||||||
"confirm2FA": "Please Confirm Authenticator Code",
|
"confirm2FA": "Please Confirm Authenticator Code",
|
||||||
"otpTitle": "2FA Methods",
|
"otpTitle": "2FA Methods",
|
||||||
|
"renewRecovery": "Renew Recovery Codes",
|
||||||
"newOTP": "Add New 2 Factor Auth"
|
"newOTP": "Add New 2 Factor Auth"
|
||||||
},
|
},
|
||||||
"panelConfig": {
|
"panelConfig": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user