forked from meteor/meteor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpending_credentials.js
124 lines (103 loc) · 3.63 KB
/
pending_credentials.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
//
// When an oauth request is made, Meteor receives oauth credentials
// in one browser tab, and temporarily persists them while that
// tab is closed, then retrieves them in the browser tab that
// initiated the credential request.
//
// _pendingCredentials is the storage mechanism used to share the
// credential between the 2 tabs
//
// Collection containing pending credentials of oauth credential requests
// Has key, credential, and createdAt fields.
OAuth._pendingCredentials = new Mongo.Collection(
"meteor_oauth_pendingCredentials", {
_preventAutopublish: true
});
OAuth._pendingCredentials._ensureIndex('key', {unique: 1});
OAuth._pendingCredentials._ensureIndex('credentialSecret');
OAuth._pendingCredentials._ensureIndex('createdAt');
// Periodically clear old entries that were never retrieved
var _cleanStaleResults = function() {
// Remove credentials older than 1 minute
var timeCutoff = new Date();
timeCutoff.setMinutes(timeCutoff.getMinutes() - 1);
OAuth._pendingCredentials.remove({ createdAt: { $lt: timeCutoff } });
};
var _cleanupHandle = Meteor.setInterval(_cleanStaleResults, 60 * 1000);
// Stores the key and credential in the _pendingCredentials collection.
// Will throw an exception if `key` is not a string.
//
// @param key {string}
// @param credential {Object} The credential to store
// @param credentialSecret {string} A secret that must be presented in
// addition to the `key` to retrieve the credential
//
OAuth._storePendingCredential = function (key, credential, credentialSecret) {
check(key, String);
check(credentialSecret, Match.Optional(String));
if (credential instanceof Error) {
credential = storableError(credential);
} else {
credential = OAuth.sealSecret(credential);
}
// 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,
credentialSecret: credentialSecret || null,
createdAt: new Date()
});
};
// Retrieves and removes a credential from the _pendingCredentials collection
//
// @param key {string}
// @param credentialSecret {string}
//
OAuth._retrievePendingCredential = function (key, credentialSecret) {
check(key, String);
var pendingCredential = OAuth._pendingCredentials.findOne({
key: key,
credentialSecret: credentialSecret || null
});
if (pendingCredential) {
OAuth._pendingCredentials.remove({ _id: pendingCredential._id });
if (pendingCredential.credential.error)
return recreateError(pendingCredential.credential.error);
else
return OAuth.openSecret(pendingCredential.credential);
} else {
return undefined;
}
};
// Convert an Error into an object that can be stored in mongo
// Note: A Meteor.Error is reconstructed as a Meteor.Error
// All other error classes are reconstructed as a plain Error.
var storableError = function(error) {
var plainObject = {};
Object.getOwnPropertyNames(error).forEach(function(key) {
plainObject[key] = error[key];
});
// Keep track of whether it's a Meteor.Error
if(error instanceof Meteor.Error) {
plainObject['meteorError'] = true;
}
return { error: plainObject };
};
// Create an error from the error format stored in mongo
var recreateError = function(errorDoc) {
var error;
if (errorDoc.meteorError) {
error = new Meteor.Error();
delete errorDoc.meteorError;
} else {
error = new Error();
}
Object.getOwnPropertyNames(errorDoc).forEach(function(key) {
error[key] = errorDoc[key];
});
return error;
};