UNPKG

@ionic/cli

Version:

A tool for creating and developing Ionic Framework mobile apps.

110 lines (109 loc) 5.22 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.OAuth2Flow = void 0; const tslib_1 = require("tslib"); const utils_fs_1 = require("@ionic/utils-fs"); const utils_network_1 = require("@ionic/utils-network"); const crypto = tslib_1.__importStar(require("crypto")); const http = tslib_1.__importStar(require("http")); const path = tslib_1.__importStar(require("path")); const qs = tslib_1.__importStar(require("querystring")); const constants_1 = require("../../constants"); const errors_1 = require("../errors"); const http_1 = require("../http"); const open_1 = require("../open"); const REDIRECT_PORT = 8123; const REDIRECT_HOST = 'localhost'; class OAuth2Flow { constructor({ redirectHost = REDIRECT_HOST, redirectPort = REDIRECT_PORT, accessTokenRequestContentType = "application/json" /* ContentType.JSON */ }, e) { this.e = e; this.oauthConfig = this.getAuthConfig(); this.redirectHost = redirectHost; this.redirectPort = redirectPort; this.accessTokenRequestContentType = accessTokenRequestContentType; } get redirectUrl() { return `http://${this.redirectHost}:${this.redirectPort}`; } async run() { const verifier = this.generateVerifier(); const challenge = this.generateChallenge(verifier); const authorizationParams = this.generateAuthorizationParameters(challenge); const authorizationUrl = `${this.oauthConfig.authorizationUrl}?${qs.stringify(authorizationParams)}`; await (0, open_1.openUrl)(authorizationUrl); const { code, state } = await this.getAuthorizationCode(); const token = await this.exchangeAuthForAccessToken(code, verifier); token.state = state; return token; } async exchangeRefreshToken(refreshToken) { const params = this.generateRefreshTokenParameters(refreshToken); const { req } = await this.e.client.make('POST', this.oauthConfig.tokenUrl, this.accessTokenRequestContentType); const res = await req.send(params); // check the response status code first here if (!res.ok) { throw new errors_1.FatalException('API request to refresh token was not successful.\n' + 'Please try to login again.\n' + (0, http_1.formatResponseError)(req, res.status)); } if (!this.checkValidExchangeTokenRes(res)) { throw new errors_1.FatalException('API request was successful, but the refreshed token was unrecognized.\n' + 'Please try to login again.\n'); } return res.body; } async getSuccessHtml() { const p = path.resolve(constants_1.ASSETS_DIRECTORY, 'oauth', 'success', 'index.html'); const contents = await (0, utils_fs_1.readFile)(p, { encoding: 'utf8' }); return contents; } async getAuthorizationCode() { if (!(await (0, utils_network_1.isPortAvailable)(this.redirectPort))) { throw new Error(`Cannot start local server. Port ${this.redirectPort} is in use.`); } const successHtml = await this.getSuccessHtml(); return new Promise((resolve, reject) => { const server = http.createServer((req, res) => { if (req.url) { const params = qs.parse(req.url.substring(req.url.indexOf('?') + 1)); if (params.code) { res.writeHead(200, { 'Content-Type': "text/html" /* ContentType.HTML */ }); res.end(successHtml); req.socket.destroy(); server.close(); const authResult = { code: Array.isArray(params.code) ? params.code[0] : params.code, state: params.state ? (Array.isArray(params.state) ? decodeURI(params.state[0]) : decodeURI(params.state)) : '', }; resolve(authResult); } // TODO, timeout, error handling } }); server.listen(this.redirectPort, this.redirectHost); }); } async exchangeAuthForAccessToken(authorizationCode, verifier) { const params = this.generateTokenParameters(authorizationCode, verifier); const { req } = await this.e.client.make('POST', this.oauthConfig.tokenUrl, this.accessTokenRequestContentType); const res = await req.send(params); if (!this.checkValidExchangeTokenRes(res)) { throw new errors_1.FatalException('API request was successful, but the response format was unrecognized.\n' + (0, http_1.formatResponseError)(req, res.status)); } return res.body; } generateVerifier() { return this.base64URLEncode(crypto.randomBytes(32)); } generateChallenge(verifier) { return this.base64URLEncode(crypto.createHash('sha256').update(verifier).digest()); } base64URLEncode(buffer) { return buffer.toString('base64') .replace(/\+/g, '-') .replace(/\//g, '_') .replace(/=/g, ''); } } exports.OAuth2Flow = OAuth2Flow;