Skip to content

Commit c89a840

Browse files
#1 Add a few iOS9+ security and convenience features
1 parent 8d17f90 commit c89a840

File tree

4 files changed

+64
-31
lines changed

4 files changed

+64
-31
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nativescript-touchid",
3-
"version": "2.0.0",
3+
"version": "2.1.0",
44
"description": "A TouchID (fingerprint scanner) module for use in NativeScript apps",
55
"main": "touchid.js",
66
"nativescript": {

touchid.android.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,9 @@ exports.available = function () {
44
});
55
};
66

7+
// shouldn't be called anyway because 'available' returned false
78
exports.verifyFingerprint = function () {
89
return new Promise(function (resolve, reject) {
910
reject("Not available");
1011
});
11-
};
12-
13-
exports.verifyFingerprintWithCustomFallback = function () {
14-
return new Promise(function (resolve, reject) {
15-
reject("Not available");
16-
});
1712
};

touchid.d.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,8 @@ declare module "nativescript-touchid" {
2222
fallbackMessage?: string;
2323
}
2424

25-
/**
26-
* Sets text on the clipboard, replacing anything currently on there.
27-
*/
2825
export function available(): Promise<boolean>;
29-
30-
/**
31-
* Gets any currently present text from the clipboard.
32-
*/
26+
export function didFingerprintDatabaseChange(): Promise<boolean>;
3327
export function verifyFingerprint(options: VerifyFingerprintOptions): Promise<string>;
3428
export function verifyFingerprintWithCustomFallback(options: verifyFingerprintWithCustomFallbackOptions): Promise<string>;
3529
}

touchid.ios.js

Lines changed: 61 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
var utils = require("utils/utils");
2+
13
var keychainItemIdentifier = "TouchIDKey";
24
var keychainItemServiceName = null;
35

@@ -14,6 +16,46 @@ var available = function () {
1416
});
1517
};
1618

19+
var didFingerprintDatabaseChange = function () {
20+
return new Promise(function (resolve, reject) {
21+
try {
22+
var laContext = LAContext.alloc().init();
23+
24+
// we expect the dev to have checked 'isAvailable' already so this should not return an error,
25+
// we do however need to run canEvaluatePolicy here in order to get a non-nil evaluatedPolicyDomainState
26+
if (!laContext.canEvaluatePolicyError(LAPolicyDeviceOwnerAuthenticationWithBiometrics, null)) {
27+
reject("Not available");
28+
return;
29+
}
30+
31+
// only supported on iOS9+, so check this.. if not supported just report back as false
32+
if (utils.ios.MajorVersion < 9) {
33+
resolve(false);
34+
return;
35+
}
36+
37+
var FingerprintDatabaseStateKey = "FingerprintDatabaseStateKey";
38+
var state = laContext.evaluatedPolicyDomainState;
39+
if (state !== null) {
40+
var stateStr = state.base64EncodedStringWithOptions(0);
41+
var storedState = NSUserDefaults.standardUserDefaults().stringForKey(FingerprintDatabaseStateKey);
42+
43+
// Store enrollment
44+
NSUserDefaults.standardUserDefaults().setObjectForKey(stateStr, FingerprintDatabaseStateKey);
45+
NSUserDefaults.standardUserDefaults().synchronize();
46+
47+
// whenever a finger is added/changed/removed the value of the storedState changes,
48+
// so compare agains a value we previously stored in the context of this app
49+
var changed = storedState !== null && stateStr !== storedState;
50+
resolve(changed);
51+
}
52+
} catch (ex) {
53+
console.log("Error in touchid.didFingerprintDatabaseChange: " + ex);
54+
resolve(false);
55+
}
56+
});
57+
};
58+
1759
/**
1860
* this 'default' method uses keychain instead of localauth so the passcode fallback can be used
1961
*/
@@ -61,25 +103,26 @@ var verifyFingerprintWithCustomFallback = function (arg) {
61103
return new Promise(function (resolve, reject) {
62104
try {
63105
var laContext = LAContext.alloc().init();
64-
if (laContext.canEvaluatePolicyError(LAPolicyDeviceOwnerAuthenticationWithBiometrics, null)) {
65-
var message = arg !== null && arg.message || "Scan your finger";
66-
if (arg !== null && arg.fallbackMessage) {
67-
laContext.localizedFallbackTitle = arg.fallbackMessage;
68-
}
69-
laContext.evaluatePolicyLocalizedReasonReply(
70-
LAPolicyDeviceOwnerAuthenticationWithBiometrics,
71-
message,
72-
function (ok, error) {
73-
if (ok) {
74-
resolve(ok);
75-
} else {
76-
reject(error);
77-
}
78-
}
79-
);
80-
} else {
106+
if (!laContext.canEvaluatePolicyError(LAPolicyDeviceOwnerAuthenticationWithBiometrics, null)) {
81107
reject("Not available");
108+
return;
82109
}
110+
111+
var message = arg !== null && arg.message || "Scan your finger";
112+
if (arg !== null && arg.fallbackMessage) {
113+
laContext.localizedFallbackTitle = arg.fallbackMessage;
114+
}
115+
laContext.evaluatePolicyLocalizedReasonReply(
116+
LAPolicyDeviceOwnerAuthenticationWithBiometrics,
117+
message,
118+
function (ok, error) {
119+
if (ok) {
120+
resolve(ok);
121+
} else {
122+
reject(error);
123+
}
124+
}
125+
);
83126
} catch (ex) {
84127
console.log("Error in touchid.verifyFingerprint: " + ex);
85128
reject(ex);
@@ -119,5 +162,6 @@ var createKeyChainEntry = function () {
119162
};
120163

121164
exports.available = available;
165+
exports.didFingerprintDatabaseChange = didFingerprintDatabaseChange;
122166
exports.verifyFingerprint = verifyFingerprint;
123167
exports.verifyFingerprintWithCustomFallback = verifyFingerprintWithCustomFallback;

0 commit comments

Comments
 (0)