/
index.ts
92 lines (79 loc) · 2.5 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import { post } from 'request';
import { parse } from 'url';
import { Server, request, createServer, ServerResponse } from 'http';
import { stringify } from 'querystring';
const OAuth2TokenURL = 'https://www.googleapis.com/oauth2/v4/token';
const OAuth2CodeURL = 'https://accounts.google.com/o/oauth2/v2/auth';
export interface Config {
clientId: string;
clientSecret: string;
scope: string;
}
export const auth = (config: Config) => {
return listenForTokens(config, (port: number) =>
require('opn')(
`${OAuth2CodeURL}?${stringify({
client_id: config.clientId,
redirect_uri: `http://localhost:${port}`,
response_type: 'code',
scope: config.scope
})}`,
{ wait: false }
)
);
};
const listenForTokens = (config: Config, ready: Function) => {
const socketList: any[] = [];
let server: Server;
let port: number;
let resolveCallback: Function;
let rejectCallback: Function;
const { clientId, clientSecret } = config;
const cleanup = (cb: Function, res: ServerResponse, text: string, result: any) => {
res.setHeader('content-type', 'text/html; charset=utf-8');
res.end(text);
socketList.forEach(s => s.destroy());
server.close(() => cb(result));
};
server = createServer((req, res) => {
const response = (e: string) => `<span style="font-size: 80px;">${e}</span>`;
const resolve = cleanup.bind(null, resolveCallback, res, response('🙌'));
const reject = cleanup.bind(null, rejectCallback, res, response('❌'));
const params = parse(req.url, true);
const { code, error } = params.query;
if (error) {
reject(error);
} else {
post(
OAuth2TokenURL,
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: encodeURI(
`client_id=${clientId}&client_secret=${clientSecret}&redirect_uri=http://localhost:${port}&grant_type=authorization_code&code=${code}`
)
},
(error, response, body) => {
if (error) {
reject(error);
} else {
resolve(JSON.parse(body));
}
}
);
}
}).listen(0, () => {
port = server.address().port;
ready(port);
});
// Used for speeding up `server.close()`.
server.on('connection', socket => {
socketList.push(socket);
socket.on('close', () => socketList.splice(socketList.indexOf(socket, 1)));
});
return new Promise((s, f) => {
resolveCallback = s;
rejectCallback = f;
});
};