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
@@ -26,6 +26,12 @@ class ShellRuntime(
26
26
 
27
27
  fun start() {
28
28
 
29
+ AppDebugLogger.log(
30
+ context,
31
+ "RUNTIME",
32
+ "Starting ShellRuntime"
33
+ )
34
+
29
35
  controller = WebViewController(
30
36
  context,
31
37
  webView,
@@ -34,14 +40,28 @@ class ShellRuntime(
34
40
  permissionHandler
35
41
  )
36
42
 
43
+ AppDebugLogger.log(
44
+ context,
45
+ "RUNTIME",
46
+ "WebViewController created"
47
+ )
48
+
49
+
37
50
  CoroutineScope(Dispatchers.IO).launch {
38
51
 
52
+ AppDebugLogger.log(
53
+ context,
54
+ "RUNTIME",
55
+ "Starting background initialization"
56
+ )
57
+
39
58
  val ok = startServer()
40
59
 
41
60
 
42
61
  if (!ok) {
43
62
 
44
- AppDebugLogger.log(
63
+ AppDebugLogger.error(
64
+ context,
45
65
  "RUNTIME",
46
66
  "Server failed"
47
67
  )
@@ -51,22 +71,53 @@ class ShellRuntime(
51
71
  }
52
72
 
53
73
 
74
+ AppDebugLogger.log(
75
+ context,
76
+ "RUNTIME",
77
+ "Server ready, switching to main thread"
78
+ )
79
+
80
+
54
81
  withContext(Dispatchers.Main) {
55
82
 
83
+ AppDebugLogger.log(
84
+ context,
85
+ "WEBVIEW",
86
+ "Setting up WebView controller"
87
+ )
88
+
56
89
  controller.setup()
57
90
 
91
+ AppDebugLogger.log(
92
+ context,
93
+ "WEBVIEW",
94
+ "WebView controller setup completed"
95
+ )
96
+
58
97
  }
59
98
 
60
99
  }
61
100
 
62
101
  }
63
102
 
64
-
65
103
  private fun startServer(): Boolean {
66
104
 
67
- if (server != null)
105
+ if (server != null) {
106
+
107
+ AppDebugLogger.log(
108
+
109
+ context,
110
+
111
+ "SERVER",
112
+
113
+ "Already running"
114
+
115
+ )
116
+
68
117
  return true
69
118
 
119
+ }
120
+
70
121
  return try {
71
122
 
72
123
  server = LocalServer(
@@ -80,32 +131,72 @@ class ShellRuntime(
80
131
  )
81
132
 
82
133
  AppDebugLogger.log(
134
+
135
+ context,
136
+
83
137
  "SERVER",
84
- "Started OK"
138
+
139
+ "Starting NanoHTTPD on port $port"
140
+
85
141
  )
86
142
 
87
143
  true
88
144
 
89
145
  } catch (e: Exception) {
90
146
 
91
- AppDebugLogger.log(
147
+ AppDebugLogger.error(
148
+
149
+ context,
150
+
92
151
  "SERVER",
93
- "Failed to start: ${e.message}"
152
+
153
+ "Failed to start",
154
+
155
+ e
156
+
94
157
  )
95
158
 
96
159
  false
97
160
  }
98
161
  }
99
162
 
100
-
101
163
  fun stop() {
102
164
 
165
+ AppDebugLogger.log(
166
+
167
+ context,
168
+
169
+ "RUNTIME",
170
+
171
+ "Stopping ShellRuntime"
172
+
173
+ )
174
+
103
175
  server?.stop()
104
176
 
177
+ AppDebugLogger.log(
178
+
179
+ context,
180
+
181
+ "SERVER",
182
+
183
+ "Server stopped"
184
+
185
+ )
186
+
105
187
  controller.destroy()
106
188
 
107
- }
189
+ AppDebugLogger.log(
190
+
191
+ context,
192
+
193
+ "WEBVIEW",
108
194
 
195
+ "WebView destroyed"
196
+
197
+ )
198
+
199
+ }
109
200
 
110
201
  fun getWebview(): WebView {
111
202
 
@@ -43,6 +43,7 @@ class WebViewController(
43
43
  private val loadRunnable = Runnable {
44
44
  webView.loadUrl("http://127.0.0.1:$port/")
45
45
  //webView.loadUrl("https://sigit.io")
46
+ //webView.loadUrl("http://127.0.0.1:$port/not-found.html")
46
47
  }
47
48
 
48
49
  private var nip07Injected = false
@@ -73,23 +74,116 @@ class WebViewController(
73
74
  displayZoomControls = false
74
75
 
75
76
  mixedContentMode = android.webkit.WebSettings.MIXED_CONTENT_NEVER_ALLOW
77
+
78
+ // Better mobile rendering
79
+ useWideViewPort = true
80
+ loadWithOverviewMode = true
81
+ textZoom = 100
76
82
  }
77
83
 
78
84
  // Standard clients are enough since overriding URL loading isn't required
79
85
  webViewClient = object : WebViewClient() {
80
86
 
81
87
  override fun onPageFinished(
82
- view: WebView?,
83
- url: String?
88
+ view: WebView?, url: String?
84
89
  ) {
85
90
  super.onPageFinished(view, url)
86
91
 
87
92
  hideLoader()
88
93
 
89
94
  if (!nip07Injected) {
90
- nip07Injected =
91
- injectNip07()
95
+ nip07Injected = injectNip07()
96
+
97
+ }
98
+ }
99
+
100
+ override fun onReceivedHttpError(
101
+
102
+ view: WebView?,
103
+
104
+ request: WebResourceRequest?,
105
+
106
+ errorResponse: WebResourceResponse?
107
+
108
+ ) {
109
+
110
+ super.onReceivedHttpError(
111
+
112
+ view,
113
+
114
+ request,
115
+
116
+ errorResponse
117
+
118
+ )
119
+
120
+ val url =
121
+
122
+ request?.url?.toString()
123
+
124
+ ?: return
92
125
 
126
+ if (url.endsWith("favicon.ico")) {
127
+
128
+ return
129
+
130
+ }
131
+ if (AppDebugLogger.isWebViewLoggingEnabled(context)) {
132
+ AppDebugLogger.error(
133
+
134
+ context,
135
+
136
+ "WEBVIEW",
137
+
138
+ "HTTP error: $url status=${errorResponse?.statusCode}"
139
+
140
+ )
141
+ }
142
+ }
143
+
144
+ override fun onReceivedError(
145
+
146
+ view: WebView?,
147
+
148
+ request: WebResourceRequest?,
149
+
150
+ error: android.webkit.WebResourceError?
151
+
152
+ ) {
153
+
154
+ super.onReceivedError(
155
+
156
+ view,
157
+
158
+ request,
159
+
160
+ error
161
+
162
+ )
163
+
164
+ val url =
165
+
166
+ request?.url?.toString()
167
+
168
+ ?: "unknown"
169
+
170
+ val message =
171
+
172
+ error?.description
173
+
174
+ ?.toString()
175
+
176
+ ?: "unknown error"
177
+ if (AppDebugLogger.isWebViewLoggingEnabled(context)) {
178
+ AppDebugLogger.error(
179
+
180
+ context,
181
+
182
+ "WEBVIEW",
183
+
184
+ "Load error: $url - $message"
185
+
186
+ )
93
187
  }
94
188
  }
95
189
 
@@ -105,22 +199,60 @@ class WebViewController(
105
199
  }
106
200
 
107
201
  override fun shouldOverrideUrlLoading(
108
- view: WebView?,
109
- request: WebResourceRequest?
202
+ view: WebView?, request: WebResourceRequest?
110
203
  ): Boolean {
111
204
  val url = request?.url ?: return true
112
205
  return url.host != "127.0.0.1"
113
206
  }
114
207
 
115
-
116
208
  }
117
209
  webChromeClient = object : WebChromeClient() {
118
210
 
119
- override fun onPermissionRequest(request: PermissionRequest) {
211
+ override fun onPermissionRequest(
212
+
213
+ request: PermissionRequest
214
+
215
+ ) {
120
216
 
121
217
  permissionHandler.onPermissionRequest(request)
122
218
 
123
219
  }
220
+
221
+ override fun onConsoleMessage(
222
+
223
+ consoleMessage: android.webkit.ConsoleMessage
224
+
225
+ ): Boolean {
226
+
227
+ val level =
228
+
229
+ when (consoleMessage.messageLevel()) {
230
+
231
+ android.webkit.ConsoleMessage.MessageLevel.ERROR -> "ERROR"
232
+
233
+ android.webkit.ConsoleMessage.MessageLevel.WARNING -> "WARN"
234
+
235
+ android.webkit.ConsoleMessage.MessageLevel.LOG -> "LOG"
236
+
237
+ else -> "DEBUG"
238
+ }
239
+ if (AppDebugLogger.isWebViewLoggingEnabled(context)) {
240
+ AppDebugLogger.log(
241
+
242
+ context,
243
+
244
+ "WEBVIEW",
245
+
246
+ "$level: ${consoleMessage.message()} " +
247
+
248
+ "(${consoleMessage.sourceId()}:${consoleMessage.lineNumber()})"
249
+
250
+ )
251
+ }
252
+ return true
253
+
254
+ }
255
+
124
256
  }
125
257
  }
126
258
 
@@ -134,7 +266,7 @@ class WebViewController(
134
266
 
135
267
  webView = webView,
136
268
 
137
- ),
269
+ ),
138
270
 
139
271
  "AndroidBridge"
140
272
 
@@ -194,22 +326,20 @@ class WebViewController(
194
326
  private fun injectNip07(): Boolean {
195
327
 
196
328
  return try {
197
- val js =
198
- context.assets
199
- .open("nip07.js")
200
- .bufferedReader()
201
- .readText()
329
+ val js = context.assets.open("nip07.js")
330
+ .bufferedReader()
331
+ .readText()
202
332
 
203
333
  webView.evaluateJavascript(
204
- js,
205
- null
334
+ js, null
206
335
  )
207
336
  true
208
337
  } catch (e: Exception) {
209
- AppDebugLogger.log(
210
- "WEBVIEW",
211
- "Failed loading nip07.js: ${e.message}"
212
- )
338
+ if (AppDebugLogger.isWebViewLoggingEnabled(context)) {
339
+ AppDebugLogger.log(
340
+ context, "WebViewController - WEBVIEW", "Failed loading nip07.js: ${e.message}"
341
+ )
342
+ }
213
343
  false
214
344
  }
215
345
  }
@@ -146,11 +146,6 @@ object Bip340Verifier {
146
146
 
147
147
  } catch (e: Exception) {
148
148
 
149
- AppDebugLogger.log(
150
- "BIP340",
151
- "Verification failed: ${e.message}"
152
- )
153
-
154
149
  false
155
150
 
156
151
  }
@@ -1,21 +1,293 @@
1
1
  package com.pakstr.app.debug
2
2
 
3
+ import android.content.Context
3
4
  import android.util.Log
4
5
  import com.pakstr.app.BuildConfig
6
+ import com.pakstr.app.RuntimeConfig
7
+ import java.text.SimpleDateFormat
8
+ import java.util.Date
9
+ import java.util.Locale
5
10
 
6
11
  object AppDebugLogger {
7
12
 
13
+ private const val TAG = "PakstrDebug"
14
+
15
+ private const val MAX_LOGS = 500
16
+
17
+ private val logs =
18
+ mutableListOf<String>()
19
+
8
20
  fun log(
21
+ context: Context,
9
22
  tag: String,
10
23
  message: String
11
24
  ) {
12
25
 
13
- if (BuildConfig.DEBUG) {
26
+ if (!isDebugEnabled(context)) {
27
+ return
28
+ }
14
29
 
15
- Log.d(
16
- tag,
30
+ save(
31
+ context,
32
+ "DEBUG",
33
+ tag,
34
+ message
35
+ )
36
+
37
+ Log.d(
38
+ TAG,
39
+ "[$tag] $message"
40
+ )
41
+ }
42
+
43
+ fun error(
44
+ context: Context,
45
+ tag: String,
46
+ message: String,
47
+ throwable: Throwable? = null
48
+ ) {
49
+ if (!isDebugEnabled(context)) {
50
+ return
51
+ }
52
+ val fullMessage =
53
+ if (throwable != null) {
54
+ "$message\n${Log.getStackTraceString(throwable)}"
55
+ } else {
17
56
  message
57
+ }
58
+
59
+
60
+ save(
61
+ context,
62
+ "ERROR",
63
+ tag,
64
+ fullMessage
65
+ )
66
+
67
+
68
+ Log.e(
69
+ TAG,
70
+ "[$tag] $message",
71
+ throwable
72
+ )
73
+ }
74
+
75
+ private fun save(
76
+ context: Context,
77
+ level: String,
78
+ tag: String,
79
+ message: String
80
+ ) {
81
+
82
+ val sanitized =
83
+ sanitize(message)
84
+
85
+ val entry =
86
+ format(
87
+ level,
88
+ tag,
89
+ sanitized
18
90
  )
91
+
92
+
93
+ logs.add(entry)
94
+
95
+
96
+ DebugLogStorage.append(
97
+ context,
98
+ entry
99
+ )
100
+
101
+
102
+ trim()
103
+ }
104
+
105
+ fun getLogs(): List<String> {
106
+
107
+ return logs.toList()
108
+
109
+ }
110
+
111
+ fun clear() {
112
+
113
+ logs.clear()
114
+
115
+ }
116
+
117
+ private fun isDebugEnabled(
118
+
119
+ context: Context
120
+
121
+ ): Boolean {
122
+
123
+ return BuildConfig.DEBUG ||
124
+
125
+ config(context).enabled
126
+
127
+ }
128
+
129
+ private fun sanitize(
130
+ message: String
131
+ ): String {
132
+
133
+ // Debug build može vidjeti sve
134
+ if (BuildConfig.DEBUG) {
135
+ return message
19
136
  }
137
+
138
+ // Release build uvijek sanitizira
139
+ return message
140
+ .replace(
141
+ Regex(
142
+ "\"plaintext\"\\s*:\\s*\".*?\""
143
+ ),
144
+ "\"plaintext\":\"***\""
145
+ )
146
+ .replace(
147
+ Regex(
148
+ "\"ciphertext\"\\s*:\\s*\".*?\""
149
+ ),
150
+ "\"ciphertext\":\"***\""
151
+ )
152
+ .replace(
153
+ Regex(
154
+ "\"sig\"\\s*:\\s*\".*?\""
155
+ ),
156
+ "\"sig\":\"***\""
157
+ )
158
+ .replace(
159
+ Regex(
160
+ "\"event\"\\s*:\\s*\".*?\""
161
+ ),
162
+ "\"event\":\"***\""
163
+ )
164
+ .replace(
165
+ Regex(
166
+ "(?i)authorization: .*"
167
+ ),
168
+ "authorization: ***"
169
+ )
170
+ .replace(
171
+ Regex(
172
+ "(?i)bearer\\s+[A-Za-z0-9._-]+"
173
+ ),
174
+ "Bearer ***"
175
+ )
176
+ .replace(
177
+ Regex(
178
+ "(?i)token=[^\\s&]+"
179
+ ),
180
+ "token=***"
181
+ )
182
+ .replace(
183
+ Regex(
184
+ "(?i)password=[^\\s&]+"
185
+ ),
186
+ "password=***"
187
+ )
188
+ }
189
+
190
+ private fun format(
191
+ level: String,
192
+ tag: String,
193
+ message: String
194
+ ): String {
195
+
196
+ val time =
197
+ SimpleDateFormat(
198
+ "yyyy-MM-dd HH:mm:ss",
199
+ Locale.US
200
+ )
201
+ .format(Date())
202
+
203
+
204
+ return "$time [$level] $tag: $message"
205
+
206
+ }
207
+
208
+ private fun trim() {
209
+
210
+ while (logs.size > MAX_LOGS) {
211
+
212
+ logs.removeAt(0)
213
+
214
+ }
215
+
216
+ }
217
+
218
+ private fun isDevelopmentBuild(): Boolean {
219
+ return BuildConfig.DEBUG
220
+ }
221
+
222
+ private fun isProductionDebug(context: Context): Boolean {
223
+ return !BuildConfig.DEBUG &&
224
+ RuntimeConfig.debugEnabled(context)
225
+ }
226
+
227
+ fun isNetworkLoggingEnabled(
228
+
229
+ context: Context
230
+
231
+ ): Boolean {
232
+
233
+ return BuildConfig.DEBUG ||
234
+
235
+ config(context).networkLogs
236
+
237
+ }
238
+
239
+ fun isWebViewLoggingEnabled(
240
+
241
+ context: Context
242
+
243
+ ): Boolean {
244
+
245
+ return BuildConfig.DEBUG ||
246
+
247
+ config(context).webViewLogs
248
+
249
+ }
250
+
251
+ fun network(
252
+ context: Context,
253
+ message: String
254
+ ) {
255
+ if (!isNetworkLoggingEnabled(context)) {
256
+ return
257
+ }
258
+
259
+ log(
260
+ context,
261
+ "HTTP",
262
+ message
263
+ )
264
+ }
265
+
266
+
267
+ fun webView(
268
+ context: Context,
269
+ message: String
270
+ ) {
271
+ if (!isWebViewLoggingEnabled(context)) {
272
+ return
273
+ }
274
+
275
+ log(
276
+ context,
277
+ "WEBVIEW",
278
+ message
279
+ )
280
+ }
281
+
282
+ private fun config(
283
+
284
+ context: Context
285
+
286
+ ): DebugConfig {
287
+
288
+ return DebugRuntimeOverride.get()
289
+
290
+ ?: RuntimeConfig.debugConfig(context)
291
+
20
292
  }
21
293
  }