| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- "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;
|