pakstr 0.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.
Files changed (73) hide show
  1. package/android-template/app/build.gradle.kts +59 -0
  2. package/android-template/app/proguard-rules.pro +21 -0
  3. package/android-template/app/src/androidTest/java/com/nostrappshell/app/ExampleInstrumentedTest.kt +24 -0
  4. package/android-template/app/src/main/AndroidManifest.xml +32 -0
  5. package/android-template/app/src/main/assets/nip07.js +35 -0
  6. package/android-template/app/src/main/assets/www/assets/hero-CLDdwZDr.png +0 -0
  7. package/android-template/app/src/main/assets/www/assets/index-CsUDhMuy.css +1 -0
  8. package/android-template/app/src/main/assets/www/assets/index-D-e3tQW5.js +56 -0
  9. package/android-template/app/src/main/assets/www/assets/vite-BF8QNONU.svg +1 -0
  10. package/android-template/app/src/main/assets/www/favicon.svg +1 -0
  11. package/android-template/app/src/main/assets/www/icons.svg +24 -0
  12. package/android-template/app/src/main/assets/www/index.html +14 -0
  13. package/android-template/app/src/main/assets/www/test.html +17 -0
  14. package/android-template/app/src/main/java/com/nostrappshell/app/ApplicationClass.kt +11 -0
  15. package/android-template/app/src/main/java/com/nostrappshell/app/Config.kt +7 -0
  16. package/android-template/app/src/main/java/com/nostrappshell/app/LocalServer.kt +51 -0
  17. package/android-template/app/src/main/java/com/nostrappshell/app/MainActivity.kt +160 -0
  18. package/android-template/app/src/main/java/com/nostrappshell/app/ShellRuntime.kt +125 -0
  19. package/android-template/app/src/main/java/com/nostrappshell/app/WebViewController.kt +139 -0
  20. package/android-template/app/src/main/java/com/nostrappshell/app/signer/AmberSigner.kt +167 -0
  21. package/android-template/app/src/main/java/com/nostrappshell/app/signer/BunkerSigner.kt +28 -0
  22. package/android-template/app/src/main/java/com/nostrappshell/app/signer/FakeSigner.kt +31 -0
  23. package/android-template/app/src/main/java/com/nostrappshell/app/signer/NostrBridge.kt +97 -0
  24. package/android-template/app/src/main/java/com/nostrappshell/app/signer/SignerManager.kt +155 -0
  25. package/android-template/app/src/main/java/com/nostrappshell/app/signer/SignerType.kt +9 -0
  26. package/android-template/app/src/main/java/com/nostrappshell/app/signer/interfaces/NostrSigner.kt +25 -0
  27. package/android-template/app/src/main/java/com/nostrappshell/app/ui/theme/Color.kt +11 -0
  28. package/android-template/app/src/main/java/com/nostrappshell/app/ui/theme/Theme.kt +57 -0
  29. package/android-template/app/src/main/java/com/nostrappshell/app/ui/theme/Type.kt +34 -0
  30. package/android-template/app/src/main/java/com/nostrappshell/app/utils/AppPreferences.kt +31 -0
  31. package/android-template/app/src/main/java/com/nostrappshell/app/utils/SignerPickerBottomSheet.kt +40 -0
  32. package/android-template/app/src/main/res/drawable/bg_bottom_sheet.xml +7 -0
  33. package/android-template/app/src/main/res/drawable/custom_loader.xml +25 -0
  34. package/android-template/app/src/main/res/drawable/ic_launcher_background.xml +170 -0
  35. package/android-template/app/src/main/res/drawable/ic_launcher_foreground.xml +30 -0
  36. package/android-template/app/src/main/res/drawable/ic_menu_browser.xml +9 -0
  37. package/android-template/app/src/main/res/drawable/selector_radio_card.xml +17 -0
  38. package/android-template/app/src/main/res/drawable/selector_radio_checkmark.xml +5 -0
  39. package/android-template/app/src/main/res/drawable/selector_radio_tint.xml +5 -0
  40. package/android-template/app/src/main/res/layout/activity_layout.xml +21 -0
  41. package/android-template/app/src/main/res/layout/dialog_picker.xml +101 -0
  42. package/android-template/app/src/main/res/mipmap-anydpi/ic_launcher.xml +6 -0
  43. package/android-template/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml +6 -0
  44. package/android-template/app/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
  45. package/android-template/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
  46. package/android-template/app/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
  47. package/android-template/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
  48. package/android-template/app/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
  49. package/android-template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
  50. package/android-template/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
  51. package/android-template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
  52. package/android-template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
  53. package/android-template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
  54. package/android-template/app/src/main/res/values/colors.xml +10 -0
  55. package/android-template/app/src/main/res/values/dimes.xml +6 -0
  56. package/android-template/app/src/main/res/values/strings.xml +3 -0
  57. package/android-template/app/src/main/res/values/themes.xml +13 -0
  58. package/android-template/app/src/main/res/xml/backup_rules.xml +13 -0
  59. package/android-template/app/src/main/res/xml/data_extraction_rules.xml +19 -0
  60. package/android-template/app/src/main/res/xml/network_security_config.xml +7 -0
  61. package/android-template/app/src/test/java/com/nostrappshell/app/ExampleUnitTest.kt +17 -0
  62. package/android-template/build.gradle.kts +5 -0
  63. package/android-template/gradle/gradle-daemon-jvm.properties +12 -0
  64. package/android-template/gradle/libs.versions.toml +41 -0
  65. package/android-template/gradle/wrapper/gradle-wrapper.jar +0 -0
  66. package/android-template/gradle/wrapper/gradle-wrapper.properties +9 -0
  67. package/android-template/gradle.properties +15 -0
  68. package/android-template/gradlew +251 -0
  69. package/android-template/gradlew.bat +94 -0
  70. package/android-template/settings.gradle.kts +27 -0
  71. package/bin/cli.js +10 -0
  72. package/bin/cli.ts +5 -0
  73. package/package.json +49 -0
@@ -0,0 +1,125 @@
1
+ package com.nostrappshell.app
2
+
3
+ import android.content.Context
4
+ import android.util.Log
5
+ import android.webkit.WebView
6
+ import com.nostrappshell.app.signer.SignerManager
7
+ import fi.iki.elonen.NanoHTTPD
8
+ import kotlinx.coroutines.CoroutineScope
9
+ import kotlinx.coroutines.Dispatchers
10
+ import kotlinx.coroutines.launch
11
+ import kotlinx.coroutines.withContext
12
+
13
+ class ShellRuntime(
14
+ private val context: Context,
15
+ private val webView: WebView,
16
+ private val signerManager: SignerManager
17
+ ) {
18
+
19
+ private val port = Config.PORT
20
+
21
+ private var server: LocalServer? = null
22
+
23
+ private lateinit var controller: WebViewController
24
+
25
+
26
+ fun start() {
27
+
28
+ controller = WebViewController(
29
+ context,
30
+ webView,
31
+ port,
32
+ signerManager
33
+ )
34
+
35
+
36
+ CoroutineScope(Dispatchers.IO).launch {
37
+
38
+ val ok = startServer()
39
+
40
+
41
+ if (!ok) {
42
+
43
+ Log.e(
44
+ "RUNTIME",
45
+ "Server failed"
46
+ )
47
+
48
+ return@launch
49
+
50
+ }
51
+
52
+
53
+ withContext(Dispatchers.Main) {
54
+
55
+ controller.setup()
56
+
57
+ }
58
+
59
+ }
60
+
61
+ }
62
+
63
+
64
+ private fun startServer(): Boolean {
65
+
66
+ if (server != null)
67
+ return true
68
+
69
+
70
+ return try {
71
+
72
+ server = LocalServer(
73
+ context,
74
+ port
75
+ )
76
+
77
+
78
+ server?.start(
79
+ NanoHTTPD.SOCKET_READ_TIMEOUT,
80
+ false
81
+ )
82
+
83
+
84
+ Log.d(
85
+ "SERVER",
86
+ "Started OK"
87
+ )
88
+
89
+
90
+ true
91
+
92
+
93
+ } catch (e: Exception) {
94
+
95
+
96
+ Log.e(
97
+ "SERVER",
98
+ "FAILED TO START",
99
+ e
100
+ )
101
+
102
+
103
+ false
104
+
105
+ }
106
+
107
+ }
108
+
109
+
110
+ fun stop() {
111
+
112
+ server?.stop()
113
+
114
+ controller.destroy()
115
+
116
+ }
117
+
118
+
119
+ fun getWebview(): WebView {
120
+
121
+ return webView
122
+
123
+ }
124
+
125
+ }
@@ -0,0 +1,139 @@
1
+ package com.nostrappshell.app
2
+
3
+ import android.app.Activity
4
+ import android.content.Context
5
+ import android.util.Log
6
+ import android.view.View
7
+ import android.webkit.CookieManager
8
+ import android.webkit.WebChromeClient
9
+ import android.webkit.WebResourceRequest
10
+ import android.webkit.WebResourceResponse
11
+ import android.webkit.WebView
12
+ import android.webkit.WebViewClient
13
+ import com.nostrappshell.app.R
14
+ import com.nostrappshell.app.signer.FakeSigner
15
+ import com.nostrappshell.app.signer.NostrBridge
16
+ import com.nostrappshell.app.signer.SignerManager
17
+ import com.nostrappshell.app.signer.interfaces.NostrSigner
18
+
19
+ class WebViewController(
20
+
21
+ private val context: Context,
22
+
23
+ private val webView: WebView,
24
+
25
+ private val port: Int,
26
+
27
+ private val signerManager: SignerManager
28
+
29
+ ) {
30
+ // Keeps a reference to the runnable to prevent memory leaks if destroyed early
31
+ private val loadRunnable = Runnable {
32
+ webView.loadUrl("http://127.0.0.1:$port/")
33
+ //webView.loadUrl("https://sigit.io")
34
+ }
35
+
36
+ fun setup() {
37
+ showLoader()
38
+ setupWebView()
39
+ loadApp()
40
+ }
41
+
42
+ private fun setupWebView() {
43
+ webView.apply {
44
+ // Idiomatically configure WebView settings using scoping functions
45
+ settings.apply {
46
+ javaScriptEnabled = true
47
+ domStorageEnabled = true
48
+
49
+ // SECURITY baseline: Prevent access to local files and content providers
50
+ //allowFileAccess = false
51
+ //allowContentAccess = false
52
+
53
+ allowFileAccess = false
54
+ allowContentAccess = false
55
+ }
56
+
57
+ // Standard clients are enough since overriding URL loading isn't required
58
+ webViewClient = object : WebViewClient() {
59
+
60
+ override fun onPageFinished(view: WebView?, url: String?) {
61
+ super.onPageFinished(view, url)
62
+ hideLoader()
63
+ val js = context.assets.open("nip07.js")
64
+
65
+ .bufferedReader()
66
+
67
+ .readText()
68
+
69
+ webView.evaluateJavascript(js, null)
70
+ }
71
+
72
+ override fun shouldInterceptRequest(
73
+
74
+ view: WebView?,
75
+
76
+ request: WebResourceRequest?
77
+
78
+ ): WebResourceResponse? {
79
+
80
+ val url = request?.url.toString()
81
+
82
+ Log.d("WEB_ASSET", "REQUEST: $url")
83
+
84
+ return super.shouldInterceptRequest(view, request)
85
+ }
86
+ }
87
+ webChromeClient = WebChromeClient()
88
+ }
89
+
90
+ webView.addJavascriptInterface(
91
+
92
+ NostrBridge(
93
+
94
+ signerManager = signerManager,
95
+
96
+ webView = webView
97
+
98
+ ),
99
+
100
+ "AndroidBridge"
101
+
102
+ )
103
+
104
+ }
105
+
106
+ /**
107
+ * Loads the local server URL with a minor delay to ensure NanoHTTPD is fully bound.
108
+ */
109
+ private fun loadApp() {
110
+ webView.postDelayed(loadRunnable, 500)
111
+ }
112
+
113
+ private fun showLoader() {
114
+ (context as? Activity)?.findViewById<View>(R.id.loader)?.visibility = View.VISIBLE
115
+ }
116
+
117
+ private fun hideLoader() {
118
+ (context as? Activity)?.findViewById<View>(R.id.loader)?.visibility = View.GONE
119
+ }
120
+
121
+ fun destroy() {
122
+ webView.stopLoading()
123
+
124
+ webView.clearCache(true)
125
+
126
+ webView.clearHistory()
127
+
128
+ CookieManager.getInstance().removeAllCookies(null)
129
+
130
+ CookieManager.getInstance().flush()
131
+
132
+ webView.loadUrl("about:blank")
133
+ webView.removeCallbacks(loadRunnable)
134
+ webView.onPause()
135
+
136
+
137
+ webView.destroy()
138
+ }
139
+ }
@@ -0,0 +1,167 @@
1
+ package com.nostrappshell.app.signer
2
+
3
+ import android.app.Activity
4
+ import android.content.Context
5
+ import android.content.Intent
6
+ import androidx.activity.result.ActivityResult
7
+ import com.nostrappshell.app.signer.interfaces.NostrSigner
8
+ import kotlinx.coroutines.CancellableContinuation
9
+ import kotlinx.coroutines.suspendCancellableCoroutine
10
+ import kotlin.coroutines.resume
11
+
12
+
13
+ class AmberSigner(
14
+ private val context: Context,
15
+ private val launchIntent: (Intent) -> Unit
16
+ ) : NostrSigner {
17
+
18
+
19
+ private var pendingPublicKey:
20
+ CancellableContinuation<String>? = null
21
+
22
+
23
+
24
+ override suspend fun getPublicKey(): String {
25
+
26
+ return suspendCancellableCoroutine { cont ->
27
+
28
+ pendingPublicKey = cont
29
+
30
+ val intent = Intent().apply {
31
+
32
+ action =
33
+
34
+ "com.greenart7c3.nostrsigner.GET_PUBLIC_KEY"
35
+
36
+ }
37
+
38
+ val activities =
39
+
40
+ context.packageManager.queryIntentActivities(
41
+
42
+ intent,
43
+
44
+ 0
45
+
46
+ )
47
+
48
+ if (activities.isEmpty()) {
49
+ activities.forEach {
50
+
51
+ println(
52
+
53
+ "Amber activity: ${it.activityInfo.packageName}/${it.activityInfo.name}"
54
+
55
+ )
56
+
57
+ }
58
+ pendingPublicKey = null
59
+
60
+ cont.resumeWith(
61
+
62
+ Result.failure(
63
+
64
+ Exception(
65
+
66
+ "Amber signer is not installed. Please install Amber to continue."
67
+
68
+ )
69
+
70
+ )
71
+
72
+ )
73
+
74
+ return@suspendCancellableCoroutine
75
+
76
+ }
77
+
78
+ launchIntent(intent)
79
+
80
+ }
81
+
82
+ }
83
+
84
+
85
+
86
+ fun handleResult(
87
+ result: ActivityResult
88
+ ) {
89
+
90
+ if (result.resultCode != Activity.RESULT_OK) {
91
+
92
+ pendingPublicKey?.resumeWith(
93
+ Result.failure(
94
+ Exception(
95
+ "Amber cancelled"
96
+ )
97
+ )
98
+ )
99
+
100
+ pendingPublicKey = null
101
+
102
+ return
103
+
104
+ }
105
+
106
+
107
+ val pubkey =
108
+ result.data
109
+ ?.getStringExtra("pubkey")
110
+
111
+
112
+ if (pubkey != null) {
113
+
114
+ pendingPublicKey?.resume(
115
+ pubkey
116
+ )
117
+
118
+ } else {
119
+
120
+ pendingPublicKey?.resumeWith(
121
+ Result.failure(
122
+ Exception(
123
+ "No public key returned"
124
+ )
125
+ )
126
+ )
127
+
128
+ }
129
+
130
+
131
+ pendingPublicKey = null
132
+
133
+ }
134
+
135
+
136
+
137
+ override suspend fun signEvent(
138
+ eventJson: String
139
+ ): String {
140
+
141
+ TODO()
142
+
143
+ }
144
+
145
+
146
+
147
+ override suspend fun nip04Encrypt(
148
+ pubkey: String,
149
+ plaintext: String
150
+ ): String {
151
+
152
+ TODO()
153
+
154
+ }
155
+
156
+
157
+
158
+ override suspend fun nip04Decrypt(
159
+ pubkey: String,
160
+ ciphertext: String
161
+ ): String {
162
+
163
+ TODO()
164
+
165
+ }
166
+
167
+ }
@@ -0,0 +1,28 @@
1
+ package com.nostrappshell.app.signer
2
+
3
+ import android.content.Context
4
+ import com.nostrappshell.app.signer.interfaces.NostrSigner
5
+
6
+ class BunkerSigner(context: Context) : NostrSigner {
7
+ override suspend fun getPublicKey(): String {
8
+ TODO("Not yet implemented")
9
+ }
10
+
11
+ override suspend fun signEvent(eventJson: String): String {
12
+ TODO("Not yet implemented")
13
+ }
14
+
15
+ override suspend fun nip04Encrypt(
16
+ pubkey: String,
17
+ plaintext: String
18
+ ): String {
19
+ TODO("Not yet implemented")
20
+ }
21
+
22
+ override suspend fun nip04Decrypt(
23
+ pubkey: String,
24
+ ciphertext: String
25
+ ): String {
26
+ TODO("Not yet implemented")
27
+ }
28
+ }
@@ -0,0 +1,31 @@
1
+ package com.nostrappshell.app.signer
2
+
3
+ import com.nostrappshell.app.signer.interfaces.NostrSigner
4
+
5
+ class FakeSigner : NostrSigner {
6
+
7
+ override suspend fun getPublicKey(): String {
8
+
9
+ return "npub1fake123"
10
+
11
+ }
12
+
13
+ override suspend fun signEvent(eventJson: String): String {
14
+
15
+ return """{"sig":"fake_signature"}"""
16
+
17
+ }
18
+
19
+ override suspend fun nip04Encrypt(pubkey: String, plaintext: String): String {
20
+
21
+ return "encrypted_fake"
22
+
23
+ }
24
+
25
+ override suspend fun nip04Decrypt(pubkey: String, ciphertext: String): String {
26
+
27
+ return "decrypted_fake"
28
+
29
+ }
30
+
31
+ }
@@ -0,0 +1,97 @@
1
+ package com.nostrappshell.app.signer
2
+
3
+ import android.os.Handler
4
+ import android.os.Looper
5
+ import android.webkit.JavascriptInterface
6
+ import android.webkit.WebView
7
+ import android.widget.Toast
8
+ import com.nostrappshell.app.signer.interfaces.NostrSigner
9
+ import kotlinx.coroutines.CoroutineScope
10
+ import kotlinx.coroutines.Dispatchers
11
+ import kotlinx.coroutines.launch
12
+
13
+ class NostrBridge(
14
+
15
+ private val webView: WebView,
16
+
17
+ private val signerManager: SignerManager
18
+
19
+ ) {
20
+
21
+ private val mainHandler = Handler(Looper.getMainLooper())
22
+
23
+ @JavascriptInterface
24
+ fun call(method: String, callbackId: String, payload: String?) {
25
+
26
+ when (method) {
27
+
28
+ "getPublicKey" -> {
29
+
30
+ CoroutineScope(Dispatchers.IO).launch {
31
+
32
+ try {
33
+
34
+ val pk = signerManager
35
+
36
+ .getSigner()
37
+
38
+ .getPublicKey()
39
+
40
+ resolve(callbackId, pk)
41
+
42
+ } catch (e: Exception) {
43
+
44
+ showToast(
45
+
46
+ e.message ?: "Signer error"
47
+
48
+ )
49
+
50
+ resolve(
51
+
52
+ callbackId,
53
+
54
+ ""
55
+
56
+ )
57
+
58
+ }
59
+
60
+ }
61
+
62
+ }
63
+
64
+ "signEvent" -> {
65
+ CoroutineScope(Dispatchers.IO).launch {
66
+ val result = signerManager.getSigner().signEvent(payload ?: "")
67
+ resolve(callbackId, result)
68
+ }
69
+ }
70
+ }
71
+ }
72
+
73
+ private fun resolve(callbackId: String, result: String) {
74
+ mainHandler.post {
75
+ val js = "window.__nostrResolve('$callbackId', '$result')"
76
+ webView.evaluateJavascript(js, null)
77
+ }
78
+ }
79
+
80
+ private fun showToast(message: String) {
81
+
82
+ mainHandler.post {
83
+
84
+ Toast.makeText(
85
+
86
+ webView.context,
87
+
88
+ message,
89
+
90
+ Toast.LENGTH_LONG
91
+
92
+ ).show()
93
+
94
+ }
95
+
96
+ }
97
+ }