@wiztivi/dana-cli 0.0.9 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,6 +13,7 @@ export interface AuthCredentials {
13
13
  export declare class AuthenticationManager {
14
14
  private static getAPIURL;
15
15
  static login(organization: string): Promise<AuthCredentials>;
16
+ static logout(organization: string, creds?: Partial<DanaToken>): Promise<void>;
16
17
  static refresh(organization: string, token: string): Promise<AuthCredentials>;
17
18
  static isTokenExpired(token: string): boolean;
18
19
  static loginNPM(organization: string, credentials: AwsCredentials): Promise<{
@@ -15,7 +15,11 @@ export class AuthenticationManager {
15
15
  const app = express();
16
16
  app.disable("x-powered-by");
17
17
  const promise = new Promise((resolve, reject) => {
18
+ const timeout = setTimeout(() => {
19
+ reject(new Error("Login timed out."));
20
+ }, 5 * 60 * 1000);
18
21
  app.get("/callback", (req, res) => {
22
+ clearTimeout(timeout);
19
23
  try {
20
24
  if (req.query.error) {
21
25
  res.send("Login failed. Check the CLI for details.");
@@ -42,6 +46,17 @@ export class AuthenticationManager {
42
46
  server.close();
43
47
  });
44
48
  }
49
+ static async logout(organization, creds) {
50
+ const url = new URL(`${AuthenticationManager.getAPIURL(organization)}/logout`);
51
+ if (creds?.id_token) {
52
+ url.searchParams.append("id_token", creds.id_token);
53
+ }
54
+ if (creds?.refresh_token) {
55
+ url.searchParams.append("refresh_token", creds.refresh_token);
56
+ }
57
+ await open(url.toString());
58
+ CredentialsHelper.delete(organization);
59
+ }
45
60
  static async refresh(organization, token) {
46
61
  const data = await fetch(`${AuthenticationManager.getAPIURL(organization)}/login?refresh_token=${token}`);
47
62
  if (!data.ok) {
@@ -1,7 +1,10 @@
1
- import { Command } from "commander";
1
+ import { Command, Option } from "commander";
2
2
  import translation from "../../common/translation/translation.js";
3
3
  import login from "./commands/login.js";
4
4
  import { statusAction } from "./commands/status.js";
5
+ import logout from "./commands/logout.js";
6
+ import { getPackagesToken } from "./commands/get-packages-token.js";
7
+ import { authHook } from "./authHook.js";
5
8
  const addAuthDefinition = () => {
6
9
  const command = new Command("auth").description(translation["command.auth.description"]);
7
10
  const loginCmd = new Command("login")
@@ -9,10 +12,22 @@ const addAuthDefinition = () => {
9
12
  .option("-o, --org <organization>", translation["command.auth.login.option.org"])
10
13
  .action(login);
11
14
  command.addCommand(loginCmd);
15
+ const logoutCmd = new Command("logout")
16
+ .description(translation["command.auth.logout.description"])
17
+ .option("-o, --org <organization>", translation["command.auth.login.option.org"])
18
+ .action(logout);
19
+ command.addCommand(logoutCmd);
12
20
  const statusCmd = new Command("status")
13
21
  .description(translation["command.auth.status.description"])
14
22
  .action(statusAction);
15
23
  command.addCommand(statusCmd);
24
+ const getPackagesTokenCmd = new Command("get-packages-token")
25
+ .description(translation["command.auth.get-packages-token.description"])
26
+ .addOption(new Option("-t, --target <target>", "Packages target").makeOptionMandatory(true).choices(["android"]))
27
+ .option("-o, --org <organization>", translation["command.auth.login.option.org"])
28
+ .hook("preAction", authHook)
29
+ .action(getPackagesToken);
30
+ command.addCommand(getPackagesTokenCmd);
16
31
  return command;
17
32
  };
18
33
  export default addAuthDefinition;
@@ -0,0 +1,6 @@
1
+ interface GetPackageTokenOptions {
2
+ target: "android";
3
+ org?: string;
4
+ }
5
+ declare const getPackagesToken: (options: GetPackageTokenOptions) => Promise<void>;
6
+ export { getPackagesToken };
@@ -0,0 +1,30 @@
1
+ import { CredentialsHelper } from "../helper/CredentialsHelper.js";
2
+ import { createCodeArtifactClient } from "../helper/CodeArtifactHelper.js";
3
+ import { GetAuthorizationTokenCommand } from "@aws-sdk/client-codeartifact";
4
+ import * as prompts from "@clack/prompts";
5
+ import { GET_PACKAGES_TOKEN_ERROR } from "../../../common/const/exitCodeConst.js";
6
+ import { DOMAIN, DOMAIN_OWNER } from "../authentConst.js";
7
+ const getAndroidToken = async (creds) => {
8
+ const client = createCodeArtifactClient(creds);
9
+ const command = new GetAuthorizationTokenCommand({
10
+ domain: DOMAIN,
11
+ domainOwner: DOMAIN_OWNER,
12
+ });
13
+ try {
14
+ const result = await client.send(command);
15
+ console.log(result.authorizationToken);
16
+ }
17
+ catch (error) {
18
+ prompts.log.error(error.message);
19
+ process.exit(GET_PACKAGES_TOKEN_ERROR);
20
+ }
21
+ };
22
+ const getPackagesToken = async (options) => {
23
+ const creds = CredentialsHelper.get(options.org);
24
+ switch (options.target) {
25
+ case "android":
26
+ // authHook ensure credentials are valid
27
+ return getAndroidToken(creds.aws);
28
+ }
29
+ };
30
+ export { getPackagesToken };
@@ -1,8 +1,8 @@
1
1
  import * as prompts from "@clack/prompts";
2
2
  import colors from "picocolors";
3
- import { LOGIN_ERROR } from "../../../common/const/exitCodeConst.js";
4
3
  import { CredentialsHelper } from "../helper/CredentialsHelper.js";
5
4
  import { AuthenticationManager } from "../AuthenticationManager.js";
5
+ import { handleError } from "../helper/CommandHelper.js";
6
6
  /*
7
7
  Login to DANA backend (with aws and cognito) and connect to npm codeartifact
8
8
  More info: https://github.com/wiztivi-rd/dana-cli/wiki/Login
@@ -24,9 +24,4 @@ const login = async ({ org }) => {
24
24
  handleError(error);
25
25
  }
26
26
  };
27
- const handleError = (error) => {
28
- const message = error instanceof Error ? error.message : error;
29
- prompts.outro(colors.red(`An issue occurred :` + message));
30
- process.exit(LOGIN_ERROR);
31
- };
32
27
  export default login;
@@ -0,0 +1,5 @@
1
+ interface LogoutOptions {
2
+ org?: string;
3
+ }
4
+ declare const logout: ({ org }: LogoutOptions) => Promise<void>;
5
+ export default logout;
@@ -0,0 +1,20 @@
1
+ import * as prompts from "@clack/prompts";
2
+ import colors from "picocolors";
3
+ import { CredentialsHelper } from "../helper/CredentialsHelper.js";
4
+ import { AuthenticationManager } from "../AuthenticationManager.js";
5
+ import { handleError } from "../helper/CommandHelper.js";
6
+ /*
7
+ Logout from DANA backend
8
+ */
9
+ const logout = async ({ org }) => {
10
+ const credentials = CredentialsHelper.get(org);
11
+ try {
12
+ prompts.intro(`Logout from ${credentials.org}...`);
13
+ await AuthenticationManager.logout(credentials.org, credentials.dana);
14
+ prompts.outro(colors.green("✓") + ` Logout successful. You are now being logged out in your browser.`);
15
+ }
16
+ catch (error) {
17
+ handleError(error);
18
+ }
19
+ };
20
+ export default logout;
@@ -0,0 +1 @@
1
+ export declare const handleError: (error: unknown) => void;
@@ -0,0 +1,8 @@
1
+ import * as prompts from "@clack/prompts";
2
+ import colors from "picocolors";
3
+ import translation from "../../../common/translation/translation.js";
4
+ import { LOGIN_ERROR } from "../../../common/const/exitCodeConst.js";
5
+ export const handleError = (error) => {
6
+ prompts.outro(colors.red(error.message ?? translation["error.common.start.message"]));
7
+ process.exit(LOGIN_ERROR);
8
+ };
@@ -18,11 +18,14 @@ export interface OrgCredentials {
18
18
  }
19
19
  export interface DanaConfig {
20
20
  lastUsedOrg: string;
21
+ version: number;
21
22
  credentials: Record<string, OrgCredentials>;
22
23
  }
24
+ export declare const CURRENT_DANA_JSON_VERSION = 2;
23
25
  export declare class CredentialsHelper {
24
26
  static readonly filePath: string;
25
- private static getConfig;
27
+ static getConfig(): DanaConfig | null;
28
+ private static migrateConfig;
26
29
  static store(credentials: {
27
30
  aws: AwsCredentials;
28
31
  dana: DanaToken;
@@ -33,4 +36,5 @@ export declare class CredentialsHelper {
33
36
  dana?: DanaToken;
34
37
  org: string;
35
38
  };
39
+ static delete(org: string): void;
36
40
  }
@@ -2,17 +2,40 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
3
  import path from "node:path";
4
4
  import { DEFAULT_ORG } from "../authentConst.js";
5
+ export const CURRENT_DANA_JSON_VERSION = 2;
5
6
  export class CredentialsHelper {
6
7
  static filePath = path.join(homedir(), ".dana.json");
7
8
  static getConfig() {
8
9
  if (!existsSync(this.filePath)) {
9
10
  return null;
10
11
  }
11
- return JSON.parse(readFileSync(this.filePath, { encoding: "utf-8" }));
12
+ let config = JSON.parse(readFileSync(this.filePath, { encoding: "utf-8" }));
13
+ const configVersion = config.version ?? 1;
14
+ if (configVersion != CURRENT_DANA_JSON_VERSION) {
15
+ config = CredentialsHelper.migrateConfig(config, configVersion);
16
+ writeFileSync(this.filePath, JSON.stringify(config, null, 4));
17
+ }
18
+ return config;
19
+ }
20
+ static migrateConfig(config, from) {
21
+ if (from === 1) {
22
+ const v1 = config;
23
+ return {
24
+ lastUsedOrg: v1.org,
25
+ credentials: {
26
+ [v1.org]: {
27
+ dana: v1.dana,
28
+ aws: v1.aws,
29
+ },
30
+ },
31
+ version: CURRENT_DANA_JSON_VERSION,
32
+ };
33
+ }
34
+ return config;
12
35
  }
13
36
  static store(credentials) {
14
37
  let config = this.getConfig();
15
- config ??= { lastUsedOrg: credentials.org, credentials: {} };
38
+ config ??= { lastUsedOrg: credentials.org, credentials: {}, version: CURRENT_DANA_JSON_VERSION };
16
39
  config.credentials ??= {};
17
40
  config.lastUsedOrg = credentials.org;
18
41
  config.credentials[credentials.org] = { aws: credentials.aws, dana: credentials.dana };
@@ -32,4 +55,11 @@ export class CredentialsHelper {
32
55
  }
33
56
  return creds;
34
57
  }
58
+ static delete(org) {
59
+ const config = this.getConfig();
60
+ if (config) {
61
+ delete config.credentials[org];
62
+ writeFileSync(this.filePath, JSON.stringify(config, null, 4));
63
+ }
64
+ }
35
65
  }
@@ -5,3 +5,4 @@ export declare const DEVICE_ERROR = 5;
5
5
  export declare const LOGIN_ERROR = 6;
6
6
  export declare const COMMAND_ERROR = 7;
7
7
  export declare const SETUP_ERROR = 8;
8
+ export declare const GET_PACKAGES_TOKEN_ERROR = 9;
@@ -5,3 +5,4 @@ export const DEVICE_ERROR = 5;
5
5
  export const LOGIN_ERROR = 6;
6
6
  export const COMMAND_ERROR = 7;
7
7
  export const SETUP_ERROR = 8;
8
+ export const GET_PACKAGES_TOKEN_ERROR = 9;
@@ -60,7 +60,7 @@ class CreateFileHelper {
60
60
  credentials: credentials?.aws,
61
61
  format: "maven",
62
62
  });
63
- let gruntOptions = `--appUrl="${registryAccount}" `;
63
+ let gruntOptions = `--appUrl="${registryAccount}" --organization="${credentials.org}" `;
64
64
  const optionsToAdd = ["appId", "appName", "appVersion", "appVersionCode", "wtvAndroidVersion"];
65
65
  for (const option of optionsToAdd) {
66
66
  gruntOptions += `--${option}="${config.androidtv?.device[option]}" `;
@@ -122,7 +122,7 @@ class UpdateFileHelper {
122
122
  static getConfigFileOutput = function (directory) {
123
123
  const configFiles = [
124
124
  "gitignoreTemplate.hbs",
125
- "editorConfigTemplate.hbs",
125
+ "editorconfigTemplate.hbs",
126
126
  "eslintrc.jsonTemplate.hbs",
127
127
  "nvmrcTemplate.hbs",
128
128
  ];
@@ -22,8 +22,10 @@
22
22
  "helper.git.status.error": "Git status is not clean or an error occurred. Try to commit your change.",
23
23
  "command.auth.description": "Authenticate to Dana framework",
24
24
  "command.auth.login.description": "Login to Dana",
25
- "command.auth.login.option.org": "Organization to login",
25
+ "command.auth.logout.description": "Logout from Dana",
26
+ "command.auth.login.option.org": "Organization to login/logout",
26
27
  "command.auth.status.description": "Get login status",
28
+ "command.auth.get-packages-token.description": "Get token for packages repository",
27
29
  "command.scrollView.description": "Add a scrollView of rails",
28
30
  "command.scrollView.option.itemView": "Item to be used in the scrollView. Default: pre-made rail",
29
31
  "command.scrollView.option.itemMargin": "Margin between items. Default: 550",
@@ -56,7 +58,7 @@
56
58
  "command.completion.argument": "Shell. Bash or zsh",
57
59
  "command.completion.success": "Completion installed to ",
58
60
  "login.info.token_expired": "Your token has expired.",
59
- "login.info.please_login": "Please run dana auth login command",
61
+ "login.info.please_login": "Please run 'dana auth login' command",
60
62
  "login.error.not_logged": "You're not logged in.",
61
63
  "login.info.logged": "You're currently logged in to Dana"
62
64
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wiztivi/dana-cli",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "description": "Dana create app CLI",
5
5
  "type": "module",
6
6
  "exports": "./dist/index.js",
@@ -28,7 +28,7 @@
28
28
  "dependencies": {
29
29
  "@aws-sdk/client-codeartifact": "^3.859.0",
30
30
  "@clack/prompts": "0.10.0",
31
- "@wiztivi/dana-templates": "^0.0.9",
31
+ "@wiztivi/dana-templates": "^0.0.10",
32
32
  "child_process": "1.0.x",
33
33
  "command-exists": "1.2.9",
34
34
  "commander": "11.1.x",