@hyodotdev/openiap 0.1.0-alpha.0 → 0.1.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.
- package/README.md +11 -9
- package/package.json +1 -1
- package/src/checks.mjs +16 -3
- package/src/findings.mjs +1 -0
- package/src/project.mjs +3 -4
package/README.md
CHANGED
|
@@ -16,12 +16,12 @@ npx @hyodotdev/openiap init ./my-product --role experience
|
|
|
16
16
|
npx @hyodotdev/openiap doctor ./my-app --json
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
| Role
|
|
20
|
-
|
|
|
21
|
-
| `app`
|
|
22
|
-
| `experience` | Paywalls and experiments to the app's purchase flow
|
|
23
|
-
| `commerce`
|
|
24
|
-
| `data`
|
|
19
|
+
| Role | Connect |
|
|
20
|
+
| ------------ | ----------------------------------------------------- |
|
|
21
|
+
| `app` | Purchases to customer access |
|
|
22
|
+
| `experience` | Paywalls and experiments to the app's purchase flow |
|
|
23
|
+
| `commerce` | Verification and access through the Commerce Protocol |
|
|
24
|
+
| `data` | Normalized events to analytics and automation |
|
|
25
25
|
|
|
26
26
|
The brief points your assistant to the matching implementation guide. Fill in
|
|
27
27
|
the customer outcome, choose any missing product decisions, and review the
|
|
@@ -62,20 +62,22 @@ Most of these produce no error message that says what is actually wrong.
|
|
|
62
62
|
| `android-horizon-app-id-missing` | warning | Horizon is selected but no manifest declares an app id. |
|
|
63
63
|
| `iapkit-secret-key-in-client` | error | A secret key is on a name that reaches the app bundle. |
|
|
64
64
|
| `iapkit-secret-key-in-env` | warning | A secret key is in an env file on a name nothing here proves is inlined. |
|
|
65
|
+
| `iapkit-secret-key-in-config` | warning | Executable app configuration contains a secret, but its presence in the app bundle is unproven. |
|
|
65
66
|
| `iapkit-env-missing-expo-prefix` | warning | Expo inlines only `EXPO_PUBLIC_` names, so the bare name reads as undefined. |
|
|
66
67
|
| `iapkit-env-unexpected-expo-prefix` | warning | An `EXPO_PUBLIC_` name is set where nothing inlines that prefix. |
|
|
67
68
|
| `iapkit-base-url-has-path` | both | The base URL is not a bare origin; every SDK rejects a path, userinfo, a query or a fragment. |
|
|
68
69
|
| `iapkit-base-url-invalid` | both | The base URL is not a URL. |
|
|
69
70
|
| `iapkit-base-url-scheme` | both | The base URL is not http or https. |
|
|
70
71
|
| `ios-scene-delegate-missing` | both | The Info.plist names a scene delegate the target lacks; the app opens to a black screen. Error when the plist names the app's own module or no class at all, warning when a linked framework could supply it. |
|
|
71
|
-
| `project-file-unreadable` | error | A path could not be read, so nothing in it was checked.
|
|
72
|
+
| `project-file-unreadable` | error | A path could not be read, so nothing in it was checked. |
|
|
72
73
|
| `project-manifest-unreadable` | error | package.json exists but will not parse, so framework detection read nothing. |
|
|
73
74
|
| `project-not-a-directory` | error | The path given is not a readable directory. |
|
|
74
75
|
|
|
75
76
|
## What it does not find
|
|
76
77
|
|
|
77
|
-
Dynamic app configuration is never executed.
|
|
78
|
-
|
|
78
|
+
Dynamic app configuration is never executed. Secret literals in it stay warnings
|
|
79
|
+
unless the file is a declared bundled asset. Reading an unprefixed environment
|
|
80
|
+
variable during configuration also does not prove its value reaches the app.
|
|
79
81
|
|
|
80
82
|
A checkout cannot answer for a device or a store account. The command prints
|
|
81
83
|
these as unchecked rather than guessing:
|
package/package.json
CHANGED
package/src/checks.mjs
CHANGED
|
@@ -233,7 +233,7 @@ function reachesBundle(root, framework, name, file) {
|
|
|
233
233
|
return pubspecAssets(root).includes(file);
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
-
/**
|
|
236
|
+
/** Distinguish bundled secrets from values used only during configuration. */
|
|
237
237
|
export function secretKeyChecks(root, framework) {
|
|
238
238
|
const findings = [];
|
|
239
239
|
for (const file of clientFiles(root)) {
|
|
@@ -300,10 +300,23 @@ export function secretKeyChecks(root, framework) {
|
|
|
300
300
|
continue;
|
|
301
301
|
}
|
|
302
302
|
|
|
303
|
-
// A key on a comment line is not shipped; anywhere else in a bundled file
|
|
304
|
-
// it is, whether or not it sits inside a string.
|
|
305
303
|
const found = codeLines(text).find((one) => SECRET_KEY.test(one.line));
|
|
306
304
|
if (!found) continue;
|
|
305
|
+
const dynamicConfig =
|
|
306
|
+
BUNDLED_FILES.includes(file) && !file.endsWith(".json");
|
|
307
|
+
if (dynamicConfig && !pubspecAssets(root).includes(file)) {
|
|
308
|
+
findings.push(
|
|
309
|
+
finding(
|
|
310
|
+
"iapkit-secret-key-in-config",
|
|
311
|
+
"warning",
|
|
312
|
+
file,
|
|
313
|
+
"An IAPKit secret key appears in executable app configuration. Nothing here proves it reaches the bundle.",
|
|
314
|
+
"Keep build-time secrets out of exported app configuration.",
|
|
315
|
+
{ line: found.number },
|
|
316
|
+
),
|
|
317
|
+
);
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
307
320
|
findings.push(
|
|
308
321
|
finding(
|
|
309
322
|
"iapkit-secret-key-in-client",
|
package/src/findings.mjs
CHANGED
|
@@ -10,6 +10,7 @@ export const FINDING_IDS = Object.freeze([
|
|
|
10
10
|
"android-horizon-app-id-missing",
|
|
11
11
|
"iapkit-secret-key-in-client",
|
|
12
12
|
"iapkit-secret-key-in-env",
|
|
13
|
+
"iapkit-secret-key-in-config",
|
|
13
14
|
"iapkit-env-missing-expo-prefix",
|
|
14
15
|
"iapkit-env-unexpected-expo-prefix",
|
|
15
16
|
"iapkit-base-url-invalid",
|
package/src/project.mjs
CHANGED
|
@@ -338,10 +338,8 @@ const ENV_TEMPLATE = /\.(example|sample|template)$/;
|
|
|
338
338
|
/** What Flutter's `dotenv` is pointed at: `env`, `env.prod`, `.env.ci`. */
|
|
339
339
|
const FLUTTER_ENV = /(^|\.)env(\..+)?$/;
|
|
340
340
|
|
|
341
|
-
/**
|
|
341
|
+
/** App configuration files inspected without evaluating executable exports. */
|
|
342
342
|
export const BUNDLED_FILES = [
|
|
343
|
-
// Expo resolves these in this order, so a key in the first one is the one
|
|
344
|
-
// that ships even when a later file also exists.
|
|
345
343
|
"app.config.ts",
|
|
346
344
|
"app.config.mts",
|
|
347
345
|
"app.config.cts",
|
|
@@ -378,7 +376,8 @@ export function pubspecAssets(root) {
|
|
|
378
376
|
.map((entry) => path.join(asset, entry))
|
|
379
377
|
.filter((file) => !isDirectory(root, file))
|
|
380
378
|
: [asset],
|
|
381
|
-
)
|
|
379
|
+
)
|
|
380
|
+
.map((asset) => path.normalize(asset));
|
|
382
381
|
}
|
|
383
382
|
|
|
384
383
|
/**
|