From 2e2ffc9d5dc9269191427cadb0139136e3b6c46d Mon Sep 17 00:00:00 2001 From: Szymon Dziedzic Date: Thu, 25 Jan 2024 10:55:06 +0100 Subject: [PATCH 01/11] [eas-json] sanitize EAS Submit inputs better --- packages/eas-json/package.json | 4 +- .../src/__tests__/submitProfiles-test.ts | 155 +++++++++++++++--- packages/eas-json/src/utils.ts | 45 ++++- yarn.lock | 12 ++ 4 files changed, 194 insertions(+), 22 deletions(-) diff --git a/packages/eas-json/package.json b/packages/eas-json/package.json index a8b2f64a71..8a43e48197 100644 --- a/packages/eas-json/package.json +++ b/packages/eas-json/package.json @@ -7,6 +7,7 @@ "dependencies": { "@babel/code-frame": "7.23.5", "@expo/eas-build-job": "1.0.56", + "@hapi/address": "5.1.1", "chalk": "4.1.2", "env-string": "1.0.1", "fs-extra": "11.2.0", @@ -15,7 +16,8 @@ "log-symbols": "4.1.0", "semver": "7.5.2", "terminal-link": "2.1.1", - "tslib": "2.4.1" + "tslib": "2.4.1", + "uuid": "9.0.1" }, "devDependencies": { "@types/babel__code-frame": "7.0.3", diff --git a/packages/eas-json/src/__tests__/submitProfiles-test.ts b/packages/eas-json/src/__tests__/submitProfiles-test.ts index cbde6bc1d3..606a8a29a2 100644 --- a/packages/eas-json/src/__tests__/submitProfiles-test.ts +++ b/packages/eas-json/src/__tests__/submitProfiles-test.ts @@ -107,10 +107,10 @@ test('ios config with all required values', async () => { ios: { appleId: 'some@email.com', ascAppId: '1223423523', - appleTeamId: 'QWERTY', + appleTeamId: 'AB32CDE81F', ascApiKeyPath: './path-ABCD.p8', - ascApiKeyIssuerId: 'abc-123-def-456', - ascApiKeyId: 'ABCD', + ascApiKeyIssuerId: '123e4567-e89b-12d3-a456-426614174000', + ascApiKeyId: 'AB32CDE81F', }, }, }, @@ -121,11 +121,11 @@ test('ios config with all required values', async () => { expect(iosProfile).toEqual({ appleId: 'some@email.com', - appleTeamId: 'QWERTY', + appleTeamId: 'AB32CDE81F', ascAppId: '1223423523', ascApiKeyPath: './path-ABCD.p8', - ascApiKeyIssuerId: 'abc-123-def-456', - ascApiKeyId: 'ABCD', + ascApiKeyIssuerId: '123e4567-e89b-12d3-a456-426614174000', + ascApiKeyId: 'AB32CDE81F', language: 'en-US', }); }); @@ -137,7 +137,7 @@ test('ios config with ascApiKey fields set to env var', async () => { ios: { appleId: 'some@email.com', ascAppId: '1223423523', - appleTeamId: 'QWERTY', + appleTeamId: 'AB32CDE81F', ascApiKeyPath: '$ASC_API_KEY_PATH', ascApiKeyIssuerId: '$ASC_API_KEY_ISSUER_ID', ascApiKeyId: '$ASC_API_KEY_ID', @@ -148,18 +148,18 @@ test('ios config with ascApiKey fields set to env var', async () => { try { process.env.ASC_API_KEY_PATH = './path-ABCD.p8'; - process.env.ASC_API_KEY_ISSUER_ID = 'abc-123-def-456'; - process.env.ASC_API_KEY_ID = 'ABCD'; + process.env.ASC_API_KEY_ISSUER_ID = '123e4567-e89b-12d3-a456-426614174000'; + process.env.ASC_API_KEY_ID = 'AB32CDE81F'; const accessor = EasJsonAccessor.fromProjectPath('/project'); const iosProfile = await EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); expect(iosProfile).toEqual({ appleId: 'some@email.com', ascAppId: '1223423523', - appleTeamId: 'QWERTY', + appleTeamId: 'AB32CDE81F', ascApiKeyPath: './path-ABCD.p8', - ascApiKeyIssuerId: 'abc-123-def-456', - ascApiKeyId: 'ABCD', + ascApiKeyIssuerId: '123e4567-e89b-12d3-a456-426614174000', + ascApiKeyId: 'AB32CDE81F', language: 'en-US', }); } finally { @@ -176,16 +176,16 @@ test('valid profile extending other profile', async () => { ios: { appleId: 'some@email.com', ascAppId: '1223423523', - appleTeamId: 'QWERTY', + appleTeamId: 'AB32CDE81F', }, }, extension: { extends: 'base', ios: { - appleTeamId: 'ABCDEF', + appleTeamId: 'AB32CDE81F', ascApiKeyPath: './path-ABCD.p8', - ascApiKeyIssuerId: 'abc-123-def-456', - ascApiKeyId: 'ABCD', + ascApiKeyIssuerId: '2af70a7a-2ac5-44d4-924e-ae97a7ca9333', + ascApiKeyId: 'AB32CDE81F', }, }, }, @@ -202,19 +202,134 @@ test('valid profile extending other profile', async () => { language: 'en-US', appleId: 'some@email.com', ascAppId: '1223423523', - appleTeamId: 'QWERTY', + appleTeamId: 'AB32CDE81F', }); expect(extendedProfile).toEqual({ language: 'en-US', appleId: 'some@email.com', ascAppId: '1223423523', - appleTeamId: 'ABCDEF', + appleTeamId: 'AB32CDE81F', ascApiKeyPath: './path-ABCD.p8', - ascApiKeyIssuerId: 'abc-123-def-456', - ascApiKeyId: 'ABCD', + ascApiKeyIssuerId: '2af70a7a-2ac5-44d4-924e-ae97a7ca9333', + ascApiKeyId: 'AB32CDE81F', }); }); +test('ios config with with invalid appleId', async () => { + await fs.writeJson('/project/eas.json', { + submit: { + release: { + ios: { + appleId: '| /bin/bash echo "hello"', + ascAppId: '1223423523', + appleTeamId: 'AB32CDE81F', + ascApiKeyPath: './path-ABCD.p8', + ascApiKeyIssuerId: '2af70a7a-2ac5-44d4-924e-ae97a7ca9333', + ascApiKeyId: 'AB32CDE81F', + }, + }, + }, + }); + + const accessor = EasJsonAccessor.fromProjectPath('/project'); + const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); + await expect(promise).rejects.toThrow( + 'Invalid Apple ID was specified. It should be a valid email address. Example: "name@domain.com".' + ); +}); + +test('ios config with with invalid ascAppId', async () => { + await fs.writeJson('/project/eas.json', { + submit: { + release: { + ios: { + appleId: 'some@example.com', + ascAppId: 'othervalue', + appleTeamId: 'AB32CDE81F', + ascApiKeyPath: './path-ABCD.p8', + ascApiKeyIssuerId: '2af70a7a-2ac5-44d4-924e-ae97a7ca9333', + ascApiKeyId: 'AB32CDE81F', + }, + }, + }, + }); + + const accessor = EasJsonAccessor.fromProjectPath('/project'); + const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); + await expect(promise).rejects.toThrow( + 'Invalid Apple App Store Connect App ID was specified. It should contain 10 digits. Example: "1234567891".' + ); +}); + +test('ios config with with invalid appleTeamId', async () => { + await fs.writeJson('/project/eas.json', { + submit: { + release: { + ios: { + appleId: 'some@example.com', + ascAppId: '1223423523', + appleTeamId: 'ls -la', + ascApiKeyPath: './path-ABCD.p8', + ascApiKeyIssuerId: '2af70a7a-2ac5-44d4-924e-ae97a7ca9333', + ascApiKeyId: 'AB32CDE81F', + }, + }, + }, + }); + + const accessor = EasJsonAccessor.fromProjectPath('/project'); + const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); + await expect(promise).rejects.toThrow( + 'Invalid Apple Team ID was specified. It should contain 10 letters or digits. Example: "AB32CDE81F".' + ); +}); + +test('ios config with with invalid ascApiKeyIssuerId', async () => { + await fs.writeJson('/project/eas.json', { + submit: { + release: { + ios: { + appleId: 'some@example.com', + ascAppId: '1223423523', + appleTeamId: 'AB32CDE81F', + ascApiKeyPath: './path-ABCD.p8', + ascApiKeyIssuerId: 'notanuuid', + ascApiKeyId: 'AB32CDE81F', + }, + }, + }, + }); + + const accessor = EasJsonAccessor.fromProjectPath('/project'); + const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); + await expect(promise).rejects.toThrow( + 'Invalid Apple App Store Connect API Key Issuer ID was specified. It should be a valid UUID. Example: "123e4567-e89b-12d3-a456-426614174000".' + ); +}); + +test('ios config with with invalid ascApiKeyId', async () => { + await fs.writeJson('/project/eas.json', { + submit: { + release: { + ios: { + appleId: 'some@example.com', + ascAppId: '1223423523', + appleTeamId: 'AB32CDE81F', + ascApiKeyPath: './path-ABCD.p8', + ascApiKeyIssuerId: '123e4567-e89b-12d3-a456-426614174000', + ascApiKeyId: 'wrong value', + }, + }, + }, + }); + + const accessor = EasJsonAccessor.fromProjectPath('/project'); + const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); + await expect(promise).rejects.toThrow( + `Invalid Apple App Store Connect API Key ID was specified. It should contain 10 letters or digits. Example: "AB32CDE81F".` + ); +}); + test('get profile names', async () => { await fs.writeJson('/project/eas.json', { submit: { diff --git a/packages/eas-json/src/utils.ts b/packages/eas-json/src/utils.ts index d6869e1fd0..9a164abc06 100644 --- a/packages/eas-json/src/utils.ts +++ b/packages/eas-json/src/utils.ts @@ -1,4 +1,6 @@ import { Platform } from '@expo/eas-build-job'; +import { isEmailValid } from '@hapi/address'; +import { validate } from 'uuid'; import { EasJsonAccessor } from './accessor'; import { resolveBuildProfile } from './build/resolver'; @@ -8,6 +10,10 @@ import { resolveSubmitProfile } from './submit/resolver'; import { SubmitProfile } from './submit/types'; import { EasJson } from './types'; +const ASC_API_KEY_ID_REGEX = /^[\dA-Z]{10}$/; +const APPLE_TEAM_ID_REGEX = /^[\dA-Z]{10}$/; +const ASC_APP_ID_REGEX = /^\d{10}$/; + interface EasJsonDeprecationWarning { message: string[]; docsUrl?: string; @@ -96,12 +102,49 @@ export class EasJsonUtils { return Object.keys(easJson?.submit ?? {}); } + public static validateSubmitProfile( + profile: SubmitProfile, + platform: T + ): void { + if (platform === Platform.IOS) { + const iosProfile = profile as SubmitProfile; + + if (iosProfile.ascApiKeyId && !ASC_API_KEY_ID_REGEX.test(iosProfile.ascApiKeyId)) { + throw new Error( + `Invalid Apple App Store Connect API Key ID was specified. It should contain 10 letters or digits. Example: "AB32CDE81F".` + ); + } + if (iosProfile.appleTeamId && !APPLE_TEAM_ID_REGEX.test(iosProfile.appleTeamId)) { + throw new Error( + `Invalid Apple Team ID was specified. It should contain 10 letters or digits. Example: "AB32CDE81F".` + ); + } + if (iosProfile.ascAppId && !ASC_APP_ID_REGEX.test(iosProfile.ascAppId)) { + throw new Error( + `Invalid Apple App Store Connect App ID was specified. It should contain 10 digits. Example: "1234567891".` + ); + } + if (iosProfile.ascApiKeyIssuerId && !validate(iosProfile.ascApiKeyIssuerId)) { + throw new Error( + `Invalid Apple App Store Connect API Key Issuer ID was specified. It should be a valid UUID. Example: "123e4567-e89b-12d3-a456-426614174000".` + ); + } + if (iosProfile.appleId && !isEmailValid(iosProfile.appleId)) { + throw new Error( + `Invalid Apple ID was specified. It should be a valid email address. Example: "name@domain.com".` + ); + } + } + } + public static async getSubmitProfileAsync( accessor: EasJsonAccessor, platform: T, profileName?: string ): Promise> { const easJson = await accessor.readAsync(); - return resolveSubmitProfile({ easJson, platform, profileName }); + const profile = resolveSubmitProfile({ easJson, platform, profileName }); + this.validateSubmitProfile(profile, platform); + return profile; } } diff --git a/yarn.lock b/yarn.lock index 7f0254247a..d45124d257 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2226,6 +2226,18 @@ resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.1.tgz#076d78ce99822258cf813ecc1e7fa460fa74d052" integrity sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg== +"@hapi/address@5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@hapi/address/-/address-5.1.1.tgz#e9925fc1b65f5cc3fbea821f2b980e4652e84cb6" + integrity sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA== + dependencies: + "@hapi/hoek" "^11.0.2" + +"@hapi/hoek@^11.0.2": + version "11.0.4" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-11.0.4.tgz#42a7f244fd3dd777792bfb74b8c6340ae9182f37" + integrity sha512-PnsP5d4q7289pS2T2EgGz147BFJ2Jpb4yrEdkpz2IhgEUzos1S7HTl7ezWh1yfYzYlj89KzLdCRkqsP6SIryeQ== + "@hapi/hoek@^9.0.0": version "9.1.0" resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.1.0.tgz#6c9eafc78c1529248f8f4d92b0799a712b6052c6" From 971c5e06a1b9f9dde50a154b8aabaefd0c48e8d7 Mon Sep 17 00:00:00 2001 From: Szymon Dziedzic Date: Thu, 25 Jan 2024 11:00:33 +0100 Subject: [PATCH 02/11] add link to docs --- packages/eas-json/src/__tests__/submitProfiles-test.ts | 6 +++--- packages/eas-json/src/utils.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/eas-json/src/__tests__/submitProfiles-test.ts b/packages/eas-json/src/__tests__/submitProfiles-test.ts index 606a8a29a2..3d54c96513 100644 --- a/packages/eas-json/src/__tests__/submitProfiles-test.ts +++ b/packages/eas-json/src/__tests__/submitProfiles-test.ts @@ -257,7 +257,7 @@ test('ios config with with invalid ascAppId', async () => { const accessor = EasJsonAccessor.fromProjectPath('/project'); const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); await expect(promise).rejects.toThrow( - 'Invalid Apple App Store Connect App ID was specified. It should contain 10 digits. Example: "1234567891".' + 'Invalid Apple App Store Connect App ID was specified. It should contain 10 digits. Example: "1234567891". Learn more: https://expo.fyi/asc-app-id.md' ); }); @@ -303,7 +303,7 @@ test('ios config with with invalid ascApiKeyIssuerId', async () => { const accessor = EasJsonAccessor.fromProjectPath('/project'); const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); await expect(promise).rejects.toThrow( - 'Invalid Apple App Store Connect API Key Issuer ID was specified. It should be a valid UUID. Example: "123e4567-e89b-12d3-a456-426614174000".' + 'Invalid Apple App Store Connect API Key Issuer ID was specified. It should be a valid UUID. Example: "123e4567-e89b-12d3-a456-426614174000". Learn more: https://expo.fyi/creating-asc-api-key.' ); }); @@ -326,7 +326,7 @@ test('ios config with with invalid ascApiKeyId', async () => { const accessor = EasJsonAccessor.fromProjectPath('/project'); const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); await expect(promise).rejects.toThrow( - `Invalid Apple App Store Connect API Key ID was specified. It should contain 10 letters or digits. Example: "AB32CDE81F".` + `Invalid Apple App Store Connect API Key ID was specified. It should contain 10 letters or digits. Example: "AB32CDE81F". Learn more: https://expo.fyi/creating-asc-api-key.` ); }); diff --git a/packages/eas-json/src/utils.ts b/packages/eas-json/src/utils.ts index 9a164abc06..a555707078 100644 --- a/packages/eas-json/src/utils.ts +++ b/packages/eas-json/src/utils.ts @@ -111,7 +111,7 @@ export class EasJsonUtils { if (iosProfile.ascApiKeyId && !ASC_API_KEY_ID_REGEX.test(iosProfile.ascApiKeyId)) { throw new Error( - `Invalid Apple App Store Connect API Key ID was specified. It should contain 10 letters or digits. Example: "AB32CDE81F".` + `Invalid Apple App Store Connect API Key ID was specified. It should contain 10 letters or digits. Example: "AB32CDE81F". Learn more: https://expo.fyi/creating-asc-api-key.` ); } if (iosProfile.appleTeamId && !APPLE_TEAM_ID_REGEX.test(iosProfile.appleTeamId)) { @@ -121,12 +121,12 @@ export class EasJsonUtils { } if (iosProfile.ascAppId && !ASC_APP_ID_REGEX.test(iosProfile.ascAppId)) { throw new Error( - `Invalid Apple App Store Connect App ID was specified. It should contain 10 digits. Example: "1234567891".` + `Invalid Apple App Store Connect App ID was specified. It should contain 10 digits. Example: "1234567891". Learn more: https://expo.fyi/asc-app-id.md.` ); } if (iosProfile.ascApiKeyIssuerId && !validate(iosProfile.ascApiKeyIssuerId)) { throw new Error( - `Invalid Apple App Store Connect API Key Issuer ID was specified. It should be a valid UUID. Example: "123e4567-e89b-12d3-a456-426614174000".` + `Invalid Apple App Store Connect API Key Issuer ID was specified. It should be a valid UUID. Example: "123e4567-e89b-12d3-a456-426614174000". Learn more: https://expo.fyi/creating-asc-api-key.` ); } if (iosProfile.appleId && !isEmailValid(iosProfile.appleId)) { From 2f0f41db8684865cdec45ef0ae6c7ac681e1ce4a Mon Sep 17 00:00:00 2001 From: Szymon Dziedzic Date: Thu, 25 Jan 2024 10:08:47 +0000 Subject: [PATCH 03/11] update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecc3566b1a..ca66c990f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ This is the log of notable changes to EAS CLI and related packages. ### 🧹 Chores - Remove support for classic updates release channel in 50+. ([#2189](https://github.com/expo/eas-cli/pull/2189) by [@wschurman](https://github.com/wschurman)) +- Validate EAS Submit inputs better. ([#2198](https://github.com/expo/eas-cli/pull/2198) by [@szdziedzic](https://github.com/szdziedzic)) ## [7.0.0](https://github.com/expo/eas-cli/releases/tag/v7.0.0) - 2024-01-19 From 13ae4c0e2a3381473357eb9a1935753fc6635acc Mon Sep 17 00:00:00 2001 From: Szymon Dziedzic Date: Thu, 25 Jan 2024 14:27:26 +0100 Subject: [PATCH 04/11] validate app specific password --- .../src/submit/ios/IosSubmitCommand.ts | 5 ++ .../ios/__tests__/IosSubmitCommand-test.ts | 53 ++++++++++++++++--- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/packages/eas-cli/src/submit/ios/IosSubmitCommand.ts b/packages/eas-cli/src/submit/ios/IosSubmitCommand.ts index d2dc5a6be1..cc67f6ba0f 100644 --- a/packages/eas-cli/src/submit/ios/IosSubmitCommand.ts +++ b/packages/eas-cli/src/submit/ios/IosSubmitCommand.ts @@ -111,6 +111,11 @@ export default class IosSubmitCommand { const envAppSpecificPassword = getenv.string('EXPO_APPLE_APP_SPECIFIC_PASSWORD', ''); if (envAppSpecificPassword) { + if (!/^[a-z]{4}-[a-z]{4}-[a-z]{4}-[a-z]{4}$/.test(envAppSpecificPassword)) { + throw new Error( + 'EXPO_APPLE_APP_SPECIFIC_PASSWORD must be in the format XXXX-XXXX-XXXX-XXXX, where X is a lowercase letter.' + ); + } return result({ sourceType: AppSpecificPasswordSourceType.userDefined, appSpecificPassword: envAppSpecificPassword, diff --git a/packages/eas-cli/src/submit/ios/__tests__/IosSubmitCommand-test.ts b/packages/eas-cli/src/submit/ios/__tests__/IosSubmitCommand-test.ts index e214002744..5d5ef512f6 100644 --- a/packages/eas-cli/src/submit/ios/__tests__/IosSubmitCommand-test.ts +++ b/packages/eas-cli/src/submit/ios/__tests__/IosSubmitCommand-test.ts @@ -78,6 +78,43 @@ describe(IosSubmitCommand, () => { jest.mocked(getOwnerAccountForProjectIdAsync).mockResolvedValue(mockJester.accounts[0]); }); + it('throws an error if using app specific passowrd in invalid format', async () => { + const projectId = uuidv4(); + const graphqlClient = {} as any as ExpoGraphqlClient; + const analytics = instance(mock()); + jest + .mocked(getArchiveAsync) + .mockImplementation(jest.requireActual('../../ArchiveSource').getArchiveAsync); + + process.env.EXPO_APPLE_APP_SPECIFIC_PASSWORD = 'ls -la'; + + const ctx = await createSubmissionContextAsync({ + platform: Platform.IOS, + projectDir: testProject.projectRoot, + archiveFlags: { + url: 'http://expo.dev/fake.ipa', + }, + profile: { + language: 'en-US', + appleId: 'test@example.com', + ascAppId: '12345678', + }, + nonInteractive: false, + actor: mockJester, + graphqlClient, + analytics, + exp: testProject.appJSON.expo, + projectId, + vcsClient, + }); + const command = new IosSubmitCommand(ctx); + await expect(command.runAsync()).rejects.toThrow( + 'EXPO_APPLE_APP_SPECIFIC_PASSWORD must be in the format XXXX-XXXX-XXXX-XXXX, where X is a lowercase letter.' + ); + + delete process.env.EXPO_APPLE_APP_SPECIFIC_PASSWORD; + }); + describe('non-interactive mode', () => { it("throws error if didn't provide appleId and ascAppId in the submit profile", async () => { const projectId = uuidv4(); @@ -118,7 +155,7 @@ describe(IosSubmitCommand, () => { .mocked(getArchiveAsync) .mockImplementation(jest.requireActual('../../ArchiveSource').getArchiveAsync); - process.env.EXPO_APPLE_APP_SPECIFIC_PASSWORD = 'supersecret'; + process.env.EXPO_APPLE_APP_SPECIFIC_PASSWORD = 'abcd-abcd-abcd-abcd'; const ctx = await createSubmissionContextAsync({ platform: Platform.IOS, @@ -147,7 +184,7 @@ describe(IosSubmitCommand, () => { archiveSource: { type: SubmissionArchiveSourceType.Url, url: 'http://expo.dev/fake.ipa' }, config: { appleIdUsername: 'test@example.com', - appleAppSpecificPassword: 'supersecret', + appleAppSpecificPassword: 'abcd-abcd-abcd-abcd', ascAppIdentifier: '12345678', }, }); @@ -182,7 +219,7 @@ describe(IosSubmitCommand, () => { return ctx; }); - process.env.EXPO_APPLE_APP_SPECIFIC_PASSWORD = 'supersecret'; + process.env.EXPO_APPLE_APP_SPECIFIC_PASSWORD = 'abcd-abcd-abcd-abcd'; const ctx = await createSubmissionContextAsync({ platform: Platform.IOS, @@ -209,7 +246,7 @@ describe(IosSubmitCommand, () => { submittedBuildId: selectedBuild.id, config: { appleIdUsername: 'other-test@example.com', - appleAppSpecificPassword: 'supersecret', + appleAppSpecificPassword: 'abcd-abcd-abcd-abcd', ascAppIdentifier: '87654321', }, archiveSource: undefined, @@ -239,7 +276,7 @@ describe(IosSubmitCommand, () => { return ctx; }); - process.env.EXPO_APPLE_APP_SPECIFIC_PASSWORD = 'supersecret'; + process.env.EXPO_APPLE_APP_SPECIFIC_PASSWORD = 'abcd-abcd-abcd-abcd'; const ctx = await createSubmissionContextAsync({ platform: Platform.IOS, @@ -266,7 +303,7 @@ describe(IosSubmitCommand, () => { submittedBuildId: selectedBuild.id, config: { appleIdUsername: 'test@example.com', - appleAppSpecificPassword: 'supersecret', + appleAppSpecificPassword: 'abcd-abcd-abcd-abcd', ascAppIdentifier: '12345678', }, archiveSource: undefined, @@ -301,7 +338,7 @@ describe(IosSubmitCommand, () => { return ctx; }); - process.env.EXPO_APPLE_APP_SPECIFIC_PASSWORD = 'supersecret'; + process.env.EXPO_APPLE_APP_SPECIFIC_PASSWORD = 'abcd-abcd-abcd-abcd'; const ctx = await createSubmissionContextAsync({ platform: Platform.IOS, @@ -329,7 +366,7 @@ describe(IosSubmitCommand, () => { submittedBuildId: selectedBuild.id, config: { appleIdUsername: 'test@example.com', - appleAppSpecificPassword: 'supersecret', + appleAppSpecificPassword: 'abcd-abcd-abcd-abcd', ascAppIdentifier: '12345678', }, archiveSource: undefined, From e24cd936ad382d90a6bef4cc07aaa8cc1decb71f Mon Sep 17 00:00:00 2001 From: Szymon Dziedzic Date: Thu, 25 Jan 2024 15:07:56 +0100 Subject: [PATCH 05/11] use Joi schema for validation --- packages/eas-json/package.json | 4 +- .../src/__tests__/submitProfiles-test.ts | 8 +-- packages/eas-json/src/schema.ts | 4 +- packages/eas-json/src/submit/resolver.ts | 4 +- packages/eas-json/src/submit/schema.ts | 44 ++++++++++++++- packages/eas-json/src/utils.ts | 55 ++++--------------- yarn.lock | 12 ---- 7 files changed, 62 insertions(+), 69 deletions(-) diff --git a/packages/eas-json/package.json b/packages/eas-json/package.json index 8a43e48197..a8b2f64a71 100644 --- a/packages/eas-json/package.json +++ b/packages/eas-json/package.json @@ -7,7 +7,6 @@ "dependencies": { "@babel/code-frame": "7.23.5", "@expo/eas-build-job": "1.0.56", - "@hapi/address": "5.1.1", "chalk": "4.1.2", "env-string": "1.0.1", "fs-extra": "11.2.0", @@ -16,8 +15,7 @@ "log-symbols": "4.1.0", "semver": "7.5.2", "terminal-link": "2.1.1", - "tslib": "2.4.1", - "uuid": "9.0.1" + "tslib": "2.4.1" }, "devDependencies": { "@types/babel__code-frame": "7.0.3", diff --git a/packages/eas-json/src/__tests__/submitProfiles-test.ts b/packages/eas-json/src/__tests__/submitProfiles-test.ts index 3d54c96513..34964bb4cd 100644 --- a/packages/eas-json/src/__tests__/submitProfiles-test.ts +++ b/packages/eas-json/src/__tests__/submitProfiles-test.ts @@ -257,7 +257,7 @@ test('ios config with with invalid ascAppId', async () => { const accessor = EasJsonAccessor.fromProjectPath('/project'); const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); await expect(promise).rejects.toThrow( - 'Invalid Apple App Store Connect App ID was specified. It should contain 10 digits. Example: "1234567891". Learn more: https://expo.fyi/asc-app-id.md' + 'Invalid Apple App Store Connect App ID ("ascAppId") was specified. It should consist of 10 digits. Example: "1234567891". Learn more: https://expo.fyi/asc-app-id.md.' ); }); @@ -280,7 +280,7 @@ test('ios config with with invalid appleTeamId', async () => { const accessor = EasJsonAccessor.fromProjectPath('/project'); const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); await expect(promise).rejects.toThrow( - 'Invalid Apple Team ID was specified. It should contain 10 letters or digits. Example: "AB32CDE81F".' + 'Invalid Apple Team ID was specified. It should consist of 10 letters or digits. Example: "AB32CDE81F".' ); }); @@ -303,7 +303,7 @@ test('ios config with with invalid ascApiKeyIssuerId', async () => { const accessor = EasJsonAccessor.fromProjectPath('/project'); const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); await expect(promise).rejects.toThrow( - 'Invalid Apple App Store Connect API Key Issuer ID was specified. It should be a valid UUID. Example: "123e4567-e89b-12d3-a456-426614174000". Learn more: https://expo.fyi/creating-asc-api-key.' + 'Invalid Apple App Store Connect API Key Issuer ID ("ascApiKeyIssuerId") was specified. It should be a valid UUID. Example: "123e4567-e89b-12d3-a456-426614174000". Learn more: https://expo.fyi/creating-asc-api-key.' ); }); @@ -326,7 +326,7 @@ test('ios config with with invalid ascApiKeyId', async () => { const accessor = EasJsonAccessor.fromProjectPath('/project'); const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); await expect(promise).rejects.toThrow( - `Invalid Apple App Store Connect API Key ID was specified. It should contain 10 letters or digits. Example: "AB32CDE81F". Learn more: https://expo.fyi/creating-asc-api-key.` + `Invalid Apple App Store Connect API Key I ("ascApiKeyId") was specified. It should consist of 10 upper case letters or digits. Example: "AB32CDE81F". Learn more: https://expo.fyi/creating-asc-api-key.` ); }); diff --git a/packages/eas-json/src/schema.ts b/packages/eas-json/src/schema.ts index bf8d2585ac..d92a74e922 100644 --- a/packages/eas-json/src/schema.ts +++ b/packages/eas-json/src/schema.ts @@ -1,7 +1,7 @@ import Joi from 'joi'; import { BuildProfileSchema } from './build/schema'; -import { SubmitProfileSchema } from './submit/schema'; +import { UnresolvedSubmitProfileSchema } from './submit/schema'; import { AppVersionSource } from './types'; export const EasJsonSchema = Joi.object({ @@ -12,5 +12,5 @@ export const EasJsonSchema = Joi.object({ promptToConfigurePushNotifications: Joi.boolean(), }), build: Joi.object().pattern(Joi.string(), BuildProfileSchema), - submit: Joi.object().pattern(Joi.string(), SubmitProfileSchema), + submit: Joi.object().pattern(Joi.string(), UnresolvedSubmitProfileSchema), }); diff --git a/packages/eas-json/src/submit/resolver.ts b/packages/eas-json/src/submit/resolver.ts index db74db5f71..9f525b0edd 100644 --- a/packages/eas-json/src/submit/resolver.ts +++ b/packages/eas-json/src/submit/resolver.ts @@ -1,7 +1,7 @@ import { Platform } from '@expo/eas-build-job'; import envString from 'env-string'; -import { AndroidSubmitProfileSchema, IosSubmitProfileSchema } from './schema'; +import { AndroidSubmitProfileSchema, UnresolvedIosSubmitProfileSchema } from './schema'; import { AndroidSubmitProfileFieldsToEvaluate, IosSubmitProfileFieldsToEvaluate, @@ -99,7 +99,7 @@ function mergeProfiles( export function getDefaultProfile(platform: T): SubmitProfile { const Schema = - platform === Platform.ANDROID ? AndroidSubmitProfileSchema : IosSubmitProfileSchema; + platform === Platform.ANDROID ? AndroidSubmitProfileSchema : UnresolvedIosSubmitProfileSchema; return Schema.validate({}, { allowUnknown: false, abortEarly: false, convert: true }).value; } diff --git a/packages/eas-json/src/submit/schema.ts b/packages/eas-json/src/submit/schema.ts index 007eb8f2d7..6dc2903ed5 100644 --- a/packages/eas-json/src/submit/schema.ts +++ b/packages/eas-json/src/submit/schema.ts @@ -19,7 +19,9 @@ export const AndroidSubmitProfileSchema = Joi.object({ }), }); -export const IosSubmitProfileSchema = Joi.object({ +// it is less strict submission schema allowing for magic syntax like "$ASC_API_KEY_PATH" +// to read value from environment variable later on +export const UnresolvedIosSubmitProfileSchema = Joi.object({ ascApiKeyPath: Joi.string(), ascApiKeyId: Joi.string(), ascApiKeyIssuerId: Joi.string(), @@ -34,8 +36,44 @@ export const IosSubmitProfileSchema = Joi.object({ metadataPath: Joi.string(), }); -export const SubmitProfileSchema = Joi.object({ +// more strict version after resolving all of the values +export const ResolvedIosSubmitProfileSchema = Joi.object({ + ascApiKeyPath: Joi.string(), + ascApiKeyId: Joi.string() + .regex(/^[\dA-Z]{10}$/) + .message( + 'Invalid Apple App Store Connect API Key I ("ascApiKeyId") was specified. It should consist of 10 upper case letters or digits. Example: "AB32CDE81F". Learn more: https://expo.fyi/creating-asc-api-key.' + ), + ascApiKeyIssuerId: Joi.string() + .uuid() + .message( + 'Invalid Apple App Store Connect API Key Issuer ID ("ascApiKeyIssuerId") was specified. It should be a valid UUID. Example: "123e4567-e89b-12d3-a456-426614174000". Learn more: https://expo.fyi/creating-asc-api-key.' + ), + appleId: Joi.string() + .email() + .message( + 'Invalid Apple ID was specified. It should be a valid email address. Example: "name@domain.com".' + ), + ascAppId: Joi.string() + .regex(/^\d{10}$/) + .message( + 'Invalid Apple App Store Connect App ID ("ascAppId") was specified. It should consist of 10 digits. Example: "1234567891". Learn more: https://expo.fyi/asc-app-id.md.' + ), + appleTeamId: Joi.string() + .regex(/^[\dA-Z]{10}$/) + .message( + 'Invalid Apple Team ID was specified. It should consist of 10 letters or digits. Example: "AB32CDE81F".' + ), + sku: Joi.string(), + language: Joi.string().default('en-US'), + companyName: Joi.string(), + appName: Joi.string(), + bundleIdentifier: Joi.string(), + metadataPath: Joi.string(), +}); + +export const UnresolvedSubmitProfileSchema = Joi.object({ extends: Joi.string(), android: AndroidSubmitProfileSchema, - ios: IosSubmitProfileSchema, + ios: UnresolvedIosSubmitProfileSchema, }); diff --git a/packages/eas-json/src/utils.ts b/packages/eas-json/src/utils.ts index a555707078..a44f102363 100644 --- a/packages/eas-json/src/utils.ts +++ b/packages/eas-json/src/utils.ts @@ -1,19 +1,14 @@ import { Platform } from '@expo/eas-build-job'; -import { isEmailValid } from '@hapi/address'; -import { validate } from 'uuid'; import { EasJsonAccessor } from './accessor'; import { resolveBuildProfile } from './build/resolver'; import { BuildProfile } from './build/types'; import { MissingEasJsonError } from './errors'; import { resolveSubmitProfile } from './submit/resolver'; +import { AndroidSubmitProfileSchema, ResolvedIosSubmitProfileSchema } from './submit/schema'; import { SubmitProfile } from './submit/types'; import { EasJson } from './types'; -const ASC_API_KEY_ID_REGEX = /^[\dA-Z]{10}$/; -const APPLE_TEAM_ID_REGEX = /^[\dA-Z]{10}$/; -const ASC_APP_ID_REGEX = /^\d{10}$/; - interface EasJsonDeprecationWarning { message: string[]; docsUrl?: string; @@ -102,41 +97,6 @@ export class EasJsonUtils { return Object.keys(easJson?.submit ?? {}); } - public static validateSubmitProfile( - profile: SubmitProfile, - platform: T - ): void { - if (platform === Platform.IOS) { - const iosProfile = profile as SubmitProfile; - - if (iosProfile.ascApiKeyId && !ASC_API_KEY_ID_REGEX.test(iosProfile.ascApiKeyId)) { - throw new Error( - `Invalid Apple App Store Connect API Key ID was specified. It should contain 10 letters or digits. Example: "AB32CDE81F". Learn more: https://expo.fyi/creating-asc-api-key.` - ); - } - if (iosProfile.appleTeamId && !APPLE_TEAM_ID_REGEX.test(iosProfile.appleTeamId)) { - throw new Error( - `Invalid Apple Team ID was specified. It should contain 10 letters or digits. Example: "AB32CDE81F".` - ); - } - if (iosProfile.ascAppId && !ASC_APP_ID_REGEX.test(iosProfile.ascAppId)) { - throw new Error( - `Invalid Apple App Store Connect App ID was specified. It should contain 10 digits. Example: "1234567891". Learn more: https://expo.fyi/asc-app-id.md.` - ); - } - if (iosProfile.ascApiKeyIssuerId && !validate(iosProfile.ascApiKeyIssuerId)) { - throw new Error( - `Invalid Apple App Store Connect API Key Issuer ID was specified. It should be a valid UUID. Example: "123e4567-e89b-12d3-a456-426614174000". Learn more: https://expo.fyi/creating-asc-api-key.` - ); - } - if (iosProfile.appleId && !isEmailValid(iosProfile.appleId)) { - throw new Error( - `Invalid Apple ID was specified. It should be a valid email address. Example: "name@domain.com".` - ); - } - } - } - public static async getSubmitProfileAsync( accessor: EasJsonAccessor, platform: T, @@ -144,7 +104,16 @@ export class EasJsonUtils { ): Promise> { const easJson = await accessor.readAsync(); const profile = resolveSubmitProfile({ easJson, platform, profileName }); - this.validateSubmitProfile(profile, platform); - return profile; + const Schema = + platform === Platform.ANDROID ? AndroidSubmitProfileSchema : ResolvedIosSubmitProfileSchema; + const { value, error } = Schema.validate(profile, { + allowUnknown: false, + abortEarly: false, + convert: true, + }); + if (error) { + throw error; + } + return value; } } diff --git a/yarn.lock b/yarn.lock index d45124d257..7f0254247a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2226,18 +2226,6 @@ resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.1.tgz#076d78ce99822258cf813ecc1e7fa460fa74d052" integrity sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg== -"@hapi/address@5.1.1": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@hapi/address/-/address-5.1.1.tgz#e9925fc1b65f5cc3fbea821f2b980e4652e84cb6" - integrity sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA== - dependencies: - "@hapi/hoek" "^11.0.2" - -"@hapi/hoek@^11.0.2": - version "11.0.4" - resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-11.0.4.tgz#42a7f244fd3dd777792bfb74b8c6340ae9182f37" - integrity sha512-PnsP5d4q7289pS2T2EgGz147BFJ2Jpb4yrEdkpz2IhgEUzos1S7HTl7ezWh1yfYzYlj89KzLdCRkqsP6SIryeQ== - "@hapi/hoek@^9.0.0": version "9.1.0" resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.1.0.tgz#6c9eafc78c1529248f8f4d92b0799a712b6052c6" From 5b124ba7531a1c26d67cefebc0f30611bd42d16d Mon Sep 17 00:00:00 2001 From: Szymon Dziedzic Date: Thu, 25 Jan 2024 15:12:08 +0100 Subject: [PATCH 06/11] fix typo --- packages/eas-json/src/__tests__/submitProfiles-test.ts | 2 +- packages/eas-json/src/submit/schema.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eas-json/src/__tests__/submitProfiles-test.ts b/packages/eas-json/src/__tests__/submitProfiles-test.ts index 34964bb4cd..0cd4046e6c 100644 --- a/packages/eas-json/src/__tests__/submitProfiles-test.ts +++ b/packages/eas-json/src/__tests__/submitProfiles-test.ts @@ -326,7 +326,7 @@ test('ios config with with invalid ascApiKeyId', async () => { const accessor = EasJsonAccessor.fromProjectPath('/project'); const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); await expect(promise).rejects.toThrow( - `Invalid Apple App Store Connect API Key I ("ascApiKeyId") was specified. It should consist of 10 upper case letters or digits. Example: "AB32CDE81F". Learn more: https://expo.fyi/creating-asc-api-key.` + `Invalid Apple App Store Connect API Key ID ("ascApiKeyId") was specified. It should consist of 10 upper case letters or digits. Example: "AB32CDE81F". Learn more: https://expo.fyi/creating-asc-api-key.` ); }); diff --git a/packages/eas-json/src/submit/schema.ts b/packages/eas-json/src/submit/schema.ts index 6dc2903ed5..6d7a90df2f 100644 --- a/packages/eas-json/src/submit/schema.ts +++ b/packages/eas-json/src/submit/schema.ts @@ -42,7 +42,7 @@ export const ResolvedIosSubmitProfileSchema = Joi.object({ ascApiKeyId: Joi.string() .regex(/^[\dA-Z]{10}$/) .message( - 'Invalid Apple App Store Connect API Key I ("ascApiKeyId") was specified. It should consist of 10 upper case letters or digits. Example: "AB32CDE81F". Learn more: https://expo.fyi/creating-asc-api-key.' + 'Invalid Apple App Store Connect API Key ID ("ascApiKeyId") was specified. It should consist of 10 upper case letters or digits. Example: "AB32CDE81F". Learn more: https://expo.fyi/creating-asc-api-key.' ), ascApiKeyIssuerId: Joi.string() .uuid() From 38da7300da8c53299c1aba2980ac60b8f73f1357 Mon Sep 17 00:00:00 2001 From: Szymon Dziedzic Date: Thu, 25 Jan 2024 15:34:59 +0100 Subject: [PATCH 07/11] minor improvements --- .../eas-json/src/__tests__/submitProfiles-test.ts | 12 ++++++------ packages/eas-json/src/submit/schema.ts | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/eas-json/src/__tests__/submitProfiles-test.ts b/packages/eas-json/src/__tests__/submitProfiles-test.ts index 0cd4046e6c..0287a56216 100644 --- a/packages/eas-json/src/__tests__/submitProfiles-test.ts +++ b/packages/eas-json/src/__tests__/submitProfiles-test.ts @@ -109,7 +109,7 @@ test('ios config with all required values', async () => { ascAppId: '1223423523', appleTeamId: 'AB32CDE81F', ascApiKeyPath: './path-ABCD.p8', - ascApiKeyIssuerId: '123e4567-e89b-12d3-a456-426614174000', + ascApiKeyIssuerId: 'b4d78f58-48c6-4f2c-96cb-94d8cd76970a', ascApiKeyId: 'AB32CDE81F', }, }, @@ -124,7 +124,7 @@ test('ios config with all required values', async () => { appleTeamId: 'AB32CDE81F', ascAppId: '1223423523', ascApiKeyPath: './path-ABCD.p8', - ascApiKeyIssuerId: '123e4567-e89b-12d3-a456-426614174000', + ascApiKeyIssuerId: 'b4d78f58-48c6-4f2c-96cb-94d8cd76970a', ascApiKeyId: 'AB32CDE81F', language: 'en-US', }); @@ -148,7 +148,7 @@ test('ios config with ascApiKey fields set to env var', async () => { try { process.env.ASC_API_KEY_PATH = './path-ABCD.p8'; - process.env.ASC_API_KEY_ISSUER_ID = '123e4567-e89b-12d3-a456-426614174000'; + process.env.ASC_API_KEY_ISSUER_ID = 'b4d78f58-48c6-4f2c-96cb-94d8cd76970a'; process.env.ASC_API_KEY_ID = 'AB32CDE81F'; const accessor = EasJsonAccessor.fromProjectPath('/project'); const iosProfile = await EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); @@ -158,7 +158,7 @@ test('ios config with ascApiKey fields set to env var', async () => { ascAppId: '1223423523', appleTeamId: 'AB32CDE81F', ascApiKeyPath: './path-ABCD.p8', - ascApiKeyIssuerId: '123e4567-e89b-12d3-a456-426614174000', + ascApiKeyIssuerId: 'b4d78f58-48c6-4f2c-96cb-94d8cd76970a', ascApiKeyId: 'AB32CDE81F', language: 'en-US', }); @@ -303,7 +303,7 @@ test('ios config with with invalid ascApiKeyIssuerId', async () => { const accessor = EasJsonAccessor.fromProjectPath('/project'); const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); await expect(promise).rejects.toThrow( - 'Invalid Apple App Store Connect API Key Issuer ID ("ascApiKeyIssuerId") was specified. It should be a valid UUID. Example: "123e4567-e89b-12d3-a456-426614174000". Learn more: https://expo.fyi/creating-asc-api-key.' + 'Invalid Apple App Store Connect API Key Issuer ID ("ascApiKeyIssuerId") was specified. It should be a valid UUID. Example: "b4d78f58-48c6-4f2c-96cb-94d8cd76970a". Learn more: https://expo.fyi/creating-asc-api-key.' ); }); @@ -316,7 +316,7 @@ test('ios config with with invalid ascApiKeyId', async () => { ascAppId: '1223423523', appleTeamId: 'AB32CDE81F', ascApiKeyPath: './path-ABCD.p8', - ascApiKeyIssuerId: '123e4567-e89b-12d3-a456-426614174000', + ascApiKeyIssuerId: 'b4d78f58-48c6-4f2c-96cb-94d8cd76970a', ascApiKeyId: 'wrong value', }, }, diff --git a/packages/eas-json/src/submit/schema.ts b/packages/eas-json/src/submit/schema.ts index 6d7a90df2f..82bc57dfa1 100644 --- a/packages/eas-json/src/submit/schema.ts +++ b/packages/eas-json/src/submit/schema.ts @@ -45,9 +45,9 @@ export const ResolvedIosSubmitProfileSchema = Joi.object({ 'Invalid Apple App Store Connect API Key ID ("ascApiKeyId") was specified. It should consist of 10 upper case letters or digits. Example: "AB32CDE81F". Learn more: https://expo.fyi/creating-asc-api-key.' ), ascApiKeyIssuerId: Joi.string() - .uuid() + .uuid({ version: 'uuidv4' }) .message( - 'Invalid Apple App Store Connect API Key Issuer ID ("ascApiKeyIssuerId") was specified. It should be a valid UUID. Example: "123e4567-e89b-12d3-a456-426614174000". Learn more: https://expo.fyi/creating-asc-api-key.' + 'Invalid Apple App Store Connect API Key Issuer ID ("ascApiKeyIssuerId") was specified. It should be a valid UUID. Example: "b4d78f58-48c6-4f2c-96cb-94d8cd76970a". Learn more: https://expo.fyi/creating-asc-api-key.' ), appleId: Joi.string() .email() From 3e6fdc6077c0f272ceabb8986cdf23dcc1599713 Mon Sep 17 00:00:00 2001 From: Szymon Dziedzic Date: Thu, 25 Jan 2024 15:37:24 +0100 Subject: [PATCH 08/11] Update packages/eas-cli/src/submit/ios/__tests__/IosSubmitCommand-test.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Stanisław Chmiela --- .../eas-cli/src/submit/ios/__tests__/IosSubmitCommand-test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eas-cli/src/submit/ios/__tests__/IosSubmitCommand-test.ts b/packages/eas-cli/src/submit/ios/__tests__/IosSubmitCommand-test.ts index 5d5ef512f6..d0687fd330 100644 --- a/packages/eas-cli/src/submit/ios/__tests__/IosSubmitCommand-test.ts +++ b/packages/eas-cli/src/submit/ios/__tests__/IosSubmitCommand-test.ts @@ -78,7 +78,7 @@ describe(IosSubmitCommand, () => { jest.mocked(getOwnerAccountForProjectIdAsync).mockResolvedValue(mockJester.accounts[0]); }); - it('throws an error if using app specific passowrd in invalid format', async () => { + it('throws an error if using app specific password in invalid format', async () => { const projectId = uuidv4(); const graphqlClient = {} as any as ExpoGraphqlClient; const analytics = instance(mock()); From d96d071278c99056561c7beabcf80f2dcfdc2e76 Mon Sep 17 00:00:00 2001 From: Szymon Dziedzic Date: Thu, 25 Jan 2024 17:30:31 +0100 Subject: [PATCH 09/11] make uuid validation less strict --- packages/eas-json/src/submit/schema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eas-json/src/submit/schema.ts b/packages/eas-json/src/submit/schema.ts index 82bc57dfa1..db47197bd4 100644 --- a/packages/eas-json/src/submit/schema.ts +++ b/packages/eas-json/src/submit/schema.ts @@ -45,7 +45,7 @@ export const ResolvedIosSubmitProfileSchema = Joi.object({ 'Invalid Apple App Store Connect API Key ID ("ascApiKeyId") was specified. It should consist of 10 upper case letters or digits. Example: "AB32CDE81F". Learn more: https://expo.fyi/creating-asc-api-key.' ), ascApiKeyIssuerId: Joi.string() - .uuid({ version: 'uuidv4' }) + .uuid() .message( 'Invalid Apple App Store Connect API Key Issuer ID ("ascApiKeyIssuerId") was specified. It should be a valid UUID. Example: "b4d78f58-48c6-4f2c-96cb-94d8cd76970a". Learn more: https://expo.fyi/creating-asc-api-key.' ), From a9fc92e61a188a63fa3cae009c06b5413cee78a7 Mon Sep 17 00:00:00 2001 From: Szymon Dziedzic Date: Fri, 26 Jan 2024 10:17:02 +0100 Subject: [PATCH 10/11] apply suggested changes --- packages/eas-json/src/submit/resolver.ts | 4 ++-- packages/eas-json/src/submit/schema.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/eas-json/src/submit/resolver.ts b/packages/eas-json/src/submit/resolver.ts index 9f525b0edd..e5c8657520 100644 --- a/packages/eas-json/src/submit/resolver.ts +++ b/packages/eas-json/src/submit/resolver.ts @@ -1,7 +1,7 @@ import { Platform } from '@expo/eas-build-job'; import envString from 'env-string'; -import { AndroidSubmitProfileSchema, UnresolvedIosSubmitProfileSchema } from './schema'; +import { AndroidSubmitProfileSchema, ResolvedIosSubmitProfileSchema } from './schema'; import { AndroidSubmitProfileFieldsToEvaluate, IosSubmitProfileFieldsToEvaluate, @@ -99,7 +99,7 @@ function mergeProfiles( export function getDefaultProfile(platform: T): SubmitProfile { const Schema = - platform === Platform.ANDROID ? AndroidSubmitProfileSchema : UnresolvedIosSubmitProfileSchema; + platform === Platform.ANDROID ? AndroidSubmitProfileSchema : ResolvedIosSubmitProfileSchema; return Schema.validate({}, { allowUnknown: false, abortEarly: false, convert: true }).value; } diff --git a/packages/eas-json/src/submit/schema.ts b/packages/eas-json/src/submit/schema.ts index db47197bd4..b1a27448f7 100644 --- a/packages/eas-json/src/submit/schema.ts +++ b/packages/eas-json/src/submit/schema.ts @@ -42,7 +42,7 @@ export const ResolvedIosSubmitProfileSchema = Joi.object({ ascApiKeyId: Joi.string() .regex(/^[\dA-Z]{10}$/) .message( - 'Invalid Apple App Store Connect API Key ID ("ascApiKeyId") was specified. It should consist of 10 upper case letters or digits. Example: "AB32CDE81F". Learn more: https://expo.fyi/creating-asc-api-key.' + 'Invalid Apple App Store Connect API Key ID ("ascApiKeyId") was specified. It should consist of 10 uppercase letters or digits. Example: "AB32CDE81F". Learn more: https://expo.fyi/creating-asc-api-key.' ), ascApiKeyIssuerId: Joi.string() .uuid() @@ -52,7 +52,7 @@ export const ResolvedIosSubmitProfileSchema = Joi.object({ appleId: Joi.string() .email() .message( - 'Invalid Apple ID was specified. It should be a valid email address. Example: "name@domain.com".' + 'Invalid Apple ID was specified. It should be a valid email address. Example: "name@example.com".' ), ascAppId: Joi.string() .regex(/^\d{10}$/) @@ -62,7 +62,7 @@ export const ResolvedIosSubmitProfileSchema = Joi.object({ appleTeamId: Joi.string() .regex(/^[\dA-Z]{10}$/) .message( - 'Invalid Apple Team ID was specified. It should consist of 10 letters or digits. Example: "AB32CDE81F".' + 'Invalid Apple Team ID was specified. It should consist of 10 uppercase letters or digits. Example: "AB32CDE81F".' ), sku: Joi.string(), language: Joi.string().default('en-US'), From 9c9320d4e113e073f692225957c1e50668b71e57 Mon Sep 17 00:00:00 2001 From: Szymon Dziedzic Date: Fri, 26 Jan 2024 10:28:37 +0100 Subject: [PATCH 11/11] fix tests --- packages/eas-json/src/__tests__/submitProfiles-test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/eas-json/src/__tests__/submitProfiles-test.ts b/packages/eas-json/src/__tests__/submitProfiles-test.ts index 0287a56216..c9a89d351c 100644 --- a/packages/eas-json/src/__tests__/submitProfiles-test.ts +++ b/packages/eas-json/src/__tests__/submitProfiles-test.ts @@ -234,7 +234,7 @@ test('ios config with with invalid appleId', async () => { const accessor = EasJsonAccessor.fromProjectPath('/project'); const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); await expect(promise).rejects.toThrow( - 'Invalid Apple ID was specified. It should be a valid email address. Example: "name@domain.com".' + 'Invalid Apple ID was specified. It should be a valid email address. Example: "name@example.com".' ); }); @@ -280,7 +280,7 @@ test('ios config with with invalid appleTeamId', async () => { const accessor = EasJsonAccessor.fromProjectPath('/project'); const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); await expect(promise).rejects.toThrow( - 'Invalid Apple Team ID was specified. It should consist of 10 letters or digits. Example: "AB32CDE81F".' + 'Invalid Apple Team ID was specified. It should consist of 10 uppercase letters or digits. Example: "AB32CDE81F".' ); }); @@ -326,7 +326,7 @@ test('ios config with with invalid ascApiKeyId', async () => { const accessor = EasJsonAccessor.fromProjectPath('/project'); const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release'); await expect(promise).rejects.toThrow( - `Invalid Apple App Store Connect API Key ID ("ascApiKeyId") was specified. It should consist of 10 upper case letters or digits. Example: "AB32CDE81F". Learn more: https://expo.fyi/creating-asc-api-key.` + `Invalid Apple App Store Connect API Key ID ("ascApiKeyId") was specified. It should consist of 10 uppercase letters or digits. Example: "AB32CDE81F". Learn more: https://expo.fyi/creating-asc-api-key.` ); });