UNPKG

4.91 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const utils_fs_1 = require("@ionic/utils-fs");
4const utils_network_1 = require("@ionic/utils-network");
5const crypto = require("crypto");
6const http = require("http");
7const path = require("path");
8const qs = require("querystring");
9const constants_1 = require("../constants");
10const open_1 = require("./open");
11const REDIRECT_PORT = 8123;
12const REDIRECT_HOST = 'localhost';
13class OAuth2Flow {
14 constructor({ authorizationUrl, tokenUrl, clientId, redirectHost = REDIRECT_HOST, redirectPort = REDIRECT_PORT }, e) {
15 this.e = e;
16 this.authorizationUrl = authorizationUrl;
17 this.tokenUrl = tokenUrl;
18 this.clientId = clientId;
19 this.redirectHost = redirectHost;
20 this.redirectPort = redirectPort;
21 }
22 get redirectUrl() {
23 return `http://${this.redirectHost}:${this.redirectPort}`;
24 }
25 async run() {
26 const verifier = this.generateVerifier();
27 const challenge = this.generateChallenge(verifier);
28 const authorizationParams = this.generateAuthorizationParameters(challenge);
29 const authorizationUrl = `${this.authorizationUrl}?${qs.stringify(authorizationParams)}`;
30 // don't doubly encode params, since `stringify` already did it
31 await open_1.openUrl(authorizationUrl, { encode: false });
32 const authorizationCode = await this.getAuthorizationCode();
33 const token = await this.getAccessToken(authorizationCode, verifier);
34 return token;
35 }
36 async getSuccessHtml() {
37 const p = path.resolve(constants_1.ASSETS_DIRECTORY, 'sso', 'success', 'index.html');
38 const contents = await utils_fs_1.readFile(p, { encoding: 'utf8' });
39 return contents;
40 }
41 async getAuthorizationCode() {
42 if (!(await utils_network_1.isPortAvailable(this.redirectPort))) {
43 throw new Error(`Cannot start local server. Port ${this.redirectPort} is in use.`);
44 }
45 const successHtml = await this.getSuccessHtml();
46 return new Promise((resolve, reject) => {
47 const server = http.createServer((req, res) => {
48 if (req.url) {
49 const params = qs.parse(req.url.substring(req.url.indexOf('?') + 1));
50 if (params.code) {
51 res.writeHead(200, { 'Content-Type': 'text/html' });
52 res.end(successHtml);
53 req.socket.destroy();
54 server.close();
55 resolve(Array.isArray(params.code) ? params.code[0] : params.code);
56 }
57 // TODO, timeout, error handling
58 }
59 });
60 server.listen(this.redirectPort, this.redirectHost);
61 });
62 }
63 async getAccessToken(authorizationCode, verifier) {
64 const params = this.generateTokenParameters(authorizationCode, verifier);
65 const { req } = await this.e.client.make('POST', this.tokenUrl);
66 const res = await req.send(params);
67 return res.body.access_token;
68 }
69 generateVerifier() {
70 return this.base64URLEncode(crypto.randomBytes(32));
71 }
72 generateChallenge(verifier) {
73 return this.base64URLEncode(crypto.createHash('sha256').update(verifier).digest());
74 }
75 base64URLEncode(buffer) {
76 return buffer.toString('base64')
77 .replace(/\+/g, '-')
78 .replace(/\//g, '_')
79 .replace(/=/g, '');
80 }
81}
82exports.OAuth2Flow = OAuth2Flow;
83const AUTHORIZATION_URL = 'https://auth.ionicframework.com/authorize';
84const TOKEN_URL = 'https://auth.ionicframework.com/oauth/token';
85const CLIENT_ID = '0kTF4wm74vppjImr11peCjQo2PIQDS3m';
86const API_AUDIENCE = 'https://api.ionicjs.com';
87class Auth0OAuth2Flow extends OAuth2Flow {
88 constructor({ email, connection, audience = API_AUDIENCE, authorizationUrl = AUTHORIZATION_URL, tokenUrl = TOKEN_URL, clientId = CLIENT_ID, ...options }, e) {
89 super({ authorizationUrl, tokenUrl, clientId, ...options }, e);
90 this.e = e;
91 this.email = email;
92 this.connection = connection;
93 this.audience = audience;
94 }
95 generateAuthorizationParameters(challenge) {
96 return {
97 audience: this.audience,
98 scope: 'openid profile email offline_access',
99 response_type: 'code',
100 connection: this.connection,
101 client_id: this.clientId,
102 code_challenge: challenge,
103 code_challenge_method: 'S256',
104 redirect_uri: this.redirectUrl,
105 };
106 }
107 generateTokenParameters(code, verifier) {
108 return {
109 grant_type: 'authorization_code',
110 client_id: this.clientId,
111 code_verifier: verifier,
112 code,
113 redirect_uri: this.redirectUrl,
114 };
115 }
116}
117exports.Auth0OAuth2Flow = Auth0OAuth2Flow;