mirror of
				https://github.com/mail-in-a-box/mailinabox.git
				synced 2025-10-30 18:50:53 +00:00 
			
		
		
		
	Reorganize TOTP in the control panel templates to allow adding multiple devices and disabling individual devices
This commit is contained in:
		
							parent
							
								
									113b7bd827
								
							
						
					
					
						commit
						30f067bc72
					
				| @ -1740,7 +1740,7 @@ paths: | |||||||
|             text/html: |             text/html: | ||||||
|               schema: |               schema: | ||||||
|                 type: string |                 type: string | ||||||
|   /mfa/totp/enable: |   /mfa/enable/totp: | ||||||
|     post: |     post: | ||||||
|       tags: |       tags: | ||||||
|         - MFA |         - MFA | ||||||
|  | |||||||
| @ -468,7 +468,7 @@ def ssl_provision_certs(): | |||||||
| def mfa_get_status(): | def mfa_get_status(): | ||||||
| 	# Anyone accessing this route is an admin, and we permit them to | 	# Anyone accessing this route is an admin, and we permit them to | ||||||
| 	# see the MFA status for any user if they submit a 'user' form | 	# see the MFA status for any user if they submit a 'user' form | ||||||
| 	# field. But we don't include provisioning info since a user can | 	# field. But we don't always include provisioning info since a user can | ||||||
| 	# only provision for themselves. | 	# only provision for themselves. | ||||||
| 	email = request.form.get('user', request.user_email) # user field if given, otherwise the user making the request | 	email = request.form.get('user', request.user_email) # user field if given, otherwise the user making the request | ||||||
| 	try: | 	try: | ||||||
| @ -485,7 +485,7 @@ def mfa_get_status(): | |||||||
| 		return (str(e), 400) | 		return (str(e), 400) | ||||||
| 	return json_response(resp) | 	return json_response(resp) | ||||||
| 
 | 
 | ||||||
| @app.route('/mfa/totp/enable', methods=['POST']) | @app.route('/mfa/enable/totp', methods=['POST']) | ||||||
| @authorized_personnel_only | @authorized_personnel_only | ||||||
| def totp_post_enable(): | def totp_post_enable(): | ||||||
| 	secret = request.form.get('secret') | 	secret = request.form.get('secret') | ||||||
|  | |||||||
| @ -1,34 +1,10 @@ | |||||||
| <style> | <style> | ||||||
|     .twofactor #totp-setup, |  | ||||||
|     .twofactor #disable-2fa, |  | ||||||
|     .twofactor #output-2fa { |  | ||||||
|         display: none; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     .twofactor.loaded .loading-indicator { |  | ||||||
|         display: none; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     .twofactor.disabled #disable-2fa, |  | ||||||
|     .twofactor.enabled #totp-setup { |  | ||||||
|         display: none; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     .twofactor.disabled #totp-setup, |  | ||||||
|     .twofactor.enabled #disable-2fa { |  | ||||||
|         display: block; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     .twofactor #totp-setup-qr img { |     .twofactor #totp-setup-qr img { | ||||||
|         display: block; |         display: block; | ||||||
|         width: 256px; |         width: 256px; | ||||||
|         max-width: 100%; |         max-width: 100%; | ||||||
|         height: auto; |         height: auto; | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     .twofactor #output-2fa.visible { |  | ||||||
|         display: block; |  | ||||||
|     } |  | ||||||
| </style> | </style> | ||||||
| 
 | 
 | ||||||
| <h2>Two-Factor Authentication</h2> | <h2>Two-Factor Authentication</h2> | ||||||
| @ -51,10 +27,11 @@ and ensure every administrator account for this control panel does the same.</st | |||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| <div class="twofactor"> | <div class="twofactor"> | ||||||
|     <div class="loading-indicator">Loading...</div> |     <div id="mfa-devices"> | ||||||
|  |     </div> | ||||||
| 
 | 
 | ||||||
|     <form id="totp-setup"> |     <form id="totp-setup" style="display: none"> | ||||||
|         <h3>Setup Instructions</h3> |         <h3>Add a TOTP Device</h3> | ||||||
| 
 | 
 | ||||||
|         <div class="form-group"> |         <div class="form-group"> | ||||||
|             <p>1. Install <a href="https://freeotp.github.io/">FreeOTP</a> or <a href="https://www.pcworld.com/article/3225913/what-is-two-factor-authentication-and-which-2fa-apps-are-best.html">any |             <p>1. Install <a href="https://freeotp.github.io/">FreeOTP</a> or <a href="https://www.pcworld.com/article/3225913/what-is-two-factor-authentication-and-which-2fa-apps-are-best.html">any | ||||||
| @ -85,24 +62,24 @@ and ensure every administrator account for this control panel does the same.</st | |||||||
|         </div> |         </div> | ||||||
|     </form> |     </form> | ||||||
| 
 | 
 | ||||||
|     <form id="disable-2fa"> |  | ||||||
|         <div class="form-group"> |  | ||||||
|             <p>Two-factor authentication is active for your account<span id="mfa-device-label"></span>.</p> |  | ||||||
|             <p>You will have to log into the admin panel again after disabling two-factor authentication.</p> |  | ||||||
|         </div> |  | ||||||
|         <div class="form-group"> |  | ||||||
|             <button type="submit" class="btn btn-danger">Disable Two-Factor Authentication</button> |  | ||||||
|         </div> |  | ||||||
|     </form> |  | ||||||
| 
 | 
 | ||||||
|     <div id="output-2fa" class="panel panel-danger"> |     <div id="output-2fa" class="panel panel-danger hidden"> | ||||||
|         <div class="panel-body"></div> |         <div class="panel-body"></div> | ||||||
|     </div> |     </div> | ||||||
|  | 
 | ||||||
|  |     <div id="mfa-device-templates" style="display: none"> | ||||||
|  |       <form class="totp" style="margin: 1em 0; border: 1px solid #AAA; padding: 10px;"> | ||||||
|  |           <p>Two-factor authentication is active for your account<span class="mfa-device-label"></span>.</p> | ||||||
|  |           <div class="form-group"> | ||||||
|  |               <button type="submit" class="btn btn-danger">Disable TOTP Device</button> | ||||||
|  |           </div> | ||||||
|  |           <p style="margin-bottom: 0">You will have to log into the admin panel again after disabling two-factor authentication.</p> | ||||||
|  |       </form> | ||||||
|  |     </div> | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| <script> | <script> | ||||||
|     var el = { |     var el = { | ||||||
|         disableForm: document.getElementById('disable-2fa'), |  | ||||||
|         output: document.getElementById('output-2fa'), |         output: document.getElementById('output-2fa'), | ||||||
|         totpSetupForm: document.getElementById('totp-setup'), |         totpSetupForm: document.getElementById('totp-setup'), | ||||||
|         totpSetupToken: document.getElementById('totp-setup-token'), |         totpSetupToken: document.getElementById('totp-setup-token'), | ||||||
| @ -130,6 +107,8 @@ and ensure every administrator account for this control panel does the same.</st | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function render_totp_setup(provisioned_totp) { |     function render_totp_setup(provisioned_totp) { | ||||||
|  |         $(el.totpSetupForm).show(); | ||||||
|  | 
 | ||||||
|         var img = document.createElement('img'); |         var img = document.createElement('img'); | ||||||
|         img.src = "data:image/png;base64," + provisioned_totp.qr_code_base64; |         img.src = "data:image/png;base64," + provisioned_totp.qr_code_base64; | ||||||
| 
 | 
 | ||||||
| @ -148,35 +127,35 @@ and ensure every administrator account for this control panel does the same.</st | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function render_disable(mfa) { |     function render_disable(mfa) { | ||||||
|         el.disableForm.addEventListener('submit', do_disable); |         var panel = $('#mfa-device-templates .' + mfa.type).clone(); | ||||||
|         el.wrapper.classList.add('enabled'); |         $('#mfa-devices').append(panel); | ||||||
|  |         panel.attr('data-mfa-id', mfa.id); | ||||||
|  |         panel.on('submit', do_disable); | ||||||
|         if (mfa.label) |         if (mfa.label) | ||||||
|           $("#mfa-device-label").text(" on device '" + mfa.label + "'"); |           panel.find(".mfa-device-label").text(" on device '" + mfa.label + "'"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function hide_error() { |     function hide_error() { | ||||||
|         el.output.querySelector('.panel-body').innerHTML = ''; |         el.output.querySelector('.panel-body').innerHTML = ''; | ||||||
|         el.output.classList.remove('visible'); |         el.output.classList.add('hidden'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function render_error(msg) { |     function render_error(msg) { | ||||||
|         el.output.querySelector('.panel-body').innerHTML = msg; |         el.output.querySelector('.panel-body').innerHTML = msg; | ||||||
|         el.output.classList.add('visible'); |         el.output.classList.remove('hidden'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function reset_view() { |     function reset_view() { | ||||||
|         el.wrapper.classList.remove('loaded', 'disabled', 'enabled'); |         el.wrapper.classList.remove('loaded', 'disabled', 'enabled'); | ||||||
| 
 |         $('#mfa-devices > *').remove(); | ||||||
|         el.disableForm.removeEventListener('submit', do_disable); |  | ||||||
| 
 | 
 | ||||||
|         hide_error(); |         hide_error(); | ||||||
| 
 | 
 | ||||||
|  |         $(el.totpSetupForm).hide(); | ||||||
|         el.totpSetupForm.reset(); |         el.totpSetupForm.reset(); | ||||||
|         el.totpSetupForm.removeEventListener('submit', do_enable_totp); |         el.totpSetupForm.removeEventListener('submit', do_enable_totp); | ||||||
| 
 |  | ||||||
|         el.totpSetupSecret.setAttribute('value', ''); |         el.totpSetupSecret.setAttribute('value', ''); | ||||||
|         el.totpSetupToken.removeEventListener('input', update_setup_disabled); |         el.totpSetupToken.removeEventListener('input', update_setup_disabled); | ||||||
| 
 |  | ||||||
|         el.totpSetupSubmit.setAttribute('disabled', ''); |         el.totpSetupSubmit.setAttribute('disabled', ''); | ||||||
|         el.totpQr.innerHTML = ''; |         el.totpQr.innerHTML = ''; | ||||||
|     } |     } | ||||||
| @ -191,16 +170,14 @@ and ensure every administrator account for this control panel does the same.</st | |||||||
|             function(res) { |             function(res) { | ||||||
|                 el.wrapper.classList.add('loaded'); |                 el.wrapper.classList.add('loaded'); | ||||||
| 
 | 
 | ||||||
|                 var has_mfa = false; |  | ||||||
|                 res.enabled_mfa.forEach(function(mfa) { |                 res.enabled_mfa.forEach(function(mfa) { | ||||||
|                     if (mfa.type == "totp") { |                     if (mfa.type == "totp") { | ||||||
|                         render_disable(mfa); |                         render_disable(mfa); | ||||||
|                         has_mfa = true; |  | ||||||
|                     } |                     } | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|                 if (!has_mfa) |                 if (res.new_mfa.totp) | ||||||
|                   render_totp_setup(res.new_mfa.totp); |                     render_totp_setup(res.new_mfa.totp); | ||||||
|             } |             } | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| @ -212,7 +189,7 @@ and ensure every administrator account for this control panel does the same.</st | |||||||
|         api( |         api( | ||||||
|             '/mfa/disable', |             '/mfa/disable', | ||||||
|             'POST', |             'POST', | ||||||
|             { type: 'totp' }, |             { id: $(this).attr('data-mfa-id') }, | ||||||
|             function() { |             function() { | ||||||
|                 do_logout(); |                 do_logout(); | ||||||
|             } |             } | ||||||
| @ -226,7 +203,7 @@ and ensure every administrator account for this control panel does the same.</st | |||||||
|         hide_error(); |         hide_error(); | ||||||
| 
 | 
 | ||||||
|         api( |         api( | ||||||
|             '/mfa/totp/enable', |             '/mfa/enable/totp', | ||||||
|             'POST', |             'POST', | ||||||
|             { |             { | ||||||
|                 token: $(el.totpSetupToken).val(), |                 token: $(el.totpSetupToken).val(), | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user