UNPKG

vtex

Version:

The platform for e-commerce apps

143 lines (142 loc) 5.14 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const async_retry_1 = tslib_1.__importDefault(require("async-retry")); const co_body_1 = tslib_1.__importDefault(require("co-body")); const get_port_1 = tslib_1.__importDefault(require("get-port")); const koa_1 = tslib_1.__importDefault(require("koa")); const api_1 = require("../../../../api"); const VTEXID_1 = require("../../../../api/clients/IOClients/external/VTEXID"); const ErrorReport_1 = require("../../../../api/error/ErrorReport"); const SUCCESS_PAGE = ` <!doctype html> <html> <head> <title>Success</title> <meta charset="utf-8"> </head> <body> <p> Você já pode fechar essa janela. </p> <p> You may now close this window. </p> <p> Ahora puedes cerrar esta ventana. </p> </body> </html>`; class LoginServer { constructor(loginConfig) { this.loginConfig = loginConfig; this.app = new koa_1.default(); this.registerLoginHandler(); this.tokenPromise = new Promise((resolve, reject) => { this.resolveTokenPromise = resolve; this.rejectTokenPromise = reject; }); } static async create(loginConfig) { const loginServer = new LoginServer(loginConfig); await loginServer.start(); return loginServer; } get token() { return this.tokenPromise; } get loginCallbackUrl() { if (!this.port) { throw new Error('LoginServer not initialized'); } return `http://127.0.0.1:${this.port}${LoginServer.LOGIN_CALLBACK_PATH}`; } setLoginState(val) { this.loginState = val; } start() { return async_retry_1.default(async (bail) => { try { const port = await get_port_1.default({ port: get_port_1.default.makeRange(3000, 3050), }); this.server = await this.initServer(port); this.port = port; api_1.logger.debug(`LoginServer started on http://localhost:${this.port}`); } catch (err) { api_1.logger.debug(`LoginServer failed to start on port:${this.port}. Reason: ${err.message}.`); if (err.code !== 'EADDRINUSE') { return bail(err); } } }, { retries: 2, maxTimeout: 50, minTimeout: 50 }); } close() { this.server.unref(); this.server.close(); } initServer(port) { return new Promise((resolve, reject) => { this.app.on('error', reject); const server = this.app.listen(port, () => { server.on('connection', socket => { socket.unref(); }); resolve(server); }); }); } registerLoginHandler() { this.app.use(async (ctx) => { var _a; ctx.set('connection', 'close'); if (ctx.path !== LoginServer.LOGIN_CALLBACK_PATH) { ctx.status = 404; ctx.body = 'Not found'; return; } ctx.socket.ref(); api_1.logger.debug(`Received ${ctx.method} login callback`); if (!this.loginState) { return this.handleError(ctx, new Error('Received login callback before setting login state')); } let body; if (ctx.method.toLowerCase() === 'post') { try { body = await co_body_1.default(ctx.req); } catch (err) { return this.handleError(ctx, err); } } else { body = { ott: (_a = ctx.query) === null || _a === void 0 ? void 0 : _a.ott }; } if (!body.ott) { return this.handleError(ctx, new Error('Missing ott on VTEX ID callback call'), { body }); } const vtexId = VTEXID_1.VTEXID.createClient({ account: this.loginConfig.account }); try { const { token } = await vtexId.validateToolbeltLogin({ account: this.loginConfig.account, secret: this.loginConfig.secret, ott: body.ott, state: this.loginState, }); this.resolveTokenPromise(token); ctx.status = 200; ctx.set('content-type', 'text/html'); ctx.body = SUCCESS_PAGE; } catch (err) { return this.handleError(ctx, err); } }); } handleError(ctx, err, details) { const errReport = ErrorReport_1.ErrorReport.createAndMaybeRegisterOnTelemetry({ originalError: err, details }); ctx.status = 500; ctx.body = { errorId: errReport.metadata.errorId, message: errReport.message, }; this.rejectTokenPromise(errReport); } } exports.LoginServer = LoginServer; LoginServer.LOGIN_CALLBACK_PATH = '/login_callback';