##// END OF EJS Templates
2fa: recovery codes copy
super-admin -
r5361:965120af default
parent child Browse files
Show More
@@ -1,140 +1,123 b''
1 <%namespace name="base" file="/base/base.mako"/>
1 <%namespace name="base" file="/base/base.mako"/>
2
2
3 <div class="panel panel-default">
3 <div class="panel panel-default">
4 <div class="panel-heading">
4 <div class="panel-heading">
5 <h3 class="panel-title">${_('Enable/Disable 2FA for your account')}</h3>
5 <h3 class="panel-title">${_('Enable/Disable 2FA for your account')}</h3>
6 </div>
6 </div>
7 <div class="panel-body">
7 <div class="panel-body">
8 <div class="form">
8 <div class="form">
9 <div class="fields">
9 <div class="fields">
10 <div class="field">
10 <div class="field">
11 <div class="label">
11 <div class="label">
12 <label>${_('2FA status')}:</label>
12 <label>${_('2FA status')}:</label>
13 </div>
13 </div>
14 <div class="checkboxes">
14 <div class="checkboxes">
15
15
16 <div class="form-check">
16 <div class="form-check">
17 <label class="form-check-label">
17 <label class="form-check-label">
18 <input type="radio" id="2faEnabled" value="1" ${'checked' if c.state_of_2fa else ''}>
18 <input type="radio" id="2faEnabled" value="1" ${'checked' if c.state_of_2fa else ''}>
19 ${_('Enabled')}
19 ${_('Enabled')}
20 </label>
20 </label>
21 <label class="form-check-label">
21 <label class="form-check-label">
22 <input type="radio" id="2faDisabled" value="0" ${'checked' if not c.state_of_2fa else ''}>
22 <input type="radio" id="2faDisabled" value="0" ${'checked' if not c.state_of_2fa else ''}>
23 ${_('Disabled')}
23 ${_('Disabled')}
24 </label>
24 </label>
25 </div>
25 </div>
26 % if c.locked_2fa:
26 % if c.locked_2fa:
27 <span class="help-block">${_('2FA settings cannot be changed here, because 2FA was forced enabled by RhodeCode Administrator.')}</span>
27 <span class="help-block">${_('2FA settings cannot be changed here, because 2FA was forced enabled by RhodeCode Administrator.')}</span>
28 % endif
28 % endif
29 </div>
29 </div>
30 </div>
30 </div>
31 </div>
31 </div>
32 <button id="saveBtn" class="btn btn-primary" ${'disabled' if c.locked_2fa else ''}>${_('Save')}</button>
32 <button id="saveBtn" class="btn btn-primary" ${'disabled' if c.locked_2fa else ''}>${_('Save')}</button>
33 </div>
33 </div>
34 <div id="codesPopup" class="modal">
35 <div class="modal-content">
36 <ul id="recoveryCodesList"></ul>
37 <button id="copyAllBtn" class="btn btn-primary">Copy All</button>
38 </div>
39 </div>
40 </div>
34 </div>
41 </div>
35 </div>
36
42 % if c.state_of_2fa:
37 % if c.state_of_2fa:
43 <div class="panel panel-default">
38 <div class="panel panel-default">
44 <div class="panel-heading">
39 <div class="panel-heading">
45 <h3 class="panel-title">${_('Regenerate 2FA recovery codes for your account')}</h3>
40 <h3 class="panel-title">${_('Regenerate 2FA recovery codes for your account')}</h3>
46 </div>
41 </div>
47 <div class="panel-body">
42 <div class="panel-body">
48 <form id="2faForm">
43 <form id="2faForm">
49 <input type="text" name="totp" placeholder="${_('Verify the code from the app')}" pattern="\d{6}"
44 <input type="text" name="totp" placeholder="${_('Verify the code from the app')}" pattern="\d{6}"
50 style="width: 20%">
45 style="width: 20%">
51 <button type="button" class="btn btn-primary" onclick="submitForm()">Verify</button>
46 <button type="button" class="btn btn-primary" onclick="submitForm()">Verify</button>
52 </form>
47 </form>
53 <div id="result"></div>
48 <div id="result"></div>
54 </div>
49 </div>
55
50
56 </div>
51 </div>
52
57 % endif
53 % endif
54
58 <script>
55 <script>
59 function submitForm() {
56 function submitForm() {
60 let formData = new FormData(document.getElementById("2faForm"));
57 let formData = new FormData(document.getElementById("2faForm"));
61 let xhr = new XMLHttpRequest();
58 let xhr = new XMLHttpRequest();
59
62 let success = function (response) {
60 let success = function (response) {
63 let recovery_codes = response.recovery_codes;
61 let recovery_codes = response.recovery_codes;
64 const codesList = document.getElementById("recoveryCodesList");
62 showRecoveryCodesPopup(recovery_codes);
63 }
65
64
66 codesList.innerHTML = "";
67 recovery_codes.forEach(code => {
68 const listItem = document.createElement("li");
69 listItem.textContent = code;
70 codesList.appendChild(listItem);
71 });
72 }
73 xhr.onreadystatechange = function () {
65 xhr.onreadystatechange = function () {
74 if (xhr.readyState == 4 && xhr.status == 200) {
66 if (xhr.readyState == 4 && xhr.status == 200) {
75 let responseDoc = new DOMParser().parseFromString(xhr.responseText, "text/html");
67 let responseDoc = new DOMParser().parseFromString(xhr.responseText, "text/html");
76 let contentToDisplay = responseDoc.querySelector('#formErrors');
68 let contentToDisplay = responseDoc.querySelector('#formErrors');
77 if (contentToDisplay) {
69 if (contentToDisplay) {
78 document.getElementById("result").innerHTML = contentToDisplay.innerHTML;
70 document.getElementById("result").innerHTML = contentToDisplay.innerHTML;
79 } else {
71 } else {
80 let regenerate_url = pyroutes.url('my_account_regenerate_2fa_recovery_codes');
72 let regenerate_url = pyroutes.url('my_account_regenerate_2fa_recovery_codes');
81 ajaxPOST(regenerate_url, {'csrf_token': CSRF_TOKEN}, success);
73 ajaxPOST(regenerate_url, {'csrf_token': CSRF_TOKEN}, success);
82 showRecoveryCodesPopup();
83 }
74 }
84 }
75 }
85 };
76 };
86 let url = pyroutes.url('check_2fa');
77 let url = pyroutes.url('check_2fa');
87 xhr.open("POST", url, true);
78 xhr.open("POST", url, true);
88 xhr.send(formData);
79 xhr.send(formData);
89 }
80 }
90 </script>
81
91 <script>
92 document.getElementById('2faEnabled').addEventListener('click', function () {
82 document.getElementById('2faEnabled').addEventListener('click', function () {
93 document.getElementById('2faDisabled').checked = false;
83 document.getElementById('2faDisabled').checked = false;
94 });
84 });
95 document.getElementById('2faDisabled').addEventListener('click', function () {
85 document.getElementById('2faDisabled').addEventListener('click', function () {
96 document.getElementById('2faEnabled').checked = false;
86 document.getElementById('2faEnabled').checked = false;
97 });
87 });
98
88
99 function getStateValue() {
89 function getStateValue() {
100 if (document.getElementById('2faEnabled').checked) {
90 if (document.getElementById('2faEnabled').checked) {
101 return '1';
91 return '1';
102 } else {
92 } else {
103 return '0';
93 return '0';
104 }
94 }
105 };
95 };
106
96
107 function saveChanges(state) {
97 function saveChanges(state) {
108
98
109 let post_data = {'state': state, 'csrf_token': CSRF_TOKEN};
99 let post_data = {'state': state, 'csrf_token': CSRF_TOKEN};
110 let url = pyroutes.url('my_account_configure_2fa');
100 let url = pyroutes.url('my_account_configure_2fa');
111
101
112 ajaxPOST(url, post_data, null)
102 ajaxPOST(url, post_data, function(){}, function(){})
113 };
103 }
104
114 document.getElementById('saveBtn').addEventListener('click', function () {
105 document.getElementById('saveBtn').addEventListener('click', function () {
115 var state = getStateValue();
106 var state = getStateValue();
116 saveChanges(state);
107 saveChanges(state);
117 });
108 });
118 </script>
109
119 <script>
110 function showRecoveryCodesPopup(recoveryCodes) {
120 function showRecoveryCodesPopup() {
111 let funcData = {'recoveryCodes': recoveryCodes}
121 const popup = document.getElementById("codesPopup");
112 let recoveryCodesHtml = renderTemplate('recoveryCodes', funcData)
122 popup.style.display = "block";
113
114 SwalNoAnimation.fire({
115 allowOutsideClick: false,
116 confirmButtonText: _gettext('I Copied the codes'),
117 title: _gettext('2FA Recovery Codes'),
118 html: recoveryCodesHtml
119 })
120
123 }
121 }
124
122
125 document.getElementById("copyAllBtn").addEventListener("click", function () {
126 const codesListItems = document.querySelectorAll("#recoveryCodesList li");
127 const allCodes = Array.from(codesListItems).map(item => item.textContent).join(", ");
128
129 const textarea = document.createElement('textarea');
130 textarea.value = allCodes;
131 document.body.appendChild(textarea);
132
133 textarea.select();
134 document.execCommand('copy');
135
136 document.body.removeChild(textarea);
137 const popup = document.getElementById("codesPopup");
138 popup.style.display = ""
139 });
140 </script>
123 </script>
General Comments 0
You need to be logged in to leave comments. Login now