@tokamakdev/plugin-local-authentication 0.1.0-beta.64 → 0.1.0-beta.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2,12 +2,15 @@ package com.tokamak.plugins.localauthentication
|
|
|
2
2
|
|
|
3
3
|
import android.hardware.biometrics.BiometricManager
|
|
4
4
|
import android.hardware.biometrics.BiometricManager.Authenticators
|
|
5
|
-
import android.hardware.biometrics.BiometricPrompt
|
|
6
|
-
import android.os.CancellationSignal
|
|
7
5
|
import com.tokamak.runtime.TokamakHost
|
|
8
6
|
import com.tokamak.runtime.TokamakPlugin
|
|
9
7
|
import com.tokamak.runtime.TokamakPluginError
|
|
10
8
|
import com.tokamak.runtime.TokamakPluginReply
|
|
9
|
+
import com.tokamak.runtime.authenticateOwner
|
|
10
|
+
import com.tokamak.runtime.optionalString
|
|
11
|
+
import com.tokamak.runtime.requireObject
|
|
12
|
+
import com.tokamak.runtime.requireOwnerAuthentication
|
|
13
|
+
import com.tokamak.runtime.requireString
|
|
11
14
|
import org.json.JSONObject
|
|
12
15
|
|
|
13
16
|
class TokamakLocalAuthenticationPlugin(
|
|
@@ -19,16 +22,12 @@ class TokamakLocalAuthenticationPlugin(
|
|
|
19
22
|
|
|
20
23
|
override fun call(method: String, arguments: Any?, reply: TokamakPluginReply) {
|
|
21
24
|
when (method) {
|
|
22
|
-
"status" ->
|
|
23
|
-
"authenticate" ->
|
|
25
|
+
"status" -> reply(Result.success(status(requireObject(arguments))))
|
|
26
|
+
"authenticate" -> authenticate(requireObject(arguments), reply)
|
|
24
27
|
else -> super.call(method, arguments, reply)
|
|
25
28
|
}
|
|
26
29
|
}
|
|
27
30
|
|
|
28
|
-
private fun respond(reply: TokamakPluginReply, operation: () -> Unit) {
|
|
29
|
-
runCatching(operation).onFailure { reply(Result.failure(pluginError(it))) }
|
|
30
|
-
}
|
|
31
|
-
|
|
32
31
|
private fun status(request: JSONObject): String =
|
|
33
32
|
when (biometrics.canAuthenticate(authenticators(request))) {
|
|
34
33
|
BiometricManager.BIOMETRIC_SUCCESS -> "available"
|
|
@@ -39,53 +38,17 @@ class TokamakLocalAuthenticationPlugin(
|
|
|
39
38
|
private fun authenticate(request: JSONObject, reply: TokamakPluginReply) {
|
|
40
39
|
val authenticators = authenticators(request)
|
|
41
40
|
val prompt = request.requireString("prompt")
|
|
42
|
-
if (prompt.isEmpty()) throw typeError("prompt must be a non-empty string")
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
val callback = PromptCallback(reply) { reply(Result.success(null)) }
|
|
46
|
-
val dialog =
|
|
47
|
-
BiometricPrompt.Builder(activity)
|
|
48
|
-
.setTitle(prompt)
|
|
49
|
-
.setAllowedAuthenticators(authenticators)
|
|
50
|
-
if ((authenticators and Authenticators.DEVICE_CREDENTIAL) == 0) {
|
|
51
|
-
dialog.setNegativeButton(
|
|
52
|
-
activity.getString(android.R.string.cancel),
|
|
53
|
-
activity.mainExecutor,
|
|
54
|
-
) { _, _ ->
|
|
55
|
-
reply(Result.failure(TokamakPluginError("NotAllowedError", "Authentication was cancelled")))
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
dialog.build().authenticate(CancellationSignal(), activity.mainExecutor, callback)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
private fun requireAvailable(authenticators: Int) {
|
|
62
|
-
when (biometrics.canAuthenticate(authenticators)) {
|
|
63
|
-
BiometricManager.BIOMETRIC_SUCCESS -> Unit
|
|
64
|
-
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE ->
|
|
65
|
-
throw TokamakPluginError.notSupported("This device cannot perform the requested authentication")
|
|
66
|
-
else -> throw notSetUp()
|
|
67
|
-
}
|
|
41
|
+
if (prompt.isEmpty()) throw TokamakPluginError.typeError("prompt must be a non-empty string")
|
|
42
|
+
host.requireOwnerAuthentication(authenticators)
|
|
43
|
+
host.authenticateOwner(prompt, authenticators, null, reply) { reply(Result.success(null)) }
|
|
68
44
|
}
|
|
69
45
|
|
|
70
46
|
private fun authenticators(request: JSONObject): Int {
|
|
71
47
|
val wireName = request.optionalString("authentication")
|
|
72
48
|
return Authentication.entries.firstOrNull { it.wireName == wireName }?.authenticators
|
|
73
|
-
?: throw typeError("authentication must be \"biometricsOrPasscode\" or \"biometrics\"")
|
|
49
|
+
?: throw TokamakPluginError.typeError("authentication must be \"biometricsOrPasscode\" or \"biometrics\"")
|
|
74
50
|
}
|
|
75
51
|
|
|
76
|
-
private fun request(arguments: Any?): JSONObject =
|
|
77
|
-
arguments as? JSONObject ?: throw typeError("$id arguments must be an object")
|
|
78
|
-
|
|
79
|
-
private fun JSONObject.requireString(name: String): String =
|
|
80
|
-
optionalString(name) ?: throw typeError("$name must be a string")
|
|
81
|
-
|
|
82
|
-
private fun JSONObject.optionalString(name: String): String? =
|
|
83
|
-
when (val value = opt(name)) {
|
|
84
|
-
null, JSONObject.NULL -> null
|
|
85
|
-
is String -> value
|
|
86
|
-
else -> throw typeError("$name must be a string")
|
|
87
|
-
}
|
|
88
|
-
|
|
89
52
|
private enum class Authentication(val wireName: String, val authenticators: Int) {
|
|
90
53
|
BIOMETRICS_OR_PASSCODE(
|
|
91
54
|
"biometricsOrPasscode",
|
|
@@ -93,46 +56,4 @@ class TokamakLocalAuthenticationPlugin(
|
|
|
93
56
|
),
|
|
94
57
|
BIOMETRICS("biometrics", Authenticators.BIOMETRIC_STRONG),
|
|
95
58
|
}
|
|
96
|
-
|
|
97
|
-
private companion object {
|
|
98
|
-
fun typeError(message: String) = TokamakPluginError("TypeError", message)
|
|
99
|
-
|
|
100
|
-
fun notSetUp() =
|
|
101
|
-
TokamakPluginError("InvalidStateError", "The requested authentication is not set up on this device")
|
|
102
|
-
|
|
103
|
-
fun notVisible() =
|
|
104
|
-
TokamakPluginError("InvalidStateError", "The app has no activity to show the authentication prompt in")
|
|
105
|
-
|
|
106
|
-
fun pluginError(error: Throwable): TokamakPluginError =
|
|
107
|
-
error as? TokamakPluginError
|
|
108
|
-
?: TokamakPluginError("OperationError", error.message ?: error.javaClass.name)
|
|
109
|
-
}
|
|
110
59
|
}
|
|
111
|
-
|
|
112
|
-
private class PromptCallback(
|
|
113
|
-
private val reply: TokamakPluginReply,
|
|
114
|
-
private val succeeded: () -> Unit,
|
|
115
|
-
) : BiometricPrompt.AuthenticationCallback() {
|
|
116
|
-
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) = succeeded()
|
|
117
|
-
|
|
118
|
-
override fun onAuthenticationError(code: Int, message: CharSequence) =
|
|
119
|
-
reply(Result.failure(authenticationError(code, message)))
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
private fun authenticationError(code: Int, message: CharSequence) =
|
|
123
|
-
TokamakPluginError(
|
|
124
|
-
when (code) {
|
|
125
|
-
BiometricPrompt.BIOMETRIC_ERROR_CANCELED,
|
|
126
|
-
BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED,
|
|
127
|
-
BiometricPrompt.BIOMETRIC_ERROR_TIMEOUT,
|
|
128
|
-
BiometricPrompt.BIOMETRIC_ERROR_LOCKOUT,
|
|
129
|
-
BiometricPrompt.BIOMETRIC_ERROR_LOCKOUT_PERMANENT,
|
|
130
|
-
-> "NotAllowedError"
|
|
131
|
-
BiometricPrompt.BIOMETRIC_ERROR_NO_BIOMETRICS,
|
|
132
|
-
BiometricPrompt.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL,
|
|
133
|
-
-> "InvalidStateError"
|
|
134
|
-
BiometricPrompt.BIOMETRIC_ERROR_HW_NOT_PRESENT -> "NotSupportedError"
|
|
135
|
-
else -> "OperationError"
|
|
136
|
-
},
|
|
137
|
-
message.toString(),
|
|
138
|
-
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokamakdev/plugin-local-authentication",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.69",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/mantty/tokamak.git",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
".": "./src/index.ts"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@tokamakdev/plugin": "0.1.0-beta.
|
|
14
|
+
"@tokamakdev/plugin": "0.1.0-beta.69"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"android",
|
package/tokamak-plugin.json
CHANGED
|
@@ -4,25 +4,17 @@
|
|
|
4
4
|
"platforms": {
|
|
5
5
|
"macos": {
|
|
6
6
|
"class": "TokamakLocalAuthenticationPlugin",
|
|
7
|
-
"sources": ["apple/LocalAuthenticationPlugin.swift"]
|
|
8
|
-
"frameworks": ["LocalAuthentication"]
|
|
7
|
+
"sources": ["apple/LocalAuthenticationPlugin.swift"]
|
|
9
8
|
},
|
|
10
9
|
"ios": {
|
|
11
10
|
"class": "TokamakLocalAuthenticationPlugin",
|
|
12
11
|
"sources": ["apple/LocalAuthenticationPlugin.swift"],
|
|
13
|
-
"frameworks": ["LocalAuthentication"],
|
|
14
|
-
"plist": "apple/Info.plist"
|
|
15
|
-
},
|
|
16
|
-
"ios-simulator": {
|
|
17
|
-
"class": "TokamakLocalAuthenticationPlugin",
|
|
18
|
-
"sources": ["apple/LocalAuthenticationPlugin.swift"],
|
|
19
|
-
"frameworks": ["LocalAuthentication"],
|
|
20
12
|
"plist": "apple/Info.plist"
|
|
21
13
|
},
|
|
22
14
|
"android": {
|
|
23
15
|
"class": "com.tokamak.plugins.localauthentication.TokamakLocalAuthenticationPlugin",
|
|
24
16
|
"sources": ["android/LocalAuthenticationPlugin.kt"],
|
|
25
|
-
"
|
|
17
|
+
"manifest": "android/AndroidManifest.xml"
|
|
26
18
|
}
|
|
27
19
|
}
|
|
28
20
|
}
|