From 9f033de1b212f9d4bad32725fa8c17d59d95d99c Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Tue, 4 Jun 2024 21:47:36 -0600 Subject: [PATCH] feat: add verify and authenticate command --- .eslintrc.json | 2 +- src/commands/authenticate.ts | 71 ++++++++++++++++++++-------------- src/commands/verify.ts | 75 ++++++++++++++++++++++++++++++++++++ test/commands/verify.test.ts | 14 +++++++ 4 files changed, 132 insertions(+), 30 deletions(-) create mode 100644 src/commands/verify.ts create mode 100644 test/commands/verify.test.ts diff --git a/.eslintrc.json b/.eslintrc.json index 1dfcfc4..e698178 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,3 @@ { - "extends": ["oclif", "oclif-typescript", "prettier"] + "extends": ["oclif", "prettier"] } diff --git a/src/commands/authenticate.ts b/src/commands/authenticate.ts index 221a8fa..05ca5e3 100644 --- a/src/commands/authenticate.ts +++ b/src/commands/authenticate.ts @@ -1,7 +1,7 @@ import { Command, Flags } from "@oclif/core"; import axios from "axios"; import chalk from "chalk"; -import inquirer from "inquirer"; +import inquirer, { type Answers, type QuestionCollection } from "inquirer"; import * as fs from "node:fs"; import * as path from "node:path"; import { fileURLToPath } from "node:url"; @@ -13,8 +13,8 @@ export default class Authenticate extends Command { static description = "Authenticate the user by saving server URL and token"; static examples = [ - "$ <%= config.bin %> <%= command.id %> --url=https://panel.dokploy.com --token=aslgjasndjanskj123%!@#", - "$ <%= config.bin %> <%= command.id %> -u https://panel.dokploy.com -t aslgjasndjanskj123%!@#", + "$ <%= config.bin %> <%= command.id %> --url=https://panel.dokploy.com --token=MRTHGZDGMRZWM43EMZSHGZTTMRTHGZDGONSGMZDTMY", + "$ <%= config.bin %> <%= command.id %> -u https://panel.dokploy.com -t MRTHGZDGMRZWM43EMZSHGZTTMRTHGZDGONSGMZDTMY", ]; static flags = { @@ -35,36 +35,50 @@ export default class Authenticate extends Command { const { flags } = await this.parse(Authenticate); - let answers: any; - if (!flags.token || !flags.url) { - answers = await inquirer.prompt([ - { - message: chalk.green( - "Enter your server URL (e.g., https://panel.dokploy.com): ", - ), - name: "url", - type: "input", - validate: (input) => (input ? true : "Server URL is required"), - }, - { - message: chalk.green( - "Enter your authentication token (e.g., aslgjasndjanskj123%!@#): ", - ), - name: "token", - type: "input", - validate: (input) => - input ? true : "Authentication token is required", - }, - ]); + let answers: Answers = {}; + + const questions: QuestionCollection[] = []; + + let config: { token?: string; url?: string } = {}; + if (fs.existsSync(configPath)) { + const configFileContent = fs.readFileSync(configPath, "utf8"); + config = JSON.parse(configFileContent); + } + + if (!flags.url) { + questions.push({ + default: config.url, + message: chalk.green( + "Enter your server URL (e.g., https://panel.dokploy.com): ", + ), + name: "url", + type: "input", + validate: (input) => (input ? true : "Server URL is required"), + }); + } + + if (!flags.token) { + questions.push({ + default: config.token, + message: chalk.green( + "Enter your authentication token (e.g., MRTHGZDGMRZWM43EMZSHGZTTMRTHGZDGONSGMZDTMY=): ", + ), + name: "token", + type: "input", + validate: (input) => + input ? true : "Authentication token is required", + }); + } + + if (questions.length > 0) { + answers = await inquirer.prompt(questions); } const url = flags.url || answers.url; const token = flags.token || answers.token; - const config = { - token, - url, - }; + config.token = token; + config.url = url; try { console.log(`\n${chalk.blue("Validating server...")}`); @@ -86,7 +100,6 @@ export default class Authenticate extends Command { if (!response.data.result.data.json) { this.error(chalk.red("Invalid token")); } - fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); this.log(chalk.green("Authentication details saved successfully.")); } catch (error) { diff --git a/src/commands/verify.ts b/src/commands/verify.ts new file mode 100644 index 0000000..2da837f --- /dev/null +++ b/src/commands/verify.ts @@ -0,0 +1,75 @@ +import { Command } from "@oclif/core"; +import axios from "axios"; +import chalk from "chalk"; +import * as fs from "node:fs"; +import * as path from "node:path"; +import { fileURLToPath } from "node:url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const configPath = path.join(__dirname, "..", "..", "config.json"); + +export default class Verify extends Command { + static description = "Verify if the saved authentication token is valid"; + + static examples = ["$ <%= config.bin %> <%= command.id %>"]; + + async run() { + console.log(chalk.blue.bold("\nVerifying Authentication Token")); + + if (!fs.existsSync(configPath)) { + this.error( + chalk.red( + "No configuration file found. Please authenticate first using `authenticate` command.", + ), + ); + } + + const configFileContent = fs.readFileSync(configPath, "utf8"); + const config = JSON.parse(configFileContent); + const { token, url } = config; + + if (!url || !token) { + this.error( + chalk.red( + "Incomplete authentication details. Please authenticate again using `authenticate` command.", + ), + ); + } + + try { + console.log(`\n${chalk.blue("Validating token...")}`); + + const response = await axios.post( + `${url}/api/trpc/auth.verifyToken`, + { + json: { + token, + }, + }, + { + headers: { + "Content-Type": "application/json", + }, + }, + ); + + if (response.data.result.data.json) { + this.log(chalk.green("Token is valid.")); + } else { + this.error( + chalk.red( + "Invalid token. Please authenticate again using `authenticate` command.", + ), + ); + } + } catch (error) { + this.error( + chalk.red( + // @ts-ignore + `Failed to verify token: ${error.message}. Please authenticate again using 'authenticate' command.`, + ), + ); + } + } +} diff --git a/test/commands/verify.test.ts b/test/commands/verify.test.ts new file mode 100644 index 0000000..7311300 --- /dev/null +++ b/test/commands/verify.test.ts @@ -0,0 +1,14 @@ +import {runCommand} from '@oclif/test' +import {expect} from 'chai' + +describe('verify', () => { + it('runs verify cmd', async () => { + const {stdout} = await runCommand('verify') + expect(stdout).to.contain('hello world') + }) + + it('runs verify --name oclif', async () => { + const {stdout} = await runCommand('verify --name oclif') + expect(stdout).to.contain('hello oclif') + }) +})