1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
import RecoveryCodes from './mfa_backup_codes.vue'
import TOTP from './mfa_totp.vue'
import Confirm from './confirm.vue'
import VueQrcode from '@chenfengyuan/vue-qrcode'
import { mapState } from 'vuex'
const Mfa = {
data: () => ({
settings: { // current settings of MFA
available: false,
enabled: false,
totp: false
},
setupState: { // setup mfa
state: '', // state of setup. '' -> 'getBackupCodes' -> 'setupOTP' -> 'complete'
setupOTPState: '' // state of setup otp. '' -> 'prepare' -> 'confirm' -> 'complete'
},
backupCodes: {
getNewCodes: false,
inProgress: false, // progress of fetch codes
codes: []
},
otpSettings: { // pre-setup setting of OTP. secret key, qrcode url.
provisioning_uri: '',
key: ''
},
currentPassword: null,
otpConfirmToken: null,
error: null,
readyInit: false
}),
components: {
'recovery-codes': RecoveryCodes,
'totp-item': TOTP,
qrcode: VueQrcode,
confirm: Confirm
},
computed: {
canSetupOTP () {
return (
(this.setupInProgress && this.backupCodesPrepared) ||
this.settings.enabled
) && !this.settings.totp && !this.setupOTPInProgress
},
setupInProgress () {
return this.setupState.state !== '' && this.setupState.state !== 'complete'
},
setupOTPInProgress () {
return this.setupState.state === 'setupOTP' && !this.completedOTP
},
prepareOTP () {
return this.setupState.setupOTPState === 'prepare'
},
confirmOTP () {
return this.setupState.setupOTPState === 'confirm'
},
completedOTP () {
return this.setupState.setupOTPState === 'completed'
},
backupCodesPrepared () {
return !this.backupCodes.inProgress && this.backupCodes.codes.length > 0
},
confirmNewBackupCodes () {
return this.backupCodes.getNewCodes
},
...mapState({
backendInteractor: (state) => state.api.backendInteractor
})
},
methods: {
activateOTP () {
if (!this.settings.enabled) {
this.setupState.state = 'getBackupcodes'
this.fetchBackupCodes()
}
},
fetchBackupCodes () {
this.backupCodes.inProgress = true
this.backupCodes.codes = []
return this.backendInteractor.generateMfaBackupCodes()
.then((res) => {
this.backupCodes.codes = res.codes
this.backupCodes.inProgress = false
})
},
getBackupCodes () { // get a new backup codes
this.backupCodes.getNewCodes = true
},
confirmBackupCodes () { // confirm getting new backup codes
this.fetchBackupCodes().then((res) => {
this.backupCodes.getNewCodes = false
})
},
cancelBackupCodes () { // cancel confirm form of new backup codes
this.backupCodes.getNewCodes = false
},
// Setup OTP
setupOTP () { // prepare setup OTP
this.setupState.state = 'setupOTP'
this.setupState.setupOTPState = 'prepare'
this.backendInteractor.mfaSetupOTP()
.then((res) => {
this.otpSettings = res
this.setupState.setupOTPState = 'confirm'
})
},
doConfirmOTP () { // handler confirm enable OTP
this.error = null
this.backendInteractor.mfaConfirmOTP({
token: this.otpConfirmToken,
password: this.currentPassword
})
.then((res) => {
if (res.error) {
this.error = res.error
return
}
this.completeSetup()
})
},
completeSetup () {
this.setupState.setupOTPState = 'complete'
this.setupState.state = 'complete'
this.currentPassword = null
this.error = null
this.fetchSettings()
},
cancelSetup () { // cancel setup
this.setupState.setupOTPState = ''
this.setupState.state = ''
this.currentPassword = null
this.error = null
},
// end Setup OTP
// fetch settings from server
async fetchSettings () {
const result = await this.backendInteractor.settingsMFA()
if (result.error) return
this.settings = result.settings
this.settings.available = true
return result
}
},
mounted () {
this.fetchSettings().then(() => {
this.readyInit = true
})
}
}
export default Mfa
|