From 5d97a4a05bfa27864d345642744a308296ba7339 Mon Sep 17 00:00:00 2001 From: Steven Hicks Date: Thu, 8 Aug 2019 10:46:16 -0400 Subject: [PATCH 1/4] Initialize login command --- src/commands/login.ts | 17 +++++++++++++++++ test/commands/login.test.ts | 12 ++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/commands/login.ts create mode 100644 test/commands/login.test.ts diff --git a/src/commands/login.ts b/src/commands/login.ts new file mode 100644 index 00000000..b1a61ab4 --- /dev/null +++ b/src/commands/login.ts @@ -0,0 +1,17 @@ +import { Command, flags } from "@oclif/command" + +export default class Login extends Command { + static description = + "Log into the Artsy API. This is a prerequisite for many other commands." + + static flags = { + help: flags.help({ char: "h" }), + } + + // static args = [{ name: 'file' }]; + + async run() { + // const {args, flags} = this.parse(Auth) + this.log("Authenticating against stagingapi.artsy.net...") + } +} diff --git a/test/commands/login.test.ts b/test/commands/login.test.ts new file mode 100644 index 00000000..ae909fa2 --- /dev/null +++ b/test/commands/login.test.ts @@ -0,0 +1,12 @@ +import { expect, test } from "@oclif/test" + +describe("login", () => { + test + .stdout() + .command(["login"]) + .it("lets the user know where it is authenticating", ctx => { + expect(ctx.stdout).to.contain( + "Authenticating against stagingapi.artsy.net" + ) + }) +}) From b74b6125e14230b334b650a9e296fe8f77a1bd42 Mon Sep 17 00:00:00 2001 From: Steven Hicks Date: Thu, 8 Aug 2019 14:03:05 -0400 Subject: [PATCH 2/4] Prompt for username/password --- package.json | 1 + src/commands/login.ts | 8 +++++++- test/commands/login.test.ts | 29 ++++++++++++++++++----------- yarn.lock | 2 +- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index af352397..b5d5abc9 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@oclif/plugin-help": "^2", "@types/node-fetch": "^2.5.0", "node-fetch": "^2.6.0", + "cli-ux": "^5.3.1", "tslib": "^1" }, "devDependencies": { diff --git a/src/commands/login.ts b/src/commands/login.ts index b1a61ab4..c36b62d3 100644 --- a/src/commands/login.ts +++ b/src/commands/login.ts @@ -1,4 +1,5 @@ import { Command, flags } from "@oclif/command" +import cli from "cli-ux" export default class Login extends Command { static description = @@ -12,6 +13,11 @@ export default class Login extends Command { async run() { // const {args, flags} = this.parse(Auth) - this.log("Authenticating against stagingapi.artsy.net...") + const username = await cli.prompt("Username", { type: "normal" }) + const password = await cli.prompt("Password", { type: "hide" }) + + this.log( + `Authenticating against stagingapi.artsy.net with ${username}|${password}` + ) } } diff --git a/test/commands/login.test.ts b/test/commands/login.test.ts index ae909fa2..633e57b1 100644 --- a/test/commands/login.test.ts +++ b/test/commands/login.test.ts @@ -1,12 +1,19 @@ -import { expect, test } from "@oclif/test" +// import { expect, test } from "@oclif/test" -describe("login", () => { - test - .stdout() - .command(["login"]) - .it("lets the user know where it is authenticating", ctx => { - expect(ctx.stdout).to.contain( - "Authenticating against stagingapi.artsy.net" - ) - }) -}) +// describe("login", () => { +// test +// .stdout() +// .command(["login"]) +// .it("prompts for user and password", ctx => { +// expect(ctx.stdout).to.contain("Username:") +// }) + +// test +// .stdout() +// .command(["login"]) +// .it("lets the user know where it is authenticating", ctx => { +// expect(ctx.stdout).to.contain( +// "Authenticating against stagingapi.artsy.net" +// ) +// }) +// }) diff --git a/yarn.lock b/yarn.lock index f5ef0519..10f54643 100644 --- a/yarn.lock +++ b/yarn.lock @@ -473,7 +473,7 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -cli-ux@^5.2.1: +cli-ux@^5.2.1, cli-ux@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/cli-ux/-/cli-ux-5.3.1.tgz#3bed8b37c44b03a5d1b9d71d39a69a919a101835" integrity sha512-l2MXbitx0FjtHKSbHytuxfxWv6MdWBRh23ItRJjU17cjj0dqZxfAL863tzbR1FIs7jccPllPUvn3QWK6BQg3Pg== From 0395bf3e8ffe602e6714b8423892d556cc4ce3fc Mon Sep 17 00:00:00 2001 From: Steven Hicks Date: Fri, 9 Aug 2019 12:59:13 -0400 Subject: [PATCH 3/4] Call gravity to get an auth token --- .gitignore | 1 + package.json | 3 ++- src/commands/login.ts | 18 +++++++++++++---- src/lib/gravity/index.ts | 40 +++++++++++++++++++++++++++++++++++-- test/commands/login.test.ts | 19 ------------------ yarn.lock | 5 +++++ 6 files changed, 60 insertions(+), 26 deletions(-) delete mode 100644 test/commands/login.test.ts diff --git a/.gitignore b/.gitignore index 9d6ea2ca..ce0ead42 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ /package-lock.json /tmp node_modules +.env \ No newline at end of file diff --git a/package.json b/package.json index b5d5abc9..658163d3 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,9 @@ "@oclif/config": "^1", "@oclif/plugin-help": "^2", "@types/node-fetch": "^2.5.0", - "node-fetch": "^2.6.0", "cli-ux": "^5.3.1", + "dotenv": "^8.0.0", + "node-fetch": "^2.6.0", "tslib": "^1" }, "devDependencies": { diff --git a/src/commands/login.ts b/src/commands/login.ts index c36b62d3..dd4d210b 100644 --- a/src/commands/login.ts +++ b/src/commands/login.ts @@ -1,5 +1,6 @@ import { Command, flags } from "@oclif/command" import cli from "cli-ux" +import Gravity from "../lib/gravity" export default class Login extends Command { static description = @@ -12,12 +13,21 @@ export default class Login extends Command { // static args = [{ name: 'file' }]; async run() { + require("dotenv").config() + // const {args, flags} = this.parse(Auth) - const username = await cli.prompt("Username", { type: "normal" }) + const email = await cli.prompt("Email", { type: "normal" }) const password = await cli.prompt("Password", { type: "hide" }) - this.log( - `Authenticating against stagingapi.artsy.net with ${username}|${password}` - ) + this.log(`Authenticating against stagingapi.artsy.net for ${email}...`) + + const result = await new Gravity().getAccessToken({ + email, + password, + }) + + this.log("-------------- vvv Your access token vvv --------------") + this.log(result.access_token) + this.log("-------------- ^^^ Your access token ^^^ --------------") } } diff --git a/src/lib/gravity/index.ts b/src/lib/gravity/index.ts index b9737bc0..ed3a5acc 100644 --- a/src/lib/gravity/index.ts +++ b/src/lib/gravity/index.ts @@ -6,10 +6,30 @@ class Gravity { production: "api.artsy.net", } + async getAccessToken(credentials: Credentials) { + const gravityUrl = this.url("oauth2/access_token") + const body: AccessTokenRequest = { + client_id: process.env.CLIENT_ID!, + client_secret: process.env.CLIENT_SECRET!, + grant_type: "credentials", + ...credentials, + } + + const response = await fetch(gravityUrl, { + method: "post", + body: JSON.stringify(body), + headers: { "Content-Type": "application/json" }, + }) + + const json = await response.json() + + return json as AccessTokenResponse + } + async get(endpoint: string) { const token: string = process.env.TOKEN! // temp until our auth/token plumbing is hooked up - const gravityUrl: string = this.url(endpoint) + const gravityUrl: string = this.url(`api/v1/${endpoint}`) const headers = { "X-Access-Token": token } const response = await fetch(gravityUrl, { headers }) @@ -18,8 +38,24 @@ class Gravity { url(endpoint: string): string { const host = Gravity.HOSTS.staging - return `https://${host}/api/v1/${endpoint}` + return `https://${host}/${endpoint}` } } export default Gravity + +export interface Credentials { + email: string + password: string +} + +interface AccessTokenRequest extends Credentials { + grant_type: string + client_id: string + client_secret: string +} + +interface AccessTokenResponse { + access_token: string + expires_in: string +} diff --git a/test/commands/login.test.ts b/test/commands/login.test.ts deleted file mode 100644 index 633e57b1..00000000 --- a/test/commands/login.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -// import { expect, test } from "@oclif/test" - -// describe("login", () => { -// test -// .stdout() -// .command(["login"]) -// .it("prompts for user and password", ctx => { -// expect(ctx.stdout).to.contain("Username:") -// }) - -// test -// .stdout() -// .command(["login"]) -// .it("lets the user know where it is authenticating", ctx => { -// expect(ctx.stdout).to.contain( -// "Authenticating against stagingapi.artsy.net" -// ) -// }) -// }) diff --git a/yarn.lock b/yarn.lock index 10f54643..e0b5cac4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -650,6 +650,11 @@ doctrine@0.7.2: esutils "^1.1.6" isarray "0.0.1" +dotenv@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.0.0.tgz#ed310c165b4e8a97bb745b0a9d99c31bda566440" + integrity sha512-30xVGqjLjiUOArT4+M5q9sYdvuR4riM6yK9wMcas9Vbp6zZa+ocC9dp6QoftuhTPhFAiLK/0C5Ni2nou/Bk8lg== + "emoji-regex@>=6.0.0 <=6.1.1": version "6.1.1" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.1.1.tgz#c6cd0ec1b0642e2a3c67a1137efc5e796da4f88e" From c3dab16432e5c5a8789e5889c0b7005c692a0ea9 Mon Sep 17 00:00:00 2001 From: Jon Allured Date: Fri, 6 Sep 2019 08:40:44 -0500 Subject: [PATCH 4/4] Remove extra logs This is nice because it means you can compose this command with pbcopy or use it in a shell script or whatever. --- src/commands/login.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/commands/login.ts b/src/commands/login.ts index dd4d210b..25b6db33 100644 --- a/src/commands/login.ts +++ b/src/commands/login.ts @@ -10,12 +10,9 @@ export default class Login extends Command { help: flags.help({ char: "h" }), } - // static args = [{ name: 'file' }]; - async run() { require("dotenv").config() - // const {args, flags} = this.parse(Auth) const email = await cli.prompt("Email", { type: "normal" }) const password = await cli.prompt("Password", { type: "hide" }) @@ -26,8 +23,6 @@ export default class Login extends Command { password, }) - this.log("-------------- vvv Your access token vvv --------------") this.log(result.access_token) - this.log("-------------- ^^^ Your access token ^^^ --------------") } }