ionic
Version:
A tool for creating and developing Ionic Framework mobile apps.
118 lines (117 loc) • 4.91 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const utils_fs_1 = require("@ionic/utils-fs");
const utils_network_1 = require("@ionic/utils-network");
const crypto = require("crypto");
const http = require("http");
const path = require("path");
const qs = require("querystring");
const constants_1 = require("../constants");
const open_1 = require("./open");
const REDIRECT_PORT = 8123;
const REDIRECT_HOST = 'localhost';
class OAuth2Flow {
constructor({ authorizationUrl, tokenUrl, clientId, redirectHost = REDIRECT_HOST, redirectPort = REDIRECT_PORT }, e) {
this.e = e;
this.authorizationUrl = authorizationUrl;
this.tokenUrl = tokenUrl;
this.clientId = clientId;
this.redirectHost = redirectHost;
this.redirectPort = redirectPort;
}
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.authorizationUrl}?${qs.stringify(authorizationParams)}`;
// don't doubly encode params, since `stringify` already did it
await open_1.openUrl(authorizationUrl, { encode: false });
const authorizationCode = await this.getAuthorizationCode();
const token = await this.getAccessToken(authorizationCode, verifier);
return token;
}
async getSuccessHtml() {
const p = path.resolve(constants_1.ASSETS_DIRECTORY, 'sso', 'success', 'index.html');
const contents = await utils_fs_1.readFile(p, { encoding: 'utf8' });
return contents;
}
async getAuthorizationCode() {
if (!(await 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' });
res.end(successHtml);
req.socket.destroy();
server.close();
resolve(Array.isArray(params.code) ? params.code[0] : params.code);
}
// TODO, timeout, error handling
}
});
server.listen(this.redirectPort, this.redirectHost);
});
}
async getAccessToken(authorizationCode, verifier) {
const params = this.generateTokenParameters(authorizationCode, verifier);
const { req } = await this.e.client.make('POST', this.tokenUrl);
const res = await req.send(params);
return res.body.access_token;
}
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;
const AUTHORIZATION_URL = 'https://auth.ionicframework.com/authorize';
const TOKEN_URL = 'https://auth.ionicframework.com/oauth/token';
const CLIENT_ID = '0kTF4wm74vppjImr11peCjQo2PIQDS3m';
const API_AUDIENCE = 'https://api.ionicjs.com';
class Auth0OAuth2Flow extends OAuth2Flow {
constructor({ email, connection, audience = API_AUDIENCE, authorizationUrl = AUTHORIZATION_URL, tokenUrl = TOKEN_URL, clientId = CLIENT_ID, ...options }, e) {
super({ authorizationUrl, tokenUrl, clientId, ...options }, e);
this.e = e;
this.email = email;
this.connection = connection;
this.audience = audience;
}
generateAuthorizationParameters(challenge) {
return {
audience: this.audience,
scope: 'openid profile email offline_access',
response_type: 'code',
connection: this.connection,
client_id: this.clientId,
code_challenge: challenge,
code_challenge_method: 'S256',
redirect_uri: this.redirectUrl,
};
}
generateTokenParameters(code, verifier) {
return {
grant_type: 'authorization_code',
client_id: this.clientId,
code_verifier: verifier,
code,
redirect_uri: this.redirectUrl,
};
}
}
exports.Auth0OAuth2Flow = Auth0OAuth2Flow;