diff --git a/packages/config/src/Config.ts b/packages/config/src/Config.ts index a15a8f59d2..c7cc1eca40 100644 --- a/packages/config/src/Config.ts +++ b/packages/config/src/Config.ts @@ -74,6 +74,8 @@ export function getConfigWithMods(projectRoot: string, options?: GetConfigOption * If a function is exported from the `app.config.js` then a partial config will be passed as an argument. * The partial config is composed from any existing app.json, and certain fields from the `package.json` like name and description. * + * If options.isPublicConfig is true, the Expo config will include only public-facing options (omitting private keys). + * The resulting config should be suitable for hosting or embedding in a publicly readable location. * * **Example** * ```js @@ -108,7 +110,7 @@ export function getConfig(projectRoot: string, options: GetConfigOptions = {}): ); function fillAndReturnConfig(config: SplitConfigs, dynamicConfigObjectType: string | null) { - return { + const configWithDefaultValues = { ...ensureConfigHasDefaultValues( projectRoot, config.expo, @@ -121,6 +123,20 @@ export function getConfig(projectRoot: string, options: GetConfigOptions = {}): dynamicConfigPath: paths.dynamicConfigPath, staticConfigPath: paths.staticConfigPath, }; + + if (options.isPublicConfig) { + if (configWithDefaultValues.exp.hooks) { + delete configWithDefaultValues.exp.hooks; + } + if (configWithDefaultValues.exp.ios?.config) { + delete configWithDefaultValues.exp.ios.config; + } + if (configWithDefaultValues.exp.android?.config) { + delete configWithDefaultValues.exp.android.config; + } + } + + return configWithDefaultValues; } // Fill in the static config diff --git a/packages/config/src/Config.types.ts b/packages/config/src/Config.types.ts index 449386f3e9..e92dcff3a9 100644 --- a/packages/config/src/Config.types.ts +++ b/packages/config/src/Config.types.ts @@ -137,6 +137,7 @@ export type ConfigContext = { }; export type GetConfigOptions = { + isPublicConfig?: boolean; skipSDKVersionRequirement?: boolean; strict?: boolean; }; diff --git a/packages/config/src/__tests__/Config-test.js b/packages/config/src/__tests__/Config-test.js index 1a710ab032..b7313089b5 100644 --- a/packages/config/src/__tests__/Config-test.js +++ b/packages/config/src/__tests__/Config-test.js @@ -37,6 +37,83 @@ describe(`getProjectConfigDescription`, () => { }); }); +describe('getConfig public config', () => { + const appJsonWithPrivateData = { + name: 'testing 123', + version: '0.1.0', + slug: 'testing-123', + sdkVersion: '100.0.0', + hooks: { + postPublish: [], + }, + android: { + config: { + googleMaps: { + apiKey: 'test-key', + }, + }, + versionCode: 1, + }, + ios: { + config: { + googleMapsApiKey: 'test-key', + }, + buildNumber: '1.0', + }, + }; + + const appJsonNoPrivateData = { + name: 'testing 123', + version: '0.1.0', + slug: 'testing-123', + sdkVersion: '100.0.0', + ios: { + buildNumber: '1.0', + }, + }; + + beforeAll(() => { + const packageJson = JSON.stringify( + { + name: 'testing123', + version: '0.1.0', + description: 'fake description', + main: 'index.js', + }, + null, + 2 + ); + + vol.fromJSON({ + '/private-data/package.json': packageJson, + '/private-data/app.json': JSON.stringify({ expo: appJsonWithPrivateData }), + '/no-private-data/package.json': packageJson, + '/no-private-data/app.json': JSON.stringify({ expo: appJsonNoPrivateData }), + }); + }); + + afterAll(() => vol.reset()); + + it('removes only private data from the config', () => { + const { exp } = getConfig('/private-data', { isPublicConfig: true }); + + expect(exp.hooks).toBeUndefined(); + + expect(exp.ios).toBeDefined(); + expect(exp.ios.buildNumber).toEqual(appJsonWithPrivateData.ios.buildNumber); + expect(exp.ios.config).toBeUndefined(); + + expect(exp.android).toBeDefined(); + expect(exp.android.versionCode).toEqual(appJsonWithPrivateData.android.versionCode); + expect(exp.android.config).toBeUndefined(); + }); + + it('does not remove properties from a config with no private data', () => { + const { exp } = getConfig('/no-private-data', { isPublicConfig: true }); + expect(exp).toMatchObject(appJsonNoPrivateData); + }); +}); + describe('readConfigJson', () => { describe('sdkVersion', () => { beforeAll(() => {