pakstr 0.3.3 → 0.4.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.
Files changed (23) hide show
  1. package/android-template/app/src/main/AndroidManifest.xml +17 -0
  2. package/android-template/app/src/main/java/com/pakstr/app/LocalServer.kt +80 -21
  3. package/android-template/app/src/main/java/com/pakstr/app/MainActivity.kt +46 -9
  4. package/android-template/app/src/main/java/com/pakstr/app/RuntimeConfig.kt +81 -37
  5. package/android-template/app/src/main/java/com/pakstr/app/ShellRuntime.kt +99 -8
  6. package/android-template/app/src/main/java/com/pakstr/app/WebViewController.kt +150 -20
  7. package/android-template/app/src/main/java/com/pakstr/app/crypto/Bip340Verifier.kt +0 -5
  8. package/android-template/app/src/main/java/com/pakstr/app/debug/AppDebugLogger.kt +275 -3
  9. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugConfig.kt +11 -0
  10. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugConfigLoader.kt +36 -0
  11. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugConfigProvider.kt +24 -0
  12. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugLogStorage.kt +107 -0
  13. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugReportExporter.kt +139 -0
  14. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugReportShare.kt +52 -0
  15. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugRuntimeOverride.kt +29 -0
  16. package/android-template/app/src/main/java/com/pakstr/app/debug/DeveloperToolsManager.kt +34 -0
  17. package/android-template/app/src/main/java/com/pakstr/app/signer/AmberSigner.kt +1 -10
  18. package/android-template/app/src/main/java/com/pakstr/app/signer/NostrBridge.kt +163 -11
  19. package/android-template/app/src/main/java/com/pakstr/app/signer/SignerManager.kt +71 -0
  20. package/android-template/app/src/main/res/xml/file_paths.xml +9 -0
  21. package/dist/runners/LocalGradleRunner.js +12 -2
  22. package/dist/runtime/runtimeConfig.js +6 -1
  23. package/package.json +1 -1
@@ -40,6 +40,23 @@
40
40
 
41
41
  </activity>
42
42
 
43
+ <provider
44
+
45
+ android:name="androidx.core.content.FileProvider"
46
+
47
+ android:authorities="${applicationId}.fileprovider"
48
+
49
+ android:exported="false"
50
+
51
+ android:grantUriPermissions="true">
52
+
53
+ <meta-data
54
+
55
+ android:name="android.support.FILE_PROVIDER_PATHS"
56
+
57
+ android:resource="@xml/file_paths" />
58
+
59
+ </provider>
43
60
  </application>
44
61
 
45
62
  </manifest>
@@ -1,9 +1,9 @@
1
1
  package com.pakstr.app
2
2
 
3
3
  import android.content.Context
4
- import android.util.Log
5
4
 
6
5
  import android.webkit.MimeTypeMap
6
+ import com.pakstr.app.debug.AppDebugLogger
7
7
 
8
8
  import fi.iki.elonen.NanoHTTPD
9
9
  import java.io.IOException
@@ -19,17 +19,29 @@ class LocalServer(
19
19
 
20
20
  ) : NanoHTTPD(port) {
21
21
 
22
- private val TAG = "LocalServer"
23
22
 
24
23
  override fun serve(session: IHTTPSession?): Response {
25
24
 
26
25
  val uri = (session?.uri ?: "/").replace("..", "")
27
26
 
27
+ AppDebugLogger.network(
28
28
 
29
+ context,
30
+ "Request: $uri"
31
+
32
+ )
29
33
  if (uri.startsWith("/api/")) {
30
34
 
31
35
  if (!RuntimeConfig.apiEnabled(context)) {
32
36
 
37
+ AppDebugLogger.network(
38
+
39
+ context,
40
+
41
+ "API request blocked: $uri"
42
+
43
+ )
44
+
33
45
  return newFixedLengthResponse(
34
46
 
35
47
  Response.Status.NOT_FOUND,
@@ -62,8 +74,10 @@ class LocalServer(
62
74
 
63
75
  return try {
64
76
 
65
- Log.d(
66
- TAG, "Serving asset: $filePath"
77
+ AppDebugLogger.network(
78
+ context,
79
+ "Serving asset: $filePath"
80
+
67
81
  )
68
82
 
69
83
  val inputStream = context.assets.open(filePath)
@@ -74,8 +88,16 @@ class LocalServer(
74
88
 
75
89
  } catch (e: IOException) {
76
90
 
77
- Log.e(
78
- TAG, "Failed loading asset: $filePath", e
91
+ AppDebugLogger.error(
92
+
93
+ context,
94
+
95
+ "SERVER",
96
+
97
+ "Failed loading asset: $filePath",
98
+
99
+ e
100
+
79
101
  )
80
102
 
81
103
  newFixedLengthResponse(
@@ -113,8 +135,11 @@ class LocalServer(
113
135
 
114
136
  super.start()
115
137
 
116
- Log.d(
117
- TAG, "🚀 LocalServer started on port $listeningPort"
138
+ AppDebugLogger.network(
139
+
140
+ context,
141
+ "LocalServer started on port $listeningPort"
142
+
118
143
  )
119
144
  }
120
145
 
@@ -122,6 +147,17 @@ class LocalServer(
122
147
  session: IHTTPSession?, uri: String
123
148
  ): Response {
124
149
 
150
+ if (AppDebugLogger.isNetworkLoggingEnabled(context)) {
151
+
152
+ AppDebugLogger.network(
153
+
154
+ context,
155
+ "Proxy request: $uri"
156
+
157
+ )
158
+
159
+ }
160
+
125
161
  return try {
126
162
 
127
163
  val config = RuntimeConfig.load(context)
@@ -129,6 +165,15 @@ class LocalServer(
129
165
  val apiBase = config.optString("apiBase")
130
166
 
131
167
  if (apiBase.isBlank()) {
168
+ AppDebugLogger.error(
169
+
170
+ context,
171
+
172
+ "API",
173
+
174
+ "apiBase missing"
175
+
176
+ )
132
177
  return newFixedLengthResponse(
133
178
  Response.Status.INTERNAL_ERROR,
134
179
  "application/json",
@@ -170,8 +215,7 @@ class LocalServer(
170
215
  session?.headers?.get("authorization")
171
216
  ?.let { auth ->
172
217
  connection.setRequestProperty(
173
- "Authorization",
174
- auth
218
+ "Authorization", auth
175
219
  )
176
220
  }
177
221
 
@@ -187,12 +231,12 @@ class LocalServer(
187
231
  val bytes = body.toByteArray(Charsets.UTF_8)
188
232
 
189
233
  connection.doOutput = true
190
- session?.headers?.get("content-type")?.let {
191
- connection.setRequestProperty(
192
- "Content-Type",
193
- it
194
- )
195
- }
234
+ session?.headers?.get("content-type")
235
+ ?.let {
236
+ connection.setRequestProperty(
237
+ "Content-Type", it
238
+ )
239
+ }
196
240
 
197
241
  connection.outputStream.use { output ->
198
242
 
@@ -202,7 +246,16 @@ class LocalServer(
202
246
  }
203
247
 
204
248
  val code = connection.responseCode
249
+ if (AppDebugLogger.isNetworkLoggingEnabled(context)) {
205
250
 
251
+ AppDebugLogger.network(
252
+
253
+ context,
254
+ "Response: $code $finalUrl"
255
+
256
+ )
257
+
258
+ }
206
259
  val stream = if (code >= 400) connection.errorStream
207
260
  else connection.inputStream
208
261
 
@@ -211,8 +264,7 @@ class LocalServer(
211
264
  it.readText()
212
265
  } ?: ""
213
266
 
214
- val responseContentType =
215
- connection.contentType ?: "application/json"
267
+ val responseContentType = connection.contentType ?: "application/json"
216
268
 
217
269
 
218
270
  connection.disconnect()
@@ -229,9 +281,16 @@ class LocalServer(
229
281
  )
230
282
 
231
283
  } catch (e: Exception) {
232
- Log.e(
233
- TAG,
234
- "Proxy failed: ${e.javaClass.simpleName}"
284
+ AppDebugLogger.error(
285
+
286
+ context,
287
+
288
+ "API",
289
+
290
+ "Proxy failed",
291
+
292
+ e
293
+
235
294
  )
236
295
  return newFixedLengthResponse(
237
296
 
@@ -3,7 +3,6 @@ package com.pakstr.app
3
3
  import android.Manifest
4
4
  import android.content.Intent
5
5
  import android.os.Bundle
6
- import android.util.Log
7
6
 
8
7
  import android.view.View
9
8
  import android.webkit.PermissionRequest
@@ -18,6 +17,10 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
18
17
  import androidx.core.view.ViewCompat
19
18
  import androidx.core.view.WindowInsetsCompat
20
19
  import androidx.core.view.updatePadding
20
+ import com.pakstr.app.debug.AppDebugLogger
21
+
22
+ import com.pakstr.app.debug.DebugReportShare
23
+ import com.pakstr.app.debug.DeveloperToolsManager
21
24
 
22
25
  import com.pakstr.app.permissions.PermissionManager
23
26
  import com.pakstr.app.permissions.interfaces.PermissionHandler
@@ -38,17 +41,26 @@ class MainActivity : AppCompatActivity(), PermissionHandler {
38
41
  private lateinit var amberLauncher:
39
42
  ActivityResultLauncher<Intent>
40
43
 
41
-
42
- private val TAG = "ShellRuntime"
43
-
44
44
  override fun onCreate(
45
+
45
46
  savedInstanceState: Bundle?
47
+
46
48
  ) {
47
49
 
48
50
  installSplashScreen()
51
+
49
52
  enableEdgeToEdge()
50
53
 
51
54
  super.onCreate(savedInstanceState)
55
+ AppDebugLogger.log(
56
+
57
+ this,
58
+
59
+ "SESSION",
60
+
61
+ "========== APP START =========="
62
+
63
+ )
52
64
 
53
65
  if (BuildConfig.DEBUG) {
54
66
 
@@ -57,45 +69,63 @@ class MainActivity : AppCompatActivity(), PermissionHandler {
57
69
  }
58
70
 
59
71
  setContentView(
72
+
60
73
  R.layout.activity_layout
74
+
61
75
  )
62
76
 
63
77
  initViews()
64
78
 
65
79
  amberLauncher =
80
+
66
81
  registerForActivityResult(
82
+
67
83
  ActivityResultContracts.StartActivityForResult()
84
+
68
85
  ) { result ->
86
+
69
87
  signerManager.handleAmberResult(result)
88
+
70
89
  }
71
90
 
72
91
  initSigner()
92
+
73
93
  signerManager.setActiveType(
94
+
74
95
  SignerType.AMBER
96
+
75
97
  )
76
- //if (AppPreferences.getBoolean("isFirstRun", true)) {
77
- //showSignerPicker()
78
- //}
79
98
 
80
99
  ViewCompat.setOnApplyWindowInsetsListener(
100
+
81
101
  container
102
+
82
103
  ) { view, insets ->
83
104
 
84
105
  val bars =
106
+
85
107
  insets.getInsets(
108
+
86
109
  WindowInsetsCompat.Type.systemBars()
110
+
87
111
  )
88
112
 
89
113
  view.updatePadding(
114
+
90
115
  top = bars.top,
116
+
91
117
  bottom = bars.bottom
118
+
92
119
  )
120
+
93
121
  insets
94
- }
95
122
 
123
+ }
96
124
 
97
125
  setupRuntime()
126
+
98
127
  setupBackNavigation()
128
+
99
129
  showLoader(true)
100
130
 
101
131
  runtime.start()
@@ -143,16 +173,17 @@ class MainActivity : AppCompatActivity(), PermissionHandler {
143
173
 
144
174
  container =
145
175
  findViewById(R.id.mainContainer)
176
+
146
177
  webView =
147
178
  findViewById(R.id.webView)
148
179
 
149
180
  loader =
150
181
  findViewById(R.id.loader)
151
182
 
183
+
152
184
  permissionManager =
153
185
  PermissionManager(this)
154
186
 
155
- WebView.setWebContentsDebuggingEnabled(true)
156
187
  }
157
188
 
158
189
  private fun handleSignerSetup() {
@@ -230,4 +261,10 @@ class MainActivity : AppCompatActivity(), PermissionHandler {
230
261
  if (show) View.VISIBLE
231
262
  else View.GONE
232
263
  }
264
+
265
+ private fun exportDebugReport() {
266
+
267
+ DebugReportShare.share(this)
268
+
269
+ }
233
270
  }
@@ -3,6 +3,7 @@ package com.pakstr.app
3
3
  import android.content.Context
4
4
  import android.util.Log
5
5
  import org.json.JSONObject
6
+ import com.pakstr.app.debug.DebugConfig
6
7
 
7
8
  object RuntimeConfig {
8
9
 
@@ -10,7 +11,6 @@ object RuntimeConfig {
10
11
 
11
12
  private var config: JSONObject? = null
12
13
 
13
-
14
14
  fun load(context: Context): JSONObject {
15
15
 
16
16
  config?.let {
@@ -21,14 +21,12 @@ object RuntimeConfig {
21
21
 
22
22
  config = try {
23
23
 
24
- val input =
25
- context.assets.open(
26
- "www/pakstr-runtime.json"
27
- )
24
+ val input = context.assets.open(
25
+ "www/pakstr-runtime.json"
26
+ )
28
27
 
29
- val json =
30
- input.bufferedReader()
31
- .use { it.readText() }
28
+ val json = input.bufferedReader()
29
+ .use { it.readText() }
32
30
 
33
31
 
34
32
  JSONObject(json)
@@ -36,9 +34,7 @@ object RuntimeConfig {
36
34
  } catch (e: Exception) {
37
35
 
38
36
  Log.e(
39
- TAG,
40
- "Failed loading runtime config",
41
- e
37
+ TAG, "Failed loading runtime config", e
42
38
  )
43
39
 
44
40
  JSONObject()
@@ -47,15 +43,13 @@ object RuntimeConfig {
47
43
 
48
44
 
49
45
  Log.d(
50
- TAG,
51
- "FINAL CONFIG: $config"
46
+ TAG, "FINAL CONFIG: $config"
52
47
  )
53
48
 
54
49
 
55
50
  return config!!
56
51
  }
57
52
 
58
-
59
53
  /**
60
54
  * Returns backend API URL.
61
55
  *
@@ -67,17 +61,13 @@ object RuntimeConfig {
67
61
  context: Context
68
62
  ): String? {
69
63
 
70
- val value =
71
- load(context)
72
- .optString(
73
- "apiBase",
74
- ""
75
- )
64
+ val value = load(context).optString(
65
+ "apiBase", ""
66
+ )
76
67
 
77
68
 
78
69
  Log.d(
79
- TAG,
80
- "apiBase=$value"
70
+ TAG, "apiBase=$value"
81
71
  )
82
72
 
83
73
 
@@ -86,7 +76,6 @@ object RuntimeConfig {
86
76
  }
87
77
  }
88
78
 
89
-
90
79
  /**
91
80
  * Determines if REST API proxy should be enabled.
92
81
  */
@@ -94,20 +83,17 @@ object RuntimeConfig {
94
83
  context: Context
95
84
  ): Boolean {
96
85
 
97
- val enabled =
98
- !apiBase(context).isNullOrBlank()
86
+ val enabled = !apiBase(context).isNullOrBlank()
99
87
 
100
88
 
101
89
  Log.d(
102
- TAG,
103
- "apiEnabled=$enabled"
90
+ TAG, "apiEnabled=$enabled"
104
91
  )
105
92
 
106
93
 
107
94
  return enabled
108
95
  }
109
96
 
110
-
111
97
  /**
112
98
  * Nostr relay URL.
113
99
  */
@@ -115,24 +101,59 @@ object RuntimeConfig {
115
101
  context: Context
116
102
  ): String {
117
103
 
118
- val relay =
104
+ val relay = load(context).optString(
105
+ "relayUrl", ""
106
+ )
107
+
108
+
109
+ Log.d(
110
+ TAG, "relayUrl=$relay"
111
+ )
112
+
113
+
114
+ return relay
115
+ }
116
+
117
+ /**
118
+
119
+ * Determines if developer debug tools are enabled.
120
+
121
+ */
122
+
123
+ fun debugEnabled(
124
+
125
+ context: Context
126
+
127
+ ): Boolean {
128
+
129
+ val enabled =
130
+
119
131
  load(context)
120
- .optString(
121
- "relayUrl",
122
- ""
132
+
133
+ .optJSONObject("debug")
134
+
135
+ ?.optBoolean(
136
+
137
+ "enabled",
138
+
139
+ false
140
+
123
141
  )
124
142
 
143
+ ?: false
125
144
 
126
145
  Log.d(
146
+
127
147
  TAG,
128
- "relayUrl=$relay"
148
+
149
+ "debugEnabled=$enabled"
150
+
129
151
  )
130
152
 
153
+ return enabled
131
154
 
132
- return relay
133
155
  }
134
156
 
135
-
136
157
  /**
137
158
  * Clears cached config.
138
159
  * Useful for testing after changing pakstr-runtime.json.
@@ -142,8 +163,31 @@ object RuntimeConfig {
142
163
  config = null
143
164
 
144
165
  Log.d(
145
- TAG,
146
- "Config cache cleared"
166
+ TAG, "Config cache cleared"
167
+ )
168
+ }
169
+
170
+ fun debugConfig(
171
+ context: Context
172
+ ): DebugConfig {
173
+
174
+ val debug = load(context).optJSONObject("debug") ?: return DebugConfig()
175
+
176
+
177
+ return DebugConfig(
178
+
179
+ enabled = debug.optBoolean(
180
+ "enabled", false
181
+ ),
182
+
183
+ networkLogs = debug.optBoolean(
184
+ "networkLogs", false
185
+ ),
186
+
187
+ webViewLogs = debug.optBoolean(
188
+ "webViewLogs", false
189
+ ),
190
+
147
191
  )
148
192
  }
149
193
  }