pakstr 0.3.4 → 0.5.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 (34) hide show
  1. package/android-template/app/build.gradle.kts +71 -4
  2. package/android-template/app/proguard-rules.pro +21 -18
  3. package/android-template/app/src/main/AndroidManifest.xml +17 -0
  4. package/android-template/app/src/main/java/com/pakstr/app/ApplicationClass.kt +14 -0
  5. package/android-template/app/src/main/java/com/pakstr/app/LocalServer.kt +80 -21
  6. package/android-template/app/src/main/java/com/pakstr/app/MainActivity.kt +61 -11
  7. package/android-template/app/src/main/java/com/pakstr/app/RuntimeConfig.kt +81 -37
  8. package/android-template/app/src/main/java/com/pakstr/app/ShellRuntime.kt +100 -9
  9. package/android-template/app/src/main/java/com/pakstr/app/WebViewController.kt +280 -20
  10. package/android-template/app/src/main/java/com/pakstr/app/crypto/Bip340Verifier.kt +0 -5
  11. package/android-template/app/src/main/java/com/pakstr/app/debug/AppDebugLogger.kt +348 -3
  12. package/android-template/app/src/main/java/com/pakstr/app/debug/CrashHandler.kt +32 -0
  13. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugConfig.kt +11 -0
  14. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugConfigLoader.kt +36 -0
  15. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugConfigProvider.kt +29 -0
  16. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugLogStorage.kt +139 -0
  17. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugPreferences.kt +85 -0
  18. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugReportExporter.kt +149 -0
  19. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugReportShare.kt +52 -0
  20. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugRuntimeOverride.kt +55 -0
  21. package/android-template/app/src/main/java/com/pakstr/app/debug/DebugSession.kt +16 -0
  22. package/android-template/app/src/main/java/com/pakstr/app/debug/DeveloperToolsManager.kt +63 -0
  23. package/android-template/app/src/main/java/com/pakstr/app/debug/WebViewDebugManager.kt +30 -0
  24. package/android-template/app/src/main/java/com/pakstr/app/debug/logging/PakstrLog.kt +16 -0
  25. package/android-template/app/src/main/java/com/pakstr/app/debug/logging/PakstrLogger.kt +154 -0
  26. package/android-template/app/src/main/java/com/pakstr/app/signer/AmberSigner.kt +1 -10
  27. package/android-template/app/src/main/java/com/pakstr/app/signer/NostrBridge.kt +163 -11
  28. package/android-template/app/src/main/java/com/pakstr/app/signer/SignerManager.kt +71 -0
  29. package/android-template/app/src/main/res/xml/file_paths.xml +9 -0
  30. package/android-template/gradle/libs.versions.toml +1 -0
  31. package/android-template/gradle.properties +2 -1
  32. package/dist/runners/LocalGradleRunner.js +12 -2
  33. package/dist/runtime/runtimeConfig.js +6 -1
  34. package/package.json +1 -1
@@ -1,12 +1,59 @@
1
+ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
2
+ import java.util.Properties
3
+ import java.io.File
4
+
1
5
  plugins {
2
6
  alias(libs.plugins.android.application)
3
7
  alias(libs.plugins.kotlin.compose)
4
8
  }
5
9
 
10
+ val keystoreProperties =
11
+
12
+ Properties()
13
+
14
+ val keystorePath =
15
+ providers.gradleProperty(
16
+ "releaseKeystoreConfig"
17
+ ).orNull
18
+
19
+ val keystorePropertiesFile =
20
+ keystorePath?.let { rootProject.file(it) }
21
+ if (keystorePropertiesFile?.exists() == true) {
22
+
23
+ keystorePropertiesFile.inputStream()
24
+ .use {
25
+ keystoreProperties.load(it)
26
+ }
27
+ }
28
+
6
29
  android {
7
30
  namespace = "com.pakstr.app"
8
31
  compileSdk = 36
9
32
 
33
+ signingConfigs {
34
+
35
+ create("release") {
36
+
37
+ if (keystorePropertiesFile?.exists() == true) {
38
+
39
+ storeFile =
40
+ File(
41
+ keystorePropertiesFile.parentFile,
42
+ keystoreProperties["storeFile"] as String
43
+ )
44
+
45
+ storePassword =
46
+ keystoreProperties["storePassword"] as String
47
+
48
+ keyAlias =
49
+ keystoreProperties["keyAlias"] as String
50
+
51
+ keyPassword =
52
+ keystoreProperties["keyPassword"] as String
53
+ }
54
+ }
55
+ }
56
+
10
57
  defaultConfig {
11
58
  applicationId = "com.pakstr.app"
12
59
  minSdk = 28
@@ -18,23 +65,43 @@ android {
18
65
  }
19
66
 
20
67
  buildTypes {
68
+
69
+ debug {
70
+ applicationIdSuffix = ".debug"
71
+ versionNameSuffix = "-debug"
72
+ }
73
+
21
74
  release {
22
- isMinifyEnabled = false
75
+ signingConfig =
76
+ signingConfigs.getByName("release")
77
+ isMinifyEnabled = true
78
+ isShrinkResources = true
23
79
  proguardFiles(
24
- getDefaultProguardFile("proguard-android-optimize.txt"),
80
+ getDefaultProguardFile(
81
+ "proguard-android-optimize.txt"
82
+ ),
25
83
  "proguard-rules.pro"
26
84
  )
27
85
  }
28
86
  }
29
87
  compileOptions {
30
- sourceCompatibility = JavaVersion.VERSION_11
31
- targetCompatibility = JavaVersion.VERSION_11
88
+ sourceCompatibility = JavaVersion.VERSION_17
89
+ targetCompatibility = JavaVersion.VERSION_17
32
90
  }
91
+
33
92
  buildFeatures {
34
93
  compose = true
35
94
  buildConfig = true
36
95
  }
37
96
  }
97
+ tasks.withType<KotlinCompile>()
98
+ .configureEach {
99
+ compilerOptions {
100
+ jvmTarget.set(
101
+ org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
102
+ )
103
+ }
104
+ }
38
105
 
39
106
  dependencies {
40
107
  implementation(libs.androidx.core.ktx)
@@ -1,21 +1,24 @@
1
- # Add project specific ProGuard rules here.
2
- # You can control the set of applied configuration files using the
3
- # proguardFiles setting in build.gradle.
4
- #
5
- # For more details, see
6
- # http://developer.android.com/guide/developing/tools/proguard.html
1
+ # JavaScript bridge
2
+ -keepclassmembers class * {
3
+ @android.webkit.JavascriptInterface <methods>;
4
+ }
7
5
 
8
- # If your project uses WebView with JS, uncomment the following
9
- # and specify the fully qualified class name to the JavaScript interface
10
- # class:
11
- #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12
- # public *;
13
- #}
6
+ # Nostr signer
7
+ -keep class com.pakstr.app.signer.** { *; }
14
8
 
15
- # Uncomment this to preserve the line number information for
16
- # debugging stack traces.
17
- #-keepattributes SourceFile,LineNumberTable
9
+ # Crypto
10
+ -keep class com.pakstr.app.crypto.** { *; }
18
11
 
19
- # If you keep the line number information, uncomment this to
20
- # hide the original source file name.
21
- #-renamesourcefileattribute SourceFile
12
+ # BouncyCastle
13
+ -keep class org.bouncycastle.crypto.** { *; }
14
+ -keep class org.bouncycastle.math.** { *; }
15
+ -keep class org.bouncycastle.asn1.** { *; }
16
+
17
+ # Ignore unavailable Java SE classes
18
+ -dontwarn javax.naming.**
19
+
20
+ # Keep Application class
21
+ -keep class com.pakstr.app.ApplicationClass { *; }
22
+
23
+ # Keep model classes used through JSON
24
+ -keep class com.pakstr.app.signer.** { *; }
@@ -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>
@@ -2,6 +2,9 @@ package com.pakstr.app
2
2
 
3
3
  import android.app.Application
4
4
  import com.pakstr.app.crypto.CryptoInitializer
5
+ import com.pakstr.app.debug.AppDebugLogger
6
+ import com.pakstr.app.debug.CrashHandler
7
+ import com.pakstr.app.debug.DebugSession
5
8
  import com.pakstr.app.utils.AppPreferences
6
9
 
7
10
  class ApplicationClass : Application() {
@@ -9,5 +12,16 @@ class ApplicationClass : Application() {
9
12
  super.onCreate()
10
13
  AppPreferences.init(this)
11
14
  CryptoInitializer.init()
15
+ CrashHandler.install(this)
16
+
17
+ AppDebugLogger.log(
18
+
19
+ this,
20
+
21
+ "SESSION",
22
+
23
+ "Session started: ${DebugSession.sessionId}"
24
+
25
+ )
12
26
  }
13
27
  }
@@ -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,12 @@ 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
+ import com.pakstr.app.debug.CrashHandler
22
+
23
+ import com.pakstr.app.debug.DebugReportShare
24
+ import com.pakstr.app.debug.DeveloperToolsManager
25
+ import com.pakstr.app.debug.WebViewDebugManager
21
26
 
22
27
  import com.pakstr.app.permissions.PermissionManager
23
28
  import com.pakstr.app.permissions.interfaces.PermissionHandler
@@ -38,64 +43,102 @@ class MainActivity : AppCompatActivity(), PermissionHandler {
38
43
  private lateinit var amberLauncher:
39
44
  ActivityResultLauncher<Intent>
40
45
 
41
-
42
- private val TAG = "ShellRuntime"
43
-
44
46
  override fun onCreate(
47
+
45
48
  savedInstanceState: Bundle?
49
+
46
50
  ) {
47
51
 
48
52
  installSplashScreen()
53
+
49
54
  enableEdgeToEdge()
50
55
 
51
56
  super.onCreate(savedInstanceState)
52
-
53
57
  if (BuildConfig.DEBUG) {
54
58
 
55
- WebView.setWebContentsDebuggingEnabled(true)
59
+ DeveloperToolsManager.enableDebug(this)
56
60
 
57
61
  }
58
62
 
63
+ WebViewDebugManager.enable(this)
64
+
65
+ AppDebugLogger.log(
66
+
67
+ this,
68
+
69
+ "TEST",
70
+
71
+ "Developer debug enabled"
72
+
73
+ )
74
+ AppDebugLogger.log(
75
+
76
+ this,
77
+
78
+ "SESSION",
79
+
80
+ "========== APP START =========="
81
+
82
+ )
83
+
59
84
  setContentView(
85
+
60
86
  R.layout.activity_layout
87
+
61
88
  )
62
89
 
63
90
  initViews()
64
91
 
65
92
  amberLauncher =
93
+
66
94
  registerForActivityResult(
95
+
67
96
  ActivityResultContracts.StartActivityForResult()
97
+
68
98
  ) { result ->
99
+
69
100
  signerManager.handleAmberResult(result)
101
+
70
102
  }
71
103
 
72
104
  initSigner()
105
+
73
106
  signerManager.setActiveType(
107
+
74
108
  SignerType.AMBER
109
+
75
110
  )
76
- //if (AppPreferences.getBoolean("isFirstRun", true)) {
77
- //showSignerPicker()
78
- //}
79
111
 
80
112
  ViewCompat.setOnApplyWindowInsetsListener(
113
+
81
114
  container
115
+
82
116
  ) { view, insets ->
83
117
 
84
118
  val bars =
119
+
85
120
  insets.getInsets(
121
+
86
122
  WindowInsetsCompat.Type.systemBars()
123
+
87
124
  )
88
125
 
89
126
  view.updatePadding(
127
+
90
128
  top = bars.top,
129
+
91
130
  bottom = bars.bottom
131
+
92
132
  )
133
+
93
134
  insets
94
- }
95
135
 
136
+ }
96
137
 
97
138
  setupRuntime()
139
+
98
140
  setupBackNavigation()
141
+
99
142
  showLoader(true)
100
143
 
101
144
  runtime.start()
@@ -143,16 +186,17 @@ class MainActivity : AppCompatActivity(), PermissionHandler {
143
186
 
144
187
  container =
145
188
  findViewById(R.id.mainContainer)
189
+
146
190
  webView =
147
191
  findViewById(R.id.webView)
148
192
 
149
193
  loader =
150
194
  findViewById(R.id.loader)
151
195
 
196
+
152
197
  permissionManager =
153
198
  PermissionManager(this)
154
199
 
155
- WebView.setWebContentsDebuggingEnabled(true)
156
200
  }
157
201
 
158
202
  private fun handleSignerSetup() {
@@ -230,4 +274,10 @@ class MainActivity : AppCompatActivity(), PermissionHandler {
230
274
  if (show) View.VISIBLE
231
275
  else View.GONE
232
276
  }
277
+
278
+ private fun exportDebugReport() {
279
+
280
+ DebugReportShare.share(this)
281
+
282
+ }
233
283
  }