Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PCC-1449 cli uses new auth flow for management access tokens #313

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 90 additions & 5 deletions packages/cli/src/cli/commands/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@
import { dirname, join } from "path";
import url, { fileURLToPath } from "url";
import { parseJwt } from "@pantheon-systems/pcc-sdk-core";
import { OAuth2Client } from "google-auth-library";
import { Credentials, OAuth2Client } from "google-auth-library";
import nunjucks from "nunjucks";
import open from "open";
import ora from "ora";
import destroyer from "server-destroy";
import AddOnApiHelper from "../../lib/addonApiHelper";
import { getApiConfig } from "../../lib/apiConfig";
import {
CREDENTIAL_TYPE,
getLocalAuthDetails,
NextJwtCredentials,
persistAuthDetails,
} from "../../lib/localStorage";
import { errorHandler } from "../exceptions";
Expand All @@ -20,13 +22,17 @@

const OAUTH_SCOPES = ["https://www.googleapis.com/auth/userinfo.email"];

function login(extraScopes: string[]): Promise<void> {
export function loginOAuth(extraScopes: string[]): Promise<void> {
return new Promise(
// eslint-disable-next-line no-async-promise-executor -- Handling promise rejection in the executor
async (resolve, reject) => {
const spinner = ora("Logging you in...").start();
try {
const authData = await getLocalAuthDetails(extraScopes);
const authData = (await getLocalAuthDetails(
CREDENTIAL_TYPE.OAUTH,
extraScopes,
)) as Credentials | null;

if (authData) {
const scopes = authData.scope?.split(" ");

Expand Down Expand Up @@ -70,7 +76,7 @@
);
const credentials = await AddOnApiHelper.getToken(code as string);
const jwtPayload = parseJwt(credentials.id_token as string);
await persistAuthDetails(credentials);
await persistAuthDetails(credentials, CREDENTIAL_TYPE.OAUTH);

res.end(
nunjucks.renderString(content.toString(), {
Expand Down Expand Up @@ -102,7 +108,86 @@
},
);
}
export default errorHandler<string[]>(login);

function login(): Promise<void> {
return new Promise(
// eslint-disable-next-line no-async-promise-executor -- Handling promise rejection in the executor
async (resolve, reject) => {
const spinner = ora("Logging you in...").start();
try {
const authData = (await getLocalAuthDetails(
CREDENTIAL_TYPE.NEXT_JWT,
)) as NextJwtCredentials | null;
if (authData) {
console.log("already exists", { authData });
// spinner.succeed(
// `You are already logged in as ${authData.email}.`,
// );
// return resolve();
}

const server = http.createServer(async (req, res) => {
try {
if (!req.url) {

Check failure

Code scanning / CodeQL

User-controlled bypass of security check High

This condition guards a sensitive
action
, but a
user-provided value
controls it.
throw new Error("No URL path provided");
}

if (req.url.indexOf("/auth-success") !== -1) {
const qs = new url.URL(req.url, "http://localhost:3030")
.searchParams;
const token = qs.get("code") as string;
const email = qs.get("email") as string;
const expiration = qs.get("expiration") as string;
const currDir = dirname(fileURLToPath(import.meta.url));
const content = readFileSync(
join(currDir, "../templates/loginSuccess.html"),
);

await persistAuthDetails(
{
token,
email,
expiration,
},
CREDENTIAL_TYPE.NEXT_JWT,
);

res.end(
nunjucks.renderString(content.toString(), {
email: email,
}),
);
server.destroy();

spinner.succeed(`You are successfully logged in as ${email}`);
resolve();
} else {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("Hello World\n");
return;
}
} catch (e) {
spinner.fail();
reject(e);
}
});

destroyer(server);

server.listen(3030, () => {
// const apiConfig = await getApiConfig();
open("http://localhost:3000/auth/cli", { wait: true }).then((cp) =>
cp.kill(),
);
});
} catch (e) {
spinner.fail();
reject(e);
}
},
);
}
export default errorHandler<void>(login);
export const LOGIN_EXAMPLES = [
{ description: "Login the user", command: "$0 login" },
];
7 changes: 5 additions & 2 deletions packages/cli/src/cli/commands/logout.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { existsSync, rmSync } from "fs";
import ora from "ora";
import { AUTH_FILE_PATH } from "../../lib/localStorage";
import { AUTH_FOLDER_PATH } from "../../lib/localStorage";
import { errorHandler } from "../exceptions";

const logout = async () => {
const spinner = ora("Logging you out...").start();
try {
if (existsSync(AUTH_FILE_PATH)) rmSync(AUTH_FILE_PATH);
if (existsSync(AUTH_FOLDER_PATH))
rmSync(AUTH_FOLDER_PATH, {
recursive: true,
});
spinner.succeed("Successfully logged you out from PPC client!");
} catch (e) {
spinner.fail();
Expand Down
31 changes: 27 additions & 4 deletions packages/cli/src/cli/commands/whoAmI.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,39 @@
import { parseJwt } from "@pantheon-systems/pcc-sdk-core";
import chalk from "chalk";
import { getLocalAuthDetails } from "../../lib/localStorage";
import { Credentials } from "google-auth-library";
import {
CREDENTIAL_TYPE,
getLocalAuthDetails,
NextJwtCredentials,
} from "../../lib/localStorage";
import { errorHandler } from "../exceptions";

const printWhoAmI = async () => {
try {
const authData = await getLocalAuthDetails();
if (!authData) {
const nextJwt = (await getLocalAuthDetails(
CREDENTIAL_TYPE.NEXT_JWT,
)) as NextJwtCredentials | null;
if (!nextJwt) {
console.log("You aren't logged in.");
} else {
console.log(`You're logged in as ${nextJwt.email}`);
}
} catch (e) {
chalk.red("Something went wrong - couldn't retrieve auth info.");
throw e;
}

try {
const authData = (await getLocalAuthDetails(
CREDENTIAL_TYPE.OAUTH,
)) as Credentials | null;
if (!authData) {
console.log(
"You aren't logged into oauth. For some actions, the oauth connection isn't necessary. If you run a command that requires it, you will be only prompted to log in with oauth at that point.",
);
} else {
const jwtPayload = parseJwt(authData.id_token as string);
console.log(`You're logged in as ${jwtPayload.email}`);
console.log(`Oauth: You're logged in as ${jwtPayload.email}`);
}
} catch (e) {
chalk.red("Something went wrong - couldn't retrieve auth info.");
Expand Down
Loading
Loading