Skip to content

Commit a084740

Browse files
committed
chore: Add gulp task for fixing/formatting + delint existing code
1 parent 5305253 commit a084740

File tree

10 files changed

+119
-75
lines changed

10 files changed

+119
-75
lines changed

dist/OAuth2.gs

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,15 @@ function createService(serviceName) {
4848
/**
4949
* Returns the redirect URI that will be used for a given script. Often this URI
5050
* needs to be entered into a configuration screen of your OAuth provider.
51-
* @param {string} [optScriptId] The script ID of your script, which can be
51+
* @param {string=} optScriptId The script ID of your script, which can be
5252
* found in the Script Editor UI under "File > Project properties". Defaults
5353
* to the script ID of the script being executed.
5454
* @return {string} The redirect URI.
5555
*/
5656
function getRedirectUri(optScriptId) {
5757
var scriptId = optScriptId || ScriptApp.getScriptId();
5858
return 'https://script.google.com/macros/d/' + encodeURIComponent(scriptId) +
59-
'/usercallback';
59+
'/usercallback';
6060
}
6161

6262
/**
@@ -228,7 +228,7 @@ Service_.prototype.setCodeVerififer = function(codeVerifier) {
228228
};
229229

230230
/**
231-
* Sets teh code verifier to a randomly generated challenge string.
231+
* Sets the code verifier to a randomly generated challenge string.
232232
* @return {!Service_} This service, for chaining
233233
*/
234234
Service_.prototype.generateCodeVerifier = function() {
@@ -724,10 +724,35 @@ Service_.prototype.parseToken_ = function(content) {
724724
} else {
725725
throw new Error('Unknown token format: ' + this.tokenFormat_);
726726
}
727-
token.granted_time = getTimeInSeconds_(new Date());
727+
this.ensureExpiresAtSet_(token);
728728
return token;
729729
};
730730

731+
/**
732+
* Adds expiresAt annotations on the token if not set.
733+
* @param {string} token A token.
734+
* @private
735+
*/
736+
Service_.prototype.ensureExpiresAtSet_ = function(token) {
737+
// handle prior migrations
738+
if (token.expiresAt !== undefined) {
739+
return;
740+
}
741+
742+
// granted_time was added in prior versions of this library
743+
var grantedTime = token.granted_time || getTimeInSeconds_(new Date());
744+
var expiresIn = token.expires_in_sec || token.expires_in || token.expires;
745+
if (expiresIn) {
746+
var expiresAt = grantedTime + Number(expiresIn);
747+
token.expiresAt = expiresAt;
748+
}
749+
var refreshTokenExpiresIn = token.refresh_token_expires_in;
750+
if (refreshTokenExpiresIn) {
751+
var refreshTokenExpiresAt = grantedTime + Number(refreshTokenExpiresIn);
752+
token.refreshTokenExpiresAt = refreshTokenExpiresAt;
753+
}
754+
};
755+
731756
/**
732757
* Refreshes a token that has expired. This is only possible if offline access
733758
* was requested when the token was authorized.
@@ -754,6 +779,11 @@ Service_.prototype.refresh = function() {
754779
if (!newToken.refresh_token) {
755780
newToken.refresh_token = token.refresh_token;
756781
}
782+
this.ensureExpiresAtSet_(token);
783+
// Propagate refresh token expiry if new token omits it
784+
if (newToken.refreshTokenExpiresAt === undefined) {
785+
newToken.refreshTokenExpiresAt = token.refreshTokenExpiresAt;
786+
}
757787
this.saveToken_(newToken);
758788
});
759789
};
@@ -805,6 +835,13 @@ Service_.prototype.isExpired_ = function(token) {
805835
var now = getTimeInSeconds_(new Date());
806836

807837
// Check the authorization token's expiration.
838+
if (token.expiresAt) {
839+
if (token.expiresAt - now < Service_.EXPIRATION_BUFFER_SECONDS_) {
840+
expired = true;
841+
}
842+
}
843+
844+
// Previous code path, provided for migration purpose, can be removed later
808845
var expiresIn = token.expires_in_sec || token.expires_in || token.expires;
809846
if (expiresIn) {
810847
var expiresTime = token.granted_time + Number(expiresIn);
@@ -833,13 +870,14 @@ Service_.prototype.isExpired_ = function(token) {
833870
*/
834871
Service_.prototype.canRefresh_ = function(token) {
835872
if (!token.refresh_token) return false;
836-
var expiresIn = token.refresh_token_expires_in;
837-
if (!expiresIn) {
873+
this.ensureExpiresAtSet_(token);
874+
if (token.refreshTokenExpiresAt === undefined) {
838875
return true;
839876
} else {
840-
var expiresTime = token.granted_time + Number(expiresIn);
841877
var now = getTimeInSeconds_(new Date());
842-
return expiresTime - now > Service_.EXPIRATION_BUFFER_SECONDS_;
878+
return (
879+
token.refreshTokenExpiresAt - now > Service_.EXPIRATION_BUFFER_SECONDS_
880+
);
843881
}
844882
};
845883

gulpfile.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,9 @@ gulp.task('lint', () => {
5959
}
6060
}));
6161
});
62+
63+
gulp.task('fix', () => {
64+
return gulp.src(['src/*.js', 'samples/*.gs', 'test/**/*.js', '!node_modules/**'])
65+
.pipe(eslint({fix: true}))
66+
.pipe(eslint.format())
67+
});

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"postversion": "MESSAGE=$(git log -1 --pretty=%B) && cd src/ && clasp version $MESSAGE",
3939
"dist": "gulp dist",
4040
"lint": "gulp lint",
41+
"lint:fix": "gulp fix",
4142
"doc": "jsdoc -c jsdoc.json src/*.js README.md",
4243
"push": "cd src; clasp push",
4344
"test": "mocha"

samples/.eslintrc.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
*/
1616

1717
module.exports = {
18-
"rules": {
19-
"no-unused-vars": "off",
20-
"valid-jsdoc": "off"
18+
'rules': {
19+
'no-unused-vars': 'off',
20+
'valid-jsdoc': 'off'
2121
}
22-
};
22+
};

samples/Onshape.gs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function run() {
2525
});
2626
var result = JSON.parse(response.getContentText());
2727
Logger.log(JSON.stringify(result, null, 2));
28-
} else {
28+
} else {
2929
var authorizationUrl = service.getAuthorizationUrl();
3030
Logger.log('Open the following URL and re-run the script: %s',
3131
authorizationUrl);
@@ -78,4 +78,4 @@ function authCallback(request) {
7878
*/
7979
function logRedirectUri() {
8080
Logger.log(OAuth2.getRedirectUri());
81-
}
81+
}

samples/StackOverflow.gs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function run() {
2121
} else {
2222
var authorizationUrl = service.getAuthorizationUrl();
2323
Logger.log('Open the following URL and re-run the script: %s',
24-
authorizationUrl);
24+
authorizationUrl);
2525
}
2626
}
2727

@@ -37,20 +37,20 @@ function reset() {
3737
*/
3838
function getService_() {
3939
return OAuth2.createService('Stack Overflow')
40-
// Set the endpoint URLs.
41-
.setAuthorizationBaseUrl('https://stackoverflow.com/oauth')
42-
.setTokenUrl('https://stackoverflow.com/oauth/access_token/json')
40+
// Set the endpoint URLs.
41+
.setAuthorizationBaseUrl('https://stackoverflow.com/oauth')
42+
.setTokenUrl('https://stackoverflow.com/oauth/access_token/json')
4343

44-
// Set the client ID and secret.
45-
.setClientId(CLIENT_ID)
46-
.setClientSecret(CLIENT_SECRET)
44+
// Set the client ID and secret.
45+
.setClientId(CLIENT_ID)
46+
.setClientSecret(CLIENT_SECRET)
4747

48-
// Set the name of the callback function that should be invoked to
49-
// complete the OAuth flow.
50-
.setCallbackFunction('authCallback')
48+
// Set the name of the callback function that should be invoked to
49+
// complete the OAuth flow.
50+
.setCallbackFunction('authCallback')
5151

52-
// Set the property store where authorized tokens should be persisted.
53-
.setPropertyStore(PropertiesService.getUserProperties());
52+
// Set the property store where authorized tokens should be persisted.
53+
.setPropertyStore(PropertiesService.getUserProperties());
5454
}
5555

5656
/**

samples/Twitter.gs

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ function run() {
2222
} else {
2323
var authorizationUrl = service.getAuthorizationUrl();
2424
Logger.log('Open the following URL and re-run the script: %s',
25-
authorizationUrl);
25+
authorizationUrl);
2626
}
2727
}
2828

@@ -31,8 +31,8 @@ function run() {
3131
*/
3232
function reset() {
3333
getService_().reset();
34-
PropertiesService.getUserProperties().deleteProperty("code_challenge");
35-
PropertiesService.getUserProperties().deleteProperty("code_verifier");
34+
PropertiesService.getUserProperties().deleteProperty('code_challenge');
35+
PropertiesService.getUserProperties().deleteProperty('code_verifier');
3636
}
3737

3838
/**
@@ -42,34 +42,34 @@ function getService_() {
4242
pkceChallengeVerifier();
4343
var userProps = PropertiesService.getUserProperties();
4444
return OAuth2.createService('Twitter')
45-
// Set the endpoint URLs.
46-
.setAuthorizationBaseUrl('https://twitter.com/i/oauth2/authorize')
47-
.setTokenUrl(
48-
'https://api.twitter.com/2/oauth2/token?code_verifier=' + userProps.getProperty("code_verifier"))
45+
// Set the endpoint URLs.
46+
.setAuthorizationBaseUrl('https://twitter.com/i/oauth2/authorize')
47+
.setTokenUrl(
48+
'https://api.twitter.com/2/oauth2/token?code_verifier=' + userProps.getProperty('code_verifier'))
4949

50-
// Set the client ID and secret.
51-
.setClientId(CLIENT_ID)
52-
.setClientSecret(CLIENT_SECRET)
50+
// Set the client ID and secret.
51+
.setClientId(CLIENT_ID)
52+
.setClientSecret(CLIENT_SECRET)
5353

54-
// Set the name of the callback function that should be invoked to
55-
// complete the OAuth flow.
56-
.setCallbackFunction('authCallback')
54+
// Set the name of the callback function that should be invoked to
55+
// complete the OAuth flow.
56+
.setCallbackFunction('authCallback')
5757

58-
// Set the property store where authorized tokens should be persisted.
59-
.setPropertyStore(userProps)
58+
// Set the property store where authorized tokens should be persisted.
59+
.setPropertyStore(userProps)
6060

61-
// Set the scopes to request (space-separated for Twitter services).
62-
.setScope('users.read tweet.read offline.access')
63-
64-
// Add parameters in the authorization url
65-
.setParam('response_type', 'code')
66-
.setParam('code_challenge_method', 'S256')
67-
.setParam('code_challenge', userProps.getProperty("code_challenge"))
61+
// Set the scopes to request (space-separated for Twitter services).
62+
.setScope('users.read tweet.read offline.access')
6863

69-
.setTokenHeaders({
70-
'Authorization': 'Basic ' + Utilities.base64Encode(CLIENT_ID + ':' + CLIENT_SECRET),
71-
'Content-Type': 'application/x-www-form-urlencoded'
72-
})
64+
// Add parameters in the authorization url
65+
.setParam('response_type', 'code')
66+
.setParam('code_challenge_method', 'S256')
67+
.setParam('code_challenge', userProps.getProperty('code_challenge'))
68+
69+
.setTokenHeaders({
70+
'Authorization': 'Basic ' + Utilities.base64Encode(CLIENT_ID + ':' + CLIENT_SECRET),
71+
'Content-Type': 'application/x-www-form-urlencoded'
72+
});
7373
}
7474

7575
/**
@@ -97,21 +97,21 @@ function logRedirectUri() {
9797
*/
9898
function pkceChallengeVerifier() {
9999
var userProps = PropertiesService.getUserProperties();
100-
if (!userProps.getProperty("code_verifier")) {
101-
var verifier = "";
102-
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
100+
if (!userProps.getProperty('code_verifier')) {
101+
var verifier = '';
102+
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';
103103

104104
for (var i = 0; i < 128; i++) {
105105
verifier += possible.charAt(Math.floor(Math.random() * possible.length));
106106
}
107107

108-
var sha256Hash = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, verifier)
108+
var sha256Hash = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, verifier);
109109

110110
var challenge = Utilities.base64Encode(sha256Hash)
111-
.replace(/\+/g, '-')
112-
.replace(/\//g, '_')
113-
.replace(/=+$/, '')
114-
userProps.setProperty("code_verifier", verifier)
115-
userProps.setProperty("code_challenge", challenge)
111+
.replace(/\+/g, '-')
112+
.replace(/\//g, '_')
113+
.replace(/=+$/, '');
114+
userProps.setProperty('code_verifier', verifier);
115+
userProps.setProperty('code_challenge', challenge);
116116
}
117117
}

src/OAuth2.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,12 @@ function getRedirectUri(optScriptId) {
6565
*/
6666
function getServiceNames(propertyStore) {
6767
var props = propertyStore.getProperties();
68-
return Object.keys(props).filter(function (key) {
68+
return Object.keys(props).filter(function(key) {
6969
var parts = key.split('.');
7070
return key.indexOf(STORAGE_PREFIX_) == 0 && parts.length > 1 && parts[1];
71-
}).map(function (key) {
71+
}).map(function(key) {
7272
return key.split('.')[1];
73-
}).reduce(function (result, key) {
73+
}).reduce(function(result, key) {
7474
if (result.indexOf(key) < 0) {
7575
result.push(key);
7676
}

test/mocks/utilities.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ var MockUtilities = function(optCache) {
2222
this.store = optCache || {};
2323
this.counter = 0;
2424
};
25-
25+
2626
MockUtilities.prototype.base64Encode = function(data) {
27-
return Buffer.from(data).toString('base64');
27+
return Buffer.from(data).toString('base64');
2828
};
2929

3030
MockUtilities.prototype.base64EncodeWebSafe = function(data) {
3131
return URLSafeBase64.encode(Buffer.from(data));
32-
}
32+
};
3333

3434
MockUtilities.prototype.base64DecodeWebSafe = function(data) {
3535
return URLSafeBase64.decode(data);
@@ -44,17 +44,17 @@ MockUtilities.prototype.newBlob = function(data) {
4444
};
4545

4646
MockUtilities.prototype.DigestAlgorithm = {
47-
SHA_256: 'sha256'
47+
SHA_256: 'sha256'
4848
};
4949

5050
MockUtilities.prototype.Charset = {
51-
US_ASCII: 'us_ascii'
51+
US_ASCII: 'us_ascii'
5252
};
5353

5454
MockUtilities.prototype.computeDigest = function(algorithm, data, charSet) {
55-
const hash = crypto.createHash(algorithm);
56-
hash.update(data);
57-
return hash.digest('utf8');
58-
}
55+
const hash = crypto.createHash(algorithm);
56+
hash.update(data);
57+
return hash.digest('utf8');
58+
};
5959

60-
module.exports = MockUtilities;
60+
module.exports = MockUtilities;

test/test.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,6 @@ describe('Service', () => {
646646
expiresAt: ONE_HOUR_LATER_SECONDS,
647647
refreshTokenExpiresAt: ONE_HOUR_LATER_SECONDS
648648
};
649-
console.log('test')
650649
assert.isTrue(service.canRefresh_(token));
651650
});
652651

0 commit comments

Comments
 (0)