@anmiles/google-api-wrapper 7.0.1 → 7.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/lib/secrets.js +23 -40
- package/dist/lib/secrets.js.map +1 -1
- package/package.json +1 -1
- package/src/lib/__tests__/secrets.test.ts +40 -47
- package/src/lib/secrets.ts +26 -19
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [7.0.2](../../tags/v7.0.2) - 2023-04-22
|
|
9
|
+
### Changed
|
|
10
|
+
- Show instructions in the browser to prevent direct opening profile-oriented pages in wrong browsers
|
|
11
|
+
|
|
8
12
|
## [7.0.1](../../tags/v7.0.1) - 2023-04-22
|
|
9
13
|
### Changed
|
|
10
14
|
- Compatibility for `open` package
|
package/dist/lib/secrets.js
CHANGED
|
@@ -1,27 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
4
|
};
|
|
@@ -29,7 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
29
6
|
exports.getCredentials = exports.getSecrets = void 0;
|
|
30
7
|
const http_1 = __importDefault(require("http"));
|
|
31
8
|
const server_destroy_1 = __importDefault(require("server-destroy"));
|
|
32
|
-
const colorette = __importStar(require("colorette"));
|
|
33
9
|
const open_1 = __importDefault(require("open"));
|
|
34
10
|
const jsonLib_1 = require("./jsonLib");
|
|
35
11
|
const logger_1 = require("./logger");
|
|
@@ -37,6 +13,7 @@ const paths_1 = require("./paths");
|
|
|
37
13
|
const secrets_1 = __importDefault(require("./secrets"));
|
|
38
14
|
exports.default = { getScopes, getSecrets, getCredentials, validateCredentials, createCredentials, checkSecrets, getSecretsError, getScopesError };
|
|
39
15
|
const callbackPort = 6006;
|
|
16
|
+
const startURI = `http://localhost:${callbackPort}/`;
|
|
40
17
|
const callbackURI = `http://localhost:${callbackPort}/oauthcallback`;
|
|
41
18
|
const tokenExpiration = 7 * 24 * 60 * 60 * 1000;
|
|
42
19
|
function getScopes() {
|
|
@@ -76,28 +53,34 @@ async function createCredentials(profile, auth, options) {
|
|
|
76
53
|
scope,
|
|
77
54
|
});
|
|
78
55
|
const server = http_1.default.createServer(async (request, response) => {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
resolve(tokens);
|
|
56
|
+
if (!request.url) {
|
|
57
|
+
response.end('');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const url = new URL(`http://${request.headers.host}${request.url}`);
|
|
61
|
+
const code = url.searchParams.get('code');
|
|
62
|
+
if (!code) {
|
|
63
|
+
response.end(formatMessage(`Please open <a href="${authUrl}">this link</a> in a browser that belongs to <strong>${profile}</strong> google profile`));
|
|
64
|
+
return;
|
|
89
65
|
}
|
|
66
|
+
response.end(formatMessage('Please close this page and return to application'));
|
|
67
|
+
server.destroy();
|
|
68
|
+
const { tokens } = await auth.getToken(code);
|
|
69
|
+
resolve(tokens);
|
|
90
70
|
});
|
|
91
71
|
(0, server_destroy_1.default)(server);
|
|
92
72
|
server.listen(callbackPort);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
else {
|
|
97
|
-
(0, open_1.default)(authUrl);
|
|
98
|
-
}
|
|
73
|
+
(0, logger_1.warn)('Please check your browser for further actions');
|
|
74
|
+
(0, open_1.default)(startURI);
|
|
99
75
|
});
|
|
100
76
|
}
|
|
77
|
+
function formatMessage(message) {
|
|
78
|
+
return [
|
|
79
|
+
'<div style="margin: 1em auto; padding: 0 1em; border: 1px solid black; max-width: 600px; text-align: center; font-family: Arial, sans-serif">',
|
|
80
|
+
`<p>${message}</p>`,
|
|
81
|
+
'</div>',
|
|
82
|
+
].join('\n');
|
|
83
|
+
}
|
|
101
84
|
function checkSecrets(profile, secretsObject, secretsFile) {
|
|
102
85
|
if (secretsObject.web.redirect_uris[0] === callbackURI) {
|
|
103
86
|
return true;
|
package/dist/lib/secrets.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/lib/secrets.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/lib/secrets.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -41,7 +41,9 @@ jest.mock<Partial<typeof colorette>>('colorette', () => ({
|
|
|
41
41
|
yellow : jest.fn().mockImplementation((text) => `yellow:${text}`),
|
|
42
42
|
}));
|
|
43
43
|
|
|
44
|
-
jest.mock
|
|
44
|
+
jest.mock('open', () => jest.fn().mockImplementation((url: string) => {
|
|
45
|
+
willOpen(url.replace('http://localhost:6006', ''));
|
|
46
|
+
}));
|
|
45
47
|
|
|
46
48
|
jest.mock<Partial<typeof jsonLib>>('../jsonLib', () => ({
|
|
47
49
|
getJSON : jest.fn().mockImplementation(() => json),
|
|
@@ -49,7 +51,7 @@ jest.mock<Partial<typeof jsonLib>>('../jsonLib', () => ({
|
|
|
49
51
|
}));
|
|
50
52
|
|
|
51
53
|
jest.mock<Partial<typeof logger>>('../logger', () => ({
|
|
52
|
-
|
|
54
|
+
warn : jest.fn(),
|
|
53
55
|
error : jest.fn().mockImplementation((error) => {
|
|
54
56
|
throw error;
|
|
55
57
|
}) as jest.Mock<never, any>,
|
|
@@ -96,8 +98,6 @@ const auth = {
|
|
|
96
98
|
getToken : jest.fn().mockResolvedValue({ tokens : credentialsJSON }),
|
|
97
99
|
} as unknown as GoogleApis.Common.OAuth2Client;
|
|
98
100
|
|
|
99
|
-
let request: http.IncomingMessage;
|
|
100
|
-
|
|
101
101
|
const response = {
|
|
102
102
|
end : jest.fn(),
|
|
103
103
|
} as unknown as http.ServerResponse;
|
|
@@ -107,6 +107,16 @@ let serverCallback: (
|
|
|
107
107
|
response: http.ServerResponse
|
|
108
108
|
) => Promise<typeof credentialsJSON>;
|
|
109
109
|
|
|
110
|
+
function willOpen(url: string | undefined, timeout?: number) {
|
|
111
|
+
setTimeout(async () => {
|
|
112
|
+
await serverCallback({
|
|
113
|
+
url,
|
|
114
|
+
headers : {
|
|
115
|
+
host : 'localhost:6006',
|
|
116
|
+
},
|
|
117
|
+
} as http.IncomingMessage, response);
|
|
118
|
+
}, timeout || 0);
|
|
119
|
+
}
|
|
110
120
|
let closedTime: number;
|
|
111
121
|
|
|
112
122
|
const on = jest.fn().mockImplementation((event: string, listener: (...args: any[]) => void) => {
|
|
@@ -285,23 +295,10 @@ describe('src/lib/secrets', () => {
|
|
|
285
295
|
});
|
|
286
296
|
|
|
287
297
|
describe('createCredentials', () => {
|
|
288
|
-
|
|
289
|
-
setTimeout(async () => {
|
|
290
|
-
await serverCallback(request, response);
|
|
291
|
-
}, timeout);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
beforeEach(() => {
|
|
295
|
-
request = {
|
|
296
|
-
url : `/request.url?code=${code}`,
|
|
297
|
-
headers : {
|
|
298
|
-
host : 'localhost:6006',
|
|
299
|
-
},
|
|
300
|
-
} as http.IncomingMessage;
|
|
301
|
-
});
|
|
298
|
+
const tokenUrl = `/request.url?code=${code}`;
|
|
302
299
|
|
|
303
300
|
it('should generate authUrl', async () => {
|
|
304
|
-
willOpen(
|
|
301
|
+
willOpen(tokenUrl, 100);
|
|
305
302
|
|
|
306
303
|
await original.createCredentials(profile, auth);
|
|
307
304
|
|
|
@@ -316,7 +313,7 @@ describe('src/lib/secrets', () => {
|
|
|
316
313
|
});
|
|
317
314
|
|
|
318
315
|
it('should generate authUrl with custom scopes', async () => {
|
|
319
|
-
willOpen(
|
|
316
|
+
willOpen(tokenUrl, 100);
|
|
320
317
|
|
|
321
318
|
await original.createCredentials(profile, auth, { scopes : [ 'scope1', 'scope2' ] });
|
|
322
319
|
|
|
@@ -328,7 +325,7 @@ describe('src/lib/secrets', () => {
|
|
|
328
325
|
});
|
|
329
326
|
|
|
330
327
|
it('should create server on 6006 port', async () => {
|
|
331
|
-
willOpen(
|
|
328
|
+
willOpen(tokenUrl, 100);
|
|
332
329
|
|
|
333
330
|
await original.createCredentials(profile, auth);
|
|
334
331
|
|
|
@@ -336,43 +333,43 @@ describe('src/lib/secrets', () => {
|
|
|
336
333
|
expect(listen).toBeCalledWith(6006);
|
|
337
334
|
});
|
|
338
335
|
|
|
339
|
-
it('should open browser page
|
|
340
|
-
willOpen(
|
|
336
|
+
it('should open browser page and warn about it', async () => {
|
|
337
|
+
willOpen(tokenUrl, 100);
|
|
341
338
|
|
|
342
339
|
await original.createCredentials(profile, auth);
|
|
343
340
|
|
|
344
|
-
expect(open).toBeCalledWith('
|
|
345
|
-
expect(logger.
|
|
341
|
+
expect(open).toBeCalledWith('http://localhost:6006/');
|
|
342
|
+
expect(logger.warn).toBeCalledWith('Please check your browser for further actions');
|
|
346
343
|
});
|
|
347
344
|
|
|
348
|
-
it('should
|
|
349
|
-
willOpen(
|
|
345
|
+
it('should show nothing on the browser page if request.url is empty', async () => {
|
|
346
|
+
willOpen('', 100);
|
|
347
|
+
willOpen(tokenUrl, 200);
|
|
350
348
|
|
|
351
|
-
await original.createCredentials(profile, auth
|
|
349
|
+
await original.createCredentials(profile, auth);
|
|
352
350
|
|
|
353
|
-
expect(
|
|
354
|
-
expect(logger.info).toBeCalledWith(`Please open yellow:https://authUrl in your browser using google profile for yellow:${profile} and allow access to yellow:https://www.googleapis.com/auth/calendar.calendars.readonly,https://www.googleapis.com/auth/calendar.events.readonly`);
|
|
351
|
+
expect(response.end).toBeCalledWith('');
|
|
355
352
|
});
|
|
356
353
|
|
|
357
|
-
it('should
|
|
358
|
-
willOpen(
|
|
354
|
+
it('should show opening instructions if opened the home page', async () => {
|
|
355
|
+
willOpen('/', 100);
|
|
356
|
+
willOpen(tokenUrl, 200);
|
|
359
357
|
|
|
360
|
-
await original.createCredentials(profile, auth
|
|
358
|
+
await original.createCredentials(profile, auth);
|
|
361
359
|
|
|
362
|
-
expect(
|
|
363
|
-
expect(logger.info).toBeCalledWith(`Please open yellow:https://authUrl in your browser using google profile for yellow:${profile} and allow access to yellow:scope1,scope2`);
|
|
360
|
+
expect(response.end).toBeCalledWith(`<div style="margin: 1em auto; padding: 0 1em; border: 1px solid black; max-width: 600px; text-align: center; font-family: Arial, sans-serif">\n<p>Please open <a href="${authUrl}">this link</a> in a browser that belongs to <strong>${profile}</strong> google profile</p>\n</div>`);
|
|
364
361
|
});
|
|
365
362
|
|
|
366
363
|
it('should ask to close webpage', async () => {
|
|
367
|
-
willOpen(
|
|
364
|
+
willOpen(tokenUrl, 100);
|
|
368
365
|
|
|
369
366
|
await original.createCredentials(profile, auth);
|
|
370
367
|
|
|
371
|
-
expect(response.end).toBeCalledWith('<
|
|
368
|
+
expect(response.end).toBeCalledWith('<div style="margin: 1em auto; padding: 0 1em; border: 1px solid black; max-width: 600px; text-align: center; font-family: Arial, sans-serif">\n<p>Please close this page and return to application</p>\n</div>');
|
|
372
369
|
});
|
|
373
370
|
|
|
374
371
|
it('should close server and destroy all connections if request.url is truthy', async () => {
|
|
375
|
-
willOpen(
|
|
372
|
+
willOpen(tokenUrl, 100);
|
|
376
373
|
|
|
377
374
|
await original.createCredentials(profile, auth);
|
|
378
375
|
|
|
@@ -384,12 +381,10 @@ describe('src/lib/secrets', () => {
|
|
|
384
381
|
it('should only resolve when request.url is truthy', async () => {
|
|
385
382
|
const emptyRequestTime = 100;
|
|
386
383
|
const requestTime = 200;
|
|
387
|
-
const emptyRequest = { ...request } as http.IncomingMessage;
|
|
388
|
-
emptyRequest.url = undefined;
|
|
389
384
|
|
|
390
385
|
const before = new Date().getTime();
|
|
391
|
-
willOpen(
|
|
392
|
-
willOpen(
|
|
386
|
+
willOpen(undefined, emptyRequestTime);
|
|
387
|
+
willOpen(tokenUrl, requestTime);
|
|
393
388
|
|
|
394
389
|
const result = await original.createCredentials(profile, auth);
|
|
395
390
|
const after = new Date().getTime();
|
|
@@ -403,12 +398,10 @@ describe('src/lib/secrets', () => {
|
|
|
403
398
|
it('should only resolve when request.url contains no code', async () => {
|
|
404
399
|
const noCodeRequestTime = 100;
|
|
405
400
|
const requestTime = 200;
|
|
406
|
-
const noCodeRequest = { ...request } as http.IncomingMessage;
|
|
407
|
-
noCodeRequest.url = '/request.url?param=value';
|
|
408
401
|
|
|
409
402
|
const before = new Date().getTime();
|
|
410
|
-
willOpen(
|
|
411
|
-
willOpen(
|
|
403
|
+
willOpen('/request.url?param=value', noCodeRequestTime);
|
|
404
|
+
willOpen(tokenUrl, requestTime);
|
|
412
405
|
|
|
413
406
|
const result = await original.createCredentials(profile, auth);
|
|
414
407
|
const after = new Date().getTime();
|
|
@@ -420,7 +413,7 @@ describe('src/lib/secrets', () => {
|
|
|
420
413
|
});
|
|
421
414
|
|
|
422
415
|
it('should return credentials JSON', async () => {
|
|
423
|
-
willOpen(
|
|
416
|
+
willOpen(tokenUrl, 100);
|
|
424
417
|
|
|
425
418
|
const result = await original.createCredentials(profile, auth);
|
|
426
419
|
|
package/src/lib/secrets.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import http from 'http';
|
|
2
2
|
import enableDestroy from 'server-destroy';
|
|
3
|
-
import * as colorette from 'colorette';
|
|
4
3
|
import open from 'open';
|
|
5
4
|
import type GoogleApis from 'googleapis';
|
|
6
5
|
import type { Secrets, AuthOptions } from '../types';
|
|
7
6
|
import { getJSON, getJSONAsync } from './jsonLib';
|
|
8
|
-
import {
|
|
7
|
+
import { warn, error } from './logger';
|
|
9
8
|
import { getScopesFile, getSecretsFile, getCredentialsFile } from './paths';
|
|
10
9
|
|
|
11
10
|
import secrets from './secrets';
|
|
@@ -14,6 +13,7 @@ export { getSecrets, getCredentials };
|
|
|
14
13
|
export default { getScopes, getSecrets, getCredentials, validateCredentials, createCredentials, checkSecrets, getSecretsError, getScopesError };
|
|
15
14
|
|
|
16
15
|
const callbackPort = 6006;
|
|
16
|
+
const startURI = `http://localhost:${callbackPort}/`;
|
|
17
17
|
const callbackURI = `http://localhost:${callbackPort}/oauthcallback`;
|
|
18
18
|
const tokenExpiration = 7 * 24 * 60 * 60 * 1000;
|
|
19
19
|
|
|
@@ -61,33 +61,40 @@ async function createCredentials(profile: string, auth: GoogleApis.Auth.OAuth2Cl
|
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
const server = http.createServer(async (request, response) => {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const code = url.searchParams.get('code');
|
|
64
|
+
if (!request.url) {
|
|
65
|
+
response.end('');
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
69
68
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
69
|
+
const url = new URL(`http://${request.headers.host}${request.url}`);
|
|
70
|
+
const code = url.searchParams.get('code');
|
|
73
71
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
if (!code) {
|
|
73
|
+
response.end(formatMessage(`Please open <a href="${authUrl}">this link</a> in a browser that belongs to <strong>${profile}</strong> google profile`));
|
|
74
|
+
return;
|
|
77
75
|
}
|
|
76
|
+
|
|
77
|
+
response.end(formatMessage('Please close this page and return to application'));
|
|
78
|
+
server.destroy();
|
|
79
|
+
const { tokens } = await auth.getToken(code);
|
|
80
|
+
resolve(tokens);
|
|
78
81
|
});
|
|
79
82
|
|
|
80
83
|
enableDestroy(server);
|
|
81
84
|
server.listen(callbackPort);
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
info(`Please open ${colorette.yellow(authUrl)} in your browser using google profile for ${colorette.yellow(profile)} and allow access to ${colorette.yellow(scope.join(','))}`);
|
|
85
|
-
} else {
|
|
86
|
-
open(authUrl);
|
|
87
|
-
}
|
|
85
|
+
warn('Please check your browser for further actions');
|
|
86
|
+
open(startURI);
|
|
88
87
|
});
|
|
89
88
|
}
|
|
90
89
|
|
|
90
|
+
function formatMessage(message: string): string {
|
|
91
|
+
return [
|
|
92
|
+
'<div style="margin: 1em auto; padding: 0 1em; border: 1px solid black; max-width: 600px; text-align: center; font-family: Arial, sans-serif">',
|
|
93
|
+
`<p>${message}</p>`,
|
|
94
|
+
'</div>',
|
|
95
|
+
].join('\n');
|
|
96
|
+
}
|
|
97
|
+
|
|
91
98
|
function checkSecrets(profile: string, secretsObject: Secrets, secretsFile: string): true | void {
|
|
92
99
|
if (secretsObject.web.redirect_uris[0] === callbackURI) {
|
|
93
100
|
return true;
|