UNPKG

zents

Version:

ZenTS is a Node.js & TypeScript MVC-Framework for building rich web applications, released as free and open-source software under the MIT License. It is designed for building web applications with modern tools and design patterns.

168 lines 6.22 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SecurityProvider = void 0; const enums_1 = require("../types/enums"); const JWT_1 = require("./JWT"); const secure_password_1 = __importDefault(require("secure-password")); const bcrypt_1 = __importDefault(require("bcrypt")); const crypto_1 = __importDefault(require("crypto")); class SecurityProvider { constructor(options, response, adapter, strategy, databaseContainer) { this.options = options; this.response = response; this.adapter = adapter; this.strategy = strategy; this.connection = databaseContainer.get(enums_1.DB_TYPE.ORM); this.argon2idGenerator = this.options.algorithm === 'argon2id' ? new secure_password_1.default({ memlimit: options.memLimit, opslimit: options.opsLimit, }) : null; } async login(context) { const username = context.body[this.options.usernameField]; const password = context.body[this.options.passwordField]; if (typeof username !== 'string' || !username.length || typeof password !== 'string' || !password.length) { return this.response.loginFailed(context); } const repository = this.connection.getRepository(this.options.userEntity); const user = await repository.findOne({ username, }); if (!user || typeof user[this.options.passwordColumn] !== 'string' || typeof user[this.options.identifierColumn] === 'undefined') { return this.response.loginFailed(context); } const passwordHash = user[this.options.passwordColumn]; if (!(await bcrypt_1.default.compare(password, passwordHash))) { return this.response.loginFailed(context); } const token = await this.generateToken(context, user[this.options.identifierColumn]); await this.adapter.create(token.sessionId); this.strategy.setToken(context, token.token); return this.response.loginSuccess(context, token.token); } async logout(context) { if (!this.strategy.hasToken(context)) { return this.response.logoutFailed(context); } const token = this.strategy.getToken(context); if (token === false) { return this.response.forbidden(context); } const parsedToken = await this.parseToken(token); if (parsedToken === false) { return this.response.forbidden(context); } await this.adapter.remove(parsedToken.sessionId); return this.response.logoutSuccess(context); } async authorize(context) { const isNotAuth = { isAuth: false, }; if (!this.strategy.hasToken(context)) { return isNotAuth; } const token = this.strategy.getToken(context); if (token === false) { return isNotAuth; } const parsedToken = await this.parseToken(token); if (parsedToken === false || !(await this.adapter.has(parsedToken.sessionId))) { return isNotAuth; } const repository = this.connection.getRepository(this.options.userEntity); const user = await repository.findOne({ [this.options.identifierColumn]: parsedToken.userId, }); if (!user) { return isNotAuth; } return { isAuth: true, sessionId: parsedToken.sessionId, user, }; } async forbidden(context) { return new Promise((resolve) => { this.response.forbidden(context); resolve(); }); } async generatePasswordHash(plainTextPassword) { let hash; if (this.options.algorithm === 'argon2id') { const passwordBuffer = Buffer.from(plainTextPassword); hash = (await this.argon2idGenerator.hash(passwordBuffer)).toString(); } else if (this.options.algorithm === 'bcrypt') { hash = await bcrypt_1.default.hash(plainTextPassword, this.options.saltRounds); } return hash; } generateSessionId() { return crypto_1.default.randomBytes(16).toString('hex'); } async generateToken(context, userId) { const sessionId = this.generateSessionId(); let providers = [ { provider: this.options.name, sessionId, userId, }, ]; if (this.strategy.hasToken(context)) { const currentToken = this.strategy.getToken(context); if (await this.verifyToken(currentToken)) { const currentData = JWT_1.JWT.decode(currentToken); if (currentData && Array.isArray(currentData.providers)) { providers = [...providers, ...currentData.providers]; } } } return { token: await JWT_1.JWT.sign({ providers, }), sessionId, }; } async verifyToken(token) { if (typeof token !== 'string' || !token.length) { return false; } const splitted = token.trim().split(' '); if (splitted.length < 2 || splitted[0].toLowerCase() !== 'bearer') { return false; } return await JWT_1.JWT.verify(splitted[1]); } async parseToken(token) { if (!(await JWT_1.JWT.verify(token))) { return false; } const decoded = JWT_1.JWT.decode(token); if (!Array.isArray(decoded.providers)) { return false; } const provider = decoded.providers.filter((data) => data.provider === this.options.name); if (!provider.length) { return false; } return provider[0]; } } exports.SecurityProvider = SecurityProvider; //# sourceMappingURL=SecurityProvider.js.map