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.
- package/android-template/app/build.gradle.kts +59 -0
- package/android-template/app/proguard-rules.pro +21 -0
- package/android-template/app/src/androidTest/java/com/nostrappshell/app/ExampleInstrumentedTest.kt +24 -0
- package/android-template/app/src/main/AndroidManifest.xml +32 -0
- package/android-template/app/src/main/assets/nip07.js +35 -0
- package/android-template/app/src/main/assets/www/assets/hero-CLDdwZDr.png +0 -0
- package/android-template/app/src/main/assets/www/assets/index-CsUDhMuy.css +1 -0
- package/android-template/app/src/main/assets/www/assets/index-D-e3tQW5.js +56 -0
- package/android-template/app/src/main/assets/www/assets/vite-BF8QNONU.svg +1 -0
- package/android-template/app/src/main/assets/www/favicon.svg +1 -0
- package/android-template/app/src/main/assets/www/icons.svg +24 -0
- package/android-template/app/src/main/assets/www/index.html +14 -0
- package/android-template/app/src/main/assets/www/test.html +17 -0
- package/android-template/app/src/main/java/com/nostrappshell/app/ApplicationClass.kt +11 -0
- package/android-template/app/src/main/java/com/nostrappshell/app/Config.kt +7 -0
- package/android-template/app/src/main/java/com/nostrappshell/app/LocalServer.kt +51 -0
- package/android-template/app/src/main/java/com/nostrappshell/app/MainActivity.kt +160 -0
- package/android-template/app/src/main/java/com/nostrappshell/app/ShellRuntime.kt +125 -0
- package/android-template/app/src/main/java/com/nostrappshell/app/WebViewController.kt +139 -0
- package/android-template/app/src/main/java/com/nostrappshell/app/signer/AmberSigner.kt +167 -0
- package/android-template/app/src/main/java/com/nostrappshell/app/signer/BunkerSigner.kt +28 -0
- package/android-template/app/src/main/java/com/nostrappshell/app/signer/FakeSigner.kt +31 -0
- package/android-template/app/src/main/java/com/nostrappshell/app/signer/NostrBridge.kt +97 -0
- package/android-template/app/src/main/java/com/nostrappshell/app/signer/SignerManager.kt +155 -0
- package/android-template/app/src/main/java/com/nostrappshell/app/signer/SignerType.kt +9 -0
- package/android-template/app/src/main/java/com/nostrappshell/app/signer/interfaces/NostrSigner.kt +25 -0
- package/android-template/app/src/main/java/com/nostrappshell/app/ui/theme/Color.kt +11 -0
- package/android-template/app/src/main/java/com/nostrappshell/app/ui/theme/Theme.kt +57 -0
- package/android-template/app/src/main/java/com/nostrappshell/app/ui/theme/Type.kt +34 -0
- package/android-template/app/src/main/java/com/nostrappshell/app/utils/AppPreferences.kt +31 -0
- package/android-template/app/src/main/java/com/nostrappshell/app/utils/SignerPickerBottomSheet.kt +40 -0
- package/android-template/app/src/main/res/drawable/bg_bottom_sheet.xml +7 -0
- package/android-template/app/src/main/res/drawable/custom_loader.xml +25 -0
- package/android-template/app/src/main/res/drawable/ic_launcher_background.xml +170 -0
- package/android-template/app/src/main/res/drawable/ic_launcher_foreground.xml +30 -0
- package/android-template/app/src/main/res/drawable/ic_menu_browser.xml +9 -0
- package/android-template/app/src/main/res/drawable/selector_radio_card.xml +17 -0
- package/android-template/app/src/main/res/drawable/selector_radio_checkmark.xml +5 -0
- package/android-template/app/src/main/res/drawable/selector_radio_tint.xml +5 -0
- package/android-template/app/src/main/res/layout/activity_layout.xml +21 -0
- package/android-template/app/src/main/res/layout/dialog_picker.xml +101 -0
- package/android-template/app/src/main/res/mipmap-anydpi/ic_launcher.xml +6 -0
- package/android-template/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml +6 -0
- package/android-template/app/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
- package/android-template/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
- package/android-template/app/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
- package/android-template/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
- package/android-template/app/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
- package/android-template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
- package/android-template/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
- package/android-template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
- package/android-template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
- package/android-template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
- package/android-template/app/src/main/res/values/colors.xml +10 -0
- package/android-template/app/src/main/res/values/dimes.xml +6 -0
- package/android-template/app/src/main/res/values/strings.xml +3 -0
- package/android-template/app/src/main/res/values/themes.xml +13 -0
- package/android-template/app/src/main/res/xml/backup_rules.xml +13 -0
- package/android-template/app/src/main/res/xml/data_extraction_rules.xml +19 -0
- package/android-template/app/src/main/res/xml/network_security_config.xml +7 -0
- package/android-template/app/src/test/java/com/nostrappshell/app/ExampleUnitTest.kt +17 -0
- package/android-template/build.gradle.kts +5 -0
- package/android-template/gradle/gradle-daemon-jvm.properties +12 -0
- package/android-template/gradle/libs.versions.toml +41 -0
- package/android-template/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android-template/gradle/wrapper/gradle-wrapper.properties +9 -0
- package/android-template/gradle.properties +15 -0
- package/android-template/gradlew +251 -0
- package/android-template/gradlew.bat +94 -0
- package/android-template/settings.gradle.kts +27 -0
- package/bin/cli.js +10 -0
- package/bin/cli.ts +5 -0
- 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
|
+
}
|