UNPKG

@minimaltech/node-infra

Version:

Minimal Technology NodeJS Infrastructure - Loopback 4 Framework

227 lines 11.7 kB
"use strict"; 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); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.defineOAuth2Controller = exports.DefaultOAuth2ExpressServer = void 0; const common_1 = require("../../../common"); const helpers_1 = require("../../../helpers"); const utilities_1 = require("../../../utilities"); const authentication_1 = require("@loopback/authentication"); const core_1 = require("@loopback/core"); const rest_1 = require("@loopback/rest"); const security_1 = require("@loopback/security"); const oauth2_server_1 = require("@node-oauth/oauth2-server"); const services_1 = require("../services"); const controllers_1 = require("../../../base/controllers"); const isEmpty_1 = __importDefault(require("lodash/isEmpty")); const node_path_1 = require("node:path"); const common_2 = require("../common"); // -------------------------------------------------------------------------------- class DefaultOAuth2ExpressServer extends rest_1.ExpressServer { constructor(opts) { super(opts.config, opts.parent); this.authServiceKey = opts.authServiceKey; this.injectionGetter = opts.injectionGetter; this.viewFolder = opts.viewFolder; this.logger = helpers_1.LoggerFactory.getLogger([DefaultOAuth2ExpressServer.name]); this.binding(); } static getInstance(opts) { if (!this.instance) { this.instance = new DefaultOAuth2ExpressServer(opts); return this.instance; } return this.instance; } getApplicationHandler() { return this.expressApp; } binding() { var _a, _b, _c; this.expressApp.set('view engine', 'ejs'); const oauth2ViewFolder = (_b = (_a = this.viewFolder) !== null && _a !== void 0 ? _a : helpers_1.applicationEnvironment.get(common_1.EnvironmentKeys.APP_ENV_OAUTH2_VIEW_FOLDER)) !== null && _b !== void 0 ? _b : (0, node_path_1.join)(__dirname, '../', 'views'); this.expressApp.set('views', oauth2ViewFolder); this.logger.info('[binding] View folder: %s', oauth2ViewFolder); const basePath = (_c = helpers_1.applicationEnvironment.get(common_1.EnvironmentKeys.APP_ENV_SERVER_BASE_PATH)) !== null && _c !== void 0 ? _c : ''; const authAction = `${basePath}/oauth2/auth`; this.logger.info('[binding] Auth action path: %s', authAction); // ----------------------------------------------------------------------------------------------------------------- this.expressApp.get('/auth', (request, response) => { var _a; const { c, r } = request.query; if (!c) { response.render('pages/auth', { message: 'Invalid client credential | Please verify query params!', payload: {}, }); return; } const payload = { title: `${helpers_1.applicationEnvironment.get(common_1.EnvironmentKeys.APP_ENV_APPLICATION_NAME)} OAuth`, action: authAction, c: decodeURIComponent(c.toString()), r: decodeURIComponent((_a = r === null || r === void 0 ? void 0 : r.toString()) !== null && _a !== void 0 ? _a : ''), }; response.render('pages/auth', { message: 'Please fill out your credential!', payload, }); }); // ----------------------------------------------------------------------------------------------------------------- this.expressApp.post('/auth', (request, response) => { const { username, password, token, redirectUrl } = request.body; const requiredProps = [ { key: 'username', value: username }, { key: 'password', value: username }, { key: 'token', value: username }, { key: 'redirectUrl', value: username }, ]; for (const prop of requiredProps) { if ((prop === null || prop === void 0 ? void 0 : prop.value) && !(0, isEmpty_1.default)(prop === null || prop === void 0 ? void 0 : prop.value)) { continue; } this.logger.error('[oauth2][post] Missing prop: %s | key: %s | value: %s', prop.key, prop.key, prop.value); response.render('pages/error', { message: `Missing prop ${prop.key} | Please check again authentication form | Make sure username, password, token and redirectUrl parameters are all available in form!`, }); return; } const oauth2Service = this.injectionGetter('services.OAuth2Service'); const decryptedClient = oauth2Service.decryptClientToken({ token }); oauth2Service .doOAuth2({ context: { request, response }, authServiceKey: this.authServiceKey, signInRequest: { identifier: { scheme: 'username', value: username }, credential: { scheme: 'basic', value: password }, clientId: decryptedClient.clientId, }, redirectUrl, }) .then(rs => { const { accessToken, accessTokenExpiresAt, client } = rs.oauth2TokenRs; if (!accessTokenExpiresAt) { response.render('pages/error', { message: 'Failed to validate accessToken expiration | Please try to request again!', }); return; } oauth2Service .doClientCallback({ c: token, oauth2Token: rs.oauth2TokenRs }) .then(() => { const url = new URL(rs.redirectUrl); url.searchParams.append('c', encodeURIComponent(token)); url.searchParams.append('clientId', client.clientId); url.searchParams.append('accessToken', accessToken); response.redirect(url.toString()); }) .catch(error => { throw error; }); }) .catch(error => { var _a; response.render('pages/error', { message: `${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : 'Failed to authenticate'} | Please try to request again!`, }); }); }); } } exports.DefaultOAuth2ExpressServer = DefaultOAuth2ExpressServer; // -------------------------------------------------------------------------------- const defineOAuth2Controller = (opts) => { var BaseOAuth2Controller_1; const { restPath = '/oauth2', tokenPath = '/token', authorizePath = '/authorize', oauth2ServiceKey = 'services.OAuth2Service', // authStrategy = { name: `${applicationEnvironment.get<string>(EnvironmentKeys.APP_ENV_APPLICATION_NAME)}_oauth2` }, } = opts !== null && opts !== void 0 ? opts : {}; let BaseOAuth2Controller = BaseOAuth2Controller_1 = class BaseOAuth2Controller extends controllers_1.BaseController { constructor(authService, getCurrentUser, httpContext) { super({ scope: BaseOAuth2Controller_1.name }); this.service = authService; this.getCurrentUser = getCurrentUser; this.httpContext = httpContext; } // ------------------------------------------------------------------------------ whoami() { return this.getCurrentUser(); } // ------------------------------------------------------------------------------ generateToken() { const { request, response } = this.httpContext; return this.service.generateToken({ request: new oauth2_server_1.Request(request), response: new oauth2_server_1.Response(response), }); } // ------------------------------------------------------------------------------ authorize() { const { request, response } = this.httpContext; return this.service.authorize({ request: new oauth2_server_1.Request(request), response: new oauth2_server_1.Response(response), }); } // ------------------------------------------------------------------------------ getOAuth2RequestPath(payload) { return this.service.getOAuth2RequestPath(payload); } }; __decorate([ (0, authentication_1.authenticate)(common_2.Authentication.STRATEGY_JWT), (0, rest_1.get)('/who-am-i'), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", void 0) ], BaseOAuth2Controller.prototype, "whoami", null); __decorate([ (0, rest_1.post)(tokenPath), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", void 0) ], BaseOAuth2Controller.prototype, "generateToken", null); __decorate([ (0, rest_1.post)(authorizePath), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", void 0) ], BaseOAuth2Controller.prototype, "authorize", null); __decorate([ (0, rest_1.post)('/request'), __param(0, (0, rest_1.requestBody)({ required: true, content: { 'application/json': { schema: (0, utilities_1.getSchemaObject)(common_2.OAuth2Request), }, }, })), __metadata("design:type", Function), __metadata("design:paramtypes", [common_2.OAuth2Request]), __metadata("design:returntype", void 0) ], BaseOAuth2Controller.prototype, "getOAuth2RequestPath", null); BaseOAuth2Controller = BaseOAuth2Controller_1 = __decorate([ (0, rest_1.api)({ basePath: restPath }), __metadata("design:paramtypes", [services_1.OAuth2Service, Function, rest_1.RequestContext]) ], BaseOAuth2Controller); (0, core_1.inject)(oauth2ServiceKey)(BaseOAuth2Controller, undefined, 0); core_1.inject.getter(security_1.SecurityBindings.USER, { optional: true })(BaseOAuth2Controller, undefined, 1); (0, core_1.inject)(rest_1.RestBindings.Http.CONTEXT)(BaseOAuth2Controller, undefined, 2); return BaseOAuth2Controller; }; exports.defineOAuth2Controller = defineOAuth2Controller; //# sourceMappingURL=oauth2.controller.js.map