From 2cdd649bec96fbdb8a43e16a08b256b16a98a662 Mon Sep 17 00:00:00 2001 From: Robin Genz Date: Thu, 2 May 2024 10:28:57 +0200 Subject: [PATCH] feat(login): add `--token` option --- src/commands/login.ts | 69 +++++++++++++++++++++++++---------------- src/commands/logout.ts | 5 +-- src/commands/whoami.ts | 14 ++++++--- src/services/users.ts | 31 ++++++++++++++++++ src/types/index.ts | 1 + src/types/user.ts | 4 +++ src/utils/userConfig.ts | 2 -- 7 files changed, 89 insertions(+), 37 deletions(-) create mode 100644 src/services/users.ts create mode 100644 src/types/user.ts diff --git a/src/commands/login.ts b/src/commands/login.ts index 0bc466e..45db3a5 100644 --- a/src/commands/login.ts +++ b/src/commands/login.ts @@ -5,42 +5,57 @@ import userConfig from '../utils/userConfig'; import { API_URL } from '../config'; import { passwordPrompt, prompt } from '../utils/prompt'; import { isRunningInCi } from '../utils/ci'; +import usersService from '../services/users'; export default defineCommand({ meta: { name: 'login', description: 'Sign in to the Capawesome Cloud Console.', }, + args: { + token: { + type: 'string', + description: 'Token to use for authentication.', + }, + }, run: async (ctx) => { - if (isRunningInCi()) { - consola.error( - 'Sign in is not supported in CI environments. Please use the CAPAWESOME_TOKEN environment variable.', + let token = ctx.args.token; + if (token) { + userConfig.write({ + token: token, + }); + try { + await usersService.me(); + } catch (error) { + userConfig.write({}); + consola.error('Invalid token.'); + return; + } + consola.success(`Successfully signed in.`); + } else { + const email = await prompt('Enter your email:', { type: 'text' }); + const password = await passwordPrompt('Enter your password:'); + consola.start('Logging in...'); + let sessionId: string; + try { + const sessionResponse = await axios.post<{ id: string }>(`${API_URL}/sessions`, { + email: email, + password: password, + }); + sessionId = sessionResponse.data.id; + } catch (error) { + consola.error('Invalid email or password.'); + return; + } + const tokenResponse = await axios.post<{ token: string }>( + `${API_URL}/tokens`, + { name: 'Capawesome CLI' }, + { headers: { Authorization: `Bearer ${sessionId}` } }, ); - return; - } - const email = await prompt('Enter your email:', { type: 'text' }); - const password = await passwordPrompt('Enter your password:'); - consola.start('Logging in...'); - let sessionId: string; - try { - const sessionResponse = await axios.post<{ id: string }>(`${API_URL}/sessions`, { - email: email, - password: password, + userConfig.write({ + token: tokenResponse.data.token, }); - sessionId = sessionResponse.data.id; - } catch (error) { - consola.error('Invalid email or password.'); - return; + consola.success(`Successfully signed in.`); } - const tokenResponse = await axios.post<{ token: string }>( - `${API_URL}/tokens`, - { name: 'Capawesome CLI' }, - { headers: { Authorization: `Bearer ${sessionId}` } }, - ); - userConfig.write({ - username: email, - token: tokenResponse.data.token, - }); - consola.success(`Successfully signed in.`); }, }); diff --git a/src/commands/logout.ts b/src/commands/logout.ts index 704a229..6b98e11 100644 --- a/src/commands/logout.ts +++ b/src/commands/logout.ts @@ -9,10 +9,7 @@ export default defineCommand({ }, args: {}, run: async () => { - const config = userConfig.read(); - delete config.username; - delete config.token; - userConfig.write(config); + userConfig.write({}); consola.success('Successfully signed out.'); }, }); diff --git a/src/commands/whoami.ts b/src/commands/whoami.ts index 3a66eff..a940e7f 100644 --- a/src/commands/whoami.ts +++ b/src/commands/whoami.ts @@ -1,6 +1,7 @@ import { defineCommand } from 'citty'; import consola from 'consola'; import userConfig from '../utils/userConfig'; +import usersService from '../services/users'; export default defineCommand({ meta: { @@ -8,11 +9,16 @@ export default defineCommand({ description: 'Show current user', }, run: async () => { - const { username } = userConfig.read(); - if (!username) { - consola.error('Not logged in'); + const { token } = userConfig.read(); + if (token) { + try { + const user = await usersService.me(); + consola.info(`Logged in as ${user.email}.`); + } catch (error) { + consola.error('Token is invalid. Please sign in again.'); + } } else { - consola.info(`Logged in as ${username}`); + consola.error('Not logged in.'); } }, }); diff --git a/src/services/users.ts b/src/services/users.ts new file mode 100644 index 0000000..258cdc7 --- /dev/null +++ b/src/services/users.ts @@ -0,0 +1,31 @@ +import { UserDto } from '../types'; +import httpClient, { HttpClient } from '../utils/http-client'; +import authorizationService from './authorization-service'; + +export interface UsersService { + me(): Promise; +} + +class UsersServiceImpl implements UsersService { + private readonly httpClient: HttpClient; + + constructor(httpClient: HttpClient) { + this.httpClient = httpClient; + } + + async me(): Promise { + const response = await this.httpClient.get('/users/me', { + headers: { + Authorization: `Bearer ${authorizationService.getCurrentAuthorizationToken()}`, + }, + }); + if (!response.success) { + throw response.error; + } + return response.data; + } +} + +const usersService = new UsersServiceImpl(httpClient); + +export default usersService; diff --git a/src/types/index.ts b/src/types/index.ts index bf61b41..466e264 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -2,3 +2,4 @@ export * from './app'; export * from './app-bundle'; export * from './app-device'; export * from './app-channel'; +export * from './user'; diff --git a/src/types/user.ts b/src/types/user.ts new file mode 100644 index 0000000..2157bc5 --- /dev/null +++ b/src/types/user.ts @@ -0,0 +1,4 @@ +export interface UserDto { + id: string; + email: string; +} diff --git a/src/utils/userConfig.ts b/src/utils/userConfig.ts index 766556c..4b9fb4b 100644 --- a/src/utils/userConfig.ts +++ b/src/utils/userConfig.ts @@ -1,13 +1,11 @@ import { readUser, writeUser } from 'rc9'; export interface IUserConfig { - username?: string; token?: string; } export interface UserConfig { read(): IUserConfig; - write(config: IUserConfig): void; }