Skip to content

Commit

Permalink
fix: support choosing AWS authentication flow when admin UI is enabled (
Browse files Browse the repository at this point in the history
#6433)

* fix: configuration-manager redesign [WIP]

* fix: optional field

* fix: acquire admin credentials properly on env add

* refactor: simplify and refactor admin credential aquisition

* fix: typo, remove unused imports

* fix: update e2e helpers, update auth-types

* fix: update refresh token on refresh

* fix: supplying access keys on init

* fix: overwriting region, code formatting

* fix: handle undefined case in object destructuring

* chore: add missing type

* fix: use general config for env vars

* refactor: change function name for consistency

* fix: don't assume env var credential usage, broken e2e tests

* fix: account for --yes flag, add types

* fix: determining accessKey behavior, update tests

* test: fix amplify pull helper

* refactor: undo bad prettier formatting

* refactor: undo bad prettier formatting

* fix: address PR feedback

* fix: address feedback from API review

* test: update tests to look for new text
  • Loading branch information
jhockett committed Feb 2, 2021
1 parent 1e115c5 commit 3bf56a8
Show file tree
Hide file tree
Showing 17 changed files with 311 additions and 215 deletions.
4 changes: 2 additions & 2 deletions .circleci/amplify_init.exp
Expand Up @@ -19,8 +19,8 @@ expect -exact "Build Command:"
send -- "\r"
expect -exact "Start Command:"
send -- "\r"
expect "Do you want to use an AWS profile?"
send -- "n\r"
expect "Select the authentication method you want to use:"
send -- "j\r"
log_user 0;
expect "accessKeyId:"
send -- "$env(AWS_ACCESS_KEY_ID)\r"
Expand Down
Expand Up @@ -62,8 +62,8 @@ export function authConfigPull(projectRootDirPath: string, params: { appId: stri
const { FACEBOOK_APP_ID, FACEBOOK_APP_SECRET, GOOGLE_APP_ID, GOOGLE_APP_SECRET, AMAZON_APP_ID, AMAZON_APP_SECRET } = getSocialProviders();
return new Promise((resolve, reject) => {
spawn(util.getCLIPath(), pullCommand, { cwd: projectRootDirPath, stripColors: true })
.wait('Do you want to use an AWS profile?')
.sendLine('y')
.wait('Select the authentication method you want to use:')
.sendCarriageReturn()
.wait('Please choose the profile you want to use')
.sendLine(s.profileName)
.wait('Choose your default editor:')
Expand Down
16 changes: 4 additions & 12 deletions packages/amplify-e2e-core/src/init/amplifyPull.ts
Expand Up @@ -19,8 +19,8 @@ export function amplifyPull(cwd: string, settings: { override?: boolean; emptyDi

if (settings.emptyDir) {
chain
.wait('Do you want to use an AWS profile')
.sendLine('y')
.wait('Select the authentication method you want to use:')
.sendCarriageReturn()
.wait('Please choose the profile you want to use')
.sendCarriageReturn()
.wait('Choose your default editor:')
Expand All @@ -40,11 +40,7 @@ export function amplifyPull(cwd: string, settings: { override?: boolean; emptyDi
.wait('Do you plan on modifying this backend?')
.sendLine('y');
} else {
chain
.wait('Pre-pull status')
.wait('Current Environment')
.wait(tableHeaderRegex)
.wait(tableSeperator);
chain.wait('Pre-pull status').wait('Current Environment').wait(tableHeaderRegex).wait(tableSeperator);
}

if (settings.override) {
Expand All @@ -58,11 +54,7 @@ export function amplifyPull(cwd: string, settings: { override?: boolean; emptyDi
if (settings.emptyDir) {
chain.wait(/Successfully pulled backend environment .+ from the cloud\./).wait("Run 'amplify pull' to sync upstream changes.");
} else {
chain
.wait('Post-pull status')
.wait('Current Environment')
.wait(tableHeaderRegex)
.wait(tableSeperator);
chain.wait('Post-pull status').wait('Current Environment').wait(tableHeaderRegex).wait(tableSeperator);
}

chain.run((err: Error) => {
Expand Down
35 changes: 19 additions & 16 deletions packages/amplify-e2e-core/src/init/initProjectHelper.ts
@@ -1,4 +1,5 @@
import { nspawn as spawn, getCLIPath, singleSelect, addCircleCITags } from '..';
import { KEY_DOWN_ARROW } from '../utils';

const defaultSettings = {
name: '\r',
Expand Down Expand Up @@ -65,8 +66,8 @@ export function initJSProjectWithProfile(cwd: string, settings: Object) {
.wait('Start Command:')
.sendCarriageReturn()
.wait('Using default provider awscloudformation')
.wait('Do you want to use an AWS profile?')
.sendLine('y')
.wait('Select the authentication method you want to use:')
.sendCarriageReturn()
.wait('Please choose the profile you want to use')
.sendLine(s.profileName)
.wait('Try "amplify add api" to create a backend API and then "amplify publish" to deploy everything')
Expand Down Expand Up @@ -104,8 +105,8 @@ export function initAndroidProjectWithProfile(cwd: string, settings: Object) {
.sendCarriageReturn()
.wait('Where is your Res directory')
.sendCarriageReturn()
.wait('Do you want to use an AWS profile?')
.sendLine('y')
.wait('Select the authentication method you want to use:')
.sendCarriageReturn()
.wait('Please choose the profile you want to use')
.sendLine(s.profileName)
.wait('Try "amplify add api" to create a backend API and then "amplify publish" to deploy everything')
Expand Down Expand Up @@ -143,8 +144,8 @@ export function initIosProjectWithProfile(cwd: string, settings: Object) {
.wait("Choose the type of app that you're building")
.sendKeyDown(3)
.sendCarriageReturn()
.wait('Do you want to use an AWS profile?')
.sendLine('y')
.wait('Select the authentication method you want to use:')
.sendCarriageReturn()
.wait('Please choose the profile you want to use')
.sendLine(s.profileName)
.wait('Try "amplify add api" to create a backend API and then "amplify publish" to deploy everything')
Expand Down Expand Up @@ -179,8 +180,8 @@ export function initFlutterProjectWithProfile(cwd: string, settings: Object) {
.wait('Where do you want to store your configuration file')
.sendLine('./lib/')
.wait('Using default provider awscloudformation')
.wait('Do you want to use an AWS profile?')
.sendConfirmYes()
.wait('Select the authentication method you want to use:')
.sendCarriageReturn()
.wait('Please choose the profile you want to use')
.sendLine(s.profileName);

Expand Down Expand Up @@ -228,8 +229,9 @@ export function initProjectWithAccessKey(cwd: string, settings: { accessKeyId: s
.wait('Start Command:')
.sendCarriageReturn()
.wait('Using default provider awscloudformation')
.wait('Do you want to use an AWS profile?')
.sendLine('n')
.wait('Select the authentication method you want to use:')
.send(KEY_DOWN_ARROW)
.sendCarriageReturn()
.pauseRecording()
.wait('accessKeyId')
.sendLine(s.accessKeyId)
Expand Down Expand Up @@ -266,8 +268,9 @@ export function initNewEnvWithAccessKey(cwd: string, s: { envName: string; acces
.wait('Enter a name for the environment')
.sendLine(s.envName)
.wait('Using default provider awscloudformation')
.wait('Do you want to use an AWS profile?')
.sendLine('n')
.wait('Select the authentication method you want to use:')
.send(KEY_DOWN_ARROW)
.sendCarriageReturn()
.pauseRecording()
.wait('accessKeyId')
.sendLine(s.accessKeyId)
Expand Down Expand Up @@ -304,8 +307,8 @@ export function initNewEnvWithProfile(cwd: string, s: { envName: string }) {
.wait('Enter a name for the environment')
.sendLine(s.envName)
.wait('Using default provider awscloudformation')
.wait('Do you want to use an AWS profile?')
.sendLine('y')
.wait('Select the authentication method you want to use:')
.sendCarriageReturn()
.wait('Please choose the profile you want to use')
.sendCarriageReturn()
.wait('Try "amplify add api" to create a backend API and then "amplify publish" to deploy everything')
Expand Down Expand Up @@ -338,8 +341,8 @@ export function amplifyInitSandbox(cwd: string, settings: {}) {
.wait('Choose your default editor:')
.sendLine(s.editor)
.wait('Using default provider awscloudformation')
.wait('Do you want to use an AWS profile?')
.sendLine('y')
.wait('Select the authentication method you want to use:')
.sendCarriageReturn()
.wait('Please choose the profile you want to use')
.sendLine(s.profileName)
.wait('Try "amplify add api" to create a backend API and then "amplify publish" to deploy everything')
Expand Down
2 changes: 1 addition & 1 deletion packages/amplify-e2e-core/src/init/pull-headless.ts
Expand Up @@ -19,7 +19,7 @@ export function pullProject(cwd: string, settings: Object) {
const s = { ...defaultSettings, ...settings };
return new Promise((resolve, reject) => {
spawn(getCLIPath(), ['pull', '--appId', s.appId, '--envName', s.envName], { cwd, stripColors: true })
.wait('Do you want to use an AWS profile?')
.wait('Select the authentication method you want to use:')
.sendLine(s.useProfile)
.wait('Please choose the profile you want to use')
.sendLine(s.profileName)
Expand Down
7 changes: 4 additions & 3 deletions packages/amplify-e2e-core/src/utils/pinpoint.ts
@@ -1,5 +1,5 @@
import { Pinpoint } from 'aws-sdk';
import { getCLIPath, nspawn as spawn, singleSelect, amplifyRegions, addCircleCITags } from '..';
import { getCLIPath, nspawn as spawn, singleSelect, amplifyRegions, addCircleCITags, KEY_DOWN_ARROW } from '..';
import _ from 'lodash';

const settings = {
Expand Down Expand Up @@ -99,8 +99,9 @@ export function initProjectForPinpoint(cwd: string) {
.wait('Start Command:')
.sendCarriageReturn()
.wait('Using default provider awscloudformation')
.wait('Do you want to use an AWS profile?')
.sendLine('n')
.wait('Select the authentication method you want to use:')
.send(KEY_DOWN_ARROW)
.sendCarriageReturn()
.pauseRecording()
.wait('accessKeyId')
.sendLine(settings.accessKeyId)
Expand Down
16 changes: 7 additions & 9 deletions packages/amplify-e2e-tests/src/environment/env.ts
Expand Up @@ -7,8 +7,8 @@ export function addEnvironment(cwd: string, settings: { envName: string; numLaye
.sendLine('n')
.wait('Enter a name for the environment')
.sendLine(settings.envName)
.wait('Do you want to use an AWS profile?')
.sendLine('yes')
.wait('Select the authentication method you want to use:')
.sendCarriageReturn()
.wait('Please choose the profile you want to use')
.sendCarriageReturn();

Expand All @@ -33,8 +33,8 @@ export function addEnvironmentWithImportedAuth(cwd: string, settings: { envName:
.sendConfirmNo()
.wait('Enter a name for the environment')
.sendLine(settings.envName)
.wait('Do you want to use an AWS profile?')
.sendConfirmYes()
.wait('Select the authentication method you want to use:')
.sendCarriageReturn()
.wait('Please choose the profile you want to use')
.sendCarriageReturn()
.wait(`already imported to '${settings.currentEnvName}' environment, do you want to import it to the new environment`)
Expand Down Expand Up @@ -69,9 +69,7 @@ export function listEnvironment(cwd: string, settings: { numEnv?: number }) {
return new Promise((resolve, reject) => {
let numEnv = settings.numEnv || 1;
let regex = /\|\s\*?[a-z]{2,10}\s+\|/;
const chain = spawn(getCLIPath(), ['env', 'list'], { cwd, stripColors: true })
.wait('| Environments |')
.wait('| ------------ |');
const chain = spawn(getCLIPath(), ['env', 'list'], { cwd, stripColors: true }).wait('| Environments |').wait('| ------------ |');

for (let i = 0; i < numEnv; ++i) {
chain.wait(regex);
Expand Down Expand Up @@ -145,8 +143,8 @@ export function addEnvironmentHostedUI(cwd: string, settings: { envName: string
.sendLine('n')
.wait('Enter a name for the environment')
.sendLine(settings.envName)
.wait('Do you want to use an AWS profile?')
.sendLine('yes')
.wait('Select the authentication method you want to use:')
.sendCarriageReturn()
.wait('Please choose the profile you want to use')
.sendCarriageReturn()
.wait('Enter your Facebook App ID for your OAuth flow:')
Expand Down
8 changes: 4 additions & 4 deletions packages/amplify-e2e-tests/src/init-special-cases/index.ts
@@ -1,5 +1,5 @@
import path from 'path';
import { nspawn as spawn, getCLIPath, singleSelect, amplifyRegions, addCircleCITags } from 'amplify-e2e-core';
import { nspawn as spawn, getCLIPath, singleSelect, amplifyRegions, addCircleCITags, KEY_DOWN_ARROW } from 'amplify-e2e-core';
import fs from 'fs-extra';
import os from 'os';

Expand Down Expand Up @@ -71,9 +71,9 @@ async function initWorkflow(cwd: string, settings: { accessKeyId: string; secret
.wait('Start Command:')
.sendCarriageReturn()
.wait('Using default provider awscloudformation')
.wait('AWS access credentials can not be found.')
.wait('Setup new user')
.sendLine('n')
.wait('Select the authentication method you want to use:')
.send(KEY_DOWN_ARROW)
.sendCarriageReturn()
.pauseRecording()
.wait('accessKeyId')
.sendLine(settings.accessKeyId)
Expand Down
1 change: 1 addition & 0 deletions packages/amplify-provider-awscloudformation/package.json
Expand Up @@ -74,6 +74,7 @@
"bottleneck": "2.19.5",
"cfn-lint": "^1.9.7",
"chalk": "^3.0.0",
"ci-info": "^2.0.0",
"cloudform": "^4.2.0",
"cloudform-types": "^4.2.0",
"columnify": "^1.5.4",
Expand Down
10 changes: 5 additions & 5 deletions packages/amplify-provider-awscloudformation/src/admin-login.ts
Expand Up @@ -7,17 +7,17 @@ import { AdminLoginServer } from './utils/admin-login-server';

export async function adminLoginFlow(context: $TSContext, appId: string, envName: string, region?: string) {
if (!region) {
const res = await isAmplifyAdminApp(appId);
if (!res.isAdminApp) {
const { isAdminApp, region: _region } = await isAmplifyAdminApp(appId);
if (!isAdminApp) {
throw new Error(`Admin UI not enabled for appId: ${appId}`);
}
region = res.region;
region = _region;
}

const url = adminVerifyUrl(appId, envName, region);
context.print.info(`Opening link: ${url}`);
await open(url, { wait: false }).catch(e => {
context.print.error('Failed to open web browser.');
context.print.error(`Failed to open web browser: ${e.message || e}`);
return;
});
const spinner = ora('Continue in browser to log in…\n').start();
Expand All @@ -34,6 +34,6 @@ export async function adminLoginFlow(context: $TSContext, appId: string, envName
);
} catch (e) {
spinner.stop();
context.print.error(e);
context.print.error(`Failed to authenticate with Amplify Admin: ${e.message || e}`);
}
}
Expand Up @@ -39,7 +39,7 @@ async function getConfiguredPinpointClient(context, category, action, envName) {
// ignore missing config
}
category = category || 'missing';
action = action || 'missing';
action = action || ['missing'];
const userAgentAction = `${category}:${action[0]}`;
const defaultOptions = {
region: mapServiceRegion(cred.region || configurationManager.resolveRegion()),
Expand Down
@@ -1,4 +1,4 @@
import { $TSContext } from 'amplify-cli-core';
import { $TSAny, $TSContext } from 'amplify-cli-core';

import aws from './aws.js';
import _ from 'lodash';
Expand Down Expand Up @@ -38,7 +38,7 @@ export class S3 {
return S3.instance;
}

private constructor(context, cred, options = {}) {
private constructor(context: $TSContext, cred: $TSAny, options = {}) {
this.context = context;
this.s3 = new aws.S3({ ...cred, ...options });
}
Expand All @@ -58,7 +58,7 @@ export class S3 {
};
}

async uploadFile(s3Params, showSpinner: boolean = true) {
async uploadFile(s3Params: $TSAny, showSpinner: boolean = true) {
// envName and bucket does not change during execution, cache them into a class level
// field.
if (this.uploadState === undefined) {
Expand Down Expand Up @@ -97,7 +97,7 @@ export class S3 {
}
}

async getFile(s3Params, envName = this.context.amplify.getEnvInfo().envName) {
async getFile(s3Params: $TSAny, envName: string = this.context.amplify.getEnvInfo().envName) {
const projectDetails = this.context.amplify.getProjectDetails();
const projectBucket = projectDetails.teamProviderInfo[envName][providerName].DeploymentBucketName;
s3Params.Bucket = projectBucket;
Expand All @@ -112,7 +112,7 @@ export class S3 {
}
}

async createBucket(bucketName, throwIfExists: boolean = false): Promise<string | void> {
async createBucket(bucketName: string, throwIfExists: boolean = false): Promise<string | void> {
// Check if bucket exists;
const params = {
Bucket: bucketName,
Expand Down Expand Up @@ -160,7 +160,7 @@ export class S3 {
return result;
}

public async deleteAllObjects(bucketName): Promise<void> {
public async deleteAllObjects(bucketName: string): Promise<void> {
logger('deleteAllObjects.s3.getAllObjectVersions', [{ BucketName: bucketName }])();
const allObjects = await this.getAllObjectVersions(bucketName);
const chunkedResult = _.chunk(allObjects, 1000);
Expand All @@ -177,7 +177,7 @@ export class S3 {
}
}

public async deleteS3Bucket(bucketName) {
public async deleteS3Bucket(bucketName: string) {
logger('deleteS3Bucket.s3.ifBucketExists', [{ BucketName: bucketName }])();
if (await this.ifBucketExists(bucketName)) {
logger('deleteS3Bucket.s3.deleteAllObjects', [{ BucketName: bucketName }])();
Expand All @@ -187,7 +187,7 @@ export class S3 {
}
}

public async emptyS3Bucket(bucketName) {
public async emptyS3Bucket(bucketName: string) {
if (await this.ifBucketExists(bucketName)) {
await this.deleteAllObjects(bucketName);
}
Expand Down

0 comments on commit 3bf56a8

Please sign in to comment.