UNPKG

@supernovaio/cli

Version:

Supernova.io Command Line Interface

199 lines (197 loc) 7.96 kB
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="b76d191d-5785-5876-addc-6c88ea2103f3")}catch(e){}}(); var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; import { SentryTraced } from "@sentry/nestjs"; import { jwtDecode } from "jwt-decode"; import keytar from "keytar"; import * as fs from "node:fs"; import * as os from "node:os"; import path from "node:path"; import { TargetEnv } from "../types/environment.js"; import { EnvTokensSchema } from "../types/login.js"; import { NotAuthorizedError } from "../types/not-authorized.error.js"; import { AuthService } from "./auth.service.js"; export class KeytarVault { async deletePassword(serviceName, account) { await keytar.deletePassword(serviceName, account); } async getPassword(serviceName, account) { return keytar.getPassword(serviceName, account); } async setPassword(serviceName, account, password) { await keytar.setPassword(serviceName, account, password); } } export class VaultService { authService; vault; serviceName = "Supernova"; constructor(authService = new AuthService(), vault = new KeytarVault()) { this.authService = authService; this.vault = vault; } async deleteTokensFromVault(env) { try { await this.vault.deletePassword(this.serviceName, `${env}_access_token`); await this.vault.deletePassword(this.serviceName, `${env}_refresh_token`); } catch { this.storeTokensInFile(env, null); } } async getLoggedInUserSub(env) { const tokens = await this.tryGetTokensFromVault(env); if (!tokens) return undefined; const decoded = jwtDecode(tokens.accessToken); return decoded.sub; } getTokensFromFile(env) { const filePath = this.tokensFilePath(); if (!fs.existsSync(filePath)) { return undefined; } const fileContent = fs.readFileSync(filePath, "utf8"); const data = JSON.parse(fileContent); return data[env] ?? {}; } async tryGetTokensFromVault(env) { if (process.env.SUPERNOVA_TOKEN) { return { accessToken: process.env.SUPERNOVA_TOKEN }; } let accessToken; let refreshToken; try { accessToken = (await this.vault.getPassword(this.serviceName, `${env}_access_token`)) ?? undefined; refreshToken = (await this.vault.getPassword(this.serviceName, `${env}_refresh_token`)) ?? undefined; } catch { const tokens = this.getTokensFromFile(env); if (tokens) { accessToken = tokens.accessToken; refreshToken = tokens.refreshToken; } } if (!accessToken) { return null; } const freshTokens = refreshToken ? await this.refreshTokens(env, accessToken, refreshToken) : undefined; if (freshTokens) { return freshTokens; } return { accessToken, refreshToken }; } async getTokensFromVault(env) { const tokens = await this.tryGetTokensFromVault(env); if (!tokens) throw new NotAuthorizedError(); return tokens; } async refreshTokens(env, accessToken, refreshToken) { const decoded = jwtDecode(accessToken); const currentTime = Math.floor(Date.now() / 1000); if (decoded.exp && decoded.exp < currentTime + 300) { const freshTokens = await this.authService.refreshToken(env, refreshToken); if (!freshTokens) { await this.deleteTokensFromVault(env); throw new NotAuthorizedError(); } await this.storeTokensToVault(freshTokens, env); return freshTokens; } return undefined; } storeTokensInFile(env, tokens) { const supernovaDir = this.supernovaDir(); const filePath = path.join(supernovaDir, "tokens.json"); if (!fs.existsSync(supernovaDir)) { fs.mkdirSync(supernovaDir, { recursive: true }); } let data = {}; if (fs.existsSync(filePath)) { const fileContent = fs.readFileSync(filePath, "utf8"); data = EnvTokensSchema.parse(JSON.parse(fileContent)); } if (tokens) data[env] = tokens; else delete data[env]; fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf8"); } async storeTokensToVault({ accessToken, refreshToken }, env) { try { await this.vault.setPassword(this.serviceName, `${env}_access_token`, accessToken); if (refreshToken) { await this.vault.setPassword(this.serviceName, `${env}_refresh_token`, refreshToken); } } catch { this.storeTokensInFile(env, { accessToken, refreshToken }); } } supernovaDir() { const homeDir = os.homedir(); return path.join(homeDir, ".supernova"); } tokensFilePath() { const homeDir = this.supernovaDir(); return path.join(homeDir, "tokens.json"); } } __decorate([ SentryTraced(), __metadata("design:type", Function), __metadata("design:paramtypes", [String]), __metadata("design:returntype", Promise) ], VaultService.prototype, "deleteTokensFromVault", null); __decorate([ SentryTraced(), __metadata("design:type", Function), __metadata("design:paramtypes", [String]), __metadata("design:returntype", Promise) ], VaultService.prototype, "getLoggedInUserSub", null); __decorate([ SentryTraced(), __metadata("design:type", Function), __metadata("design:paramtypes", [String]), __metadata("design:returntype", Object) ], VaultService.prototype, "getTokensFromFile", null); __decorate([ SentryTraced(), __metadata("design:type", Function), __metadata("design:paramtypes", [String]), __metadata("design:returntype", Promise) ], VaultService.prototype, "tryGetTokensFromVault", null); __decorate([ SentryTraced(), __metadata("design:type", Function), __metadata("design:paramtypes", [String]), __metadata("design:returntype", Promise) ], VaultService.prototype, "getTokensFromVault", null); __decorate([ SentryTraced(), __metadata("design:type", Function), __metadata("design:paramtypes", [String, String, String]), __metadata("design:returntype", Promise) ], VaultService.prototype, "refreshTokens", null); __decorate([ SentryTraced(), __metadata("design:type", Function), __metadata("design:paramtypes", [String, Object]), __metadata("design:returntype", void 0) ], VaultService.prototype, "storeTokensInFile", null); __decorate([ SentryTraced(), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, String]), __metadata("design:returntype", Promise) ], VaultService.prototype, "storeTokensToVault", null); //# sourceMappingURL=vault.service.js.map //# debugId=b76d191d-5785-5876-addc-6c88ea2103f3