Skip to content

Commit

Permalink
Revert "[eas-json] validate EAS Submit inputs better" (#2200)
Browse files Browse the repository at this point in the history
* Revert "[eas-json] validate EAS Submit inputs better"

* revert changelog revert

* update CHANGELOG.md
  • Loading branch information
szdziedzic committed Jan 26, 2024
1 parent 62d149a commit 61543c7
Show file tree
Hide file tree
Showing 8 changed files with 38 additions and 243 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ This is the log of notable changes to EAS CLI and related packages.

### 🐛 Bug fixes

- Revert incorrect EAS Submit input validation changes. ([#2200](https://github.com/expo/eas-cli/pull/2200) by [@szdziedzic](https://github.com/szdziedzic))

### 🧹 Chores

## [7.1.0](https://github.com/expo/eas-cli/releases/tag/v7.1.0) - 2024-01-26
Expand Down
5 changes: 0 additions & 5 deletions packages/eas-cli/src/submit/ios/IosSubmitCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,6 @@ 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,
Expand Down
53 changes: 8 additions & 45 deletions packages/eas-cli/src/submit/ios/__tests__/IosSubmitCommand-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,43 +78,6 @@ describe(IosSubmitCommand, () => {
jest.mocked(getOwnerAccountForProjectIdAsync).mockResolvedValue(mockJester.accounts[0]);
});

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<Analytics>());
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();
Expand Down Expand Up @@ -155,7 +118,7 @@ describe(IosSubmitCommand, () => {
.mocked(getArchiveAsync)
.mockImplementation(jest.requireActual('../../ArchiveSource').getArchiveAsync);

process.env.EXPO_APPLE_APP_SPECIFIC_PASSWORD = 'abcd-abcd-abcd-abcd';
process.env.EXPO_APPLE_APP_SPECIFIC_PASSWORD = 'supersecret';

const ctx = await createSubmissionContextAsync({
platform: Platform.IOS,
Expand Down Expand Up @@ -184,7 +147,7 @@ describe(IosSubmitCommand, () => {
archiveSource: { type: SubmissionArchiveSourceType.Url, url: 'http://expo.dev/fake.ipa' },
config: {
appleIdUsername: 'test@example.com',
appleAppSpecificPassword: 'abcd-abcd-abcd-abcd',
appleAppSpecificPassword: 'supersecret',
ascAppIdentifier: '12345678',
},
});
Expand Down Expand Up @@ -219,7 +182,7 @@ describe(IosSubmitCommand, () => {
return ctx;
});

process.env.EXPO_APPLE_APP_SPECIFIC_PASSWORD = 'abcd-abcd-abcd-abcd';
process.env.EXPO_APPLE_APP_SPECIFIC_PASSWORD = 'supersecret';

const ctx = await createSubmissionContextAsync({
platform: Platform.IOS,
Expand All @@ -246,7 +209,7 @@ describe(IosSubmitCommand, () => {
submittedBuildId: selectedBuild.id,
config: {
appleIdUsername: 'other-test@example.com',
appleAppSpecificPassword: 'abcd-abcd-abcd-abcd',
appleAppSpecificPassword: 'supersecret',
ascAppIdentifier: '87654321',
},
archiveSource: undefined,
Expand Down Expand Up @@ -276,7 +239,7 @@ describe(IosSubmitCommand, () => {
return ctx;
});

process.env.EXPO_APPLE_APP_SPECIFIC_PASSWORD = 'abcd-abcd-abcd-abcd';
process.env.EXPO_APPLE_APP_SPECIFIC_PASSWORD = 'supersecret';

const ctx = await createSubmissionContextAsync({
platform: Platform.IOS,
Expand All @@ -303,7 +266,7 @@ describe(IosSubmitCommand, () => {
submittedBuildId: selectedBuild.id,
config: {
appleIdUsername: 'test@example.com',
appleAppSpecificPassword: 'abcd-abcd-abcd-abcd',
appleAppSpecificPassword: 'supersecret',
ascAppIdentifier: '12345678',
},
archiveSource: undefined,
Expand Down Expand Up @@ -338,7 +301,7 @@ describe(IosSubmitCommand, () => {
return ctx;
});

process.env.EXPO_APPLE_APP_SPECIFIC_PASSWORD = 'abcd-abcd-abcd-abcd';
process.env.EXPO_APPLE_APP_SPECIFIC_PASSWORD = 'supersecret';

const ctx = await createSubmissionContextAsync({
platform: Platform.IOS,
Expand Down Expand Up @@ -366,7 +329,7 @@ describe(IosSubmitCommand, () => {
submittedBuildId: selectedBuild.id,
config: {
appleIdUsername: 'test@example.com',
appleAppSpecificPassword: 'abcd-abcd-abcd-abcd',
appleAppSpecificPassword: 'supersecret',
ascAppIdentifier: '12345678',
},
archiveSource: undefined,
Expand Down
155 changes: 20 additions & 135 deletions packages/eas-json/src/__tests__/submitProfiles-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,10 @@ test('ios config with all required values', async () => {
ios: {
appleId: 'some@email.com',
ascAppId: '1223423523',
appleTeamId: 'AB32CDE81F',
appleTeamId: 'QWERTY',
ascApiKeyPath: './path-ABCD.p8',
ascApiKeyIssuerId: 'b4d78f58-48c6-4f2c-96cb-94d8cd76970a',
ascApiKeyId: 'AB32CDE81F',
ascApiKeyIssuerId: 'abc-123-def-456',
ascApiKeyId: 'ABCD',
},
},
},
Expand All @@ -121,11 +121,11 @@ test('ios config with all required values', async () => {

expect(iosProfile).toEqual({
appleId: 'some@email.com',
appleTeamId: 'AB32CDE81F',
appleTeamId: 'QWERTY',
ascAppId: '1223423523',
ascApiKeyPath: './path-ABCD.p8',
ascApiKeyIssuerId: 'b4d78f58-48c6-4f2c-96cb-94d8cd76970a',
ascApiKeyId: 'AB32CDE81F',
ascApiKeyIssuerId: 'abc-123-def-456',
ascApiKeyId: 'ABCD',
language: 'en-US',
});
});
Expand All @@ -137,7 +137,7 @@ test('ios config with ascApiKey fields set to env var', async () => {
ios: {
appleId: 'some@email.com',
ascAppId: '1223423523',
appleTeamId: 'AB32CDE81F',
appleTeamId: 'QWERTY',
ascApiKeyPath: '$ASC_API_KEY_PATH',
ascApiKeyIssuerId: '$ASC_API_KEY_ISSUER_ID',
ascApiKeyId: '$ASC_API_KEY_ID',
Expand All @@ -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 = 'b4d78f58-48c6-4f2c-96cb-94d8cd76970a';
process.env.ASC_API_KEY_ID = 'AB32CDE81F';
process.env.ASC_API_KEY_ISSUER_ID = 'abc-123-def-456';
process.env.ASC_API_KEY_ID = 'ABCD';
const accessor = EasJsonAccessor.fromProjectPath('/project');
const iosProfile = await EasJsonUtils.getSubmitProfileAsync(accessor, Platform.IOS, 'release');

expect(iosProfile).toEqual({
appleId: 'some@email.com',
ascAppId: '1223423523',
appleTeamId: 'AB32CDE81F',
appleTeamId: 'QWERTY',
ascApiKeyPath: './path-ABCD.p8',
ascApiKeyIssuerId: 'b4d78f58-48c6-4f2c-96cb-94d8cd76970a',
ascApiKeyId: 'AB32CDE81F',
ascApiKeyIssuerId: 'abc-123-def-456',
ascApiKeyId: 'ABCD',
language: 'en-US',
});
} finally {
Expand All @@ -176,16 +176,16 @@ test('valid profile extending other profile', async () => {
ios: {
appleId: 'some@email.com',
ascAppId: '1223423523',
appleTeamId: 'AB32CDE81F',
appleTeamId: 'QWERTY',
},
},
extension: {
extends: 'base',
ios: {
appleTeamId: 'AB32CDE81F',
appleTeamId: 'ABCDEF',
ascApiKeyPath: './path-ABCD.p8',
ascApiKeyIssuerId: '2af70a7a-2ac5-44d4-924e-ae97a7ca9333',
ascApiKeyId: 'AB32CDE81F',
ascApiKeyIssuerId: 'abc-123-def-456',
ascApiKeyId: 'ABCD',
},
},
},
Expand All @@ -202,134 +202,19 @@ test('valid profile extending other profile', async () => {
language: 'en-US',
appleId: 'some@email.com',
ascAppId: '1223423523',
appleTeamId: 'AB32CDE81F',
appleTeamId: 'QWERTY',
});
expect(extendedProfile).toEqual({
language: 'en-US',
appleId: 'some@email.com',
ascAppId: '1223423523',
appleTeamId: 'AB32CDE81F',
appleTeamId: 'ABCDEF',
ascApiKeyPath: './path-ABCD.p8',
ascApiKeyIssuerId: '2af70a7a-2ac5-44d4-924e-ae97a7ca9333',
ascApiKeyId: 'AB32CDE81F',
ascApiKeyIssuerId: 'abc-123-def-456',
ascApiKeyId: 'ABCD',
});
});

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@example.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 ("ascAppId") was specified. It should consist of 10 digits. Example: "1234567891". Learn more: https://expo.fyi/asc-app-id.md.'
);
});

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 consist of 10 uppercase 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 ("ascApiKeyIssuerId") was specified. It should be a valid UUID. Example: "b4d78f58-48c6-4f2c-96cb-94d8cd76970a". Learn more: https://expo.fyi/creating-asc-api-key.'
);
});

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: 'b4d78f58-48c6-4f2c-96cb-94d8cd76970a',
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 ("ascApiKeyId") was specified. It should consist of 10 uppercase letters or digits. Example: "AB32CDE81F". Learn more: https://expo.fyi/creating-asc-api-key.`
);
});

test('get profile names', async () => {
await fs.writeJson('/project/eas.json', {
submit: {
Expand Down
4 changes: 2 additions & 2 deletions packages/eas-json/src/schema.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Joi from 'joi';

import { BuildProfileSchema } from './build/schema';
import { UnresolvedSubmitProfileSchema } from './submit/schema';
import { SubmitProfileSchema } from './submit/schema';
import { AppVersionSource } from './types';

export const EasJsonSchema = Joi.object({
Expand All @@ -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(), UnresolvedSubmitProfileSchema),
submit: Joi.object().pattern(Joi.string(), SubmitProfileSchema),
});
4 changes: 2 additions & 2 deletions packages/eas-json/src/submit/resolver.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Platform } from '@expo/eas-build-job';
import envString from 'env-string';

import { AndroidSubmitProfileSchema, ResolvedIosSubmitProfileSchema } from './schema';
import { AndroidSubmitProfileSchema, IosSubmitProfileSchema } from './schema';
import {
AndroidSubmitProfileFieldsToEvaluate,
IosSubmitProfileFieldsToEvaluate,
Expand Down Expand Up @@ -99,7 +99,7 @@ function mergeProfiles<T extends Platform>(

export function getDefaultProfile<T extends Platform>(platform: T): SubmitProfile<T> {
const Schema =
platform === Platform.ANDROID ? AndroidSubmitProfileSchema : ResolvedIosSubmitProfileSchema;
platform === Platform.ANDROID ? AndroidSubmitProfileSchema : IosSubmitProfileSchema;
return Schema.validate({}, { allowUnknown: false, abortEarly: false, convert: true }).value;
}

Expand Down
Loading

0 comments on commit 61543c7

Please sign in to comment.