pakstr 0.8.4 → 0.8.6

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.
@@ -190,7 +190,6 @@ class MainActivity : AppCompatActivity(), PermissionHandler {
190
190
 
191
191
  val remainingDuration = SupportUnlock.remainingDuration(this)
192
192
  if (!BuildConfig.DEBUG &&
193
- !RuntimeConfig.debugEnabled(this) &&
194
193
  remainingDuration > 0L
195
194
  ) {
196
195
  diagnosticsHandler.postDelayed(
@@ -14,7 +14,7 @@ object RuntimeConfig {
14
14
  fun load(context: Context): JSONObject {
15
15
 
16
16
  config?.let {
17
- Log.d(TAG, "Returning cached config: $it")
17
+ debug("Returning cached config")
18
18
  return it
19
19
  }
20
20
 
@@ -33,8 +33,9 @@ object RuntimeConfig {
33
33
 
34
34
  } catch (e: Exception) {
35
35
 
36
- Log.e(
37
- TAG, "Failed loading runtime config", e
36
+ debugError(
37
+ "Failed loading runtime config",
38
+ e
38
39
  )
39
40
 
40
41
  JSONObject()
@@ -42,9 +43,7 @@ object RuntimeConfig {
42
43
  }
43
44
 
44
45
 
45
- Log.d(
46
- TAG, "FINAL CONFIG: $config"
47
- )
46
+ debug("Runtime config loaded")
48
47
 
49
48
 
50
49
  return config!!
@@ -66,9 +65,7 @@ object RuntimeConfig {
66
65
  )
67
66
 
68
67
 
69
- Log.d(
70
- TAG, "apiBase=$value"
71
- )
68
+ debug("apiBase=$value")
72
69
 
73
70
 
74
71
  return value.takeIf {
@@ -86,9 +83,7 @@ object RuntimeConfig {
86
83
  val enabled = !apiBase(context).isNullOrBlank()
87
84
 
88
85
 
89
- Log.d(
90
- TAG, "apiEnabled=$enabled"
91
- )
86
+ debug("apiEnabled=$enabled")
92
87
 
93
88
 
94
89
  return enabled
@@ -106,9 +101,7 @@ object RuntimeConfig {
106
101
  )
107
102
 
108
103
 
109
- Log.d(
110
- TAG, "relayUrl=$relay"
111
- )
104
+ debug("relayUrl=$relay")
112
105
 
113
106
 
114
107
  return relay
@@ -142,13 +135,7 @@ object RuntimeConfig {
142
135
 
143
136
  ?: false
144
137
 
145
- Log.d(
146
-
147
- TAG,
148
-
149
- "debugEnabled=$enabled"
150
-
151
- )
138
+ debug("debugEnabled=$enabled")
152
139
 
153
140
  return enabled
154
141
 
@@ -162,9 +149,19 @@ object RuntimeConfig {
162
149
 
163
150
  config = null
164
151
 
165
- Log.d(
166
- TAG, "Config cache cleared"
167
- )
152
+ debug("Config cache cleared")
153
+ }
154
+
155
+ private fun debug(message: String) {
156
+ if (BuildConfig.DEBUG) {
157
+ Log.d(TAG, message)
158
+ }
159
+ }
160
+
161
+ private fun debugError(message: String, throwable: Throwable) {
162
+ if (BuildConfig.DEBUG) {
163
+ Log.e(TAG, message, throwable)
164
+ }
168
165
  }
169
166
 
170
167
  fun debugConfig(
@@ -95,7 +95,9 @@ class WebViewController(
95
95
  nip07Injected = injectNip07()
96
96
 
97
97
  }
98
- injectDebugLogger()
98
+ if (AppDebugLogger.isWebViewLoggingEnabled(context)) {
99
+ injectDebugLogger()
100
+ }
99
101
  }
100
102
 
101
103
  override fun onReceivedHttpError(
@@ -33,16 +33,18 @@ object AppDebugLogger {
33
33
  return
34
34
  }
35
35
 
36
+ val sanitized = sanitize(message)
37
+
36
38
  save(
37
39
  context,
38
40
  "DEBUG",
39
41
  tag,
40
- message
42
+ sanitized
41
43
  )
42
44
 
43
45
  Log.d(
44
46
  TAG,
45
- "[$tag] $message"
47
+ "[$tag] $sanitized"
46
48
  )
47
49
  }
48
50
 
@@ -61,20 +63,20 @@ object AppDebugLogger {
61
63
  } else {
62
64
  message
63
65
  }
66
+ val sanitized = sanitize(fullMessage)
64
67
 
65
68
 
66
69
  save(
67
70
  context,
68
71
  "ERROR",
69
72
  tag,
70
- fullMessage
73
+ sanitized
71
74
  )
72
75
 
73
76
 
74
77
  Log.e(
75
78
  TAG,
76
- "[$tag] $message",
77
- throwable
79
+ "[$tag] $sanitized"
78
80
  )
79
81
  }
80
82
 
@@ -85,14 +87,11 @@ object AppDebugLogger {
85
87
  message: String
86
88
  ) {
87
89
 
88
- val sanitized =
89
- sanitize(message)
90
-
91
90
  val entry =
92
91
  format(
93
92
  level,
94
93
  tag,
95
- sanitized
94
+ message
96
95
  )
97
96
 
98
97
 
@@ -136,64 +135,62 @@ object AppDebugLogger {
136
135
 
137
136
  }
138
137
 
139
- private fun sanitize(
138
+ internal fun sanitize(
140
139
  message: String
141
140
  ): String {
142
141
 
143
- // Debug build može vidjeti sve
144
142
  if (BuildConfig.DEBUG) {
145
143
  return message
146
144
  }
147
145
 
148
- // Release build uvijek sanitizira
149
146
  return message
150
147
  .replace(
151
148
  Regex(
152
- "\"plaintext\"\\s*:\\s*\".*?\""
153
- ),
154
- "\"plaintext\":\"***\""
155
- )
156
- .replace(
157
- Regex(
158
- "\"ciphertext\"\\s*:\\s*\".*?\""
159
- ),
160
- "\"ciphertext\":\"***\""
161
- )
149
+ "(?i)\"(plaintext|ciphertext|content|sig|signature|event|signing_?payload|private_?key|secret|seed|mnemonic|password|token|jwt|cookie|authorization)\"\\s*:\\s*\"(?:\\\\.|[^\"])*\""
150
+ )
151
+ ) { match ->
152
+ val key = match.groupValues[1]
153
+ "\"$key\":\"***\""
154
+ }
162
155
  .replace(
163
156
  Regex(
164
- "\"sig\"\\s*:\\s*\".*?\""
165
- ),
166
- "\"sig\":\"***\""
167
- )
157
+ "(?i)\"(event|signing_?payload)\"\\s*:\\s*(\\{[^\\r\\n]*}|\\[[^\\r\\n]*])"
158
+ )
159
+ ) { match ->
160
+ val key = match.groupValues[1]
161
+ "\"$key\":\"***\""
162
+ }
168
163
  .replace(
169
164
  Regex(
170
- "\"event\"\\s*:\\s*\".*?\""
171
- ),
172
- "\"event\":\"***\""
173
- )
165
+ "(?i)(authorization|proxy-authorization|cookie|set-cookie)\\s*:\\s*[^\\r\\n]+"
166
+ )
167
+ ) { match ->
168
+ "${match.groupValues[1]}: ***"
169
+ }
174
170
  .replace(
175
171
  Regex(
176
- "(?i)authorization: .*"
172
+ "(?i)bearer\\s+[^\\s,;]+"
177
173
  ),
178
- "authorization: ***"
174
+ "Bearer ***"
179
175
  )
180
176
  .replace(
181
177
  Regex(
182
- "(?i)bearer\\s+[A-Za-z0-9._-]+"
183
- ),
184
- "Bearer ***"
185
- )
178
+ "(?i)(token|auth_?token|jwt|password|private_?key|secret|seed|mnemonic|signature|sig|event|signing_?payload|plaintext|ciphertext|cookie)=([^\\s&]+)"
179
+ )
180
+ ) { match ->
181
+ "${match.groupValues[1]}=***"
182
+ }
186
183
  .replace(
187
184
  Regex(
188
- "(?i)token=[^\\s&]+"
185
+ "(?i)\\b(nsec1)[023456789acdefghjklmnpqrstuvwxyz]+"
189
186
  ),
190
- "token=***"
187
+ "nsec1***"
191
188
  )
192
189
  .replace(
193
190
  Regex(
194
- "(?i)password=[^\\s&]+"
191
+ "\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\b"
195
192
  ),
196
- "password=***"
193
+ "JWT***"
197
194
  )
198
195
  }
199
196
 
@@ -106,7 +106,7 @@ object DebugReportExporter {
106
106
  ${RuntimeConfig.apiEnabled(context)}
107
107
 
108
108
  WebView Debug:
109
- ${BuildConfig.DEBUG || RuntimeConfig.debugEnabled(context)}
109
+ ${BuildConfig.DEBUG || SupportUnlock.isActive(context)}
110
110
 
111
111
  Logs:
112
112
  -------------------
@@ -120,30 +120,6 @@ object DebugReportExporter {
120
120
  text: String
121
121
  ): String {
122
122
 
123
- return text
124
- .replace(
125
- Regex("(?i)authorization:\\s*.*"),
126
- "authorization: ***"
127
- )
128
- .replace(
129
- Regex("(?i)bearer\\s+[a-zA-Z0-9._-]+"),
130
- "Bearer ***"
131
- )
132
- .replace(
133
- Regex("(?i)token=.*"),
134
- "token=***"
135
- )
136
- .replace(
137
- Regex("(?i)password=.*"),
138
- "password=***"
139
- )
140
- .replace(
141
- Regex("(?i)private.?key=.*"),
142
- "privateKey=***"
143
- )
144
- .replace(
145
- Regex("(?i)nsec[a-zA-Z0-9]+"),
146
- "nsec***"
147
- )
123
+ return AppDebugLogger.sanitize(text)
148
124
  }
149
125
  }
@@ -2,13 +2,10 @@ package com.pakstr.app.debug
2
2
 
3
3
  import android.content.Context
4
4
  import com.pakstr.app.BuildConfig
5
- import com.pakstr.app.RuntimeConfig
6
-
7
5
  object DeveloperToolsAccessManager {
8
6
 
9
7
  fun canOpenDeveloperTools(context: Context): Boolean {
10
8
  return BuildConfig.DEBUG ||
11
- RuntimeConfig.debugEnabled(context) ||
12
9
  SupportUnlock.isActive(context)
13
10
  }
14
11
  }
@@ -43,6 +43,12 @@ class DeveloperToolsActivity : AppCompatActivity() {
43
43
  override fun onCreate(savedInstanceState: Bundle?) {
44
44
  enableEdgeToEdge()
45
45
  super.onCreate(savedInstanceState)
46
+
47
+ if (!DeveloperToolsAccessManager.canOpenDeveloperTools(this)) {
48
+ finish()
49
+ return
50
+ }
51
+
46
52
  setContentView(R.layout.activity_developer_tools)
47
53
 
48
54
  setupToolbar()
@@ -123,7 +129,7 @@ class DeveloperToolsActivity : AppCompatActivity() {
123
129
  }
124
130
 
125
131
  private fun isWebViewDebugEnabled(): Boolean {
126
- return BuildConfig.DEBUG || RuntimeConfig.debugEnabled(this)
132
+ return BuildConfig.DEBUG || SupportUnlock.isActive(this)
127
133
  }
128
134
 
129
135
  private fun setupLogActions() {
@@ -1,10 +1,8 @@
1
1
  package com.pakstr.app.debug
2
2
 
3
- import android.R.attr.enabled
4
3
  import android.content.Context
5
4
  import android.webkit.WebView
6
5
  import com.pakstr.app.BuildConfig
7
- import com.pakstr.app.RuntimeConfig
8
6
 
9
7
  object WebViewDebugManager {
10
8
 
@@ -13,18 +11,15 @@ object WebViewDebugManager {
13
11
  context: Context
14
12
  ) {
15
13
 
16
- WebView.setWebContentsDebuggingEnabled(
17
- BuildConfig.DEBUG ||
18
- RuntimeConfig.debugEnabled(context)
19
- )
20
- AppDebugLogger.log(
14
+ val enabled = BuildConfig.DEBUG ||
15
+ SupportUnlock.isActive(context)
21
16
 
22
- context,
17
+ WebView.setWebContentsDebuggingEnabled(enabled)
23
18
 
19
+ AppDebugLogger.log(
20
+ context,
24
21
  "WEBVIEW",
25
-
26
22
  "WebView debugging enabled: $enabled"
27
-
28
23
  )
29
24
  }
30
25
  }
@@ -1,6 +1,7 @@
1
1
  package com.pakstr.app.debug.logging
2
2
 
3
3
  import android.util.Log
4
+ import com.pakstr.app.BuildConfig
4
5
  import com.pakstr.app.debug.logging.PakstrLog
5
6
  import java.text.SimpleDateFormat
6
7
  import java.util.Date
@@ -18,6 +19,8 @@ object PakstrLogger {
18
19
  tag: String,
19
20
  message: String
20
21
  ) {
22
+ if (!BuildConfig.DEBUG) return
23
+
21
24
  add(
22
25
  PakstrLog.Level.DEBUG,
23
26
  tag,
@@ -35,6 +38,8 @@ object PakstrLogger {
35
38
  tag: String,
36
39
  message: String
37
40
  ) {
41
+ if (!BuildConfig.DEBUG) return
42
+
38
43
  add(
39
44
  PakstrLog.Level.INFO,
40
45
  tag,
@@ -52,6 +57,8 @@ object PakstrLogger {
52
57
  tag: String,
53
58
  message: String
54
59
  ) {
60
+ if (!BuildConfig.DEBUG) return
61
+
55
62
  add(
56
63
  PakstrLog.Level.WARN,
57
64
  tag,
@@ -70,6 +77,7 @@ object PakstrLogger {
70
77
  message: String,
71
78
  throwable: Throwable? = null
72
79
  ) {
80
+ if (!BuildConfig.DEBUG) return
73
81
 
74
82
  add(
75
83
  PakstrLog.Level.ERROR,
@@ -7,12 +7,13 @@ exports.patchIcon = patchIcon;
7
7
  const fs_1 = __importDefault(require("fs"));
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const sharp_1 = __importDefault(require("sharp"));
10
- async function patchIcon(androidRoot, iconPath, backgroundColor = "#FFFFFF") {
10
+ const assetPath_1 = require("../core/assetPath");
11
+ async function patchIcon(androidRoot, iconPath, backgroundColor = "#FFFFFF", manifestDir = process.cwd()) {
11
12
  if (!iconPath) {
12
13
  console.log("ℹ️ No icon provided");
13
14
  return;
14
15
  }
15
- const absoluteIconPath = path_1.default.resolve(process.cwd(), iconPath);
16
+ const absoluteIconPath = (0, assetPath_1.resolveAssetPath)(iconPath, manifestDir);
16
17
  if (!fs_1.default.existsSync(absoluteIconPath)) {
17
18
  throw new Error(`❌ Icon not found: ${absoluteIconPath}`);
18
19
  }
@@ -10,6 +10,7 @@ const permissionMap = {
10
10
  internet: "android.permission.INTERNET",
11
11
  camera: "android.permission.CAMERA",
12
12
  notifications: "android.permission.POST_NOTIFICATIONS",
13
+ vibrate: "android.permission.VIBRATE",
13
14
  };
14
15
  function patchPermissions(androidRoot, manifest) {
15
16
  if (!manifest.permissions?.length) {
@@ -18,7 +19,7 @@ function patchPermissions(androidRoot, manifest) {
18
19
  const file = path_1.default.join(androidRoot, "app/src/main/AndroidManifest.xml");
19
20
  let xml = fs_1.default.readFileSync(file, "utf-8");
20
21
  for (const perm of manifest.permissions) {
21
- const androidPermission = permissionMap[perm];
22
+ const androidPermission = permissionMap[perm.trim().toLowerCase()];
22
23
  if (!androidPermission) {
23
24
  console.warn(`⚠️ Unknown permission: ${perm}`);
24
25
  continue;
@@ -7,12 +7,13 @@ exports.patchSplash = patchSplash;
7
7
  const fs_1 = __importDefault(require("fs"));
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const sharp_1 = __importDefault(require("sharp"));
10
- async function patchSplash(androidRoot, splashPath, backgroundColor) {
10
+ const assetPath_1 = require("../core/assetPath");
11
+ async function patchSplash(androidRoot, splashPath, backgroundColor, manifestDir = process.cwd()) {
11
12
  if (!splashPath) {
12
13
  console.log("ℹ️ No splash provided");
13
14
  return;
14
15
  }
15
- const absolutePath = path_1.default.resolve(splashPath);
16
+ const absolutePath = (0, assetPath_1.resolveAssetPath)(splashPath, manifestDir);
16
17
  if (!fs_1.default.existsSync(absolutePath)) {
17
18
  throw new Error(`❌ Splash not found: ${absolutePath}`);
18
19
  }
@@ -51,7 +51,7 @@ async function buildCommand(args) {
51
51
  ? (workspace = (0, releaseWorkspace_1.createReleaseWorkspace)(templateRoot)).androidRoot
52
52
  : templateRoot;
53
53
  console.log("📱 Android:", androidRoot);
54
- await prepareAndroidProject(androidRoot, ctx.dist, manifest, appName);
54
+ await prepareAndroidProject(androidRoot, ctx.dist, manifest, appName, ctx.manifestDir);
55
55
  if (signingInput) {
56
56
  signing = (0, releaseSigning_1.createReleaseSigningContext)(signingInput);
57
57
  signingInput.keystoreBase64 = "";
@@ -110,7 +110,7 @@ async function buildCommand(args) {
110
110
  console.log("📦 Output:", finalPath);
111
111
  openFolder(finalPath);
112
112
  }
113
- async function prepareAndroidProject(androidRoot, distPath, manifest, appName) {
113
+ async function prepareAndroidProject(androidRoot, distPath, manifest, appName, manifestDir) {
114
114
  const assetsTarget = path_1.default.join(androidRoot, "app/src/main/assets/www");
115
115
  if (!fs_1.default.existsSync(distPath)) {
116
116
  throw new Error("Web assets not found");
@@ -122,10 +122,10 @@ async function prepareAndroidProject(androidRoot, distPath, manifest, appName) {
122
122
  (0, gradle_1.patchGradle)(androidRoot, manifest);
123
123
  (0, branding_1.patchAppName)(androidRoot, appName);
124
124
  if (manifest.ui?.icon) {
125
- await (0, icon_1.patchIcon)(androidRoot, manifest.ui.icon, manifest.backgroundColor ?? "#FFFFFF");
125
+ await (0, icon_1.patchIcon)(androidRoot, manifest.ui.icon, manifest.backgroundColor ?? "#FFFFFF", manifestDir);
126
126
  }
127
127
  if (manifest.ui?.splash) {
128
- await (0, splash_1.patchSplash)(androidRoot, manifest.ui.splash.image, manifest.ui.splash.background ?? "#FFFFFF");
128
+ await (0, splash_1.patchSplash)(androidRoot, manifest.ui.splash.image, manifest.ui.splash.background ?? "#FFFFFF", manifestDir);
129
129
  }
130
130
  (0, permissions_1.patchPermissions)(androidRoot, manifest);
131
131
  (0, generatedProjectVerification_1.verifyGeneratedAndroidProject)(androidRoot, {
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.resolveAssetPath = resolveAssetPath;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ function resolveAssetPath(assetPath, manifestDir) {
10
+ if (path_1.default.isAbsolute(assetPath)) {
11
+ return assetPath;
12
+ }
13
+ const manifestRelativePath = path_1.default.resolve(manifestDir, assetPath);
14
+ if (fs_1.default.existsSync(manifestRelativePath)) {
15
+ return manifestRelativePath;
16
+ }
17
+ const cwdRelativePath = path_1.default.resolve(process.cwd(), assetPath);
18
+ if (fs_1.default.existsSync(cwdRelativePath)) {
19
+ return cwdRelativePath;
20
+ }
21
+ return manifestRelativePath;
22
+ }
@@ -92,6 +92,8 @@ function createBuildContext(args) {
92
92
  const androidRoot = path_1.default.resolve(process.cwd(), "android-template");
93
93
  return {
94
94
  manifest,
95
+ manifestPath,
96
+ manifestDir: path_1.default.dirname(manifestPath),
95
97
  dist: path_1.default.resolve(web),
96
98
  out,
97
99
  androidRoot,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pakstr",
3
- "version": "0.8.4",
3
+ "version": "0.8.6",
4
4
  "description": "CLI for packaging Nostr web apps into Android APKs",
5
5
  "type": "commonjs",
6
6
  "main": "dist/index.js",