diff --git a/docs/history.md b/docs/history.md index 1664baa212..4a14171e9d 100644 --- a/docs/history.md +++ b/docs/history.md @@ -28,12 +28,20 @@ * `oauth`: - `_endOfPopupResponseTemplate` and `_endOfRedirectResponseTemplate` are no longer a property but now a function that returns a promise of the same value as before - - the following methods are now async: + - the following server methods are now async: - `OAuth._renderOauthResults` - `OAuth._endOfLoginResponse` - `OAuth.renderEndOfLoginResponse` - `OAuth._storePendingCredential` - `OAuth._retrievePendingCredential` + - `ensureConfigured` + - `_cleanStaleResults` + +* `oauth1`: + - the following server methods are now async: + - `OAuth._storeRequestToken` + - `OAuth._retrieveRequestToken` + #### Internal API changes diff --git a/packages/oauth/oauth_server.js b/packages/oauth/oauth_server.js index 7c705d07fd..ebf9873fcc 100644 --- a/packages/oauth/oauth_server.js +++ b/packages/oauth/oauth_server.js @@ -156,7 +156,7 @@ const middleware = async (req, res, next) => { throw new Error(`Unexpected OAuth service ${serviceName}`); // Make sure we're configured - ensureConfigured(serviceName); + await ensureConfigured(serviceName); const handler = OAuth._requestHandlers[service.version]; if (!handler) @@ -167,7 +167,6 @@ const middleware = async (req, res, next) => { } else { requestData = req.body; } - await handler(service, requestData, res); } catch (err) { // if we got thrown an error, save it off, it will get passed to @@ -179,7 +178,7 @@ const middleware = async (req, res, next) => { // style the error or react to it in any way. if (requestData?.state && err instanceof Error) { try { // catch any exceptions to avoid crashing runner - OAuth._storePendingCredential(OAuth._credentialTokenFromQuery(requestData), err); + await OAuth._storePendingCredential(OAuth._credentialTokenFromQuery(requestData), err); } catch (err) { // Ignore the error and just give up. If we failed to store the // error, then the login will just fail with a generic error. @@ -193,7 +192,7 @@ const middleware = async (req, res, next) => { // think to check server logs (we hope?) // Catch errors because any exception here will crash the runner. try { - OAuth._endOfLoginResponse(res, { + await OAuth._endOfLoginResponse(res, { query: requestData, loginStyle: OAuth._loginStyleFromQuery(requestData), error: err @@ -237,11 +236,14 @@ const oauthServiceName = req => { }; // Make sure we're configured -const ensureConfigured = serviceName => { - if (!ServiceConfiguration.configurations.findOne({service: serviceName})) { - throw new ServiceConfiguration.ConfigError(); - } -}; +const ensureConfigured = + async serviceName => { + const config = + await ServiceConfiguration.configurations.findOne({ service: serviceName }) + if (!config) { + throw new ServiceConfiguration.ConfigError(); + } + }; const isSafe = value => { // This matches strings generated by `Random.secret` and diff --git a/packages/oauth/pending_credentials.js b/packages/oauth/pending_credentials.js index 71623acc31..bb68cb0931 100644 --- a/packages/oauth/pending_credentials.js +++ b/packages/oauth/pending_credentials.js @@ -16,18 +16,22 @@ OAuth._pendingCredentials = new Mongo.Collection( _preventAutopublish: true }); -OAuth._pendingCredentials.createIndex('key', { unique: true }); -OAuth._pendingCredentials.createIndex('credentialSecret'); -OAuth._pendingCredentials.createIndex('createdAt'); +// TODO[FIBERS]: I Need TLA +async function init() { + await OAuth._pendingCredentials.createIndex('key', { unique: true }); + await OAuth._pendingCredentials.createIndex('credentialSecret'); + await OAuth._pendingCredentials.createIndex('createdAt'); +} +init() // Periodically clear old entries that were never retrieved -const _cleanStaleResults = () => { +const _cleanStaleResults = async () => { // Remove credentials older than 1 minute const timeCutoff = new Date(); timeCutoff.setMinutes(timeCutoff.getMinutes() - 1); - OAuth._pendingCredentials.remove({ createdAt: { $lt: timeCutoff } }); + await OAuth._pendingCredentials.remove({ createdAt: { $lt: timeCutoff } }); }; const _cleanupHandle = Meteor.setInterval(_cleanStaleResults, 60 * 1000); @@ -78,7 +82,6 @@ OAuth._retrievePendingCredential = key, credentialSecret, }); - if (pendingCredential) { await OAuth._pendingCredentials.remove({ _id: pendingCredential._id }); if (pendingCredential.credential.error) diff --git a/packages/oauth1/oauth1_pending_request_tokens.js b/packages/oauth1/oauth1_pending_request_tokens.js index db23f400fa..06b11feb52 100644 --- a/packages/oauth1/oauth1_pending_request_tokens.js +++ b/packages/oauth1/oauth1_pending_request_tokens.js @@ -47,13 +47,13 @@ const _cleanupHandle = Meteor.setInterval(_cleanStaleResults, 60 * 1000); // @param requestToken {string} // @param requestTokenSecret {string} // -OAuth._storeRequestToken = (key, requestToken, requestTokenSecret) => { +OAuth._storeRequestToken = async (key, requestToken, requestTokenSecret) => { check(key, String); // We do an upsert here instead of an insert in case the user happens // to somehow send the same `state` parameter twice during an OAuth // login; we don't want a duplicate key error. - OAuth._pendingRequestTokens.upsert({ + await OAuth._pendingRequestTokens.upsert({ key, }, { key, @@ -69,12 +69,12 @@ OAuth._storeRequestToken = (key, requestToken, requestTokenSecret) => { // // @param key {string} // -OAuth._retrieveRequestToken = key => { +OAuth._retrieveRequestToken = async key => { check(key, String); - const pendingRequestToken = OAuth._pendingRequestTokens.findOne({ key: key }); + const pendingRequestToken = await OAuth._pendingRequestTokens.findOne({ key: key }); if (pendingRequestToken) { - OAuth._pendingRequestTokens.remove({ _id: pendingRequestToken._id }); + await OAuth._pendingRequestTokens.remove({ _id: pendingRequestToken._id }); return { requestToken: OAuth.openSecret(pendingRequestToken.requestToken), requestTokenSecret: OAuth.openSecret( diff --git a/packages/oauth1/oauth1_server.js b/packages/oauth1/oauth1_server.js index d0c8e3732a..a8ffb501ef 100644 --- a/packages/oauth1/oauth1_server.js +++ b/packages/oauth1/oauth1_server.js @@ -26,7 +26,7 @@ OAuth._queryParamsWithAuthTokenUrl = (authUrl, oauthBinding, params = {}, whitel // connect middleware OAuth._requestHandlers['1'] = async (service, query, res) => { - const config = ServiceConfiguration.configurations.findOne({service: service.serviceName}); + const config = await ServiceConfiguration.configurations.findOne({service: service.serviceName}); if (! config) { throw new ServiceConfiguration.ConfigError(service.serviceName); } @@ -48,7 +48,7 @@ OAuth._requestHandlers['1'] = async (service, query, res) => { await oauthBinding.prepareRequestToken(callbackUrl); // Keep track of request token so we can verify it on the next step - OAuth._storeRequestToken( + await OAuth._storeRequestToken( OAuth._credentialTokenFromQuery(query), oauthBinding.requestToken, oauthBinding.requestTokenSecret); @@ -76,7 +76,7 @@ OAuth._requestHandlers['1'] = async (service, query, res) => { // and close the window to allow the login handler to proceed // Get the user's request token so we can verify it and clear it - const requestTokenInfo = OAuth._retrieveRequestToken( + const requestTokenInfo = await OAuth._retrieveRequestToken( OAuth._credentialTokenFromQuery(query)); if (! requestTokenInfo) { @@ -102,7 +102,7 @@ OAuth._requestHandlers['1'] = async (service, query, res) => { // Store the login result so it can be retrieved in another // browser tab by the result handler - OAuth._storePendingCredential(credentialToken, { + await OAuth._storePendingCredential(credentialToken, { serviceName: service.serviceName, serviceData: oauthResult.serviceData, options: oauthResult.options @@ -111,6 +111,6 @@ OAuth._requestHandlers['1'] = async (service, query, res) => { // Either close the window, redirect, or render nothing // if all else fails - OAuth._renderOauthResults(res, query, credentialSecret); + await OAuth._renderOauthResults(res, query, credentialSecret); } }; diff --git a/packages/oauth1/oauth1_tests.js b/packages/oauth1/oauth1_tests.js index d4b283a97a..bc87f6a2af 100644 --- a/packages/oauth1/oauth1_tests.js +++ b/packages/oauth1/oauth1_tests.js @@ -23,7 +23,7 @@ const testPendingCredential = async (test, method) => { this.accessTokenSecret = twitterfooAccessTokenSecret; }; - ServiceConfiguration.configurations.insert({service: serviceName}); + await ServiceConfiguration.configurations.insert({service: serviceName}); try { // register a fake login service @@ -40,7 +40,7 @@ const testPendingCredential = async (test, method) => { })); // simulate logging in using twitterfoo - OAuth._storeRequestToken(credentialToken, twitterfooAccessToken); + await OAuth._storeRequestToken(credentialToken, twitterfooAccessToken); const req = { method, @@ -73,9 +73,8 @@ const testPendingCredential = async (test, method) => { }; await OAuthTest.middleware(req, res); const credentialSecret = respData; - // Test that the result for the token is available - let result = OAuth._retrievePendingCredential(credentialToken, + let result = await OAuth._retrievePendingCredential(credentialToken, credentialSecret); const serviceData = OAuth.openSecrets(result.serviceData); test.equal(result.serviceName, serviceName); @@ -86,7 +85,7 @@ const testPendingCredential = async (test, method) => { test.equal(result.options.option1, twitterOption1); // Test that pending credential is removed after being retrieved - result = OAuth._retrievePendingCredential(credentialToken); + result = await OAuth._retrievePendingCredential(credentialToken); test.isUndefined(result); } finally { @@ -110,24 +109,24 @@ Tinytest.addAsync("oauth1 - pendingCredential is stored and can be retrieved (wi } }); -Tinytest.add("oauth1 - duplicate key for request token", test => { +Tinytest.addAsync("oauth1 - duplicate key for request token", async test => { const key = Random.id(); const token = Random.id(); const secret = Random.id(); - OAuth._storeRequestToken(key, token, secret); + await OAuth._storeRequestToken(key, token, secret); const newToken = Random.id(); const newSecret = Random.id(); - OAuth._storeRequestToken(key, newToken, newSecret); - const result = OAuth._retrieveRequestToken(key); + await OAuth._storeRequestToken(key, newToken, newSecret); + const result = await OAuth._retrieveRequestToken(key); test.equal(result.requestToken, newToken); test.equal(result.requestTokenSecret, newSecret); }); -Tinytest.add("oauth1 - null, undefined key for request token", test => { +Tinytest.addAsync("oauth1 - null, undefined key for request token", async test => { const token = Random.id(); const secret = Random.id(); - test.throws(() => OAuth._storeRequestToken(null, token, secret)); - test.throws(() => OAuth._storeRequestToken(undefined, token, secret)); + await test.throwsAsync(() => OAuth._storeRequestToken(null, token, secret)); + await test.throwsAsync(() => OAuth._storeRequestToken(undefined, token, secret)); }); Tinytest.add("oauth1 - signature is built correctly", test => {