@anmiles/google-api-wrapper 6.1.1 → 7.0.0

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 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.0](../../tags/v7.0.0) - 2023-04-22
9
+ ### Changed
10
+ - Invalidate tokens after 7 days due to Google policy for testing apps
11
+
8
12
  ## [6.1.1](../../tags/v6.1.1) - 2023-03-27
9
13
  ### Changed
10
14
  - Immediately destroy server after receiving needed response
@@ -7,8 +7,8 @@ declare const _default: {
7
7
  checkJSON: typeof checkJSON;
8
8
  };
9
9
  export default _default;
10
- declare function getJSON<T>(filename: string, createCallback: () => Exclude<T, Promise<any>>): T;
11
- declare function getJSONAsync<T>(filename: string, createCallbackAsync: () => Promise<T>): Promise<T>;
10
+ declare function getJSON<T>(filename: string, createCallback: () => Exclude<T, Promise<any>>, validateJSON?: (json: T) => boolean): T;
11
+ declare function getJSONAsync<T>(filename: string, createCallbackAsync: () => Promise<T>, validateJSONAsync?: (json: T) => Promise<boolean>): Promise<T>;
12
12
  declare function writeJSON<T>(filename: string, json: T): void;
13
13
  declare function readJSON<T>(filename: string): T;
14
14
  declare function checkJSON<T>(filename: string, json: T): void;
@@ -9,9 +9,12 @@ const logger_1 = require("./logger");
9
9
  const paths_1 = require("./paths");
10
10
  const jsonLib_1 = __importDefault(require("./jsonLib"));
11
11
  exports.default = { getJSON, getJSONAsync, writeJSON, readJSON, checkJSON };
12
- function getJSON(filename, createCallback) {
12
+ function getJSON(filename, createCallback, validateJSON) {
13
13
  if (fs_1.default.existsSync(filename)) {
14
- return jsonLib_1.default.readJSON(filename);
14
+ const json = jsonLib_1.default.readJSON(filename);
15
+ if (!validateJSON || validateJSON(json)) {
16
+ return json;
17
+ }
15
18
  }
16
19
  const json = createCallback();
17
20
  jsonLib_1.default.checkJSON(filename, json);
@@ -20,12 +23,16 @@ function getJSON(filename, createCallback) {
20
23
  return json;
21
24
  }
22
25
  exports.getJSON = getJSON;
23
- async function getJSONAsync(filename, createCallbackAsync) {
26
+ async function getJSONAsync(filename, createCallbackAsync, validateJSONAsync) {
24
27
  if (fs_1.default.existsSync(filename)) {
25
- return jsonLib_1.default.readJSON(filename);
28
+ const json = jsonLib_1.default.readJSON(filename);
29
+ if (!validateJSONAsync || await validateJSONAsync(json)) {
30
+ return json;
31
+ }
26
32
  }
27
33
  const json = await createCallbackAsync();
28
34
  jsonLib_1.default.checkJSON(filename, json);
35
+ (0, paths_1.ensureFile)(filename);
29
36
  jsonLib_1.default.writeJSON(filename, json);
30
37
  return json;
31
38
  }
@@ -1 +1 @@
1
- {"version":3,"file":"jsonLib.js","sourceRoot":"","sources":["../../src/lib/jsonLib.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;AACpB,qCAAiC;AACjC,mCAAqC;AAErC,wDAAgC;AAGhC,kBAAe,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AAEzE,SAAS,OAAO,CAAI,QAAgB,EAAE,cAA8C;IACnF,IAAI,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;QAC5B,OAAO,iBAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;KAClC;IAED,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;IAC9B,iBAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAClC,IAAA,kBAAU,EAAC,QAAQ,CAAC,CAAC;IACrB,iBAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAClC,OAAO,IAAI,CAAC;AACb,CAAC;AAbQ,0BAAO;AAehB,KAAK,UAAU,YAAY,CAAI,QAAgB,EAAE,mBAAqC;IACrF,IAAI,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;QAC5B,OAAO,iBAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;KAClC;IAED,MAAM,IAAI,GAAG,MAAM,mBAAmB,EAAE,CAAC;IACzC,iBAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAClC,iBAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAClC,OAAO,IAAI,CAAC;AACb,CAAC;AAxBiB,oCAAY;AA0B9B,SAAS,SAAS,CAAI,QAAgB,EAAE,IAAO;IAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACtD,YAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;AACxC,CAAC;AA7B+B,8BAAS;AA+BzC,SAAS,QAAQ,CAAI,QAAgB;IACpC,MAAM,UAAU,GAAG,YAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;IACxD,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAM,CAAC;AACpC,CAAC;AAED,SAAS,SAAS,CAAI,QAAgB,EAAE,IAAO;IAC9C,IAAI,IAAI,EAAE;QACT,OAAO;KACP;IACD,IAAA,cAAK,EAAC,QAAQ,QAAQ,sGAAsG,CAAC,CAAC;AAC/H,CAAC"}
1
+ {"version":3,"file":"jsonLib.js","sourceRoot":"","sources":["../../src/lib/jsonLib.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;AACpB,qCAAiC;AACjC,mCAAqC;AAErC,wDAAgC;AAGhC,kBAAe,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AAEzE,SAAS,OAAO,CAAI,QAAgB,EAAE,cAA8C,EAAE,YAAmC;IACxH,IAAI,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;QAC5B,MAAM,IAAI,GAAG,iBAAO,CAAC,QAAQ,CAAI,QAAQ,CAAC,CAAC;QAE3C,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE;YACxC,OAAO,IAAI,CAAC;SACZ;KACD;IAED,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;IAC9B,iBAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAClC,IAAA,kBAAU,EAAC,QAAQ,CAAC,CAAC;IACrB,iBAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAClC,OAAO,IAAI,CAAC;AACb,CAAC;AAjBQ,0BAAO;AAmBhB,KAAK,UAAU,YAAY,CAAI,QAAgB,EAAE,mBAAqC,EAAE,iBAAiD;IACxI,IAAI,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;QAC5B,MAAM,IAAI,GAAG,iBAAO,CAAC,QAAQ,CAAI,QAAQ,CAAC,CAAC;QAE3C,IAAI,CAAC,iBAAiB,IAAI,MAAM,iBAAiB,CAAC,IAAI,CAAC,EAAE;YACxD,OAAO,IAAI,CAAC;SACZ;KACD;IAED,MAAM,IAAI,GAAG,MAAM,mBAAmB,EAAE,CAAC;IACzC,iBAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAClC,IAAA,kBAAU,EAAC,QAAQ,CAAC,CAAC;IACrB,iBAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAClC,OAAO,IAAI,CAAC;AACb,CAAC;AAjCiB,oCAAY;AAmC9B,SAAS,SAAS,CAAI,QAAgB,EAAE,IAAO;IAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACtD,YAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;AACxC,CAAC;AAtC+B,8BAAS;AAwCzC,SAAS,QAAQ,CAAI,QAAgB;IACpC,MAAM,UAAU,GAAG,YAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;IACxD,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAM,CAAC;AACpC,CAAC;AAED,SAAS,SAAS,CAAI,QAAgB,EAAE,IAAO;IAC9C,IAAI,IAAI,EAAE;QACT,OAAO;KACP;IACD,IAAA,cAAK,EAAC,QAAQ,QAAQ,sGAAsG,CAAC,CAAC;AAC/H,CAAC"}
@@ -5,6 +5,7 @@ declare const _default: {
5
5
  getScopes: typeof getScopes;
6
6
  getSecrets: typeof getSecrets;
7
7
  getCredentials: typeof getCredentials;
8
+ validateCredentials: typeof validateCredentials;
8
9
  createCredentials: typeof createCredentials;
9
10
  checkSecrets: typeof checkSecrets;
10
11
  getSecretsError: typeof getSecretsError;
@@ -14,6 +15,7 @@ export default _default;
14
15
  declare function getScopes(): string[];
15
16
  declare function getSecrets(profile: string): Secrets;
16
17
  declare function getCredentials(profile: string, auth: GoogleApis.Common.OAuth2Client, options?: AuthOptions): Promise<GoogleApis.Auth.Credentials>;
18
+ declare function validateCredentials(credentials: GoogleApis.Auth.Credentials): Promise<boolean>;
17
19
  declare function createCredentials(profile: string, auth: GoogleApis.Auth.OAuth2Client, options?: AuthOptions): Promise<GoogleApis.Auth.Credentials>;
18
20
  declare function checkSecrets(profile: string, secretsObject: Secrets, secretsFile: string): true | void;
19
21
  declare function getScopesError(scopesFile: string): string;
@@ -30,13 +30,15 @@ exports.getCredentials = exports.getSecrets = void 0;
30
30
  const http_1 = __importDefault(require("http"));
31
31
  const server_destroy_1 = __importDefault(require("server-destroy"));
32
32
  const colorette = __importStar(require("colorette"));
33
+ const open_1 = __importDefault(require("open"));
33
34
  const jsonLib_1 = require("./jsonLib");
34
35
  const logger_1 = require("./logger");
35
36
  const paths_1 = require("./paths");
36
37
  const secrets_1 = __importDefault(require("./secrets"));
37
- exports.default = { getScopes, getSecrets, getCredentials, createCredentials, checkSecrets, getSecretsError, getScopesError };
38
+ exports.default = { getScopes, getSecrets, getCredentials, validateCredentials, createCredentials, checkSecrets, getSecretsError, getScopesError };
38
39
  const callbackPort = 6006;
39
40
  const callbackURI = `http://localhost:${callbackPort}/oauthcallback`;
41
+ const tokenExpiration = 7 * 24 * 60 * 60 * 1000;
40
42
  function getScopes() {
41
43
  const scopesFile = (0, paths_1.getScopesFile)();
42
44
  const scopes = (0, jsonLib_1.getJSON)(scopesFile, () => (0, logger_1.error)(secrets_1.default.getScopesError(scopesFile)));
@@ -53,9 +55,18 @@ async function getCredentials(profile, auth, options) {
53
55
  const credentialsFile = (0, paths_1.getCredentialsFile)(profile);
54
56
  return (options === null || options === void 0 ? void 0 : options.temporary)
55
57
  ? secrets_1.default.createCredentials(profile, auth, options)
56
- : (0, jsonLib_1.getJSONAsync)(credentialsFile, () => secrets_1.default.createCredentials(profile, auth, options));
58
+ : (0, jsonLib_1.getJSONAsync)(credentialsFile, () => secrets_1.default.createCredentials(profile, auth, options), secrets_1.default.validateCredentials);
57
59
  }
58
60
  exports.getCredentials = getCredentials;
61
+ async function validateCredentials(credentials) {
62
+ if (!credentials.access_token) {
63
+ return false;
64
+ }
65
+ if (!credentials.expiry_date) {
66
+ return true;
67
+ }
68
+ return new Date().getTime() - credentials.expiry_date < tokenExpiration;
69
+ }
59
70
  async function createCredentials(profile, auth, options) {
60
71
  const scope = (options === null || options === void 0 ? void 0 : options.scopes) || secrets_1.default.getScopes();
61
72
  return new Promise((resolve) => {
@@ -79,7 +90,12 @@ async function createCredentials(profile, auth, options) {
79
90
  });
80
91
  (0, server_destroy_1.default)(server);
81
92
  server.listen(callbackPort);
82
- (0, logger_1.info)(`Please open ${colorette.yellow(authUrl)} in your browser using google profile for ${colorette.yellow(profile)} and allow access to ${colorette.yellow(scope.join(','))}`);
93
+ if (options === null || options === void 0 ? void 0 : options.temporary) {
94
+ (0, logger_1.info)(`Please open ${colorette.yellow(authUrl)} in your browser using google profile for ${colorette.yellow(profile)} and allow access to ${colorette.yellow(scope.join(','))}`);
95
+ }
96
+ else {
97
+ (0, open_1.default)(authUrl);
98
+ }
83
99
  });
84
100
  }
85
101
  function checkSecrets(profile, secretsObject, secretsFile) {
@@ -1 +1 @@
1
- {"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/lib/secrets.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../src/lib/secrets.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,gDAAwB;AACxB,oEAA2C;AAC3C,qDAAuC;AACvC,gDAAwB;AAGxB,uCAAkD;AAClD,qCAAuC;AACvC,mCAA4E;AAE5E,wDAAgC;AAGhC,kBAAe,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,CAAC;AAEhJ,MAAM,YAAY,GAAM,IAAI,CAAC;AAC7B,MAAM,WAAW,GAAO,oBAAoB,YAAY,gBAAgB,CAAC;AACzE,MAAM,eAAe,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEhD,SAAS,SAAS;IACjB,MAAM,UAAU,GAAG,IAAA,qBAAa,GAAE,CAAC;IACnC,MAAM,MAAM,GAAO,IAAA,iBAAO,EAAW,UAAU,EAAE,GAAG,EAAE,CAAC,IAAA,cAAK,EAAC,iBAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAU,CAAC,CAAC;IAC3G,OAAO,MAAM,CAAC;AACf,CAAC;AAED,SAAS,UAAU,CAAC,OAAe;IAClC,MAAM,WAAW,GAAK,IAAA,sBAAc,EAAC,OAAO,CAAC,CAAC;IAC9C,MAAM,aAAa,GAAG,IAAA,iBAAO,EAAU,WAAW,EAAE,GAAG,EAAE,CAAC,IAAA,cAAK,EAAC,iBAAO,CAAC,eAAe,CAAC,OAAO,EAAE,WAAW,CAAC,CAAU,CAAC,CAAC;IACzH,iBAAO,CAAC,YAAY,CAAC,OAAO,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC;IAC1D,OAAO,aAAa,CAAC;AACtB,CAAC;AAlBQ,gCAAU;AAoBnB,KAAK,UAAU,cAAc,CAAC,OAAe,EAAE,IAAoC,EAAE,OAAqB;IACzG,MAAM,eAAe,GAAG,IAAA,0BAAkB,EAAC,OAAO,CAAC,CAAC;IAEpD,OAAO,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,SAAS;QACxB,CAAC,CAAC,iBAAO,CAAC,iBAAiB,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC;QACnD,CAAC,CAAC,IAAA,sBAAY,EAAC,eAAe,EAAE,GAAG,EAAE,CAAC,iBAAO,CAAC,iBAAiB,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,iBAAO,CAAC,mBAAmB,CAAC,CAAC;AACxH,CAAC;AA1BoB,wCAAc;AA4BnC,KAAK,UAAU,mBAAmB,CAAC,WAAwC;IAC1E,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE;QAC9B,OAAO,KAAK,CAAC;KACb;IAED,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE;QAC7B,OAAO,IAAI,CAAC;KACZ;IAED,OAAO,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,WAAW,CAAC,WAAW,GAAG,eAAe,CAAC;AACzE,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,OAAe,EAAE,IAAkC,EAAE,OAAqB;IAC1G,MAAM,KAAK,GAAG,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,KAAI,iBAAO,CAAC,SAAS,EAAE,CAAC;IAErD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC;YACpC,qCAAqC;YACrC,WAAW,EAAG,SAAS;YACvB,KAAK;SACL,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,cAAI,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE;YAC5D,QAAQ,CAAC,GAAG,CAAC,+GAA+G,CAAC,CAAC;YAE9H,IAAI,OAAO,CAAC,GAAG,EAAE;gBAChB,MAAM,GAAG,GAAI,IAAI,GAAG,CAAC,UAAU,OAAO,CAAC,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;gBACrE,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBAE1C,IAAI,CAAC,IAAI,EAAE;oBACV,OAAO;iBACP;gBAED,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjB,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBAC7C,OAAO,CAAC,MAAM,CAAC,CAAC;aAChB;QACF,CAAC,CAAC,CAAC;QAEH,IAAA,wBAAa,EAAC,MAAM,CAAC,CAAC;QACtB,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAE5B,IAAI,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,SAAS,EAAE;YACvB,IAAA,aAAI,EAAC,eAAe,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,6CAA6C,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,wBAAwB,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;SAChL;aAAM;YACN,IAAA,cAAI,EAAC,OAAO,CAAC,CAAC;SACd;IACF,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,OAAe,EAAE,aAAsB,EAAE,WAAmB;IACjF,IAAI,aAAa,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,WAAW,EAAE;QACvD,OAAO,IAAI,CAAC;KACZ;IACD,IAAA,cAAK,EAAC,qDAAqD,WAAW,MAAM,iBAAO,CAAC,eAAe,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;AAC9H,CAAC;AAED,SAAS,cAAc,CAAC,UAAkB;IACzC,OAAO;QACN,QAAQ,UAAU,aAAa;QAC/B,iDAAiD,UAAU,kCAAkC;KAC7F,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACd,CAAC;AAED,SAAS,eAAe,CAAC,OAAe,EAAE,WAAmB;IAC5D,OAAO;QACN,QAAQ,WAAW,aAAa;QAChC,2BAA2B;QAC3B,wDAAwD;QACxD,yBAAyB;QACzB,2DAA2D;QAC3D,yDAAyD;QACzD,+DAA+D;QAC/D,sCAAsC;QACtC,0BAA0B;QAC1B,yDAAyD;QACzD,iDAAiD;QACjD,qDAAqD;QACrD,2BAA2B;QAC3B,wBAAwB;QACxB,wCAAwC;QACxC,0GAA0G;QAC1G,mCAAmC;QACnC,oCAAoC;QACpC,uBAAuB,iBAAO,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;QACtD,mCAAmC;QACnC,yBAAyB;QACzB,wBAAwB;QACxB,mCAAmC;QACnC,oDAAoD;QACpD,6CAA6C;QAC7C,+DAA+D;QAC/D,mDAAmD;QACnD,yCAAyC;QACzC,wCAAwC,WAAW,EAAE;QACrD,wBAAwB;QACxB,uEAAuE,OAAO,OAAO;QACrF,8BAA8B;KAC9B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACd,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anmiles/google-api-wrapper",
3
- "version": "6.1.1",
3
+ "version": "7.0.0",
4
4
  "description": "Provides quick interface for getting google API data",
5
5
  "keywords": [
6
6
  "google",
@@ -32,6 +32,7 @@
32
32
  "colorette": "^2.0.19",
33
33
  "execa": "^5.1.1",
34
34
  "googleapis": "^104.0.0",
35
+ "open": "^9.1.0",
35
36
  "server-destroy": "^1.0.1"
36
37
  },
37
38
  "devDependencies": {
@@ -33,11 +33,15 @@ const json = { key : 'value' };
33
33
  const jsonString = JSON.stringify(json, null, ' ');
34
34
  const fallbackJSON = { fallbackKey : 'fallbackValue' };
35
35
 
36
+ let fileExists: boolean;
37
+ let validation: boolean;
38
+
39
+ const validateCallback = jest.fn().mockImplementation(() => validation);
40
+ const validateCallbackAsync = jest.fn().mockImplementation(async () => validation);
41
+
36
42
  const createCallback = jest.fn().mockReturnValue(fallbackJSON);
37
43
  const createCallbackAsync = jest.fn().mockResolvedValue(fallbackJSON);
38
44
 
39
- let fileExists: boolean;
40
-
41
45
  describe('src/lib/jsonLib', () => {
42
46
  describe('readJSON', () => {
43
47
  it('should read specified file', () => {
@@ -62,91 +66,175 @@ describe('src/lib/jsonLib', () => {
62
66
  });
63
67
 
64
68
  describe('getJSON', () => {
65
- it('should call readJSON if file exists', () => {
69
+
70
+ it('should call readJSON if file exists and json is valid', () => {
66
71
  fileExists = true;
72
+ validation = true;
67
73
 
68
- original.getJSON(filename, createCallback);
74
+ original.getJSON(filename, createCallback, validateCallback);
69
75
 
70
76
  expect(jsonLib.readJSON).toBeCalledWith(filename);
71
77
  expect(createCallback).not.toBeCalled();
72
78
  });
73
79
 
80
+ it('should call createCallback if file exists but json is not valid', () => {
81
+ fileExists = true;
82
+ validation = false;
83
+
84
+ original.getJSON(filename, createCallback, validateCallback);
85
+
86
+ expect(jsonLib.readJSON).toBeCalledWith(filename);
87
+ expect(createCallback).toBeCalledWith();
88
+ });
89
+
74
90
  it('should call createCallback if file not exists', () => {
75
91
  fileExists = false;
76
92
 
77
- original.getJSON(filename, createCallback);
93
+ original.getJSON(filename, createCallback, validateCallback);
78
94
 
79
95
  expect(jsonLib.readJSON).not.toBeCalled();
80
96
  expect(createCallback).toBeCalledWith();
81
97
  });
82
98
 
99
+ it('should not write fallback JSON back if file exists and json is valid', () => {
100
+ fileExists = true;
101
+ validation = true;
102
+
103
+ original.getJSON(filename, createCallback, validateCallback);
104
+
105
+ expect(jsonLib.writeJSON).not.toBeCalled();
106
+ });
107
+
108
+ it('should write fallback JSON back if file exists but json is not valid', () => {
109
+ fileExists = true;
110
+ validation = false;
111
+
112
+ original.getJSON(filename, createCallback, validateCallback);
113
+
114
+ expect(jsonLib.checkJSON).toBeCalledWith(filename, fallbackJSON);
115
+ expect(paths.ensureFile).toBeCalledWith(filename);
116
+ expect(jsonLib.writeJSON).toBeCalledWith(filename, fallbackJSON);
117
+ });
118
+
83
119
  it('should write fallback JSON back if file not exists', () => {
84
120
  fileExists = false;
85
121
 
86
- original.getJSON(filename, createCallback);
122
+ original.getJSON(filename, createCallback, validateCallback);
87
123
 
88
124
  expect(jsonLib.checkJSON).toBeCalledWith(filename, fallbackJSON);
89
125
  expect(paths.ensureFile).toBeCalledWith(filename);
90
126
  expect(jsonLib.writeJSON).toBeCalledWith(filename, fallbackJSON);
91
127
  });
92
128
 
93
- it('should return JSON if file exists', () => {
129
+ it('should return JSON if file exists and json is valid', () => {
94
130
  fileExists = true;
131
+ validation = true;
95
132
 
96
- const result = original.getJSON(filename, createCallback);
133
+ const result = original.getJSON(filename, createCallback, validateCallback);
97
134
 
98
135
  expect(result).toEqual(json);
99
136
  });
100
137
 
138
+ it('should return fallback JSON if file exists but json is not valid', () => {
139
+ fileExists = true;
140
+ validation = false;
141
+
142
+ const result = original.getJSON(filename, createCallback, validateCallback);
143
+
144
+ expect(result).toEqual(fallbackJSON);
145
+ });
146
+
101
147
  it('should return fallback JSON if file not exists', () => {
102
148
  fileExists = false;
103
149
 
104
- const result = original.getJSON(filename, createCallback);
150
+ const result = original.getJSON(filename, createCallback, validateCallback);
105
151
 
106
152
  expect(result).toEqual(fallbackJSON);
107
153
  });
108
154
  });
109
155
 
110
156
  describe('getJSONAsync', () => {
111
- it('should call readJSON if file exists', async () => {
157
+ it('should call readJSON if file exists and json is valid', async () => {
112
158
  fileExists = true;
159
+ validation = true;
113
160
 
114
- await original.getJSONAsync(filename, createCallbackAsync);
161
+ await original.getJSONAsync(filename, createCallbackAsync, validateCallbackAsync);
115
162
 
116
163
  expect(jsonLib.readJSON).toBeCalledWith(filename);
117
164
  expect(createCallbackAsync).not.toBeCalled();
118
165
  });
119
166
 
167
+ it('should call createCallback if file exists but json is not valid', async () => {
168
+ fileExists = true;
169
+ validation = false;
170
+
171
+ await original.getJSONAsync(filename, createCallbackAsync, validateCallbackAsync);
172
+
173
+ expect(jsonLib.readJSON).toBeCalledWith(filename);
174
+ expect(createCallbackAsync).toBeCalledWith();
175
+ });
176
+
120
177
  it('should call createCallback if file not exists', async () => {
121
178
  fileExists = false;
122
179
 
123
- await original.getJSONAsync(filename, createCallbackAsync);
180
+ await original.getJSONAsync(filename, createCallbackAsync, validateCallbackAsync);
124
181
 
125
182
  expect(jsonLib.readJSON).not.toBeCalled();
126
183
  expect(createCallbackAsync).toBeCalledWith();
127
184
  });
128
185
 
186
+ it('should not write fallback JSON back if file exists and json is valid', async () => {
187
+ fileExists = true;
188
+ validation = true;
189
+
190
+ await original.getJSONAsync(filename, createCallbackAsync, validateCallbackAsync);
191
+
192
+ expect(jsonLib.writeJSON).not.toBeCalled();
193
+ });
194
+
195
+ it('should write fallback JSON back if file exists but json is not valid', async () => {
196
+ fileExists = true;
197
+ validation = false;
198
+
199
+ await original.getJSONAsync(filename, createCallbackAsync, validateCallbackAsync);
200
+
201
+ expect(jsonLib.checkJSON).toBeCalledWith(filename, fallbackJSON);
202
+ expect(paths.ensureFile).toBeCalledWith(filename);
203
+ expect(jsonLib.writeJSON).toBeCalledWith(filename, fallbackJSON);
204
+ });
205
+
129
206
  it('should write fallback JSON back if file not exists', async () => {
130
207
  fileExists = false;
131
208
 
132
- await original.getJSONAsync(filename, createCallbackAsync);
209
+ await original.getJSONAsync(filename, createCallbackAsync, validateCallbackAsync);
133
210
 
134
211
  expect(jsonLib.checkJSON).toBeCalledWith(filename, fallbackJSON);
212
+ expect(paths.ensureFile).toBeCalledWith(filename);
135
213
  expect(jsonLib.writeJSON).toBeCalledWith(filename, fallbackJSON);
136
214
  });
137
215
 
138
- it('should return JSON if file exists', async () => {
216
+ it('should return JSON if file exists and json is valid', async () => {
139
217
  fileExists = true;
218
+ validation = true;
140
219
 
141
- const result = await original.getJSONAsync(filename, createCallbackAsync);
220
+ const result = await original.getJSONAsync(filename, createCallbackAsync, validateCallbackAsync);
142
221
 
143
222
  expect(result).toEqual(json);
144
223
  });
145
224
 
225
+ it('should return fallback JSON if file exists but json is not valid', async () => {
226
+ fileExists = true;
227
+ validation = false;
228
+
229
+ const result = await original.getJSONAsync(filename, createCallbackAsync, validateCallbackAsync);
230
+
231
+ expect(result).toEqual(fallbackJSON);
232
+ });
233
+
146
234
  it('should return fallback JSON if file not exists', async () => {
147
235
  fileExists = false;
148
236
 
149
- const result = await original.getJSONAsync(filename, createCallbackAsync);
237
+ const result = await original.getJSONAsync(filename, createCallbackAsync, validateCallbackAsync);
150
238
 
151
239
  expect(result).toEqual(fallbackJSON);
152
240
  });
@@ -1,6 +1,7 @@
1
1
  import http from 'http';
2
2
  import path from 'path';
3
3
  import * as colorette from 'colorette';
4
+ import open from 'open';
4
5
  import type GoogleApis from 'googleapis';
5
6
  import jsonLib from '../jsonLib';
6
7
  import logger from '../logger';
@@ -9,13 +10,14 @@ import type { Secrets } from '../../types';
9
10
  import secrets from '../secrets';
10
11
  const original = jest.requireActual('../secrets').default as typeof secrets;
11
12
  jest.mock<typeof secrets>('../secrets', () => ({
12
- getScopes : jest.fn().mockImplementation(() => scopesJSON),
13
- getSecrets : jest.fn().mockImplementation(() => secretsJSON),
14
- getCredentials : jest.fn(),
15
- createCredentials : jest.fn(),
16
- checkSecrets : jest.fn(),
17
- getScopesError : jest.fn().mockImplementation(() => scopesError),
18
- getSecretsError : jest.fn().mockImplementation(() => secretsError),
13
+ getScopes : jest.fn().mockImplementation(() => scopesJSON),
14
+ getSecrets : jest.fn().mockImplementation(() => secretsJSON),
15
+ getCredentials : jest.fn(),
16
+ validateCredentials : jest.fn(),
17
+ createCredentials : jest.fn(),
18
+ checkSecrets : jest.fn(),
19
+ getScopesError : jest.fn().mockImplementation(() => scopesError),
20
+ getSecretsError : jest.fn().mockImplementation(() => secretsError),
19
21
  }));
20
22
 
21
23
  jest.mock<Partial<typeof http>>('http', () => ({
@@ -39,6 +41,8 @@ jest.mock<Partial<typeof colorette>>('colorette', () => ({
39
41
  yellow : jest.fn().mockImplementation((text) => `yellow:${text}`),
40
42
  }));
41
43
 
44
+ jest.mock<Partial<typeof open>>('open', () => jest.fn());
45
+
42
46
  jest.mock<Partial<typeof jsonLib>>('../jsonLib', () => ({
43
47
  getJSON : jest.fn().mockImplementation(() => json),
44
48
  getJSONAsync : jest.fn().mockImplementation(async () => json),
@@ -89,7 +93,7 @@ const code = 'code';
89
93
  const authUrl = 'https://authUrl';
90
94
  const auth = {
91
95
  generateAuthUrl : jest.fn().mockReturnValue(authUrl),
92
- getToken : jest.fn().mockReturnValue({ tokens : credentialsJSON }),
96
+ getToken : jest.fn().mockResolvedValue({ tokens : credentialsJSON }),
93
97
  } as unknown as GoogleApis.Common.OAuth2Client;
94
98
 
95
99
  let request: http.IncomingMessage;
@@ -255,6 +259,31 @@ describe('src/lib/secrets', () => {
255
259
  });
256
260
  });
257
261
 
262
+ describe('validateCredentials', () => {
263
+ it('should return false if no access token', async () => {
264
+ expect(await original.validateCredentials({})).toEqual(false);
265
+ });
266
+
267
+ it('should return true if no expiration', async () => {
268
+ // eslint-disable-next-line camelcase
269
+ expect(await original.validateCredentials({ access_token : 'token' })).toEqual(true);
270
+ });
271
+
272
+ it('should return true if credentials are not more than 1 week ago', async () => {
273
+ const expiryDate = new Date();
274
+ expiryDate.setDate(expiryDate.getDate() - 6);
275
+ // eslint-disable-next-line camelcase
276
+ expect(await original.validateCredentials({ access_token : 'token', expiry_date : expiryDate.getTime() })).toEqual(true);
277
+ });
278
+
279
+ it('should return true if credentials are more than 1 week ago', async () => {
280
+ const expiryDate = new Date();
281
+ expiryDate.setDate(expiryDate.getDate() - 8);
282
+ // eslint-disable-next-line camelcase
283
+ expect(await original.validateCredentials({ access_token : 'token', expiry_date : expiryDate.getTime() })).toEqual(false);
284
+ });
285
+ });
286
+
258
287
  describe('createCredentials', () => {
259
288
  function willOpen(request: http.IncomingMessage, timeout: number) {
260
289
  setTimeout(async () => {
@@ -307,19 +336,30 @@ describe('src/lib/secrets', () => {
307
336
  expect(listen).toBeCalledWith(6006);
308
337
  });
309
338
 
310
- it('should ask to open browser page', async () => {
339
+ it('should open browser page without prompt if this is permanent request that tends to save credentials in the file', async () => {
311
340
  willOpen(request, 100);
312
341
 
313
342
  await original.createCredentials(profile, auth);
314
343
 
344
+ expect(open).toBeCalledWith('https://authUrl');
345
+ expect(logger.info).not.toBeCalled();
346
+ });
347
+
348
+ it('should ask to open browser page', async () => {
349
+ willOpen(request, 100);
350
+
351
+ await original.createCredentials(profile, auth, { temporary : true });
352
+
353
+ expect(open).not.toBeCalled();
315
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`);
316
355
  });
317
356
 
318
357
  it('should ask to open browser page with custom scopes', async () => {
319
358
  willOpen(request, 100);
320
359
 
321
- await original.createCredentials(profile, auth, { scopes : [ 'scope1', 'scope2' ] });
360
+ await original.createCredentials(profile, auth, { temporary : true, scopes : [ 'scope1', 'scope2' ] });
322
361
 
362
+ expect(open).not.toBeCalled();
323
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`);
324
364
  });
325
365
 
@@ -7,9 +7,13 @@ import jsonLib from './jsonLib';
7
7
  export { getJSON, getJSONAsync, writeJSON };
8
8
  export default { getJSON, getJSONAsync, writeJSON, readJSON, checkJSON };
9
9
 
10
- function getJSON<T>(filename: string, createCallback: () => Exclude<T, Promise<any>>): T {
10
+ function getJSON<T>(filename: string, createCallback: () => Exclude<T, Promise<any>>, validateJSON?: (json: T) => boolean): T {
11
11
  if (fs.existsSync(filename)) {
12
- return jsonLib.readJSON(filename);
12
+ const json = jsonLib.readJSON<T>(filename);
13
+
14
+ if (!validateJSON || validateJSON(json)) {
15
+ return json;
16
+ }
13
17
  }
14
18
 
15
19
  const json = createCallback();
@@ -19,13 +23,18 @@ function getJSON<T>(filename: string, createCallback: () => Exclude<T, Promise<a
19
23
  return json;
20
24
  }
21
25
 
22
- async function getJSONAsync<T>(filename: string, createCallbackAsync: () => Promise<T>): Promise<T> {
26
+ async function getJSONAsync<T>(filename: string, createCallbackAsync: () => Promise<T>, validateJSONAsync?: (json: T) => Promise<boolean>): Promise<T> {
23
27
  if (fs.existsSync(filename)) {
24
- return jsonLib.readJSON(filename);
28
+ const json = jsonLib.readJSON<T>(filename);
29
+
30
+ if (!validateJSONAsync || await validateJSONAsync(json)) {
31
+ return json;
32
+ }
25
33
  }
26
34
 
27
35
  const json = await createCallbackAsync();
28
36
  jsonLib.checkJSON(filename, json);
37
+ ensureFile(filename);
29
38
  jsonLib.writeJSON(filename, json);
30
39
  return json;
31
40
  }
@@ -1,6 +1,7 @@
1
1
  import http from 'http';
2
2
  import enableDestroy from 'server-destroy';
3
3
  import * as colorette from 'colorette';
4
+ import open from 'open';
4
5
  import type GoogleApis from 'googleapis';
5
6
  import type { Secrets, AuthOptions } from '../types';
6
7
  import { getJSON, getJSONAsync } from './jsonLib';
@@ -10,10 +11,11 @@ import { getScopesFile, getSecretsFile, getCredentialsFile } from './paths';
10
11
  import secrets from './secrets';
11
12
 
12
13
  export { getSecrets, getCredentials };
13
- export default { getScopes, getSecrets, getCredentials, createCredentials, checkSecrets, getSecretsError, getScopesError };
14
+ export default { getScopes, getSecrets, getCredentials, validateCredentials, createCredentials, checkSecrets, getSecretsError, getScopesError };
14
15
 
15
- const callbackPort = 6006;
16
- const callbackURI = `http://localhost:${callbackPort}/oauthcallback`;
16
+ const callbackPort = 6006;
17
+ const callbackURI = `http://localhost:${callbackPort}/oauthcallback`;
18
+ const tokenExpiration = 7 * 24 * 60 * 60 * 1000;
17
19
 
18
20
  function getScopes(): string[] {
19
21
  const scopesFile = getScopesFile();
@@ -33,7 +35,19 @@ async function getCredentials(profile: string, auth: GoogleApis.Common.OAuth2Cli
33
35
 
34
36
  return options?.temporary
35
37
  ? secrets.createCredentials(profile, auth, options)
36
- : getJSONAsync(credentialsFile, () => secrets.createCredentials(profile, auth, options));
38
+ : getJSONAsync(credentialsFile, () => secrets.createCredentials(profile, auth, options), secrets.validateCredentials);
39
+ }
40
+
41
+ async function validateCredentials(credentials: GoogleApis.Auth.Credentials): Promise<boolean> {
42
+ if (!credentials.access_token) {
43
+ return false;
44
+ }
45
+
46
+ if (!credentials.expiry_date) {
47
+ return true;
48
+ }
49
+
50
+ return new Date().getTime() - credentials.expiry_date < tokenExpiration;
37
51
  }
38
52
 
39
53
  async function createCredentials(profile: string, auth: GoogleApis.Auth.OAuth2Client, options?: AuthOptions): Promise<GoogleApis.Auth.Credentials> {
@@ -65,7 +79,12 @@ async function createCredentials(profile: string, auth: GoogleApis.Auth.OAuth2Cl
65
79
 
66
80
  enableDestroy(server);
67
81
  server.listen(callbackPort);
68
- info(`Please open ${colorette.yellow(authUrl)} in your browser using google profile for ${colorette.yellow(profile)} and allow access to ${colorette.yellow(scope.join(','))}`);
82
+
83
+ if (options?.temporary) {
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
+ }
69
88
  });
70
89
  }
71
90