mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-11 02:15:48 +02:00
101 lines
2.8 KiB
TypeScript
101 lines
2.8 KiB
TypeScript
import { createVNode, render } from 'vue'
|
|
import { Modal, message } from 'ant-design-vue'
|
|
import { useCookies } from '@vueuse/integrations/useCookies'
|
|
import Authorization from '@/components/TwoFA/Authorization.vue'
|
|
import twoFA from '@/api/2fa'
|
|
import { useUserStore } from '@/pinia'
|
|
|
|
const use2FAModal = () => {
|
|
const refOTPAuthorization = ref<typeof Authorization>()
|
|
const randomId = Math.random().toString(36).substring(2, 8)
|
|
const { secureSessionId } = storeToRefs(useUserStore())
|
|
|
|
const injectStyles = () => {
|
|
const style = document.createElement('style')
|
|
|
|
style.innerHTML = `
|
|
.${randomId} .ant-modal-title {
|
|
font-size: 1.125rem;
|
|
}
|
|
`
|
|
document.head.appendChild(style)
|
|
}
|
|
|
|
const open = async (): Promise<string> => {
|
|
const twoFAStatus = await twoFA.status()
|
|
const { status: secureSessionStatus } = await twoFA.secure_session_status()
|
|
|
|
return new Promise((resolve, reject) => {
|
|
if (!twoFAStatus.enabled) {
|
|
resolve('')
|
|
|
|
return
|
|
}
|
|
|
|
const cookies = useCookies(['nginx-ui-2fa'])
|
|
const ssid = cookies.get('secure_session_id')
|
|
if (ssid && secureSessionStatus) {
|
|
resolve(ssid)
|
|
secureSessionId.value = ssid
|
|
|
|
return
|
|
}
|
|
injectStyles()
|
|
let container: HTMLDivElement | null = document.createElement('div')
|
|
document.body.appendChild(container)
|
|
|
|
const close = () => {
|
|
render(null, container!)
|
|
document.body.removeChild(container!)
|
|
container = null
|
|
}
|
|
|
|
const setSessionId = (sessionId: string) => {
|
|
cookies.set('secure_session_id', sessionId, { maxAge: 60 * 3 })
|
|
close()
|
|
secureSessionId.value = sessionId
|
|
resolve(sessionId)
|
|
}
|
|
|
|
const verifyOTP = (passcode: string, recovery: string) => {
|
|
twoFA.start_secure_session_by_otp(passcode, recovery).then(async r => {
|
|
setSessionId(r.session_id)
|
|
}).catch(async () => {
|
|
refOTPAuthorization.value?.clearInput()
|
|
await message.error($gettext('Invalid passcode or recovery code'))
|
|
})
|
|
}
|
|
|
|
const vnode = createVNode(Modal, {
|
|
open: true,
|
|
title: $gettext('Two-factor authentication required'),
|
|
centered: true,
|
|
maskClosable: false,
|
|
class: randomId,
|
|
footer: false,
|
|
onCancel: () => {
|
|
close()
|
|
// eslint-disable-next-line prefer-promise-reject-errors
|
|
reject()
|
|
},
|
|
}, {
|
|
default: () => h(
|
|
Authorization,
|
|
{
|
|
ref: refOTPAuthorization,
|
|
twoFAStatus,
|
|
class: 'mt-3',
|
|
onSubmitOTP: verifyOTP,
|
|
onSubmitSecureSessionID: setSessionId,
|
|
},
|
|
),
|
|
})
|
|
|
|
render(vnode, container!)
|
|
})
|
|
}
|
|
|
|
return { open }
|
|
}
|
|
|
|
export default use2FAModal
|