pakstr 0.0.4 → 0.2.0
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.
- package/android-template/app/build.gradle.kts +3 -0
- package/android-template/app/src/androidTest/java/com/pakstr/app/ExampleInstrumentedTest.kt +8 -3
- package/android-template/app/src/androidTest/java/com/pakstr/app/signer/NostrEventBuilderTest.kt +67 -0
- package/android-template/app/src/androidTest/java/com/pakstr/app/signer/NostrSignatureVerifierTest.kt +43 -0
- package/android-template/app/src/main/AndroidManifest.xml +15 -3
- package/android-template/app/src/main/assets/nip07.js +85 -4
- package/android-template/app/src/main/assets/www/index.html +215 -0
- package/android-template/app/src/main/java/com/pakstr/app/ApplicationClass.kt +2 -0
- package/android-template/app/src/main/java/com/pakstr/app/LocalServer.kt +35 -10
- package/android-template/app/src/main/java/com/pakstr/app/MainActivity.kt +121 -101
- package/android-template/app/src/main/java/com/pakstr/app/ShellRuntime.kt +5 -6
- package/android-template/app/src/main/java/com/pakstr/app/WebViewController.kt +69 -20
- package/android-template/app/src/main/java/com/pakstr/app/crypto/Bip340Verifier.kt +318 -0
- package/android-template/app/src/main/java/com/pakstr/app/crypto/CryptoInitializer.kt +34 -0
- package/android-template/app/src/main/java/com/pakstr/app/crypto/Nip04Crypto.kt +33 -0
- package/android-template/app/src/main/java/com/pakstr/app/crypto/NostrEncryption.kt +16 -0
- package/android-template/app/src/main/java/com/pakstr/app/crypto/NostrEventHasher.kt +100 -0
- package/android-template/app/src/main/java/com/pakstr/app/crypto/NostrEventVerifier.kt +54 -0
- package/android-template/app/src/main/java/com/pakstr/app/crypto/NostrSignatureVerifier.kt +43 -0
- package/android-template/app/src/main/java/com/pakstr/app/crypto/Secp256k1.kt +63 -0
- package/android-template/app/src/main/java/com/pakstr/app/debug/AppDebugLogger.kt +21 -0
- package/android-template/app/src/main/java/com/pakstr/app/signer/AmberSigner.kt +427 -74
- package/android-template/app/src/main/java/com/pakstr/app/signer/BunkerSigner.kt +14 -0
- package/android-template/app/src/main/java/com/pakstr/app/signer/FakeSigner.kt +14 -0
- package/android-template/app/src/main/java/com/pakstr/app/signer/NostrBridge.kt +297 -32
- package/android-template/app/src/main/java/com/pakstr/app/signer/NostrEventBuilder.kt +39 -0
- package/android-template/app/src/main/java/com/pakstr/app/signer/SignerManager.kt +103 -73
- package/android-template/app/src/main/java/com/pakstr/app/signer/SignerType.kt +0 -1
- package/android-template/app/src/main/java/com/pakstr/app/signer/exceptions/SignerUnavailableException.kt +5 -0
- package/android-template/app/src/main/java/com/pakstr/app/signer/interfaces/NostrSigner.kt +10 -0
- package/android-template/app/src/main/res/values/strings.xml +1 -1
- package/package.json +1 -1
|
@@ -4,93 +4,358 @@ import android.os.Handler
|
|
|
4
4
|
import android.os.Looper
|
|
5
5
|
import android.webkit.JavascriptInterface
|
|
6
6
|
import android.webkit.WebView
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
import com.pakstr.app.debug.AppDebugLogger
|
|
9
|
+
import com.pakstr.app.signer.exceptions.SignerUnavailableException
|
|
8
10
|
import kotlinx.coroutines.CoroutineScope
|
|
9
11
|
import kotlinx.coroutines.Dispatchers
|
|
12
|
+
import kotlinx.coroutines.SupervisorJob
|
|
10
13
|
import kotlinx.coroutines.launch
|
|
14
|
+
import org.json.JSONObject
|
|
11
15
|
|
|
12
16
|
class NostrBridge(
|
|
13
|
-
|
|
14
17
|
private val webView: WebView,
|
|
15
|
-
|
|
16
18
|
private val signerManager: SignerManager
|
|
17
|
-
|
|
18
19
|
) {
|
|
19
20
|
|
|
20
21
|
private val mainHandler = Handler(Looper.getMainLooper())
|
|
21
22
|
|
|
23
|
+
private val scope = CoroutineScope(
|
|
24
|
+
SupervisorJob() + Dispatchers.IO
|
|
25
|
+
)
|
|
26
|
+
|
|
22
27
|
@JavascriptInterface
|
|
23
|
-
fun call(
|
|
28
|
+
fun call(
|
|
29
|
+
method: String,
|
|
30
|
+
callbackId: String,
|
|
31
|
+
payload: String?
|
|
32
|
+
) {
|
|
24
33
|
|
|
25
34
|
when (method) {
|
|
26
35
|
|
|
27
36
|
"getPublicKey" -> {
|
|
28
37
|
|
|
29
|
-
|
|
38
|
+
scope.launch {
|
|
30
39
|
|
|
31
40
|
try {
|
|
41
|
+
val pk =
|
|
42
|
+
signerManager
|
|
43
|
+
.getSigner()
|
|
44
|
+
.getPublicKey()
|
|
45
|
+
resolve(
|
|
46
|
+
callbackId,
|
|
47
|
+
pk
|
|
48
|
+
)
|
|
49
|
+
} catch (e: SignerUnavailableException) {
|
|
50
|
+
resolve(
|
|
51
|
+
callbackId,
|
|
52
|
+
errorResponse(
|
|
53
|
+
"SIGNER_UNAVAILABLE",
|
|
54
|
+
e.message ?: "Signer unavailable"
|
|
55
|
+
)
|
|
56
|
+
)
|
|
32
57
|
|
|
33
|
-
|
|
58
|
+
} catch (e: Exception) {
|
|
59
|
+
resolve(
|
|
60
|
+
callbackId,
|
|
61
|
+
errorResponse(
|
|
62
|
+
"SIGNER_ERROR",
|
|
63
|
+
e.message ?: "Unknown signer error"
|
|
64
|
+
)
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
34
69
|
|
|
35
|
-
|
|
70
|
+
"signEvent" -> {
|
|
71
|
+
AppDebugLogger.log(
|
|
72
|
+
"NOSTR_SIGN",
|
|
73
|
+
"Signing event request"
|
|
74
|
+
)
|
|
36
75
|
|
|
37
|
-
|
|
76
|
+
scope.launch {
|
|
38
77
|
|
|
39
|
-
|
|
78
|
+
try {
|
|
79
|
+
require(!payload.isNullOrBlank()) {
|
|
80
|
+
"Event payload is empty"
|
|
81
|
+
}
|
|
40
82
|
|
|
41
|
-
|
|
83
|
+
val result =
|
|
84
|
+
signerManager
|
|
85
|
+
.getSigner()
|
|
86
|
+
.signEvent(
|
|
87
|
+
payload
|
|
88
|
+
)
|
|
42
89
|
|
|
43
|
-
|
|
90
|
+
resolve(
|
|
91
|
+
callbackId,
|
|
92
|
+
result
|
|
93
|
+
)
|
|
44
94
|
|
|
45
|
-
|
|
95
|
+
} catch (e: SignerUnavailableException) {
|
|
46
96
|
|
|
97
|
+
resolve(
|
|
98
|
+
callbackId,
|
|
99
|
+
errorResponse(
|
|
100
|
+
"SIGNER_UNAVAILABLE",
|
|
101
|
+
e.message ?: "Signer unavailable"
|
|
102
|
+
)
|
|
47
103
|
)
|
|
48
104
|
|
|
105
|
+
} catch (e: Exception) {
|
|
49
106
|
resolve(
|
|
107
|
+
callbackId,
|
|
108
|
+
errorResponse(
|
|
109
|
+
"SIGNER_ERROR",
|
|
110
|
+
e.message ?: "Unknown signer error"
|
|
111
|
+
)
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
"nip04_encrypt" -> {
|
|
50
118
|
|
|
119
|
+
scope.launch {
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
|
|
123
|
+
require(!payload.isNullOrBlank()) {
|
|
124
|
+
"NIP04 encrypt payload is empty"
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
val json =
|
|
128
|
+
JSONObject(payload)
|
|
129
|
+
|
|
130
|
+
val pubkey =
|
|
131
|
+
json.getString("pubkey")
|
|
132
|
+
|
|
133
|
+
val plaintext =
|
|
134
|
+
json.getString("plaintext")
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
val result =
|
|
138
|
+
signerManager
|
|
139
|
+
.getSigner()
|
|
140
|
+
.nip04Encrypt(
|
|
141
|
+
pubkey,
|
|
142
|
+
plaintext
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
resolve(
|
|
51
147
|
callbackId,
|
|
148
|
+
result
|
|
149
|
+
)
|
|
52
150
|
|
|
53
|
-
|
|
151
|
+
} catch (e: SignerUnavailableException) {
|
|
54
152
|
|
|
153
|
+
resolve(
|
|
154
|
+
callbackId,
|
|
155
|
+
errorResponse(
|
|
156
|
+
"SIGNER_UNAVAILABLE",
|
|
157
|
+
e.message ?: "Signer unavailable"
|
|
158
|
+
)
|
|
55
159
|
)
|
|
56
160
|
|
|
161
|
+
} catch (e: Exception) {
|
|
162
|
+
|
|
163
|
+
resolve(
|
|
164
|
+
callbackId,
|
|
165
|
+
errorResponse(
|
|
166
|
+
"SIGNER_ERROR",
|
|
167
|
+
e.message ?: "Unknown signer error"
|
|
168
|
+
)
|
|
169
|
+
)
|
|
57
170
|
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
"nip04_decrypt" -> {
|
|
176
|
+
|
|
177
|
+
scope.launch {
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
|
|
181
|
+
require(!payload.isNullOrBlank()) {
|
|
182
|
+
"NIP04 decrypt payload is empty"
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
val json =
|
|
187
|
+
JSONObject(payload)
|
|
188
|
+
|
|
189
|
+
val pubkey =
|
|
190
|
+
json.getString("pubkey")
|
|
191
|
+
|
|
192
|
+
val ciphertext =
|
|
193
|
+
json.getString("ciphertext")
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
val result =
|
|
197
|
+
signerManager
|
|
198
|
+
.getSigner()
|
|
199
|
+
.nip04Decrypt(
|
|
200
|
+
pubkey,
|
|
201
|
+
ciphertext
|
|
202
|
+
)
|
|
58
203
|
|
|
204
|
+
|
|
205
|
+
resolve(
|
|
206
|
+
callbackId,
|
|
207
|
+
result
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
} catch (e: SignerUnavailableException) {
|
|
212
|
+
|
|
213
|
+
resolve(
|
|
214
|
+
callbackId,
|
|
215
|
+
errorResponse(
|
|
216
|
+
"SIGNER_UNAVAILABLE",
|
|
217
|
+
e.message ?: "Signer unavailable"
|
|
218
|
+
)
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
} catch (e: Exception) {
|
|
222
|
+
|
|
223
|
+
resolve(
|
|
224
|
+
callbackId,
|
|
225
|
+
errorResponse(
|
|
226
|
+
"SIGNER_ERROR",
|
|
227
|
+
e.message ?: "Unknown signer error"
|
|
228
|
+
)
|
|
229
|
+
)
|
|
230
|
+
}
|
|
59
231
|
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
"nip44_encrypt" -> {
|
|
235
|
+
|
|
236
|
+
scope.launch {
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
|
|
240
|
+
val json =
|
|
241
|
+
JSONObject(payload ?: "")
|
|
242
|
+
|
|
243
|
+
val result =
|
|
244
|
+
signerManager
|
|
245
|
+
.getSigner()
|
|
246
|
+
.nip44Encrypt(
|
|
247
|
+
json.getString("pubkey"),
|
|
248
|
+
json.getString("plaintext")
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
resolve(
|
|
252
|
+
callbackId,
|
|
253
|
+
result
|
|
254
|
+
)
|
|
255
|
+
|
|
60
256
|
|
|
257
|
+
} catch (e: Exception) {
|
|
258
|
+
|
|
259
|
+
resolve(
|
|
260
|
+
callbackId,
|
|
261
|
+
errorResponse(
|
|
262
|
+
"SIGNER_ERROR",
|
|
263
|
+
e.message ?: ""
|
|
264
|
+
)
|
|
265
|
+
)
|
|
266
|
+
}
|
|
267
|
+
}
|
|
61
268
|
}
|
|
62
269
|
|
|
63
|
-
"
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
270
|
+
"nip44_decrypt" -> {
|
|
271
|
+
|
|
272
|
+
scope.launch {
|
|
273
|
+
|
|
274
|
+
try {
|
|
275
|
+
|
|
276
|
+
val json =
|
|
277
|
+
JSONObject(payload ?: "")
|
|
278
|
+
|
|
279
|
+
val result =
|
|
280
|
+
signerManager
|
|
281
|
+
.getSigner()
|
|
282
|
+
.nip44Decrypt(
|
|
283
|
+
json.getString("pubkey"),
|
|
284
|
+
json.getString("ciphertext")
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
resolve(
|
|
288
|
+
callbackId,
|
|
289
|
+
result
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
} catch (e: Exception) {
|
|
294
|
+
|
|
295
|
+
resolve(
|
|
296
|
+
callbackId,
|
|
297
|
+
errorResponse(
|
|
298
|
+
"SIGNER_ERROR",
|
|
299
|
+
e.message ?: ""
|
|
300
|
+
)
|
|
301
|
+
)
|
|
302
|
+
}
|
|
67
303
|
}
|
|
68
304
|
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
305
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
306
|
+
else -> {
|
|
307
|
+
|
|
308
|
+
resolve(
|
|
309
|
+
callbackId,
|
|
310
|
+
""
|
|
311
|
+
)
|
|
312
|
+
}
|
|
76
313
|
}
|
|
77
314
|
}
|
|
78
315
|
|
|
79
|
-
private fun
|
|
316
|
+
private fun resolve(
|
|
317
|
+
callbackId: String,
|
|
318
|
+
result: String
|
|
319
|
+
) {
|
|
320
|
+
|
|
321
|
+
AppDebugLogger.log(
|
|
322
|
+
"NOSTR_BRIDGE",
|
|
323
|
+
"Bridge response received"
|
|
324
|
+
)
|
|
80
325
|
|
|
81
326
|
mainHandler.post {
|
|
82
327
|
|
|
83
|
-
|
|
328
|
+
val js =
|
|
329
|
+
"""
|
|
330
|
+
window.__nostrResolve(
|
|
331
|
+
${JSONObject.quote(callbackId)},
|
|
332
|
+
${JSONObject.quote(result)}
|
|
333
|
+
);
|
|
334
|
+
""".trimIndent()
|
|
84
335
|
|
|
85
|
-
|
|
336
|
+
webView.evaluateJavascript(js, null)
|
|
337
|
+
}
|
|
338
|
+
}
|
|
86
339
|
|
|
87
|
-
|
|
340
|
+
private fun errorResponse(
|
|
341
|
+
code: String,
|
|
342
|
+
message: String
|
|
343
|
+
): String {
|
|
88
344
|
|
|
89
|
-
|
|
345
|
+
return JSONObject()
|
|
346
|
+
.apply {
|
|
90
347
|
|
|
91
|
-
|
|
348
|
+
put(
|
|
349
|
+
"error",
|
|
350
|
+
code
|
|
351
|
+
)
|
|
92
352
|
|
|
93
|
-
|
|
353
|
+
put(
|
|
354
|
+
"message",
|
|
355
|
+
message
|
|
356
|
+
)
|
|
94
357
|
|
|
358
|
+
}
|
|
359
|
+
.toString()
|
|
95
360
|
}
|
|
96
|
-
}
|
|
361
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
package com.pakstr.app.signer
|
|
2
|
+
|
|
3
|
+
import com.pakstr.app.crypto.NostrEventHasher
|
|
4
|
+
import org.json.JSONObject
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Builds Nostr events before signing.
|
|
8
|
+
*
|
|
9
|
+
* Generates the event ID according to Nostr event hashing rules
|
|
10
|
+
* and adds it to the event JSON.
|
|
11
|
+
*
|
|
12
|
+
* The generated ID is later used as the message that gets signed
|
|
13
|
+
* by the external signer (e.g. Amber).
|
|
14
|
+
*/
|
|
15
|
+
object NostrEventBuilder {
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Calculates and adds the Nostr event ID.
|
|
19
|
+
*
|
|
20
|
+
* @param event unsigned Nostr event JSON
|
|
21
|
+
* @return the same event containing the generated "id" field
|
|
22
|
+
*/
|
|
23
|
+
fun addId(
|
|
24
|
+
event: JSONObject
|
|
25
|
+
): JSONObject {
|
|
26
|
+
|
|
27
|
+
val id = NostrEventHasher.hashEvent(
|
|
28
|
+
event
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
event.put(
|
|
32
|
+
"id", id
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
return event
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
}
|
|
@@ -1,148 +1,178 @@
|
|
|
1
1
|
package com.pakstr.app.signer
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
|
+
import android.content.Intent
|
|
4
5
|
import androidx.activity.result.ActivityResult
|
|
6
|
+
import androidx.activity.result.ActivityResultLauncher
|
|
5
7
|
import com.pakstr.app.signer.interfaces.NostrSigner
|
|
6
|
-
|
|
8
|
+
import androidx.core.content.edit
|
|
9
|
+
import com.pakstr.app.signer.exceptions.SignerUnavailableException
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Manages Nostr signer selection and lifecycle.
|
|
13
|
+
*
|
|
14
|
+
* Provides a single access point for obtaining the active NostrSigner
|
|
15
|
+
* implementation used by the application.
|
|
16
|
+
*
|
|
17
|
+
* Supported signer types:
|
|
18
|
+
*
|
|
19
|
+
* - Amber
|
|
20
|
+
* External Android signer app using the nostrsigner URI scheme.
|
|
21
|
+
*
|
|
22
|
+
* - Fake
|
|
23
|
+
* Test signer used for development and testing.
|
|
24
|
+
*
|
|
25
|
+
* - Bunker
|
|
26
|
+
* Reserved for NIP-46 remote signer implementation.
|
|
27
|
+
*
|
|
28
|
+
* The selected signer type is persisted using SharedPreferences.
|
|
29
|
+
* The signer instance is cached and recreated only when the user
|
|
30
|
+
* changes the active signer.
|
|
31
|
+
*/
|
|
7
32
|
class SignerManager(
|
|
8
|
-
|
|
9
|
-
private val
|
|
33
|
+
context: Context,
|
|
34
|
+
private val amberLauncher: ActivityResultLauncher<Intent>
|
|
10
35
|
) {
|
|
36
|
+
private val context =
|
|
37
|
+
context.applicationContext
|
|
11
38
|
|
|
12
39
|
private val prefs =
|
|
13
|
-
context.getSharedPreferences(
|
|
40
|
+
this.context.getSharedPreferences(
|
|
14
41
|
"signer",
|
|
15
42
|
Context.MODE_PRIVATE
|
|
16
43
|
)
|
|
17
44
|
|
|
18
|
-
|
|
19
45
|
private var activeSigner: NostrSigner? = null
|
|
20
46
|
|
|
47
|
+
private var currentUserPubkey: String? = null
|
|
21
48
|
|
|
22
49
|
fun getActiveType(): SignerType? {
|
|
23
50
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
51
|
+
val value =
|
|
52
|
+
prefs.getString(
|
|
53
|
+
"type",
|
|
54
|
+
SignerType.AMBER.name
|
|
55
|
+
)
|
|
28
56
|
|
|
29
|
-
|
|
57
|
+
return try {
|
|
58
|
+
SignerType.valueOf(value.toString())
|
|
30
59
|
|
|
60
|
+
} catch (_: IllegalArgumentException) {
|
|
61
|
+
SignerType.AMBER
|
|
31
62
|
}
|
|
32
|
-
|
|
33
63
|
}
|
|
34
64
|
|
|
65
|
+
suspend fun getCurrentUserPubkey(): String {
|
|
35
66
|
|
|
36
|
-
|
|
67
|
+
currentUserPubkey?.let {
|
|
37
68
|
|
|
38
|
-
|
|
39
|
-
.putString(
|
|
40
|
-
"type",
|
|
41
|
-
type.name
|
|
42
|
-
)
|
|
43
|
-
.apply()
|
|
69
|
+
return it
|
|
44
70
|
|
|
71
|
+
}
|
|
45
72
|
|
|
46
|
-
|
|
73
|
+
val pk =
|
|
47
74
|
|
|
48
|
-
|
|
75
|
+
getSigner()
|
|
49
76
|
|
|
77
|
+
.getPublicKey()
|
|
50
78
|
|
|
51
|
-
|
|
79
|
+
currentUserPubkey = pk
|
|
80
|
+
|
|
81
|
+
return pk
|
|
82
|
+
|
|
83
|
+
}
|
|
52
84
|
|
|
85
|
+
fun setActiveType(
|
|
86
|
+
type: SignerType
|
|
87
|
+
) {
|
|
53
88
|
|
|
54
|
-
|
|
55
|
-
|
|
89
|
+
prefs.edit {
|
|
90
|
+
putString(
|
|
91
|
+
"type",
|
|
92
|
+
type.name
|
|
93
|
+
)
|
|
56
94
|
}
|
|
57
95
|
|
|
96
|
+
activeSigner = null
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Returns the currently selected signer implementation.
|
|
101
|
+
*
|
|
102
|
+
* Creates the signer lazily on first request and reuses the same
|
|
103
|
+
* instance until the signer type changes.
|
|
104
|
+
*/
|
|
105
|
+
fun getSigner(): NostrSigner {
|
|
58
106
|
|
|
59
|
-
activeSigner
|
|
107
|
+
activeSigner?.let {
|
|
108
|
+
return it
|
|
109
|
+
}
|
|
60
110
|
|
|
61
|
-
|
|
111
|
+
val signer =
|
|
112
|
+
when (getActiveType()) {
|
|
62
113
|
|
|
63
114
|
SignerType.AMBER -> {
|
|
64
115
|
|
|
65
116
|
if (!isAmberInstalled()) {
|
|
66
|
-
|
|
117
|
+
throw SignerUnavailableException(
|
|
118
|
+
"Amber signer application is not installed"
|
|
119
|
+
)
|
|
67
120
|
}
|
|
68
121
|
|
|
69
122
|
AmberSigner(
|
|
70
|
-
|
|
71
|
-
context,
|
|
72
|
-
|
|
73
|
-
launchAmber
|
|
74
|
-
|
|
123
|
+
amberLauncher
|
|
75
124
|
)
|
|
76
|
-
|
|
77
125
|
}
|
|
78
126
|
|
|
79
127
|
SignerType.BUNKER -> {
|
|
128
|
+
throw SignerUnavailableException(
|
|
129
|
+
"Bunker signer is not implemented"
|
|
130
|
+
)
|
|
131
|
+
}
|
|
80
132
|
|
|
133
|
+
SignerType.FAKE -> {
|
|
81
134
|
FakeSigner()
|
|
82
|
-
|
|
83
135
|
}
|
|
84
136
|
|
|
85
137
|
null -> {
|
|
86
138
|
|
|
87
139
|
throw IllegalStateException(
|
|
88
|
-
|
|
89
140
|
"No signer selected"
|
|
90
|
-
|
|
91
141
|
)
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
else -> {
|
|
96
|
-
|
|
97
|
-
FakeSigner()
|
|
98
|
-
|
|
99
142
|
}
|
|
100
|
-
|
|
101
143
|
}
|
|
102
144
|
|
|
145
|
+
activeSigner = signer
|
|
103
146
|
|
|
104
|
-
return
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
fun handleAmberResult(
|
|
111
|
-
result: ActivityResult
|
|
112
|
-
) {
|
|
113
|
-
|
|
114
|
-
val signer =
|
|
115
|
-
activeSigner
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (signer is AmberSigner) {
|
|
119
|
-
|
|
120
|
-
signer.handleResult(result)
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
|
|
147
|
+
return signer
|
|
124
148
|
}
|
|
125
149
|
|
|
126
150
|
private fun isAmberInstalled(): Boolean {
|
|
127
151
|
|
|
128
152
|
return try {
|
|
129
153
|
|
|
130
|
-
context.packageManager
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
)
|
|
154
|
+
context.packageManager
|
|
155
|
+
.getPackageInfo(
|
|
156
|
+
"com.greenart7c3.nostrsigner",
|
|
157
|
+
0
|
|
158
|
+
)
|
|
137
159
|
|
|
138
160
|
true
|
|
139
161
|
|
|
140
|
-
} catch (
|
|
162
|
+
} catch (_: Exception) {
|
|
141
163
|
|
|
142
164
|
false
|
|
143
|
-
|
|
144
165
|
}
|
|
145
|
-
|
|
146
166
|
}
|
|
147
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Forwards Android Activity results back to the active Amber signer.
|
|
170
|
+
*
|
|
171
|
+
* Required because Amber communication is based on the Android
|
|
172
|
+
* Activity Result API.
|
|
173
|
+
*/
|
|
174
|
+
fun handleAmberResult(result: ActivityResult) {
|
|
175
|
+
(activeSigner as? AmberSigner)
|
|
176
|
+
?.onResult(result)
|
|
177
|
+
}
|
|
148
178
|
}
|