pakstr 0.31.0 → 1.0.1
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/README.md +1 -1
- package/android-template/app/build.gradle.kts +1 -0
- package/android-template/app/src/androidTest/java/com/pakstr/app/PakstrWebBridgeTest.kt +153 -0
- package/android-template/app/src/main/assets/nip07.js +124 -74
- package/android-template/app/src/main/java/com/pakstr/app/AppOrigin.kt +77 -0
- package/android-template/app/src/main/java/com/pakstr/app/PakstrBridge.kt +5 -5
- package/android-template/app/src/main/java/com/pakstr/app/PakstrWebBridge.kt +89 -0
- package/android-template/app/src/main/java/com/pakstr/app/WebMessageRouter.kt +186 -0
- package/android-template/app/src/main/java/com/pakstr/app/WebViewController.kt +65 -49
- package/android-template/app/src/main/java/com/pakstr/app/signer/AmberRequestChannel.kt +156 -0
- package/android-template/app/src/main/java/com/pakstr/app/signer/AmberSigner.kt +142 -390
- package/android-template/app/src/main/java/com/pakstr/app/signer/NostrBridge.kt +69 -489
- package/android-template/app/src/main/java/com/pakstr/app/signer/SignerManager.kt +13 -2
- package/android-template/app/src/test/java/com/pakstr/app/AppOriginTest.kt +114 -0
- package/android-template/app/src/test/java/com/pakstr/app/WebMessageRouterTest.kt +279 -0
- package/android-template/app/src/test/java/com/pakstr/app/signer/AmberRequestChannelTest.kt +294 -0
- package/android-template/app/src/test/java/com/pakstr/app/signer/NostrBridgeDispatchTest.kt +113 -0
- package/android-template/gradle/libs.versions.toml +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
package com.pakstr.app.signer
|
|
2
|
+
|
|
3
|
+
import com.pakstr.app.signer.interfaces.NostrSigner
|
|
4
|
+
import kotlinx.coroutines.runBlocking
|
|
5
|
+
import org.json.JSONArray
|
|
6
|
+
import org.json.JSONObject
|
|
7
|
+
import org.junit.Assert.assertEquals
|
|
8
|
+
import org.junit.Assert.assertThrows
|
|
9
|
+
import org.junit.Assert.assertTrue
|
|
10
|
+
import org.junit.Test
|
|
11
|
+
|
|
12
|
+
class NostrBridgeDispatchTest {
|
|
13
|
+
private val pubkey = "b".repeat(64)
|
|
14
|
+
|
|
15
|
+
@Test
|
|
16
|
+
fun each_method_reaches_the_matching_signer_call_with_its_arguments() {
|
|
17
|
+
val signer = RecordingSigner()
|
|
18
|
+
val bridge = NostrBridge(signerProvider = { signer })
|
|
19
|
+
val event = JSONObject()
|
|
20
|
+
.put("kind", 1)
|
|
21
|
+
.put("created_at", 1_700_000_000)
|
|
22
|
+
.put("tags", JSONArray().put(JSONArray().put("t").put("x")))
|
|
23
|
+
.put("content", "hi")
|
|
24
|
+
|
|
25
|
+
runBlocking {
|
|
26
|
+
assertEquals("pk", bridge.handle("getPublicKey", null))
|
|
27
|
+
assertEquals("signed", bridge.handle("signEvent", event))
|
|
28
|
+
assertEquals("c04", bridge.handle("nip04_encrypt", JSONObject().put("pubkey", pubkey).put("plaintext", "p")))
|
|
29
|
+
assertEquals("p04", bridge.handle("nip04_decrypt", JSONObject().put("pubkey", pubkey).put("ciphertext", "c")))
|
|
30
|
+
assertEquals("c44", bridge.handle("nip44_encrypt", JSONObject().put("pubkey", pubkey).put("plaintext", "p")))
|
|
31
|
+
assertEquals("p44", bridge.handle("nip44_decrypt", JSONObject().put("pubkey", pubkey).put("ciphertext", "c")))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
assertEquals(
|
|
35
|
+
listOf(
|
|
36
|
+
listOf("getPublicKey"),
|
|
37
|
+
listOf("signEvent", event.toString()),
|
|
38
|
+
listOf("nip04Encrypt", pubkey, "p"),
|
|
39
|
+
listOf("nip04Decrypt", pubkey, "c"),
|
|
40
|
+
listOf("nip44Encrypt", pubkey, "p"),
|
|
41
|
+
listOf("nip44Decrypt", pubkey, "c")
|
|
42
|
+
),
|
|
43
|
+
signer.calls
|
|
44
|
+
)
|
|
45
|
+
assertEquals(event.toString(), JSONObject(signer.calls[1][1]).toString())
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@Test
|
|
49
|
+
fun invalid_arguments_fail_before_the_signer_is_requested() {
|
|
50
|
+
var requested = 0
|
|
51
|
+
val bridge = NostrBridge(signerProvider = { requested++; RecordingSigner() })
|
|
52
|
+
|
|
53
|
+
val cases = listOf(
|
|
54
|
+
Triple("signEvent", null, "Event payload is empty"),
|
|
55
|
+
Triple("nip04_encrypt", null, "NIP04 encrypt payload is empty"),
|
|
56
|
+
Triple("nip04_decrypt", null, "NIP04 decrypt payload is empty"),
|
|
57
|
+
Triple("nip04_encrypt", JSONObject().put("pubkey", pubkey), null),
|
|
58
|
+
Triple("nip44_encrypt", null, null),
|
|
59
|
+
Triple("nip44_decrypt", JSONObject().put("ciphertext", "c"), null)
|
|
60
|
+
)
|
|
61
|
+
for ((method, params, message) in cases) {
|
|
62
|
+
val error = assertThrows(Exception::class.java) {
|
|
63
|
+
runBlocking { bridge.handle(method, params) }
|
|
64
|
+
}
|
|
65
|
+
if (message != null) assertEquals(method, message, error.message)
|
|
66
|
+
}
|
|
67
|
+
assertEquals(0, requested)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@Test
|
|
71
|
+
fun unsupported_methods_are_rejected_without_a_signer() {
|
|
72
|
+
var requested = 0
|
|
73
|
+
val bridge = NostrBridge(signerProvider = { requested++; RecordingSigner() })
|
|
74
|
+
|
|
75
|
+
for (method in listOf("", "call", "debugLog", "getPublicKey ", "nip04Encrypt", "__proto__")) {
|
|
76
|
+
val error = assertThrows(UnsupportedBridgeMethodException::class.java) {
|
|
77
|
+
runBlocking { bridge.handle(method, null) }
|
|
78
|
+
}
|
|
79
|
+
assertEquals("Unsupported method", error.message)
|
|
80
|
+
}
|
|
81
|
+
assertEquals(0, requested)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@Test
|
|
85
|
+
fun failures_are_logged_and_rethrown_without_payloads() {
|
|
86
|
+
val logs = mutableListOf<String>()
|
|
87
|
+
val bridge = NostrBridge(
|
|
88
|
+
signerProvider = { throw IllegalStateException("boom") },
|
|
89
|
+
log = { logs += it },
|
|
90
|
+
logError = { message, _ -> logs += message }
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
assertThrows(IllegalStateException::class.java) {
|
|
94
|
+
runBlocking {
|
|
95
|
+
bridge.handle("nip44_encrypt", JSONObject().put("pubkey", pubkey).put("plaintext", "secret text"))
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
assertEquals(listOf("Request: nip44_encrypt", "nip44_encrypt failed"), logs)
|
|
100
|
+
assertTrue(logs.none { "secret text" in it })
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private class RecordingSigner : NostrSigner {
|
|
104
|
+
val calls = mutableListOf<List<String>>()
|
|
105
|
+
|
|
106
|
+
override suspend fun getPublicKey(): String = "pk".also { calls += listOf("getPublicKey") }
|
|
107
|
+
override suspend fun signEvent(eventJson: String): String = "signed".also { calls += listOf("signEvent", eventJson) }
|
|
108
|
+
override suspend fun nip04Encrypt(pubkey: String, plaintext: String) = "c04".also { calls += listOf("nip04Encrypt", pubkey, plaintext) }
|
|
109
|
+
override suspend fun nip04Decrypt(pubkey: String, ciphertext: String) = "p04".also { calls += listOf("nip04Decrypt", pubkey, ciphertext) }
|
|
110
|
+
override suspend fun nip44Encrypt(pubkey: String, plaintext: String) = "c44".also { calls += listOf("nip44Encrypt", pubkey, plaintext) }
|
|
111
|
+
override suspend fun nip44Decrypt(pubkey: String, ciphertext: String) = "p44".also { calls += listOf("nip44Decrypt", pubkey, ciphertext) }
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -17,6 +17,7 @@ json = "20250517"
|
|
|
17
17
|
okhttp = "4.12.0"
|
|
18
18
|
securityCrypto = "1.1.0"
|
|
19
19
|
zxingCore = "3.5.3"
|
|
20
|
+
webkit = "1.18.0"
|
|
20
21
|
|
|
21
22
|
[libraries]
|
|
22
23
|
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" }
|
|
@@ -42,6 +43,7 @@ json = { module = "org.json:json", version.ref = "json" }
|
|
|
42
43
|
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
|
|
43
44
|
androidx-security-crypto = { module = "androidx.security:security-crypto", version.ref = "securityCrypto" }
|
|
44
45
|
zxing-core = { module = "com.google.zxing:core", version.ref = "zxingCore" }
|
|
46
|
+
androidx-webkit = { module = "androidx.webkit:webkit", version.ref = "webkit" }
|
|
45
47
|
|
|
46
48
|
[plugins]
|
|
47
49
|
android-application = { id = "com.android.application", version.ref = "agp" }
|