mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2025-10-26 07:46:35 +01:00
Merge pull request #1585 from master3395/v2.5.5-dev
Add regenerateTwoFASecret functionality and UI support
This commit is contained in:
@@ -180,6 +180,48 @@ app.controller('modifyUser', function ($scope, $http) {
|
||||
}
|
||||
};
|
||||
|
||||
$scope.regenerateSecret = function() {
|
||||
if (!$scope.accountUsername) {
|
||||
alert('Please select a user first.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!confirm('Are you sure you want to regenerate the 2FA secret? This will generate a new secret key and you will need to update your authenticator app.')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var url = "/users/regenerateTwoFASecret";
|
||||
var data = {
|
||||
accountUsername: $scope.accountUsername
|
||||
};
|
||||
var config = {
|
||||
headers: {
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
}
|
||||
};
|
||||
|
||||
$http.post(url, data, config).then(function(response) {
|
||||
if (response.data.status === 1) {
|
||||
// Update the secret key and formatted version
|
||||
$scope.secretKey = response.data.secretKey;
|
||||
$scope.formattedSecretKey = response.data.secretKey.match(/.{1,4}/g).join(' ');
|
||||
|
||||
// Update the QR code with new provisioning URI
|
||||
qrCode.set({
|
||||
value: response.data.otpauth
|
||||
});
|
||||
|
||||
// Show success message
|
||||
alert('2FA secret has been successfully regenerated! Please update your authenticator app with the new QR code or secret key.');
|
||||
} else {
|
||||
alert('Error regenerating 2FA secret: ' + response.data.error_message);
|
||||
}
|
||||
}, function(error) {
|
||||
console.error('Error regenerating 2FA secret:', error);
|
||||
alert('Failed to regenerate 2FA secret. Please try again.');
|
||||
});
|
||||
};
|
||||
|
||||
// WebAuthn Functions
|
||||
$scope.loadWebAuthnData = function() {
|
||||
if (!$scope.accountUsername) return;
|
||||
|
||||
@@ -319,6 +319,14 @@
|
||||
</div>
|
||||
<small class="text-muted mt-1 d-block">{% trans "Enter this key in your authenticator app if you cannot scan QR codes." %}</small>
|
||||
</div>
|
||||
|
||||
<!-- Regenerate Secret Button -->
|
||||
<div class="mt-3" ng-show="twofa">
|
||||
<button type="button" class="btn btn-warning" ng-click="regenerateSecret()" title="{% trans 'Generate a new 2FA secret key' %}">
|
||||
<i class="fa fa-refresh"></i> {% trans "Regenerate Secret" %}
|
||||
</button>
|
||||
<small class="text-muted d-block mt-1">{% trans "Warning: This will generate a new secret key. You'll need to update your authenticator app." %}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -40,4 +40,5 @@ urlpatterns = [
|
||||
path('migrateUser', homeDirectoryViews.migrateUser, name='migrateUser'),
|
||||
path('userMigration', views.userMigration, name='userMigration'),
|
||||
path('disable2FA', views.disable2FA, name='disable2FA'),
|
||||
path('regenerateTwoFASecret', views.regenerateTwoFASecret, name='regenerateTwoFASecret'),
|
||||
]
|
||||
|
||||
@@ -504,11 +504,22 @@ def saveModifications(request):
|
||||
user.lastName = lastName
|
||||
user.email = email
|
||||
user.type = 0
|
||||
|
||||
# Check if 2FA is being enabled (transition from 0 to 1)
|
||||
was_2fa_disabled = user.twoFA == 0
|
||||
user.twoFA = twofa
|
||||
|
||||
# If 2FA is being disabled, clear the secret key
|
||||
if twofa == 0:
|
||||
user.secretKey = 'None'
|
||||
# If 2FA is being enabled (transition from disabled to enabled), always generate a new secret
|
||||
elif twofa == 1 and was_2fa_disabled:
|
||||
import pyotp
|
||||
user.secretKey = pyotp.random_base32()
|
||||
|
||||
# Log the secret regeneration for security audit
|
||||
from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging
|
||||
logging.writeToFile(f'2FA secret auto-regenerated for user: {accountUsername} by admin: {val}')
|
||||
|
||||
if securityLevel == 'LOW':
|
||||
user.securityLevel = secMiddleware.LOW
|
||||
@@ -1136,3 +1147,73 @@ def disable2FA(request):
|
||||
data_ret = secure_error_response(e, 'Failed to disable 2FA')
|
||||
json_data = json.dumps(data_ret)
|
||||
return HttpResponse(json_data)
|
||||
|
||||
|
||||
def regenerateTwoFASecret(request):
|
||||
"""
|
||||
Manually regenerate 2FA secret for a specific user
|
||||
"""
|
||||
try:
|
||||
val = request.session['userID']
|
||||
currentACL = ACLManager.loadedACL(val)
|
||||
|
||||
if currentACL['admin'] != 1:
|
||||
data_ret = {'status': 0, 'error_message': 'Unauthorized access. Admin privileges required.'}
|
||||
json_data = json.dumps(data_ret)
|
||||
return HttpResponse(json_data)
|
||||
|
||||
if request.method == 'POST':
|
||||
data = json.loads(request.body)
|
||||
accountUsername = data.get('accountUsername')
|
||||
|
||||
if not accountUsername:
|
||||
data_ret = {'status': 0, 'error_message': 'Username is required.'}
|
||||
json_data = json.dumps(data_ret)
|
||||
return HttpResponse(json_data)
|
||||
|
||||
try:
|
||||
user = Administrator.objects.get(userName=accountUsername)
|
||||
|
||||
# Check if user has 2FA enabled
|
||||
if not user.twoFA:
|
||||
data_ret = {'status': 0, 'error_message': '2FA is not enabled for this user.'}
|
||||
json_data = json.dumps(data_ret)
|
||||
return HttpResponse(json_data)
|
||||
|
||||
# Generate new secret key
|
||||
import pyotp
|
||||
new_secret = pyotp.random_base32()
|
||||
user.secretKey = new_secret
|
||||
user.save()
|
||||
|
||||
# Generate new QR code provisioning URI
|
||||
otpauth = pyotp.totp.TOTP(new_secret).provisioning_uri(user.email, issuer_name="CyberPanel")
|
||||
|
||||
# Log the secret regeneration for security audit
|
||||
from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging
|
||||
logging.writeToFile(f'2FA secret manually regenerated for user: {accountUsername} by admin: {val}')
|
||||
|
||||
data_ret = {
|
||||
'status': 1,
|
||||
'error_message': '2FA secret successfully regenerated.',
|
||||
'message': f'Two-factor authentication secret has been regenerated for user {accountUsername}.',
|
||||
'secretKey': new_secret,
|
||||
'otpauth': otpauth
|
||||
}
|
||||
json_data = json.dumps(data_ret)
|
||||
return HttpResponse(json_data)
|
||||
|
||||
except Administrator.DoesNotExist:
|
||||
data_ret = {'status': 0, 'error_message': 'User not found.'}
|
||||
json_data = json.dumps(data_ret)
|
||||
return HttpResponse(json_data)
|
||||
|
||||
data_ret = {'status': 0, 'error_message': 'Invalid request method.'}
|
||||
json_data = json.dumps(data_ret)
|
||||
return HttpResponse(json_data)
|
||||
|
||||
except Exception as e:
|
||||
secure_log_error(e, 'regenerateTwoFASecret', request.session.get('userID', 'Unknown'))
|
||||
data_ret = secure_error_response(e, 'Failed to regenerate 2FA secret')
|
||||
json_data = json.dumps(data_ret)
|
||||
return HttpResponse(json_data)
|
||||
|
||||
Reference in New Issue
Block a user