-
Notifications
You must be signed in to change notification settings - Fork 96
Expand file tree
/
Copy pathOnboardingLayout.qml
More file actions
310 lines (243 loc) · 10.3 KB
/
Copy pathOnboardingLayout.qml
File metadata and controls
310 lines (243 loc) · 10.3 KB
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
import QtCore
import QtQuick
import QtQuick.Controls
import StatusQ
import StatusQ.Controls
import StatusQ.Core
import StatusQ.Core.Theme
import AppLayouts.Onboarding.stores
import AppLayouts.Onboarding.enums
import StatusQ.Core.Utils as SQUtils
import utils
Page {
id: root
required property OnboardingStore onboardingStore
required property Keychain keychain
required property bool privacyModeFeatureEnabled
// list of language/locale codes, e.g. ["cs_CZ","ko","fr"]
required property var availableLanguages
// language currently selected for translations, e.g. "cs"
required property string currentLanguage
property bool isKeycardEnabled: true
property bool networkChecksEnabled: true
property alias keycardPinInfoPageDelay: onboardingFlow.keycardPinInfoPageDelay
readonly property alias stack: onboardingFlow // TODO remove external stack access
readonly property string currentPageName: {
if (!stack.topLevelItem)
return ""
const item = stack.topLevelItem instanceof Loader ? stack.topLevelItem.item
: stack.topLevelItem
return Utils.objectTypeName(item)
}
signal changeLanguageRequested(string newLanguageCode)
signal shareUsageDataRequested(bool enabled)
signal skippedBiometricFlow()
// flow: Onboarding.OnboardingFlow
signal finished(int flow, var data)
// -> "keyUid:string": User ID to login; "method:int": password or keycard (cf Onboarding.LoginMethod.*) enum;
// "data:var": contains "password" or "pin"
signal loginRequested(string keyUid, int method, var data)
signal keycardRequested()
function restartFlow() {
unload()
onboardingFlow.restart()
}
function unload() {
onboardingFlow.clear()
d.resetState()
}
// clear the stack and load the LoginScreen
// the purpose is to return from main/splash screen in case of a late stage error
// and use the below error handler (onAccountLoginError)
function unwindToLoginScreen() {
restartFlow()
}
QtObject {
id: d
// constants
readonly property int numWordsToVerify: 4
// state collected
property string password
property string keycardPin
property bool enableBiometrics
property string seedphrase
property string keyUid // Used in LoginWithLostKeycardSeedphrase
property url backupImportFileUrl
// login screen state
property string selectedProfileKeyId
property bool thirdpartyServicesEnabled: true
function resetState() {
d.password = ""
d.keycardPin = ""
d.enableBiometrics = false
d.seedphrase = ""
d.keyUid = ""
d.backupImportFileUrl = ""
d.selectedProfileKeyId = ""
d.thirdpartyServicesEnabled = true
}
readonly property var settings: Settings { /* https://bugreports.qt.io/browse/QTBUG-135039 */
property bool keycardPromoShown // whether we've seen the keycard promo banner on KeycardIntroPage
function reset() {
keycardPromoShown = false
}
}
function finishFlow(flow) {
const data = {
password: d.password,
keycardPin: d.keycardPin,
seedphrase: d.seedphrase,
keyUid: d.keyUid,
backupImportFileUrl: d.backupImportFileUrl,
enableBiometrics: d.enableBiometrics,
thirdpartyServicesEnabled: d.thirdpartyServicesEnabled
}
root.finished(flow, data)
}
function loadMnemonic() {
root.onboardingStore.loadMnemonic(d.seedphrase)
}
function authorize(pin) {
if (!pin && !d.keycardPin) {
console.warn("OnboardingLayout: authorize pin not provided")
return
}
if (!pin) {
pin = d.keycardPin
}
root.onboardingStore.authorize(pin)
}
}
background: Rectangle {
color: Theme.palette.background
}
OnboardingFlow {
id: onboardingFlow
anchors.fill: parent
loginAccountsModel: root.onboardingStore.loginAccountsModel
availableLanguages: root.availableLanguages
currentLanguage: root.currentLanguage
keycardState: root.onboardingStore.keycardState
keycardUID: root.onboardingStore.keycardUID
pinSettingState: root.onboardingStore.pinSettingState
authorizationState: root.onboardingStore.authorizationState
restoreKeysExportState: root.onboardingStore.restoreKeysExportState
syncState: root.onboardingStore.syncState
addKeyPairState: root.onboardingStore.addKeyPairState
displayKeycardPromoBanner: !d.settings.keycardPromoShown
biometricsAvailable: root.keychain.available
isKeycardEnabled: root.isKeycardEnabled
networkChecksEnabled: root.networkChecksEnabled
generateMnemonic: root.onboardingStore.generateMnemonic
isBiometricsLogin: (account) => root.keychain.hasCredential(account) === Keychain.StatusSuccess
passwordStrengthScoreFunction: root.onboardingStore.getPasswordStrengthScore
isSeedPhraseValid: root.onboardingStore.validMnemonic
isSeedPhraseDuplicate: root.onboardingStore.isMnemonicDuplicate
validateConnectionString: root.onboardingStore.validateLocalPairingConnectionString
tryToSetPukFunction: root.onboardingStore.setPuk
remainingPinAttempts: root.onboardingStore.keycardRemainingPinAttempts
remainingPukAttempts: root.onboardingStore.keycardRemainingPukAttempts
onChangeLanguageRequested: (newLanguageCode) => root.changeLanguageRequested(newLanguageCode)
onLoginRequested: (keyUid, method, data) => root.loginRequested(keyUid, method, data)
onSetPinRequested: (pin) => {
d.keycardPin = pin
root.onboardingStore.setPin(pin)
}
onLoadMnemonicRequested: d.loadMnemonic()
onAuthorizationRequested: (pin) => d.authorize(pin)
onShareUsageDataRequested: (enabled) => root.shareUsageDataRequested(enabled)
onPerformKeycardFactoryResetRequested: root.onboardingStore.startKeycardFactoryReset()
onSyncProceedWithConnectionString: (connectionString) =>
root.onboardingStore.inputConnectionStringForBootstrapping(connectionString)
onSeedphraseSubmitted: (seedphrase) => d.seedphrase = seedphrase
onKeyUidSubmitted: (keyUid) => d.keyUid = keyUid
onSetPasswordRequested: (password) => d.password = password
onEnableBiometricsRequested: (enabled) => d.enableBiometrics = enabled
onLinkActivated: (link) => Qt.openUrlExternally(link)
onExportKeysRequested: root.onboardingStore.exportRecoverKeys()
onImportLocalBackupRequested: (importFilePath) => d.backupImportFileUrl = importFilePath
onFinished: (flow) => d.finishFlow(flow)
onKeycardRequested: {
root.keycardRequested()
root.onboardingStore.startKeycardDetection()
}
onBiometricsRequested: (profileId) => {
const isKeycardProfile = SQUtils.ModelUtils.getByKey(
onboardingStore.loginAccountsModel, "keyUid",
profileId, "keycardCreatedAccount")
const reason = isKeycardProfile ? qsTr("fetch pin") : qsTr("fetch password")
root.keychain.requestGetCredential(reason, profileId)
}
onDismissBiometricsRequested: {
if (root.keychain.loading)
root.keychain.cancelActiveRequest()
}
privacyModeFeatureEnabled: root.privacyModeFeatureEnabled
thirdpartyServicesEnabled: d.thirdpartyServicesEnabled
onToggleThirdpartyServicesEnabledRequested: {
d.thirdpartyServicesEnabled = !d.thirdpartyServicesEnabled
}
onSkippedBiometricFlow: root.skippedBiometricFlow()
}
// needs to be on top of the stack
// we're here only to provide the Back button feature
StatusMouseArea {
anchors.fill: parent
acceptedButtons: Qt.BackButton
cursorShape: undefined // don't override the cursor coming from the stack
enabled: backButton.visible
onClicked: onboardingFlow.popTopLevelItem()
}
StatusBackButton {
id: backButton
width: 44
height: 44
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.margins: Theme.padding
opacity: onboardingFlow.depth > 1 && !onboardingFlow.topLevelStack.busy &&
onboardingFlow.backAvailable ? 1 : 0
visible: opacity > 0
Behavior on opacity {
NumberAnimation { duration: 100 }
}
onClicked: onboardingFlow.popTopLevelItem()
}
Keys.onPressed: function(e) {
if (e.key === Qt.Key_Back && backButton.visible) {
e.accepted = true
onboardingFlow.popTopLevelItem()
}
}
Connections {
target: onboardingFlow.topLevelItem
ignoreUnknownSignals: true
function onRequestOpenLink(link: string) {
Qt.openUrlExternally(link)
}
}
// error handler for the LoginScreen
Connections {
target: root.onboardingStore
function onAccountLoginError(error: string, wrongPassword: bool) {
const loginScreen = onboardingFlow.loginScreen
if (!loginScreen)
return
loginScreen.setAccountLoginError(error, wrongPassword)
}
}
Connections {
target: root.keychain
function onGetCredentialRequestCompleted(status, secret) {
if (status === Keychain.StatusSuccess)
onboardingFlow.setBiometricResponse(secret)
else if (status === Keychain.StatusNotFound)
onboardingFlow.setBiometricResponse("", qsTr("Credentials not found."))
else if (status === Keychain.StatusFallbackSelected)
onboardingFlow.setBiometricResponse("", "")
else if (status !== Keychain.StatusCancelled)
onboardingFlow.setBiometricResponse("", qsTr("Fetching credentials failed."))
}
}
Component.onCompleted: restartFlow()
}