diff --git a/packages/oauth/oauth_tests.js b/packages/oauth/oauth_tests.js index d560ae10d3..0984ab57ad 100644 --- a/packages/oauth/oauth_tests.js +++ b/packages/oauth/oauth_tests.js @@ -28,3 +28,22 @@ Tinytest.add("oauth - pendingCredential handles Meteor.Errors", function (test) test.equal(result.stack, testError.stack); test.isUndefined(result.meteorError); }); + +Tinytest.add("oauth - null, undefined key for pendingCredential", function (test) { + var cred = Random.id(); + test.throws(function () { + OAuth._storePendingCredential(null, cred); + }); + test.throws(function () { + OAuth._storePendingCredential(undefined, cred); + }); +}); + +Tinytest.add("oauth - pendingCredential handles duplicate key", function (test) { + var key = Random.id(); + var cred = Random.id(); + OAuth._storePendingCredential(key, cred); + var newCred = Random.id(); + OAuth._storePendingCredential(key, newCred); + test.equal(OAuth._retrievePendingCredential(key), newCred); +}); diff --git a/packages/oauth/pending_credentials.js b/packages/oauth/pending_credentials.js index e841b06124..d5197a8d53 100644 --- a/packages/oauth/pending_credentials.js +++ b/packages/oauth/pending_credentials.js @@ -31,19 +31,27 @@ var _cleanStaleResults = function() { var _cleanupHandle = Meteor.setInterval(_cleanStaleResults, 60 * 1000); -// Stores the key and credential in the _pendingCredentials collection +// Stores the key and credential in the _pendingCredentials collection. +// Will throw an exception if `key` is not a string. // // @param key {string} // @param credential {string} The credential to store // OAuth._storePendingCredential = function (key, credential) { + check(key, String); + if (credential instanceof Error) { credential = storableError(credential); } else { credential = OAuth.sealSecret(credential); } - OAuth._pendingCredentials.insert({ + // 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._pendingCredentials.upsert({ + key: key + }, { key: key, credential: credential, createdAt: new Date() diff --git a/packages/oauth1/oauth1_pending_request_tokens.js b/packages/oauth1/oauth1_pending_request_tokens.js index 76e8d88401..ff025a577f 100644 --- a/packages/oauth1/oauth1_pending_request_tokens.js +++ b/packages/oauth1/oauth1_pending_request_tokens.js @@ -15,7 +15,8 @@ // For this reason, the _pendingRequestTokens are stored in the database // so they can be shared across Meteor App servers. // - +// XXX This code is fairly similar to oauth/pending_credentials.js -- +// maybe we can combine them somehow. // Collection containing pending request tokens // Has key, requestToken, requestTokenSecret, and createdAt fields. @@ -39,14 +40,22 @@ var _cleanStaleResults = function() { var _cleanupHandle = Meteor.setInterval(_cleanStaleResults, 60 * 1000); -// Stores the key and request token in the _pendingRequestTokens collection +// Stores the key and request token in the _pendingRequestTokens collection. +// Will throw an exception if `key` is not a string. // // @param key {string} // @param requestToken {string} // @param requestTokenSecret {string} // OAuth._storeRequestToken = function (key, requestToken, requestTokenSecret) { - OAuth._pendingRequestTokens.insert({ + 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({ + key: key + }, { key: key, requestToken: OAuth.sealSecret(requestToken), requestTokenSecret: OAuth.sealSecret(requestTokenSecret), diff --git a/packages/oauth1/oauth1_tests.js b/packages/oauth1/oauth1_tests.js index f85ead956f..3820a337e8 100644 --- a/packages/oauth1/oauth1_tests.js +++ b/packages/oauth1/oauth1_tests.js @@ -84,3 +84,27 @@ Tinytest.add("oauth1 - pendingCredential is stored and can be retrieved (with oa OAuthEncryption.loadKey(null); } }); + +Tinytest.add("oauth1 - duplicate key for request token", function (test) { + var key = Random.id(); + var token = Random.id(); + var secret = Random.id(); + OAuth._storeRequestToken(key, token, secret); + var newToken = Random.id(); + var newSecret = Random.id(); + OAuth._storeRequestToken(key, newToken, newSecret); + var result = OAuth._retrieveRequestToken(key); + test.equal(result.requestToken, newToken); + test.equal(result.requestTokenSecret, newSecret); +}); + +Tinytest.add("oauth1 - null, undefined key for request token", function (test) { + var token = Random.id(); + var secret = Random.id(); + test.throws(function () { + OAuth._storeRequestToken(null, token, secret); + }); + test.throws(function () { + OAuth._storeRequestToken(undefined, token, secret); + }); +});