@@ -15,8 +15,8 @@ export class FingerprintAuth implements FingerprintAuthApi {
15
15
16
16
constructor ( ) {
17
17
this . keyguardManager = androidUtils
18
- . getApplicationContext ( )
19
- . getSystemService ( "keyguard" ) ;
18
+ . getApplicationContext ( )
19
+ . getSystemService ( "keyguard" ) ;
20
20
}
21
21
22
22
// TODO can we detect face on the Samsung S8?
@@ -37,10 +37,10 @@ export class FingerprintAuth implements FingerprintAuthApi {
37
37
}
38
38
39
39
const fingerprintManager = androidUtils
40
- . getApplicationContext ( )
41
- . getSystemService (
42
- "fingerprint"
43
- ) as android . hardware . fingerprint . FingerprintManager ;
40
+ . getApplicationContext ( )
41
+ . getSystemService (
42
+ "fingerprint"
43
+ ) as android . hardware . fingerprint . FingerprintManager ;
44
44
45
45
if ( ! fingerprintManager . isHardwareDetected ( ) ) {
46
46
// Device doesn't support fingerprint authentication
@@ -59,7 +59,7 @@ export class FingerprintAuth implements FingerprintAuthApi {
59
59
} else {
60
60
// User hasn't enrolled any fingerprints to authenticate with
61
61
reject (
62
- `User hasn't enrolled any fingerprints to authenticate with`
62
+ `User hasn't enrolled any fingerprints to authenticate with`
63
63
) ;
64
64
}
65
65
} else {
@@ -83,12 +83,11 @@ export class FingerprintAuth implements FingerprintAuthApi {
83
83
} ) ;
84
84
}
85
85
86
-
87
86
private verifyWithCustomAndroidUI ( resolve , reject , authenticationCallback ) {
88
87
// this instance is com.jesusm.kfingerprintmanager.KFingerprintManager, not the android OS fingerprint manager
89
88
this . fingerPrintManager . authenticate (
90
- authenticationCallback ,
91
- this . getActivity ( ) . getSupportFragmentManager ( )
89
+ authenticationCallback ,
90
+ this . getActivity ( ) . getSupportFragmentManager ( )
92
91
) ;
93
92
}
94
93
@@ -98,73 +97,73 @@ export class FingerprintAuth implements FingerprintAuthApi {
98
97
// in case 'activity.getSupportFragmentManager' is available ({N} started supporting it,
99
98
// or the user added our Activity to their Android manifest), use the 3rd party FP library
100
99
const hasSupportFragment =
101
- this . getActivity ( ) . getSupportFragmentManager !== undefined ;
100
+ this . getActivity ( ) . getSupportFragmentManager !== undefined ;
102
101
103
102
if ( options . useCustomAndroidUI && ! hasSupportFragment ) {
104
103
reject ( {
105
104
code : ERROR_CODES . DEVELOPER_ERROR ,
106
105
message :
107
- "Custom Fingerprint UI requires changes to AndroidManifest.xml. See the nativescript-fingerprint-auth documentation."
106
+ "Custom Fingerprint UI requires changes to AndroidManifest.xml. See the nativescript-fingerprint-auth documentation."
108
107
} ) ;
109
108
} else if ( options . useCustomAndroidUI && hasSupportFragment ) {
110
109
if ( ! this . fingerPrintManager ) {
111
110
this . fingerPrintManager = new com . jesusm . kfingerprintmanager . KFingerprintManager (
112
- androidUtils . getApplicationContext ( ) ,
113
- KEY_NAME
111
+ androidUtils . getApplicationContext ( ) ,
112
+ KEY_NAME
114
113
) ;
115
114
}
116
115
const that = this ;
117
116
const callback = new com . jesusm . kfingerprintmanager . KFingerprintManager . AuthenticationCallback (
118
- {
119
- attempts : 0 ,
120
- onAuthenticationFailedWithHelp ( help ) : void {
121
- if ( ++ this . attempts < 3 ) {
122
- // just invoke the UI again as it's very sensitive (need a timeout to prevent an infinite loop)
123
- setTimeout (
124
- ( ) => that . verifyWithCustomAndroidUI ( resolve , reject , this ) ,
125
- 50
126
- ) ;
127
- } else {
117
+ {
118
+ attempts : 0 ,
119
+ onAuthenticationFailedWithHelp ( help ) : void {
120
+ if ( ++ this . attempts < 3 ) {
121
+ // just invoke the UI again as it's very sensitive (need a timeout to prevent an infinite loop)
122
+ setTimeout (
123
+ ( ) => that . verifyWithCustomAndroidUI ( resolve , reject , this ) ,
124
+ 50
125
+ ) ;
126
+ } else {
127
+ reject ( {
128
+ code : ERROR_CODES . RECOVERABLE_ERROR ,
129
+ message : help
130
+ } ) ;
131
+ }
132
+ } ,
133
+ onAuthenticationSuccess ( ) : void {
134
+ resolve ( ) ;
135
+ } ,
136
+ onSuccessWithManualPassword ( password ) : void {
137
+ resolve ( password ) ;
138
+ } ,
139
+ onFingerprintNotRecognized ( ) : void {
140
+ if ( ++ this . attempts < 3 ) {
141
+ // just invoke the UI again as it's very sensitive (need a timeout to prevent an infinite loop)
142
+ setTimeout (
143
+ ( ) => that . verifyWithCustomAndroidUI ( resolve , reject , this ) ,
144
+ 50
145
+ ) ;
146
+ } else {
147
+ reject ( {
148
+ code : ERROR_CODES . NOT_RECOGNIZED ,
149
+ message : "Fingerprint not recognized."
150
+ } ) ;
151
+ }
152
+ } ,
153
+ onFingerprintNotAvailable ( ) : void {
128
154
reject ( {
129
- code : ERROR_CODES . RECOVERABLE_ERROR ,
130
- message : help
155
+ code : ERROR_CODES . NOT_CONFIGURED ,
156
+ message :
157
+ 'Secure lock screen hasn\'t been set up.\n Go to "Settings -> Security -> Screenlock" to set up a lock screen.'
131
158
} ) ;
132
- }
133
- } ,
134
- onAuthenticationSuccess ( ) : void {
135
- resolve ( ) ;
136
- } ,
137
- onSuccessWithManualPassword ( password ) : void {
138
- resolve ( password ) ;
139
- } ,
140
- onFingerprintNotRecognized ( ) : void {
141
- if ( ++ this . attempts < 3 ) {
142
- // just invoke the UI again as it's very sensitive (need a timeout to prevent an infinite loop)
143
- setTimeout (
144
- ( ) => that . verifyWithCustomAndroidUI ( resolve , reject , this ) ,
145
- 50
146
- ) ;
147
- } else {
159
+ } ,
160
+ onCancelled ( ) : void {
148
161
reject ( {
149
- code : ERROR_CODES . NOT_RECOGNIZED ,
150
- message : "Fingerprint not recognized. "
162
+ code : ERROR_CODES . PASSWORD_FALLBACK_SELECTED ,
163
+ message : "Cancelled by user "
151
164
} ) ;
152
165
}
153
- } ,
154
- onFingerprintNotAvailable ( ) : void {
155
- reject ( {
156
- code : ERROR_CODES . NOT_CONFIGURED ,
157
- message :
158
- 'Secure lock screen hasn\'t been set up.\n Go to "Settings -> Security -> Screenlock" to set up a lock screen.'
159
- } ) ;
160
- } ,
161
- onCancelled ( ) : void {
162
- reject ( {
163
- code : ERROR_CODES . PASSWORD_FALLBACK_SELECTED ,
164
- message : "Cancelled by user"
165
- } ) ;
166
166
}
167
- }
168
167
) ;
169
168
this . verifyWithCustomAndroidUI ( resolve , reject , callback ) ;
170
169
} else {
@@ -183,14 +182,14 @@ export class FingerprintAuth implements FingerprintAuthApi {
183
182
}
184
183
}
185
184
app . android . off (
186
- app . AndroidApplication . activityResultEvent ,
187
- onActivityResult
185
+ app . AndroidApplication . activityResultEvent ,
186
+ onActivityResult
188
187
) ;
189
188
} ;
190
189
191
190
app . android . on (
192
- app . AndroidApplication . activityResultEvent ,
193
- onActivityResult
191
+ app . AndroidApplication . activityResultEvent ,
192
+ onActivityResult
194
193
) ;
195
194
196
195
if ( ! this . keyguardManager ) {
@@ -200,13 +199,13 @@ export class FingerprintAuth implements FingerprintAuthApi {
200
199
} ) ;
201
200
}
202
201
if (
203
- this . keyguardManager &&
204
- ! this . keyguardManager . isKeyguardSecure ( )
202
+ this . keyguardManager &&
203
+ ! this . keyguardManager . isKeyguardSecure ( )
205
204
) {
206
205
reject ( {
207
206
code : ERROR_CODES . NOT_CONFIGURED ,
208
207
message :
209
- 'Secure lock screen hasn\'t been set up.\n Go to "Settings -> Security -> Screenlock" to set up a lock screen.'
208
+ 'Secure lock screen hasn\'t been set up.\n Go to "Settings -> Security -> Screenlock" to set up a lock screen.'
210
209
} ) ;
211
210
}
212
211
@@ -235,11 +234,23 @@ export class FingerprintAuth implements FingerprintAuthApi {
235
234
}
236
235
237
236
verifyFingerprintWithCustomFallback (
238
- options : VerifyFingerprintWithCustomFallbackOptions
237
+ options : VerifyFingerprintWithCustomFallbackOptions
239
238
) : Promise < any > {
240
239
return this . verifyFingerprint ( options ) ;
241
240
}
242
241
242
+ close ( ) : void {
243
+ const fragmentManager = this . getActivity ( ) . getSupportFragmentManager ( ) ;
244
+ // this is for custom ui
245
+ const fragmentTag = "KFingerprintManager:fingerprintDialog" ;
246
+ const fragment = fragmentManager . findFragmentByTag ( fragmentTag ) ;
247
+ if ( fragment ) {
248
+ fragmentManager . beginTransaction ( ) . remove ( fragment ) . commit ( ) ;
249
+ } else {
250
+ // AFAIK it's not possible to programmatically close the standard one
251
+ }
252
+ }
253
+
243
254
/**
244
255
* Creates a symmetric key in the Android Key Store which can only be used after the user has
245
256
* authenticated with device credentials within the last X seconds.
@@ -249,37 +260,37 @@ export class FingerprintAuth implements FingerprintAuthApi {
249
260
const keyStore = java . security . KeyStore . getInstance ( "AndroidKeyStore" ) ;
250
261
keyStore . load ( null ) ;
251
262
const keyGenerator = javax . crypto . KeyGenerator . getInstance (
252
- android . security . keystore . KeyProperties . KEY_ALGORITHM_AES ,
253
- "AndroidKeyStore"
263
+ android . security . keystore . KeyProperties . KEY_ALGORITHM_AES ,
264
+ "AndroidKeyStore"
254
265
) ;
255
266
256
267
keyGenerator . init (
257
- new android . security . keystore . KeyGenParameterSpec . Builder (
258
- KEY_NAME ,
259
- android . security . keystore . KeyProperties . PURPOSE_ENCRYPT |
260
- android . security . keystore . KeyProperties . PURPOSE_DECRYPT
261
- )
262
- . setBlockModes ( [
263
- android . security . keystore . KeyProperties . BLOCK_MODE_CBC
264
- ] )
265
- . setUserAuthenticationRequired ( true )
266
- . setUserAuthenticationValidityDurationSeconds (
267
- options && options . authenticationValidityDuration
268
- ? options . authenticationValidityDuration
269
- : 5
268
+ new android . security . keystore . KeyGenParameterSpec . Builder (
269
+ KEY_NAME ,
270
+ android . security . keystore . KeyProperties . PURPOSE_ENCRYPT |
271
+ android . security . keystore . KeyProperties . PURPOSE_DECRYPT
270
272
)
271
- . setEncryptionPaddings ( [
272
- android . security . keystore . KeyProperties . ENCRYPTION_PADDING_PKCS7
273
- ] )
274
- . build ( )
273
+ . setBlockModes ( [
274
+ android . security . keystore . KeyProperties . BLOCK_MODE_CBC
275
+ ] )
276
+ . setUserAuthenticationRequired ( true )
277
+ . setUserAuthenticationValidityDurationSeconds (
278
+ options && options . authenticationValidityDuration
279
+ ? options . authenticationValidityDuration
280
+ : 5
281
+ )
282
+ . setEncryptionPaddings ( [
283
+ android . security . keystore . KeyProperties . ENCRYPTION_PADDING_PKCS7
284
+ ] )
285
+ . build ( )
275
286
) ;
276
287
keyGenerator . generateKey ( ) ;
277
288
} catch ( error ) {
278
289
// checks if the AES algorithm is implemented by the AndroidKeyStore
279
290
if (
280
- `${ error . nativeException } ` . indexOf (
281
- "java.security.NoSuchAlgorithmException:"
282
- ) > - 1
291
+ `${ error . nativeException } ` . indexOf (
292
+ "java.security.NoSuchAlgorithmException:"
293
+ ) > - 1
283
294
) {
284
295
// You need a device with API level >= 23 in order to detect if the user has already been authenticated in the last x seconds.
285
296
}
@@ -293,9 +304,9 @@ export class FingerprintAuth implements FingerprintAuthApi {
293
304
const secretKey = keyStore . getKey ( KEY_NAME , null ) ;
294
305
295
306
const cipher = javax . crypto . Cipher . getInstance (
296
- `${ android . security . keystore . KeyProperties . KEY_ALGORITHM_AES } /${
297
- android . security . keystore . KeyProperties . BLOCK_MODE_CBC
298
- } /${ android . security . keystore . KeyProperties . ENCRYPTION_PADDING_PKCS7 } `
307
+ `${ android . security . keystore . KeyProperties . KEY_ALGORITHM_AES } /${
308
+ android . security . keystore . KeyProperties . BLOCK_MODE_CBC
309
+ } /${ android . security . keystore . KeyProperties . ENCRYPTION_PADDING_PKCS7 } `
299
310
) ;
300
311
301
312
cipher . init ( javax . crypto . Cipher . ENCRYPT_MODE , secretKey ) ;
@@ -304,17 +315,17 @@ export class FingerprintAuth implements FingerprintAuthApi {
304
315
return true ;
305
316
} catch ( error ) {
306
317
if (
307
- `${ error . nativeException } ` . indexOf (
308
- "android.security.keystore.UserNotAuthenticatedException"
309
- ) > - 1
318
+ `${ error . nativeException } ` . indexOf (
319
+ "android.security.keystore.UserNotAuthenticatedException"
320
+ ) > - 1
310
321
) {
311
322
// the user must provide their credentials in order to proceed
312
323
this . showAuthenticationScreen ( options ) ;
313
324
return undefined ;
314
325
} else if (
315
- `${ error . nativeException } ` . indexOf (
316
- "android.security.keystore.KeyPermanentlyInvalidatedException"
317
- ) > - 1
326
+ `${ error . nativeException } ` . indexOf (
327
+ "android.security.keystore.KeyPermanentlyInvalidatedException"
328
+ ) > - 1
318
329
) {
319
330
// Invalid fingerprint
320
331
console . log ( error ) ;
@@ -331,14 +342,14 @@ export class FingerprintAuth implements FingerprintAuthApi {
331
342
private showAuthenticationScreen ( options ) : void {
332
343
// https://developer.android.com/reference/android/app/KeyguardManager#createConfirmDeviceCredentialIntent(java.lang.CharSequence,%2520java.lang.CharSequence)
333
344
const intent = ( this
334
- . keyguardManager as any ) . createConfirmDeviceCredentialIntent (
335
- options && options . title ? options . title : null ,
336
- options && options . message ? options . message : null
345
+ . keyguardManager as any ) . createConfirmDeviceCredentialIntent (
346
+ options && options . title ? options . title : null ,
347
+ options && options . message ? options . message : null
337
348
) ;
338
349
if ( intent !== null ) {
339
350
this . getActivity ( ) . startActivityForResult (
340
- intent ,
341
- REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS
351
+ intent ,
352
+ REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS
342
353
) ;
343
354
}
344
355
}
0 commit comments