mirror of
				https://github.com/MHSanaei/3x-ui.git
				synced 2025-10-31 04:12:51 +00:00 
			
		
		
		
	 5d11e6e13f
			
		
	
	
		5d11e6e13f
		
			
		
	
	
	
	
		
			
			* chore: add `resetTwoFactor` argument for main.go fixes #3025 * chore: reset two-factor authentication after changing admin credentials * chore: reset two-factor authentication after changing admin credentials --------- Co-authored-by: somebodywashere <68244480+somebodywashere@users.noreply.github.com> Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
		
			
				
	
	
		
			125 lines
		
	
	
		
			No EOL
		
	
	
		
			4.2 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			125 lines
		
	
	
		
			No EOL
		
	
	
		
			4.2 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
| {{define "modals/twoFactorModal"}}
 | |
| <a-modal id="two-factor-modal" v-model="twoFactorModal.visible" :title="twoFactorModal.title" :closable="true"
 | |
|     :class="themeSwitcher.currentTheme">
 | |
|     <template v-if="twoFactorModal.type === 'set'">
 | |
|         <p>{{ i18n "pages.settings.security.twoFactorModalSteps" }}</p>
 | |
|         <a-divider></a-divider>
 | |
|         <p>{{ i18n "pages.settings.security.twoFactorModalFirstStep" }}</p>
 | |
|         <div :style="{ display: 'flex', alignItems: 'center', flexDirection: 'column', gap: '12px' }">
 | |
|             <div class="qr-bg" :style="{ width: '180px', height: '180px' }">
 | |
|                 <canvas @click="copy(twoFactorModal.token)" id="twofactor-qrcode" class="qr-cv"></canvas>
 | |
|             </div>
 | |
|             <span :style="{ fontSize: '12px', fontFamily: 'monospace' }">[[ twoFactorModal.token ]]</span>
 | |
|         </div>
 | |
|         <a-divider></a-divider>
 | |
|         <p>{{ i18n "pages.settings.security.twoFactorModalSecondStep" }}</p>
 | |
|         <a-input v-model.trim="twoFactorModal.enteredCode" :style="{ width: '100%' }"></a-input>
 | |
|     </template>
 | |
|     <template v-if="twoFactorModal.type === 'confirm'">
 | |
|         <p>[[ twoFactorModal.description ]]</p>
 | |
|         <a-input v-model.trim="twoFactorModal.enteredCode" :style="{ width: '100%' }"></a-input>
 | |
|     </template>
 | |
|     <template slot="footer">
 | |
|         <a-button @click="twoFactorModal.cancel">
 | |
|             <span>{{ i18n "cancel" }}</span>
 | |
|         </a-button>
 | |
|         <a-button type="primary" :disabled="twoFactorModal.enteredCode.length < 6" @click="twoFactorModal.ok">
 | |
|             <span>{{ i18n "confirm" }}</span>
 | |
|         </a-button>
 | |
|     </template>
 | |
| </a-modal>
 | |
| 
 | |
| <script>
 | |
|     const twoFactorModal = {
 | |
|         title: '',
 | |
|         description: '',
 | |
|         fileName: '',
 | |
|         token: '',
 | |
|         enteredCode: '',
 | |
|         visible: false,
 | |
|         type: 'set',
 | |
|         confirm: null,
 | |
|         totpObject: null,
 | |
|         qrImage: "",
 | |
|         ok() {
 | |
|             if (twoFactorModal.totpObject.generate() === twoFactorModal.enteredCode) {
 | |
|                 ObjectUtil.execute(twoFactorModal.confirm, true)
 | |
| 
 | |
|                 twoFactorModal.close()
 | |
|             } else {
 | |
|                 Vue.prototype.$message['error']('{{ i18n "pages.settings.security.twoFactorModalError" }}')
 | |
|             }
 | |
|         },
 | |
|         cancel() {
 | |
|             ObjectUtil.execute(twoFactorModal.confirm, false)
 | |
| 
 | |
|             twoFactorModal.close()
 | |
|         },
 | |
|         show: function ({
 | |
|             title = '',
 | |
|             description = '',
 | |
|             token = '',
 | |
|             type = 'set',
 | |
|             confirm = (success) => { }
 | |
|         }) {
 | |
|             this.title = title;
 | |
|             this.description = description;
 | |
|             this.token = token;
 | |
|             this.visible = true;
 | |
|             this.confirm = confirm;
 | |
|             this.type = type;
 | |
| 
 | |
|             this.totpObject = new OTPAuth.TOTP({
 | |
|                 issuer: "3x-ui",
 | |
|                 label: "Administrator",
 | |
|                 algorithm: "SHA1",
 | |
|                 digits: 6,
 | |
|                 period: 30,
 | |
|                 secret: twoFactorModal.token,
 | |
|             });
 | |
|         },
 | |
|         close: function () {
 | |
|             twoFactorModal.enteredCode = "";
 | |
|             twoFactorModal.visible = false;
 | |
|         },
 | |
|     };
 | |
| 
 | |
|     const twoFactorModalApp = new Vue({
 | |
|         delimiters: ['[[', ']]'],
 | |
|         el: '#two-factor-modal',
 | |
|         data: {
 | |
|             twoFactorModal: twoFactorModal,
 | |
|         },
 | |
|         updated() {
 | |
|           if (
 | |
|             this.twoFactorModal.visible &&
 | |
|             this.twoFactorModal.type === 'set' &&
 | |
|             document.getElementById('twofactor-qrcode')
 | |
|           ) {
 | |
|             this.setQrCode('twofactor-qrcode', this.twoFactorModal.totpObject.toString());
 | |
|           }
 | |
|         },
 | |
|         methods: {
 | |
|           setQrCode(elementId, content) {
 | |
|             new QRious({
 | |
|               element: document.getElementById(elementId),
 | |
|               size: 200,
 | |
|               value: content,
 | |
|               background: 'white',
 | |
|               backgroundAlpha: 0,
 | |
|               foreground: 'black',
 | |
|               padding: 2,
 | |
|               level: 'L'
 | |
|             });
 | |
|           },
 | |
|           copy(content) {
 | |
|             ClipboardManager
 | |
|               .copyText(content)
 | |
|               .then(() => {
 | |
|                 app.$message.success('{{ i18n "copied" }}')
 | |
|               })
 | |
|           },
 | |
|         }
 | |
|     });
 | |
| </script>
 | |
| {{end}} |