@supernovaio/cli
Version:
Supernova.io Command Line Interface
199 lines (197 loc) • 7.96 kB
JavaScript
!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