| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import { API, showError } from '../helpers'; |
| import { |
| prepareCredentialRequestOptions, |
| buildAssertionResult, |
| isPasskeySupported, |
| } from '../helpers/passkey'; |
|
|
| |
| |
| |
| |
| export class SecureVerificationService { |
| |
| |
| |
| |
| static async checkAvailableVerificationMethods() { |
| try { |
| const [twoFAResponse, passkeyResponse, passkeySupported] = |
| await Promise.all([ |
| API.get('/api/user/2fa/status'), |
| API.get('/api/user/passkey'), |
| isPasskeySupported(), |
| ]); |
|
|
| console.log('=== DEBUGGING VERIFICATION METHODS ==='); |
| console.log('2FA Response:', JSON.stringify(twoFAResponse, null, 2)); |
| console.log( |
| 'Passkey Response:', |
| JSON.stringify(passkeyResponse, null, 2), |
| ); |
|
|
| const has2FA = |
| twoFAResponse.data?.success && |
| twoFAResponse.data?.data?.enabled === true; |
| const hasPasskey = |
| passkeyResponse.data?.success && |
| passkeyResponse.data?.data?.enabled === true; |
|
|
| console.log('has2FA calculation:', { |
| success: twoFAResponse.data?.success, |
| dataExists: !!twoFAResponse.data?.data, |
| enabled: twoFAResponse.data?.data?.enabled, |
| result: has2FA, |
| }); |
|
|
| console.log('hasPasskey calculation:', { |
| success: passkeyResponse.data?.success, |
| dataExists: !!passkeyResponse.data?.data, |
| enabled: passkeyResponse.data?.data?.enabled, |
| result: hasPasskey, |
| }); |
|
|
| const result = { |
| has2FA, |
| hasPasskey, |
| passkeySupported, |
| }; |
|
|
| return result; |
| } catch (error) { |
| console.error('Failed to check verification methods:', error); |
| return { |
| has2FA: false, |
| hasPasskey: false, |
| passkeySupported: false, |
| }; |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| static async verify2FA(code) { |
| if (!code?.trim()) { |
| throw new Error('请输入验证码或备用码'); |
| } |
|
|
| |
| const verifyResponse = await API.post('/api/verify', { |
| method: '2fa', |
| code: code.trim(), |
| }); |
|
|
| if (!verifyResponse.data?.success) { |
| throw new Error(verifyResponse.data?.message || '验证失败'); |
| } |
|
|
| |
| } |
|
|
| |
| |
| |
| |
| static async verifyPasskey() { |
| try { |
| |
| const beginResponse = await API.post('/api/user/passkey/verify/begin'); |
| if (!beginResponse.data?.success) { |
| throw new Error(beginResponse.data?.message || '开始验证失败'); |
| } |
|
|
| |
| const publicKey = prepareCredentialRequestOptions( |
| beginResponse.data.data.options, |
| ); |
|
|
| |
| const credential = await navigator.credentials.get({ publicKey }); |
| if (!credential) { |
| throw new Error('Passkey 验证被取消'); |
| } |
|
|
| |
| const assertionResult = buildAssertionResult(credential); |
|
|
| |
| const finishResponse = await API.post( |
| '/api/user/passkey/verify/finish', |
| assertionResult, |
| ); |
| if (!finishResponse.data?.success) { |
| throw new Error(finishResponse.data?.message || '验证失败'); |
| } |
|
|
| |
| const verifyResponse = await API.post('/api/verify', { |
| method: 'passkey', |
| }); |
|
|
| if (!verifyResponse.data?.success) { |
| throw new Error(verifyResponse.data?.message || '验证失败'); |
| } |
|
|
| |
| } catch (error) { |
| if (error.name === 'NotAllowedError') { |
| throw new Error('Passkey 验证被取消或超时'); |
| } else if (error.name === 'InvalidStateError') { |
| throw new Error('Passkey 验证状态无效'); |
| } else { |
| throw error; |
| } |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| static async verify(method, code = '') { |
| switch (method) { |
| case '2fa': |
| return await this.verify2FA(code); |
| case 'passkey': |
| return await this.verifyPasskey(); |
| default: |
| throw new Error(`不支持的验证方式: ${method}`); |
| } |
| } |
| } |
|
|
| |
| |
| |
| export const createApiCalls = { |
| |
| |
| |
| |
| viewChannelKey: (channelId) => async () => { |
| |
| const response = await API.post(`/api/channel/${channelId}/key`, {}); |
| return response.data; |
| }, |
|
|
| |
| |
| |
| |
| |
| |
| custom: |
| (url, method = 'POST', extraData = {}) => |
| async () => { |
| |
| const data = extraData; |
|
|
| let response; |
| switch (method.toUpperCase()) { |
| case 'GET': |
| response = await API.get(url, { params: data }); |
| break; |
| case 'POST': |
| response = await API.post(url, data); |
| break; |
| case 'PUT': |
| response = await API.put(url, data); |
| break; |
| case 'DELETE': |
| response = await API.delete(url, { data }); |
| break; |
| default: |
| throw new Error(`不支持的HTTP方法: ${method}`); |
| } |
| return response.data; |
| }, |
| }; |
|
|