##// 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 1 <%namespace name="base" file="/base/base.mako"/>
2 2
3 3 <div class="panel panel-default">
4 4 <div class="panel-heading">
5 5 <h3 class="panel-title">${_('Enable/Disable 2FA for your account')}</h3>
6 6 </div>
7 7 <div class="panel-body">
8 8 <div class="form">
9 9 <div class="fields">
10 10 <div class="field">
11 11 <div class="label">
12 12 <label>${_('2FA status')}:</label>
13 13 </div>
14 14 <div class="checkboxes">
15 15
16 16 <div class="form-check">
17 17 <label class="form-check-label">
18 18 <input type="radio" id="2faEnabled" value="1" ${'checked' if c.state_of_2fa else ''}>
19 19 ${_('Enabled')}
20 20 </label>
21 21 <label class="form-check-label">
22 22 <input type="radio" id="2faDisabled" value="0" ${'checked' if not c.state_of_2fa else ''}>
23 23 ${_('Disabled')}
24 24 </label>
25 25 </div>
26 26 % if c.locked_2fa:
27 27 <span class="help-block">${_('2FA settings cannot be changed here, because 2FA was forced enabled by RhodeCode Administrator.')}</span>
28 28 % endif
29 29 </div>
30 30 </div>
31 31 </div>
32 32 <button id="saveBtn" class="btn btn-primary" ${'disabled' if c.locked_2fa else ''}>${_('Save')}</button>
33 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 34 </div>
39 35 </div>
40 </div>
41 </div>
36
42 37 % if c.state_of_2fa:
43 38 <div class="panel panel-default">
44 39 <div class="panel-heading">
45 40 <h3 class="panel-title">${_('Regenerate 2FA recovery codes for your account')}</h3>
46 41 </div>
47 42 <div class="panel-body">
48 43 <form id="2faForm">
49 44 <input type="text" name="totp" placeholder="${_('Verify the code from the app')}" pattern="\d{6}"
50 45 style="width: 20%">
51 46 <button type="button" class="btn btn-primary" onclick="submitForm()">Verify</button>
52 47 </form>
53 48 <div id="result"></div>
54 49 </div>
55 50
56 51 </div>
52
57 53 % endif
54
58 55 <script>
59 56 function submitForm() {
60 57 let formData = new FormData(document.getElementById("2faForm"));
61 58 let xhr = new XMLHttpRequest();
59
62 60 let success = function (response) {
63 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 65 xhr.onreadystatechange = function () {
74 66 if (xhr.readyState == 4 && xhr.status == 200) {
75 67 let responseDoc = new DOMParser().parseFromString(xhr.responseText, "text/html");
76 68 let contentToDisplay = responseDoc.querySelector('#formErrors');
77 69 if (contentToDisplay) {
78 70 document.getElementById("result").innerHTML = contentToDisplay.innerHTML;
79 71 } else {
80 72 let regenerate_url = pyroutes.url('my_account_regenerate_2fa_recovery_codes');
81 73 ajaxPOST(regenerate_url, {'csrf_token': CSRF_TOKEN}, success);
82 showRecoveryCodesPopup();
83 74 }
84 75 }
85 76 };
86 77 let url = pyroutes.url('check_2fa');
87 78 xhr.open("POST", url, true);
88 79 xhr.send(formData);
89 80 }
90 </script>
91 <script>
81
92 82 document.getElementById('2faEnabled').addEventListener('click', function () {
93 83 document.getElementById('2faDisabled').checked = false;
94 84 });
95 85 document.getElementById('2faDisabled').addEventListener('click', function () {
96 86 document.getElementById('2faEnabled').checked = false;
97 87 });
98 88
99 89 function getStateValue() {
100 90 if (document.getElementById('2faEnabled').checked) {
101 91 return '1';
102 92 } else {
103 93 return '0';
104 94 }
105 95 };
106 96
107 97 function saveChanges(state) {
108 98
109 99 let post_data = {'state': state, 'csrf_token': CSRF_TOKEN};
110 100 let url = pyroutes.url('my_account_configure_2fa');
111 101
112 ajaxPOST(url, post_data, null)
113 };
102 ajaxPOST(url, post_data, function(){}, function(){})
103 }
104
114 105 document.getElementById('saveBtn').addEventListener('click', function () {
115 106 var state = getStateValue();
116 107 saveChanges(state);
117 108 });
118 </script>
119 <script>
120 function showRecoveryCodesPopup() {
121 const popup = document.getElementById("codesPopup");
122 popup.style.display = "block";
109
110 function showRecoveryCodesPopup(recoveryCodes) {
111 let funcData = {'recoveryCodes': recoveryCodes}
112 let recoveryCodesHtml = renderTemplate('recoveryCodes', funcData)
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 123 </script>
General Comments 0
You need to be logged in to leave comments. Login now