Skip to content

Commit

Permalink
remove reliance on aws cli
Browse files Browse the repository at this point in the history
  • Loading branch information
cnuss committed Dec 5, 2023
1 parent ad64d4c commit 81e867f
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 10 deletions.
3 changes: 2 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
- Write to env?
- Test with AWS Extension
- See if this can set AWS Builder ID for AWS Extension
- Try to invoke AWS Select Connection afterwards
- Onboarding experience for brand new user / org
- Don't rely on the `aws` CLI to update profile
- Loading progress indicator between inputs
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@
},
"devDependencies": {
"@scaffoldly/openapi-generator": "^2.0.0",
"@types/fs-extra": "^11.0.4",
"@types/humanize-duration": "^3.27.3",
"@types/ini": "^1.3.34",
"@types/mocha": "^10.0.3",
"@types/node": "18.x",
"@types/qrcode-svg": "^1.1.4",
Expand All @@ -135,8 +137,10 @@
"@aws-sdk/client-sts": "^3.458.0",
"@octokit/rest": "^20.0.2",
"axios": "^1.6.2",
"fs-extra": "^11.2.0",
"humanize-duration": "^3.31.0",
"ini": "^4.1.1",
"qrcode-svg": "^1.1.0",
"which": "^4.0.0"
}
}
}
117 changes: 109 additions & 8 deletions src/aws.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import * as vscode from "vscode";
import * as ini from "ini";
import { ApiFactory } from "./api";
import { TotpHelper } from "./totp";
import { AssumeRoleWithSAMLCommand, STSClient } from "@aws-sdk/client-sts";
import { exec } from "./exec";
// import { exec } from "./exec";
import humanizeDuration from "humanize-duration";
import { AwsRoleSelection, Configuration, ProfileName } from "./config";
import { isAxiosError } from "axios";
import { dirname, join } from "path";
import { mkdirp } from "fs-extra";
import { fileExists, getHomeDirectory } from "./util";
import { readFileSync, writeFileSync } from "fs";

export const assumeAwsRole = (
configuration: Configuration,
Expand Down Expand Up @@ -133,14 +138,22 @@ export const assumeAwsRole = (
configuration.assumeAws.profile.name,
roleSelection
);
const base = ["aws", "configure"];
base.push("--profile", profileName);
base.push("set");

await exec([...base, "region", configuration.assumeAws.region]);
await exec([...base, "aws_access_key_id", AccessKeyId]);
await exec([...base, "aws_secret_access_key", SecretAccessKey]);
await exec([...base, "aws_session_token", SessionToken]);
await updateProfile(profileName, {
region: configuration.assumeAws.region,
accessKeyId: AccessKeyId,
secretAccessKey: SecretAccessKey,
sessionToken: SessionToken,
});

// const base = ["aws", "configure"];
// base.push("--profile", profileName);
// base.push("set");

// await exec([...base, "region", configuration.assumeAws.region]);
// await exec([...base, "aws_access_key_id", AccessKeyId]);
// await exec([...base, "aws_secret_access_key", SecretAccessKey]);
// await exec([...base, "aws_session_token", SessionToken]);

if (!isRefresh) {
vscode.window.showInformationMessage(
Expand Down Expand Up @@ -229,3 +242,91 @@ export const stopRefresh = (apiFactory: ApiFactory): (() => void) => {
}
};
};

const getCredentialsFilename = (): string => {
return (
process.env.AWS_SHARED_CREDENTIALS_FILE ||
join(getHomeDirectory(), ".aws", "credentials")
);
};

const getConfigFilename = (): string => {
return (
process.env.AWS_CONFIG_FILE || join(getHomeDirectory(), ".aws", "config")
);
};

const getConfigAndCredentials = async (): Promise<{
config: { [key: string]: any };
configFile: string;
credentials: { [key: string]: any };
credentialsFile: string;
}> => {
const configFile = getConfigFilename();
const credentialsFile = getCredentialsFilename();

const config = (await fileExists(configFile))
? ini.parse(readFileSync(configFile, "utf-8"))
: {};

const credentials = (await fileExists(credentialsFile))
? ini.parse(readFileSync(credentialsFile, "utf-8"))
: {};

return { config, configFile, credentials, credentialsFile };
};

const updateProfile = async (
profile: string,
options: {
region: string;
accessKeyId: string;
secretAccessKey: string;
sessionToken: string;
}
): Promise<void> => {
const filepath = dirname(getCredentialsFilename());
if (!(await fileExists(filepath))) {
await mkdirp(filepath);
}

const { config, configFile, credentials, credentialsFile } =
await getConfigAndCredentials();

let section: string | undefined = undefined;
let profileHeader = `profile ${profile}`;

// Prevent escaping of "." in profile name
if (profile.indexOf(".") !== -1) {
const parts = profile.split(".");
profile = parts.pop() || "";
profileHeader = profile;
section = `profile ${parts.join(".")}`;
}

config[profileHeader] = {
region: options.region,
};

credentials[profile] = {
aws_access_key_id: options.accessKeyId,
aws_secret_access_key: options.secretAccessKey,
aws_session_token: options.sessionToken,
};

writeFileSync(
configFile,
ini.stringify(config, {
whitespace: true,
section,
})
);

writeFileSync(
credentialsFile,
ini.stringify(credentials, {
whitespace: true,
section: section ? section.replace("profile ", "") : undefined,
})
);
};
44 changes: 44 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import * as vscode from "vscode";
import * as path from "path";
import * as os from "os";

const hasCode = <T>(error: T): error is T & { code: string } => {
return typeof (error as { code?: unknown }).code === "string";
};

const isFileNotFoundError = (err: unknown): boolean => {
if (err instanceof vscode.FileSystemError) {
return err.code === vscode.FileSystemError.FileNotFound().code;
} else if (hasCode(err)) {
return err.code === "ENOENT";
}

return false;
};

export const fileExists = async (
file: string | vscode.Uri
): Promise<boolean> => {
const uri = typeof file === "string" ? vscode.Uri.file(file) : file;

return vscode.workspace.fs.stat(uri).then(
() => true,
(err) => !isFileNotFoundError(err)
);
};

export const getHomeDirectory = (): string => {
if (process.env.HOME !== undefined) {
return process.env.HOME;
}
if (process.env.USERPROFILE !== undefined) {
return process.env.USERPROFILE;
}
if (process.env.HOMEPATH !== undefined) {
const homeDrive: string = process.env.HOMEDRIVE || "C:";

return path.join(homeDrive, process.env.HOMEPATH);
}

return os.homedir();
};
34 changes: 34 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1043,16 +1043,36 @@
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==

"@types/fs-extra@^11.0.4":
version "11.0.4"
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-11.0.4.tgz#e16a863bb8843fba8c5004362b5a73e17becca45"
integrity sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==
dependencies:
"@types/jsonfile" "*"
"@types/node" "*"

"@types/humanize-duration@^3.27.3":
version "3.27.3"
resolved "https://registry.yarnpkg.com/@types/humanize-duration/-/humanize-duration-3.27.3.tgz#fa49ada1cc65222d5f1295c7756b6877f5a96bcf"
integrity sha512-wiiiFYjnrYDJE/ujU7wS/NShqp12IKrejozjDtcejP0zYi+cjyjVcfZHwcFUDKVJ7tHGsmgeW2ED92ABIIjfpg==

"@types/ini@^1.3.34":
version "1.3.34"
resolved "https://registry.yarnpkg.com/@types/ini/-/ini-1.3.34.tgz#99a69ecfccdfc3f6e91b411d4208aaa3c4cc9685"
integrity sha512-FafeLhwmWucTi31ZYg/6aHBZNyrogQ35aDvSW7zMAz3HMhUqQ4G/NBya8c5pe2jwoYsDFwra8O9/yZotong76g==

"@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.8":
version "7.0.15"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==

"@types/jsonfile@*":
version "6.1.4"
resolved "https://registry.yarnpkg.com/@types/jsonfile/-/jsonfile-6.1.4.tgz#614afec1a1164e7d670b4a7ad64df3e7beb7b702"
integrity sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==
dependencies:
"@types/node" "*"

"@types/mocha@^10.0.3":
version "10.0.6"
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.6.tgz#818551d39113081048bdddbef96701b4e8bb9d1b"
Expand Down Expand Up @@ -2207,6 +2227,15 @@ fs-extra@^10.1.0:
jsonfile "^6.0.1"
universalify "^2.0.0"

fs-extra@^11.2.0:
version "11.2.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b"
integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
universalify "^2.0.0"

fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
Expand Down Expand Up @@ -2459,6 +2488,11 @@ inherits@2, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==

ini@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.1.tgz#d95b3d843b1e906e56d6747d5447904ff50ce7a1"
integrity sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==

ini@~1.3.0:
version "1.3.8"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
Expand Down

0 comments on commit 81e867f

Please sign in to comment.