nativekeel 0.1.21 → 0.1.22
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 +1 -1
- package/package.json +1 -1
- package/src/security.js +15 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Health check for React Native and Expo apps. One command, no install, no account
|
|
|
6
6
|
npx nativekeel
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
**What's new in 0.1.
|
|
9
|
+
**What's new in 0.1.22:** auth tokens in AsyncStorage/MMKV are found by what is stored, not only by the key name. **0.1.21:** corrected 16 KB page dates: Google Play blocks updates without them from 1 February 2027 (high until then). Recent releases added a *Start here* list in every report, hacking risks mapped to OWASP MASVS, crash and performance checks. Every check is tuned on 470 open-source React Native and Expo apps to keep false alarms out ([what we found in them](https://dev.to/keel_alican_akyol/we-scanned-470-open-source-react-native-apps-here-is-what-breaks-them-5072)). [All releases →](https://nativekeel.com/changelog)
|
|
10
10
|
|
|
11
11
|
```
|
|
12
12
|
Summary 4 critical · 5 high · 4 medium · 6 low
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nativekeel",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.22",
|
|
4
4
|
"description": "Health check for React Native and Expo apps: upgrade blockers, store deadlines, crash risks, vulnerable dependencies and leaked secrets, with a step-by-step upgrade plan.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/security.js
CHANGED
|
@@ -569,10 +569,24 @@ export function weakCrypto(root) {
|
|
|
569
569
|
export function tokenStorage(root) {
|
|
570
570
|
const hits = [];
|
|
571
571
|
for (const file of jsFiles(root)) {
|
|
572
|
+
// Web-only files (keychain.web.ts) have no Keychain to use; the mobile file decides.
|
|
573
|
+
if (/\.web\.[cm]?[jt]sx?$/.test(file)) continue;
|
|
572
574
|
const text = read(file);
|
|
573
575
|
if (!text || !/AsyncStorage|MMKV/.test(text)) continue;
|
|
576
|
+
const at = (i) => `${path.relative(root, file)}:${text.slice(0, i).split('\n').length}`;
|
|
577
|
+
const seen = new Set();
|
|
578
|
+
// By key name: setItem('access_token', …)
|
|
574
579
|
for (const m of text.matchAll(/\b(?:AsyncStorage\.setItem|storage\.set|mmkv\.set)\s*\(\s*['"`@]?([\w@.\-:]*?(?:access_?token|refresh_?token|auth_?token|id_?token|jwt|session_?token|bearer)[\w.\-:]*)['"`]?\s*,/gi)) {
|
|
575
|
-
|
|
580
|
+
seen.add(m.index);
|
|
581
|
+
hits.push(`${m[1]} (${at(m.index)})`);
|
|
582
|
+
}
|
|
583
|
+
// By value: setItem(TOKEN_KEY, token), setItem('user', JSON.stringify({ token })). Push
|
|
584
|
+
// notification and device tokens are not secrets.
|
|
585
|
+
for (const m of text.matchAll(/\b(?:AsyncStorage\.setItem|(?:storage|mmkv)\.set(?:String)?)\s*\(\s*([^,()]{1,60}),\s*([^;\n]{0,120})/g)) {
|
|
586
|
+
if (seen.has(m.index)) continue;
|
|
587
|
+
if (!/\b(?:access_?token|refresh_?token|auth_?token|id_?token|session_?token|login_?token|accessToken|refreshToken|authToken|idToken|sessionToken|loginToken|jwt|token)\b/i.test(m[2])) continue;
|
|
588
|
+
if (/push|fcm|apns|expo_?push|notif|device|firebase|messaging/i.test(m[1] + m[2])) continue;
|
|
589
|
+
hits.push(`${m[1].trim()} (${at(m.index)})`);
|
|
576
590
|
}
|
|
577
591
|
}
|
|
578
592
|
if (!hits.length) return [];
|