UNPKG

open-collaboration-server

Version:

Open Collaboration Server implementation, part of the Open Collaboration Tools project

148 lines 5.84 kB
// ****************************************************************************** // Copyright 2024 TypeFox GmbH // This program and the accompanying materials are made available under the // terms of the MIT License, which is available in the project root. // ****************************************************************************** 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; }; import { inject, injectable, postConstruct } from 'inversify'; import { isUser } from './types.js'; import { UserManager } from './user-manager.js'; import * as jose from 'jose'; import { customAlphabet } from 'nanoid'; import { Emitter } from 'open-collaboration-protocol'; import { Logger } from './utils/logging.js'; import { Configuration } from './utils/configuration.js'; import { getLocalFilename } from './collaboration-server.js'; let CredentialsManager = class CredentialsManager { userManager; logger; configuration; deferredAuths = new Map(); nanoid = this.generateAlphabet(); initialize() { if (this.configuration.getValue('oct-jwt-private-key') === undefined) { this.logger.warn('OCT_JWT_PRIVATE_KEY env variable is not set. Using a static key for development purposes.'); } } async confirmUser(confirmToken, user) { const auth = this.deferredAuths.get(confirmToken); if (!auth) { throw this.logger.createErrorAndLog('Login timed out'); } const registeredUser = await this.userManager.registerUser(user); const userClaim = { id: registeredUser.id, name: registeredUser.name, email: registeredUser.email, authProvider: registeredUser.authProvider }; this.logger.info(`Will generate JWT for user [id: ${userClaim.id} | name: ${userClaim.name} | email: ${userClaim.email}]`); const jwt = await this.generateJwt(userClaim); auth.update(jwt); return jwt; } async startAuth() { const confirmToken = this.secureId(); const updateEmitter = new Emitter(); const failureEmitter = new Emitter(); const dispose = () => { clearTimeout(timeout); this.deferredAuths.delete(confirmToken); updateEmitter.dispose(); failureEmitter.dispose(); }; const timeout = setTimeout(() => { failureEmitter.fire(new Error('Request timed out')); dispose(); }, 300_000); // 5 minutes of timeout const delayedAuth = { update: jwt => { delayedAuth.jwt = jwt; updateEmitter.fire(jwt); }, onUpdate: updateEmitter.event, onFail: failureEmitter.event, dispose }; this.deferredAuths.set(confirmToken, delayedAuth); return confirmToken; } async getAuth(confirmToken) { return this.deferredAuths.get(confirmToken); } async getUser(token) { const user = await this.verifyJwt(token, isUser); if (typeof user.id !== 'string' || typeof user.name !== 'string') { throw this.logger.createErrorAndLog('User token is not valid'); } return user; } async verifyJwt(jwt, verify) { const key = this.getJwtPrivateKey(); const { payload } = await jose.jwtVerify(jwt, key); if (verify(payload)) { return payload; } else { throw this.logger.createErrorAndLog('JWT payload is not valid'); } } getJwtPrivateKey() { const key = this.configuration.getValue('oct-jwt-private-key') ?? getLocalFilename(import.meta.url); return Buffer.from(key); } async generateJwt(payload) { const [key, expiration] = await Promise.all([ this.getJwtPrivateKey(), this.getJwtExpiration() ]); const signJwt = new jose.SignJWT(payload) .setProtectedHeader({ alg: 'HS256' }) .setIssuedAt(); if (expiration !== undefined) { signJwt.setExpirationTime(expiration); } return signJwt.sign(key); } async getJwtExpiration() { return undefined; } generateAlphabet() { let alphabet = ''; for (let digit = 48 /* '0' */; digit <= 57 /* '9' */; digit++) { alphabet += String.fromCharCode(digit); } for (let letter = 65 /* 'A' */; letter <= 90 /* 'Z' */; letter++) { alphabet += String.fromCharCode(letter); } for (let letter = 97 /* 'a' */; letter <= 122 /* 'z' */; letter++) { alphabet += String.fromCharCode(letter); } return customAlphabet(alphabet, 24); } secureId() { return this.nanoid(24); } }; __decorate([ inject(UserManager) ], CredentialsManager.prototype, "userManager", void 0); __decorate([ inject(Logger) ], CredentialsManager.prototype, "logger", void 0); __decorate([ inject(Configuration) ], CredentialsManager.prototype, "configuration", void 0); __decorate([ postConstruct() ], CredentialsManager.prototype, "initialize", null); CredentialsManager = __decorate([ injectable() ], CredentialsManager); export { CredentialsManager }; //# sourceMappingURL=credentials-manager.js.map