runcloud 0.2.151 → 0.2.153
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/dist/commands/appStoreEvaluate.js +41 -4
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/runcloud-0.2.153.tgz +0 -0
- package/runcloud-0.2.151.tgz +0 -0
|
@@ -151,7 +151,9 @@ function evaluateLocalItem(root, appJson, item) {
|
|
|
151
151
|
return evaluateConfigItem(appJson, item, rule);
|
|
152
152
|
switch (item.id) {
|
|
153
153
|
case 'hardcoded_secrets':
|
|
154
|
-
return patternItem(root, item, /sk-[A-Za-z0-9]{20,}|AIza[0-9A-Za-z_-]{30,}|-----BEGIN.*PRIVATE KEY|api[_-]?key\s*[:=]\s*['"][A-Za-z0-9]{16,}/i, 'fail', 'Hardcoded secret-like value found.', 'No secret-like values found.'
|
|
154
|
+
return patternItem(root, item, /sk-[A-Za-z0-9]{20,}|AIza[0-9A-Za-z_-]{30,}|-----BEGIN.*PRIVATE KEY|api[_-]?key\s*[:=]\s*['"][A-Za-z0-9]{16,}/i, 'fail', 'Hardcoded secret-like value found.', 'No secret-like values found.', {
|
|
155
|
+
filter: (match) => !isFirebaseClientKey(root, match),
|
|
156
|
+
});
|
|
155
157
|
case 'http_endpoints':
|
|
156
158
|
return patternItem(root, item, /http:\/\/(?!localhost|127\.0\.0\.1)/i, 'warning', 'Non-local HTTP endpoint found.', 'No non-local HTTP endpoints found.');
|
|
157
159
|
case 'placeholder_content':
|
|
@@ -287,6 +289,16 @@ function patternItem(root, item, regex, statusOnHit, messageOnHit, messageOnMiss
|
|
|
287
289
|
return makeItem(item, statusOnHit, messageOnHit, evidence(matches));
|
|
288
290
|
return makeItem(item, 'pass', messageOnMiss, `scan: no matches for ${regex}`);
|
|
289
291
|
}
|
|
292
|
+
const MICROPHONE_USE = /expo-av|AudioRecorder|requestRecordingPermissionsAsync|requestMicrophonePermissions/i;
|
|
293
|
+
function isFirebaseClientKey(root, match) {
|
|
294
|
+
if (!/AIza[0-9A-Za-z_-]{30,}/.test(match.text))
|
|
295
|
+
return false;
|
|
296
|
+
if (/(^|\/)(GoogleService-Info\.plist|google-services\.json)$/.test(match.file))
|
|
297
|
+
return true;
|
|
298
|
+
if (!/\bapiKey['"]?\s*:/.test(match.text))
|
|
299
|
+
return false;
|
|
300
|
+
return /initializeApp\s*\(|authDomain/.test(readText(path.join(root, match.file)) ?? '');
|
|
301
|
+
}
|
|
290
302
|
function missingPermissionRequirements(root, appJson) {
|
|
291
303
|
const missing = [...missingIosUsageDescriptions(root, appJson)];
|
|
292
304
|
const permissions = arrayOfStrings(getPath(appJson, ['expo', 'android', 'permissions']));
|
|
@@ -295,7 +307,7 @@ function missingPermissionRequirements(root, appJson) {
|
|
|
295
307
|
{ name: 'camera', used: /expo-camera|CameraView|requestCameraPermissions/i, permissions: ['CAMERA'] },
|
|
296
308
|
{ name: 'location', used: /expo-location|getCurrentPositionAsync|watchPositionAsync/i, permissions: ['ACCESS_FINE_LOCATION', 'ACCESS_COARSE_LOCATION'] },
|
|
297
309
|
{ name: 'photos', used: /expo-image-picker|expo-media-library|MediaLibrary/i, permissions: ['READ_MEDIA_IMAGES', 'READ_EXTERNAL_STORAGE'] },
|
|
298
|
-
{ name: 'microphone', used:
|
|
310
|
+
{ name: 'microphone', used: MICROPHONE_USE, permissions: ['RECORD_AUDIO'] },
|
|
299
311
|
{ name: 'notifications', used: /expo-notifications/i, permissions: ['POST_NOTIFICATIONS'] },
|
|
300
312
|
];
|
|
301
313
|
for (const check of androidChecks) {
|
|
@@ -314,13 +326,15 @@ function missingIosUsageDescriptions(root, appJson) {
|
|
|
314
326
|
{ name: 'camera', used: /expo-camera|CameraView|requestCameraPermissions/i, keys: ['NSCameraUsageDescription'] },
|
|
315
327
|
{ name: 'location', used: /expo-location|getCurrentPositionAsync|watchPositionAsync/i, keys: ['NSLocationWhenInUseUsageDescription', 'NSLocationAlwaysAndWhenInUseUsageDescription'] },
|
|
316
328
|
{ name: 'photos', used: /expo-image-picker|expo-media-library|MediaLibrary/i, keys: ['NSPhotoLibraryUsageDescription'] },
|
|
317
|
-
{ name: 'microphone', used:
|
|
329
|
+
{ name: 'microphone', used: MICROPHONE_USE, keys: ['NSMicrophoneUsageDescription'] },
|
|
318
330
|
];
|
|
331
|
+
const pkg = readJson(path.join(root, 'package.json'));
|
|
332
|
+
const installed = new Set(['dependencies', 'devDependencies'].flatMap((field) => Object.keys(objectValue(getPath(pkg, [field])))));
|
|
319
333
|
const missing = [];
|
|
320
334
|
for (const check of checks) {
|
|
321
335
|
if (!check.used.test(source))
|
|
322
336
|
continue;
|
|
323
|
-
if (!check.keys.some((key) =>
|
|
337
|
+
if (!check.keys.some((key) => builtWithPurposeString(key, infoPlist, appJson, installed))) {
|
|
324
338
|
missing.push(`ios ${check.name} usage description (${check.keys.join(' or ')})`);
|
|
325
339
|
}
|
|
326
340
|
}
|
|
@@ -333,6 +347,29 @@ function missingIosUsageDescriptions(root, appJson) {
|
|
|
333
347
|
}
|
|
334
348
|
return missing;
|
|
335
349
|
}
|
|
350
|
+
const PLUGIN_PURPOSE_STRINGS = {
|
|
351
|
+
'expo-camera': { auto: true, keys: { NSCameraUsageDescription: 'cameraPermission', NSMicrophoneUsageDescription: 'microphonePermission' } },
|
|
352
|
+
'expo-image-picker': { auto: true, keys: { NSPhotoLibraryUsageDescription: 'photosPermission', NSCameraUsageDescription: 'cameraPermission', NSMicrophoneUsageDescription: 'microphonePermission' } },
|
|
353
|
+
'expo-media-library': { auto: true, keys: { NSPhotoLibraryUsageDescription: 'photosPermission' } },
|
|
354
|
+
'expo-av': { auto: true, keys: { NSMicrophoneUsageDescription: 'microphonePermission' } },
|
|
355
|
+
'expo-location': { auto: true, keys: { NSLocationWhenInUseUsageDescription: 'locationWhenInUsePermission', NSLocationAlwaysAndWhenInUseUsageDescription: 'locationAlwaysAndWhenInUsePermission' } },
|
|
356
|
+
'expo-audio': { auto: false, keys: { NSMicrophoneUsageDescription: 'microphonePermission' } },
|
|
357
|
+
};
|
|
358
|
+
function builtWithPurposeString(key, infoPlist, appJson, installed) {
|
|
359
|
+
let written = hasValue(infoPlist[key]);
|
|
360
|
+
for (const [name, plugin] of Object.entries(PLUGIN_PURPOSE_STRINGS)) {
|
|
361
|
+
const option = plugin.keys[key];
|
|
362
|
+
if (!option)
|
|
363
|
+
continue;
|
|
364
|
+
const listed = configPluginOptions(appJson, name);
|
|
365
|
+
if (!listed && !(plugin.auto && installed.has(name)))
|
|
366
|
+
continue;
|
|
367
|
+
if (listed?.[option] === false)
|
|
368
|
+
return false;
|
|
369
|
+
written = true;
|
|
370
|
+
}
|
|
371
|
+
return written;
|
|
372
|
+
}
|
|
336
373
|
function configPluginOptions(appJson, name) {
|
|
337
374
|
const plugins = getPath(appJson, ['expo', 'plugins']);
|
|
338
375
|
if (!Array.isArray(plugins))
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const CLI_VERSION = '0.2.
|
|
1
|
+
export const CLI_VERSION = '0.2.153';
|
package/package.json
CHANGED
|
Binary file
|
package/runcloud-0.2.151.tgz
DELETED
|
Binary file
|