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 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.21:** corrected 16 KB page dates: Google Play blocks updates without them from 1 February 2027 (high until then). **0.1.20:** warns about `ImageBackground`, `SafeAreaView`, `DrawerLayoutAndroid` and `UTFSequence`, which React Native has deprecated and will remove (143 of 470 apps we test import one). 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 450+ open-source React Native and Expo apps to keep false alarms out. [All releases →](https://nativekeel.com/changelog)
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.21",
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
- hits.push(`${m[1]} (${path.relative(root, file)}:${text.slice(0, m.index).split('\n').length})`);
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 [];