pakstr 0.20.0 → 0.21.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.
Files changed (50) hide show
  1. package/README.md +1 -1
  2. package/android-template/app/build.gradle.kts +4 -0
  3. package/android-template/app/src/androidTest/java/com/pakstr/app/signer/SignerManagerTest.kt +273 -0
  4. package/android-template/app/src/main/assets/www/index.html +0 -6
  5. package/android-template/app/src/main/java/com/pakstr/app/LocalServer.kt +20 -4
  6. package/android-template/app/src/main/java/com/pakstr/app/MainActivity.kt +130 -12
  7. package/android-template/app/src/main/java/com/pakstr/app/crypto/Bip340Hash.kt +56 -0
  8. package/android-template/app/src/main/java/com/pakstr/app/crypto/Bip340Signer.kt +104 -0
  9. package/android-template/app/src/main/java/com/pakstr/app/crypto/Bip340Verifier.kt +20 -170
  10. package/android-template/app/src/main/java/com/pakstr/app/crypto/Nip44Crypto.kt +513 -0
  11. package/android-template/app/src/main/java/com/pakstr/app/crypto/Nip46ClientKey.kt +140 -0
  12. package/android-template/app/src/main/java/com/pakstr/app/crypto/NostrEventHasher.kt +3 -28
  13. package/android-template/app/src/main/java/com/pakstr/app/crypto/NostrEventSerializer.kt +74 -0
  14. package/android-template/app/src/main/java/com/pakstr/app/crypto/Secp256k1.kt +100 -0
  15. package/android-template/app/src/main/java/com/pakstr/app/signer/BunkerSigner.kt +32 -7
  16. package/android-template/app/src/main/java/com/pakstr/app/signer/NostrBridge.kt +36 -9
  17. package/android-template/app/src/main/java/com/pakstr/app/signer/SignerManager.kt +240 -163
  18. package/android-template/app/src/main/java/com/pakstr/app/signer/bunker/BunkerConfig.kt +175 -0
  19. package/android-template/app/src/main/java/com/pakstr/app/signer/bunker/BunkerConnectionStore.kt +144 -0
  20. package/android-template/app/src/main/java/com/pakstr/app/signer/bunker/Nip46Client.kt +79 -0
  21. package/android-template/app/src/main/java/com/pakstr/app/signer/bunker/Nip46Models.kt +319 -0
  22. package/android-template/app/src/main/java/com/pakstr/app/signer/bunker/Nip46PairingClient.kt +159 -0
  23. package/android-template/app/src/main/java/com/pakstr/app/signer/bunker/Nip46PairingQrCode.kt +35 -0
  24. package/android-template/app/src/main/java/com/pakstr/app/signer/bunker/Nip46PairingUri.kt +104 -0
  25. package/android-template/app/src/main/java/com/pakstr/app/signer/bunker/Nip46Protocol.kt +695 -0
  26. package/android-template/app/src/main/java/com/pakstr/app/signer/bunker/Nip46RelayTransport.kt +489 -0
  27. package/android-template/app/src/main/java/com/pakstr/app/signer/bunker/RelayNip46Client.kt +403 -0
  28. package/android-template/app/src/main/java/com/pakstr/app/utils/BunkerPairingDialog.kt +82 -0
  29. package/android-template/app/src/main/java/com/pakstr/app/utils/SignerPickerBottomSheet.kt +78 -17
  30. package/android-template/app/src/main/res/layout/activity_layout.xml +1 -0
  31. package/android-template/app/src/main/res/layout/dialog_bunker_pairing.xml +75 -0
  32. package/android-template/app/src/main/res/layout/dialog_picker.xml +60 -31
  33. package/android-template/app/src/main/res/values/strings.xml +27 -0
  34. package/android-template/app/src/test/java/com/pakstr/app/LocalServerQueryKeepAliveTest.kt +118 -0
  35. package/android-template/app/src/test/java/com/pakstr/app/crypto/Bip340SignerTest.kt +133 -0
  36. package/android-template/app/src/test/java/com/pakstr/app/crypto/Nip44CryptoTest.kt +199 -0
  37. package/android-template/app/src/test/java/com/pakstr/app/crypto/Nip46ClientKeyProtocolTest.kt +82 -0
  38. package/android-template/app/src/test/java/com/pakstr/app/crypto/Nip46ClientKeyTest.kt +52 -0
  39. package/android-template/app/src/test/java/com/pakstr/app/crypto/NostrEventSerializerTest.kt +42 -0
  40. package/android-template/app/src/test/java/com/pakstr/app/signer/NostrBridgeErrorTest.kt +32 -0
  41. package/android-template/app/src/test/java/com/pakstr/app/signer/bunker/BunkerConfigTest.kt +120 -0
  42. package/android-template/app/src/test/java/com/pakstr/app/signer/bunker/Nip46ModelsTest.kt +111 -0
  43. package/android-template/app/src/test/java/com/pakstr/app/signer/bunker/Nip46PairingClientTest.kt +271 -0
  44. package/android-template/app/src/test/java/com/pakstr/app/signer/bunker/Nip46PairingQrCodeTest.kt +54 -0
  45. package/android-template/app/src/test/java/com/pakstr/app/signer/bunker/Nip46PairingUriTest.kt +80 -0
  46. package/android-template/app/src/test/java/com/pakstr/app/signer/bunker/Nip46ProtocolTest.kt +578 -0
  47. package/android-template/app/src/test/java/com/pakstr/app/signer/bunker/Nip46RelayTransportTest.kt +508 -0
  48. package/android-template/app/src/test/java/com/pakstr/app/signer/bunker/RelayNip46ClientTest.kt +678 -0
  49. package/android-template/gradle/libs.versions.toml +8 -0
  50. package/package.json +1 -1
@@ -0,0 +1,35 @@
1
+ package com.pakstr.app.signer.bunker
2
+
3
+ import com.google.zxing.BarcodeFormat
4
+ import com.google.zxing.EncodeHintType
5
+ import com.google.zxing.qrcode.QRCodeWriter
6
+ import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
7
+ import com.google.zxing.common.BitMatrix
8
+
9
+ internal object Nip46PairingQrCode {
10
+ fun encode(
11
+ pairingUri: String,
12
+ sizePixels: Int
13
+ ): BitMatrix {
14
+ require(pairingUri.isNotBlank()) {
15
+ "Pairing URI must not be blank"
16
+ }
17
+ require(sizePixels > 0) {
18
+ "QR code size must be positive"
19
+ }
20
+
21
+ return QRCodeWriter().encode(
22
+ pairingUri,
23
+ BarcodeFormat.QR_CODE,
24
+ sizePixels,
25
+ sizePixels,
26
+ mapOf(
27
+ EncodeHintType.CHARACTER_SET to Charsets.UTF_8.name(),
28
+ EncodeHintType.ERROR_CORRECTION to ErrorCorrectionLevel.M,
29
+ EncodeHintType.MARGIN to QUIET_ZONE_MODULES
30
+ )
31
+ )
32
+ }
33
+
34
+ private const val QUIET_ZONE_MODULES = 4
35
+ }
@@ -0,0 +1,104 @@
1
+ package com.pakstr.app.signer.bunker
2
+
3
+ import com.pakstr.app.crypto.Bip340Verifier
4
+ import java.net.URI
5
+ import java.net.URLEncoder
6
+ import java.nio.charset.StandardCharsets
7
+
8
+ class Nip46PairingUri private constructor(
9
+ val clientPubkey: String,
10
+ relayUrls: List<String>,
11
+ val secret: String,
12
+ val permissions: String?,
13
+ val clientName: String?
14
+ ) {
15
+ val relayUrls: List<String> = relayUrls.toList()
16
+
17
+ fun encode(): String {
18
+ val parameters = mutableListOf<Pair<String, String>>()
19
+ relayUrls.forEach { parameters += "relay" to it }
20
+ permissions?.let { parameters += "perms" to it }
21
+ clientName?.let { parameters += "name" to it }
22
+ parameters += "secret" to secret
23
+
24
+ return "nostrconnect://$clientPubkey?" +
25
+ parameters.joinToString("&") { (name, value) ->
26
+ "${encodeParameter(name)}=${encodeParameter(value)}"
27
+ }
28
+ }
29
+
30
+ override fun toString(): String {
31
+ return "Nip46PairingUri(" +
32
+ "clientPubkey=${clientPubkey.take(12)}..., " +
33
+ "relayCount=${relayUrls.size}, " +
34
+ "hasPermissions=${permissions != null}, " +
35
+ "hasClientName=${clientName != null}" +
36
+ ")"
37
+ }
38
+
39
+ companion object {
40
+ fun create(
41
+ clientPubkey: String,
42
+ relayUrls: List<String>,
43
+ secret: String,
44
+ permissions: String? = null,
45
+ clientName: String? = null
46
+ ): Nip46PairingUri {
47
+ require(
48
+ clientPubkey.matches(Regex("[0-9a-f]{64}")) &&
49
+ Bip340Verifier.isValidXOnlyPubkey(clientPubkey)
50
+ ) {
51
+ "Invalid client public key"
52
+ }
53
+ require(relayUrls.isNotEmpty()) {
54
+ "At least one relay is required"
55
+ }
56
+ val validatedRelays = relayUrls.map(::validateRelay)
57
+ require(secret.isNotBlank() && secret.length <= 256) {
58
+ "Invalid pairing secret"
59
+ }
60
+ permissions?.let {
61
+ require(it.isNotBlank() && it.length <= 4_096) {
62
+ "Invalid requested permissions"
63
+ }
64
+ }
65
+ clientName?.let {
66
+ require(it.isNotBlank() && it.length <= 256) {
67
+ "Invalid client name"
68
+ }
69
+ }
70
+ return Nip46PairingUri(
71
+ clientPubkey,
72
+ validatedRelays,
73
+ secret,
74
+ permissions,
75
+ clientName
76
+ )
77
+ }
78
+
79
+ private fun validateRelay(value: String): String {
80
+ val uri =
81
+ try {
82
+ URI(value)
83
+ } catch (_: Exception) {
84
+ throw IllegalArgumentException("Invalid relay URL")
85
+ }
86
+ require(
87
+ uri.scheme == "wss" &&
88
+ !uri.host.isNullOrBlank() &&
89
+ uri.rawUserInfo == null &&
90
+ uri.rawFragment == null
91
+ ) {
92
+ "Invalid relay URL"
93
+ }
94
+ return uri.toASCIIString()
95
+ }
96
+
97
+ private fun encodeParameter(value: String): String {
98
+ return URLEncoder.encode(
99
+ value,
100
+ StandardCharsets.UTF_8.name()
101
+ )
102
+ }
103
+ }
104
+ }