From 9773c5e472cdcad8e76360c23f658052238220f1 Mon Sep 17 00:00:00 2001 From: googleworkspace-bot <109114539+googleworkspace-bot@users.noreply.github.com> Date: Fri, 23 Sep 2022 10:24:06 -0600 Subject: [PATCH] chore(main): release 1.42.0 (#395) * chore(main): release 1.42.0 * chore: Update dist/ and docs/ directories * Update CHANGELOG.md * chore: Update dist/ and docs/ directories Co-authored-by: Steve Bazyl --- CHANGELOG.md | 12 + dist/OAuth2.gs | 54 +++- docs/Service_.html | 436 ++++++++++++++++++++++++++++-- docs/Storage_.html | 20 +- docs/global.html | 351 ++++++++++++++++++++++-- docs/index.html | 26 +- docs/scripts/linenumber.js | 16 -- docs/scripts/prettify/lang-css.js | 16 -- docs/scripts/prettify/prettify.js | 16 -- docs/styles/jsdoc-default.css | 16 -- docs/styles/prettify-jsdoc.css | 16 -- docs/styles/prettify-tomorrow.css | 16 -- package-lock.json | 4 +- package.json | 2 +- 14 files changed, 820 insertions(+), 181 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..3917630f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +## 1.42.0 (2022-09-22) + +### Features + +* PKCE code verifier support ([#339](https://github.com/googleworkspace/apps-script-oauth2/pull/339)) + +### Bug Fixes + +* "Prompt" property for auth URL in sample ([#317](https://github.com/googleworkspace/apps-script-oauth2/issues/317)) ([6da6876](https://github.com/googleworkspace/apps-script-oauth2/commit/6da68763a98586ae0bc916e5258ea7f0bebf4cb2)) +* prevent samples from leaking OAuth client ID + Secret to users ([#379](https://github.com/googleworkspace/apps-script-oauth2/issues/379)) ([a5480c1](https://github.com/googleworkspace/apps-script-oauth2/commit/a5480c177386a807461b84d1b84627e272bc2355)) diff --git a/dist/OAuth2.gs b/dist/OAuth2.gs index db80e1f9..7f3b7768 100644 --- a/dist/OAuth2.gs +++ b/dist/OAuth2.gs @@ -48,7 +48,7 @@ function createService(serviceName) { /** * Returns the redirect URI that will be used for a given script. Often this URI * needs to be entered into a configuration screen of your OAuth provider. - * @param {string} [optScriptId] The script ID of your script, which can be + * @param {string=} optScriptId The script ID of your script, which can be * found in the Script Editor UI under "File > Project properties". Defaults * to the script ID of the script being executed. * @return {string} The redirect URI. @@ -56,7 +56,7 @@ function createService(serviceName) { function getRedirectUri(optScriptId) { var scriptId = optScriptId || ScriptApp.getScriptId(); return 'https://script.google.com/macros/d/' + encodeURIComponent(scriptId) + - '/usercallback'; + '/usercallback'; } /** @@ -228,7 +228,7 @@ Service_.prototype.setCodeVerififer = function(codeVerifier) { }; /** - * Sets teh code verifier to a randomly generated challenge string. + * Sets the code verifier to a randomly generated challenge string. * @return {!Service_} This service, for chaining */ Service_.prototype.generateCodeVerifier = function() { @@ -724,10 +724,35 @@ Service_.prototype.parseToken_ = function(content) { } else { throw new Error('Unknown token format: ' + this.tokenFormat_); } - token.granted_time = getTimeInSeconds_(new Date()); + this.ensureExpiresAtSet_(token); return token; }; +/** + * Adds expiresAt annotations on the token if not set. + * @param {string} token A token. + * @private + */ +Service_.prototype.ensureExpiresAtSet_ = function(token) { + // handle prior migrations + if (token.expiresAt !== undefined) { + return; + } + + // granted_time was added in prior versions of this library + var grantedTime = token.granted_time || getTimeInSeconds_(new Date()); + var expiresIn = token.expires_in_sec || token.expires_in || token.expires; + if (expiresIn) { + var expiresAt = grantedTime + Number(expiresIn); + token.expiresAt = expiresAt; + } + var refreshTokenExpiresIn = token.refresh_token_expires_in; + if (refreshTokenExpiresIn) { + var refreshTokenExpiresAt = grantedTime + Number(refreshTokenExpiresIn); + token.refreshTokenExpiresAt = refreshTokenExpiresAt; + } +}; + /** * Refreshes a token that has expired. This is only possible if offline access * was requested when the token was authorized. @@ -754,6 +779,11 @@ Service_.prototype.refresh = function() { if (!newToken.refresh_token) { newToken.refresh_token = token.refresh_token; } + this.ensureExpiresAtSet_(token); + // Propagate refresh token expiry if new token omits it + if (newToken.refreshTokenExpiresAt === undefined) { + newToken.refreshTokenExpiresAt = token.refreshTokenExpiresAt; + } this.saveToken_(newToken); }); }; @@ -805,6 +835,13 @@ Service_.prototype.isExpired_ = function(token) { var now = getTimeInSeconds_(new Date()); // Check the authorization token's expiration. + if (token.expiresAt) { + if (token.expiresAt - now < Service_.EXPIRATION_BUFFER_SECONDS_) { + expired = true; + } + } + + // Previous code path, provided for migration purpose, can be removed later var expiresIn = token.expires_in_sec || token.expires_in || token.expires; if (expiresIn) { var expiresTime = token.granted_time + Number(expiresIn); @@ -833,13 +870,14 @@ Service_.prototype.isExpired_ = function(token) { */ Service_.prototype.canRefresh_ = function(token) { if (!token.refresh_token) return false; - var expiresIn = token.refresh_token_expires_in; - if (!expiresIn) { + this.ensureExpiresAtSet_(token); + if (token.refreshTokenExpiresAt === undefined) { return true; } else { - var expiresTime = token.granted_time + Number(expiresIn); var now = getTimeInSeconds_(new Date()); - return expiresTime - now > Service_.EXPIRATION_BUFFER_SECONDS_; + return ( + token.refreshTokenExpiresAt - now > Service_.EXPIRATION_BUFFER_SECONDS_ + ); } }; diff --git a/docs/Service_.html b/docs/Service_.html index 2dfe6cb4..c3f48cfc 100644 --- a/docs/Service_.html +++ b/docs/Service_.html @@ -1,20 +1,4 @@ - - @@ -491,6 +475,111 @@
Returns:
+

generateCodeVerifier() → (non-null) {Service_}

+ + + + + + +
+ Sets the code verifier to a randomly generated challenge string. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ This service, for chaining +
+ + + +
+
+ Type +
+
+ +Service_ + + +
+
+ + + + + + + + + + + + +

getAccessToken() → {string}

@@ -2734,6 +2823,317 @@
Returns:
+

setCodeChallengeMethod(method) → (non-null) {Service_}

+ + + + + + +
+ Set the code challenge method for PKCE. The default value method +when a code verifier is set is S256. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
method + + +string + + + + Challenge method, either "S256" or "plain"
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ This service, for chaining +
+ + + +
+
+ Type +
+
+ +Service_ + + +
+
+ + + + + + + + + + + + + +

setCodeVerififer(codeVerifier) → (non-null) {Service_}

+ + + + + + +
+ Set the code verifier used for PKCE. For most use cases, +prefer `generateCodeVerifier` to automatically initialize the +value with a generated challenge string. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
codeVerifier + + +string + + + + A random challenge string
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ This service, for chaining +
+ + + +
+
+ Type +
+
+ +Service_ + + +
+
+ + + + + + + + + + + + +

setExpirationMinutes(expirationMinutes) → (non-null) {Service_}

@@ -5316,13 +5716,13 @@
Returns:

diff --git a/docs/Storage_.html b/docs/Storage_.html index cc4c9d88..43c1a6fe 100644 --- a/docs/Storage_.html +++ b/docs/Storage_.html @@ -1,20 +1,4 @@ - - @@ -1045,13 +1029,13 @@
Parameters:

diff --git a/docs/global.html b/docs/global.html index 3b144825..a9409b0a 100644 --- a/docs/global.html +++ b/docs/global.html @@ -1,20 +1,4 @@ - - @@ -576,6 +560,183 @@
Returns:
+

encodeChallenge_(method, codeVerifier) → {string}

+ + + + + + +
+ Encodes a challenge string for PKCE. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
method + + +string + + + + Encoding method (S256 or plain)
codeVerifier + + +string + + + + String to encode
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ BASE64(SHA256(ASCII(codeVerifier))) +
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + +

encodeJwt_(payload, key) → {string}

@@ -753,6 +914,160 @@
Returns:
+

encodeUrlSafeBase64NoPadding_(value) → {string}

+ + + + + + +
+ Wrapper around base64 encoded to strip padding. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
value + + +string + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Web safe base64 encoded with padding removed. +
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + +

extend_(destination, source) → {Object}

@@ -1726,13 +2041,13 @@
Returns:

diff --git a/docs/index.html b/docs/index.html index 7500cc9d..db77c345 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,20 +1,4 @@ - - @@ -59,8 +43,7 @@

-

OAuth2 for Apps Script

-

OAuth2 for Apps Script is a library for Google Apps Script that provides the +

OAuth2 for Apps Script is a library for Google Apps Script that provides the ability to create and authorize OAuth2 tokens as well as refresh them when they expire. This library uses Apps Script's StateTokenBuilder @@ -131,6 +114,9 @@

1. Create the OAuth2 service

information is not persisted to any data store, so you'll need to create this object each time you want to use it. The example below shows how to create a service for the Google Drive API.

+

Ensure the method is private (has an underscore at the end of the name) to +prevent clients from being able to call the method to read your client ID and +secret.

function getDriveService_() {
   // Create a new service with the given name. The name will be used when
   // persisting the authorized token, so ensure it is unique within the
@@ -836,13 +822,13 @@ 

Utilities.js


- Documentation generated by JSDoc 3.6.4 on Fri May 14 2021 09:53:29 GMT-0400 (Eastern Daylight Time) + Documentation generated by JSDoc 3.6.11
diff --git a/docs/scripts/linenumber.js b/docs/scripts/linenumber.js index 8e949198..4354785c 100644 --- a/docs/scripts/linenumber.js +++ b/docs/scripts/linenumber.js @@ -1,19 +1,3 @@ -/** - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - /*global document */ (() => { const source = document.getElementsByClassName('prettyprint source linenums'); diff --git a/docs/scripts/prettify/lang-css.js b/docs/scripts/prettify/lang-css.js index 4504d176..041e1f59 100644 --- a/docs/scripts/prettify/lang-css.js +++ b/docs/scripts/prettify/lang-css.js @@ -1,18 +1,2 @@ -/** - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); diff --git a/docs/scripts/prettify/prettify.js b/docs/scripts/prettify/prettify.js index 61409473..eef5ad7e 100644 --- a/docs/scripts/prettify/prettify.js +++ b/docs/scripts/prettify/prettify.js @@ -1,19 +1,3 @@ -/** - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; (function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= [],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c