|
|
<%namespace name="base" file="/base/base.mako"/>
|
|
|
|
|
|
<div class="panel panel-default">
|
|
|
<div class="panel-heading">
|
|
|
<h3 class="panel-title">${_('Enable/Disable 2FA for your account')}</h3>
|
|
|
</div>
|
|
|
<div class="panel-body">
|
|
|
<div class="form">
|
|
|
<div class="fields">
|
|
|
<div class="field">
|
|
|
<div class="label">
|
|
|
<label>${_('2FA status')}:</label>
|
|
|
</div>
|
|
|
<div class="checkboxes">
|
|
|
|
|
|
<div class="form-check">
|
|
|
<label class="form-check-label">
|
|
|
<input type="radio" id="2faEnabled" value="1" ${'checked' if c.state_of_2fa else ''}>
|
|
|
${_('Enabled')}
|
|
|
</label>
|
|
|
<label class="form-check-label">
|
|
|
<input type="radio" id="2faDisabled" value="0" ${'checked' if not c.state_of_2fa else ''}>
|
|
|
${_('Disabled')}
|
|
|
</label>
|
|
|
</div>
|
|
|
% if c.locked_2fa:
|
|
|
<span class="help-block">${_('2FA settings cannot be changed here, because 2FA was forced enabled by RhodeCode Administrator.')}</span>
|
|
|
% endif
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<button id="saveBtn" class="btn btn-primary" ${'disabled' if c.locked_2fa else ''}>${_('Save')}</button>
|
|
|
</div>
|
|
|
<div id="codesPopup" class="modal">
|
|
|
<div class="modal-content">
|
|
|
<ul id="recoveryCodesList"></ul>
|
|
|
<button id="copyAllBtn" class="btn btn-primary">Copy All</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
% if c.state_of_2fa:
|
|
|
<div class="panel panel-default">
|
|
|
<div class="panel-heading">
|
|
|
<h3 class="panel-title">${_('Regenerate 2FA recovery codes for your account')}</h3>
|
|
|
</div>
|
|
|
<div class="panel-body">
|
|
|
<form id="2faForm">
|
|
|
<input type="text" name="totp" placeholder="${_('Verify the code from the app')}" pattern="\d{6}"
|
|
|
style="width: 20%">
|
|
|
<button type="button" class="btn btn-primary" onclick="submitForm()">Verify</button>
|
|
|
</form>
|
|
|
<div id="result"></div>
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
% endif
|
|
|
<script>
|
|
|
function submitForm() {
|
|
|
let formData = new FormData(document.getElementById("2faForm"));
|
|
|
let xhr = new XMLHttpRequest();
|
|
|
let success = function (response) {
|
|
|
let recovery_codes = response.recovery_codes;
|
|
|
const codesList = document.getElementById("recoveryCodesList");
|
|
|
|
|
|
codesList.innerHTML = "";
|
|
|
recovery_codes.forEach(code => {
|
|
|
const listItem = document.createElement("li");
|
|
|
listItem.textContent = code;
|
|
|
codesList.appendChild(listItem);
|
|
|
});
|
|
|
}
|
|
|
xhr.onreadystatechange = function () {
|
|
|
if (xhr.readyState == 4 && xhr.status == 200) {
|
|
|
let responseDoc = new DOMParser().parseFromString(xhr.responseText, "text/html");
|
|
|
let contentToDisplay = responseDoc.querySelector('#formErrors');
|
|
|
if (contentToDisplay) {
|
|
|
document.getElementById("result").innerHTML = contentToDisplay.innerHTML;
|
|
|
} else {
|
|
|
let regenerate_url = pyroutes.url('my_account_regenerate_2fa_recovery_codes');
|
|
|
ajaxPOST(regenerate_url, {'csrf_token': CSRF_TOKEN}, success);
|
|
|
showRecoveryCodesPopup();
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
let url = pyroutes.url('check_2fa');
|
|
|
xhr.open("POST", url, true);
|
|
|
xhr.send(formData);
|
|
|
}
|
|
|
</script>
|
|
|
<script>
|
|
|
document.getElementById('2faEnabled').addEventListener('click', function () {
|
|
|
document.getElementById('2faDisabled').checked = false;
|
|
|
});
|
|
|
document.getElementById('2faDisabled').addEventListener('click', function () {
|
|
|
document.getElementById('2faEnabled').checked = false;
|
|
|
});
|
|
|
|
|
|
function getStateValue() {
|
|
|
if (document.getElementById('2faEnabled').checked) {
|
|
|
return '1';
|
|
|
} else {
|
|
|
return '0';
|
|
|
}
|
|
|
};
|
|
|
|
|
|
function saveChanges(state) {
|
|
|
|
|
|
let post_data = {'state': state, 'csrf_token': CSRF_TOKEN};
|
|
|
let url = pyroutes.url('my_account_configure_2fa');
|
|
|
|
|
|
ajaxPOST(url, post_data, null)
|
|
|
};
|
|
|
document.getElementById('saveBtn').addEventListener('click', function () {
|
|
|
var state = getStateValue();
|
|
|
saveChanges(state);
|
|
|
});
|
|
|
</script>
|
|
|
<script>
|
|
|
function showRecoveryCodesPopup() {
|
|
|
const popup = document.getElementById("codesPopup");
|
|
|
popup.style.display = "block";
|
|
|
}
|
|
|
|
|
|
document.getElementById("copyAllBtn").addEventListener("click", function () {
|
|
|
const codesListItems = document.querySelectorAll("#recoveryCodesList li");
|
|
|
const allCodes = Array.from(codesListItems).map(item => item.textContent).join(", ");
|
|
|
|
|
|
const textarea = document.createElement('textarea');
|
|
|
textarea.value = allCodes;
|
|
|
document.body.appendChild(textarea);
|
|
|
|
|
|
textarea.select();
|
|
|
document.execCommand('copy');
|
|
|
|
|
|
document.body.removeChild(textarea);
|
|
|
const popup = document.getElementById("codesPopup");
|
|
|
popup.style.display = ""
|
|
|
});
|
|
|
</script>
|
|
|
|