auth 0.0.9 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,281 +0,0 @@
1
- var access = require("../access"),
2
- crypto = require("crypto"),
3
- _ = require("underscore"),
4
- access = require("../access"),
5
- Token = require("./token"),
6
- outcome = require("outcome"),
7
- step = require("step"),
8
- dsync = require("dsync"),
9
- structr = require("structr"),
10
- outcome = require("outcome"),
11
- comerr = require("comerr"),
12
- verify = require("verify")();
13
-
14
- exports.model = function(options) {
15
-
16
- var database = options.connection;
17
-
18
- Token.model(database);
19
-
20
- var Schema = database.base.Schema,
21
- ObjectId = Schema.Types.ObjectId;
22
-
23
-
24
- verify.register("password", "Invalid password. Must be at least 6 chars.").len(6);
25
-
26
- /**
27
- */
28
-
29
- var Account = new Schema({
30
-
31
- /**
32
- */
33
-
34
- validated: { type: Boolean, default: false },
35
-
36
- /**
37
- */
38
-
39
- validatedAt: { type: Date, default: Date.now },
40
-
41
- /**
42
- */
43
-
44
- validationKey: { type: String, default: function() {
45
- return Date.now() + "_" + Math.round(Math.random()*44332482393);
46
- }},
47
-
48
- /**
49
- */
50
-
51
- password: { type: String, required: true, set: hashPass, select: false, default: randomPass },
52
-
53
- /**
54
- */
55
-
56
- createdAt: { type: Date, default: Date.now }
57
- });
58
-
59
- Account.publicMethods = ["getMainToken", "createToken"];
60
-
61
- Account.plugin(dsync.schema);
62
- Account.add(options.fields || {});
63
-
64
- var authFields;
65
-
66
- if(!(authFields = options.authFields)) {
67
- Account.add({ email: { type: String, required: true, index: { unique: true }} });
68
- authFields = ["email", "password"];
69
- }
70
-
71
-
72
- /**
73
- * makes this account the owner of the target item. NOT used
74
- * for querying since mongodb cannot do deep object searching
75
- */
76
-
77
- Account.methods.ownItem = function(item, acc) {
78
- if(!item.owners) item.owners = [];
79
- var self = this;
80
-
81
- if(!acc) {
82
- acc = access.all(false);
83
- }
84
-
85
- if(!(acc instanceof Array)) {
86
- acc = [acc];
87
- }
88
-
89
-
90
- if(!item.owners.length) {
91
- acc.push(access.SUPER); //owner
92
- }
93
-
94
- if(this.isItemOwner(item)) return;
95
-
96
- item.owners.push({
97
- account: self._id,
98
- access: acc
99
- });
100
- }
101
-
102
- /**
103
- */
104
-
105
- Account.methods.shareItem = Account.methods.ownItem;
106
-
107
- /**
108
- */
109
-
110
- Account.methods.disownItem = function(item) {
111
- console.log(item.owners.remove);
112
- }
113
-
114
- /**
115
- */
116
-
117
- Account.methods.lockdownItem = function(item) {
118
- item._account = this;
119
- }
120
-
121
- /**
122
- * returns true / false if authorized for the given action
123
- */
124
-
125
- Account.methods.authorized = function(item, access) {
126
-
127
- //MUST
128
- return this.isItemOwner(item, access) && (this.token ? this.token.authorized(item, access) : true);
129
- }
130
-
131
- /**
132
- * dead simple flow-control function. Use it like this:
133
- * if(!user.hasItemAccess(item)) return user.unauthorized(callback);
134
- */
135
-
136
- Account.methods.unauthorized = function(callback) {
137
-
138
- var err = new comerr.Unauthorized();
139
-
140
- return arguments.length ? callback(err) : err;
141
- }
142
-
143
-
144
- /**
145
- * returns true
146
- */
147
-
148
- Account.methods.isItemOwner = function(item, acc) {
149
-
150
- if(!acc) acc = access.all(true);
151
- if(!(acc instanceof Array)) acc = [acc];
152
-
153
- var self = this;
154
- //first check if the owner exists. If
155
- return !!_.find(item.owners, function(owner) {
156
- return String(owner.account) == String(self._id) &&
157
- !!_.intersection(acc, owner.access).length;
158
- });
159
- }
160
-
161
-
162
- /**
163
- * wraps owner tags around a query
164
- */
165
-
166
- Account.methods.addToSearch = function(query, access) {
167
-
168
- if(arguments.length === 1 && ((typeof query === "string") || (query instanceof Array))) {
169
- access = query;
170
- query = {};
171
- }
172
-
173
- if(!query) query = {};
174
-
175
- var oaccount,
176
- oaccess,
177
- search = {
178
- "owners.account": this._id,
179
- }
180
-
181
- //do?
182
- /*if(!access) {
183
- access = "SUPER";
184
- }*/
185
-
186
- //TODO - make
187
- if(access) {
188
- search["owners.access"] = access;
189
- }
190
-
191
- return _.extend(query, search);
192
- }
193
-
194
- /**
195
- * returns the main account token
196
- */
197
-
198
- Account.methods.getMainToken = function(callback) {
199
- this.model("tokens").getMainToken(this, callback);
200
- }
201
-
202
- /**
203
- */
204
-
205
- Account.methods.createToken = function(options, callback) {
206
- this.model("tokens").createToken(this, options, callback);
207
- }
208
-
209
- /**
210
- */
211
-
212
- Account.statics.signup = function(acc, callback) {
213
- var Account = this;
214
-
215
- if(!verify.check(acc).onError(callback).has("email", "password").success) return;
216
-
217
- var on = outcome.error(callback);
218
-
219
- //email must be lower case - it generally is. What if they're signing up on an apple device?
220
- acc.email = acc.email.toLowerCase();
221
-
222
- step(
223
- function() {
224
- Account.findOne({ email: acc.email }, this);
225
- },
226
- on.success(function(account) {
227
- if(account) return callback(new comerr.AlreadyExists("That account name is already taken."));
228
- new Account(acc).save(this);
229
- }),
230
- on.success(function(account) {
231
- callback(null, account);
232
- Account.emit("signup", account);
233
- })
234
- );
235
- }
236
-
237
- /**
238
- */
239
-
240
- Account.statics.login = function(credentials, callback) {
241
-
242
- var Token = this.model("tokens");
243
-
244
- if(!callback) callback = function(){};
245
- if(credentials.token) {
246
- return Token.login(credentials, callback);
247
- } else {
248
-
249
- var q = {};
250
-
251
-
252
- authFields.forEach(function(fieldName) {
253
- q[fieldName] = fieldName == "password" ? hashPass(String(credentials.password)) : credentials[fieldName];
254
- if(fieldName == "email") q[fieldName] = String(credentials[fieldName]).toLowerCase();
255
- });
256
-
257
-
258
- this.findOne(q, outcome.error(callback).success(function(account) {
259
- if(!account) return callback(new comerr.IncorrectInput("Incorrect email / password"));
260
- callback(null, account);
261
- }));
262
- }
263
- }
264
-
265
- /**
266
- */
267
-
268
- function hashPass(pass) {
269
- return crypto.createHash("sha1").update(pass).digest("hex");
270
- }
271
-
272
- /**
273
- */
274
-
275
- function randomPass() {
276
- return hashPass(Date.now() + "_" + Math.round(Math.random() * 99999))
277
- }
278
-
279
- return database.model("accounts", Account);
280
- }
281
-
@@ -1,28 +0,0 @@
1
- exports.model = function(con) {
2
- var Schema = con.base.Schema,
3
- ObjectId = Schema.Types.ObjectId;
4
-
5
-
6
- var LostPasswordSchema = new Schema({
7
-
8
- /**
9
- */
10
-
11
- "createdAt": { type: Date, default: Date.now },
12
-
13
- /**
14
- * 10 minutes
15
- */
16
-
17
- "expiresAt": { type: Date, default: Date.now() + 1000 * 60 * 60 },
18
-
19
- /**
20
- * account this associated with
21
- */
22
-
23
- "account": ObjectId
24
- });
25
-
26
-
27
- return con.model("lostPassword", LostPasswordSchema);
28
- }
@@ -1,298 +0,0 @@
1
-
2
- /**
3
- * tokens are especially useful when turning on / off features
4
- * of an account. They're used for items such as bookmarklets, and perhaps
5
- * public tokens which modifies the user's account.
6
- */
7
-
8
- var step = require("step"),
9
- outcome = require("outcome"),
10
- access = require("../access"),
11
- _ = require("underscore"),
12
- dsync = require("dsync"),
13
- comerr = require("comerr");
14
-
15
- exports.model = function(database) {
16
-
17
- var Schema = database.base.Schema,
18
- ObjectId = Schema.Types.ObjectId;
19
-
20
- var Scope = new Schema({
21
-
22
- /**
23
- * the specific
24
- */
25
-
26
- item: ObjectId,
27
-
28
- /**
29
- * col - collection is reserved
30
- */
31
-
32
- collectionName: String,
33
-
34
- /**
35
- * access level, read, write, read+write
36
- */
37
-
38
- access: [String]
39
- });
40
-
41
- var Token = new Schema({
42
-
43
- /**
44
- * granter of this token
45
- */
46
-
47
-
48
- account: { type: ObjectId, required: true },
49
-
50
- /**
51
- */
52
-
53
- createdAt: { type: Date, default: Date.now },
54
-
55
- /**
56
- * public key used to login. This can be refreshed.
57
- */
58
-
59
- key: { type: String, default: generateKey },
60
-
61
- /**
62
- * when does the token expire?
63
- */
64
-
65
- expiresAt: Date,
66
-
67
- /**
68
- */
69
-
70
- scopes: { type: [ Scope ], select: false },
71
-
72
- /**
73
- * time in seconds to keep token alive for. -1 = forever
74
- */
75
-
76
- ttl: { type: Number, default: -1, select: false },
77
-
78
- /**
79
- */
80
-
81
- main: { type: Boolean, select: false }
82
-
83
- });
84
-
85
- Token.publicKeys = ["account", "createdAt", "expiresAt", "key"];
86
- Token.plugin(dsync.schema);
87
-
88
- /**
89
- */
90
-
91
- Token.statics.getMainToken = function(account, callback) {
92
-
93
-
94
- var self = this, Token = this, on = outcome.error(callback);
95
- step(
96
-
97
- /**
98
- */
99
-
100
- function() {
101
- self.findOne({ account: account._id, main: true }, this);
102
- },
103
-
104
- /**
105
- */
106
-
107
- on.success(function(token) {
108
- var next = this;
109
- if(!token) {
110
- token = new Token({
111
- main: true,
112
- account: account._id,
113
- scopes:[{
114
- collectionName: null, //ALL
115
- item: null, //ALL
116
- access: access.all(true)
117
- }]
118
- });
119
-
120
- return token.save(function() {
121
- next(null, token);
122
- });
123
- }
124
- account.token = token;
125
- next(null, token);
126
- }),
127
-
128
- /**
129
- */
130
-
131
- callback
132
- );
133
- }
134
-
135
- /**
136
- * login with a token
137
- */
138
-
139
- Token.statics.login = function(options, callback) {
140
- var token = options.token,
141
- Account = this.model("accounts"),
142
- Token = this,
143
- on = outcome.error(callback);
144
-
145
- var t, a;
146
-
147
- step(
148
-
149
- /**
150
- */
151
-
152
- function() {
153
- Token.findOne({ key: token }, this);
154
- },
155
-
156
- /**
157
- */
158
-
159
- on.success(function(token) {
160
-
161
- //404
162
- if(!token) return callback(new comerr.NotFound("token does not exist", { type: "token" }));
163
-
164
- //expired - TODO - add in query: {$or:[{expiresAt:null},{expiresAt:{$lt:new Date()}}]}
165
- if(token.expiresAt && token.expiresAt.getTime() < Date.now().getTime()) {
166
- token.remove();
167
- return callback(new comerr.Expired("token has expired"));
168
- }
169
-
170
- //find the user
171
- t = token;
172
- Account.findOne({ _id: token.account }, this);
173
- }),
174
-
175
- /**
176
- */
177
-
178
- on.success(function(account) {
179
-
180
- //this shouldn't happen
181
- if(!account) return callback(new comerr.NotFound("account does not exist", { type: "account" }));
182
-
183
- a = account;
184
- //attach the token so the account can restrict some access to features
185
- account.token = t;
186
-
187
- this(null, account);
188
- }),
189
-
190
- /**
191
- */
192
-
193
- callback
194
- );
195
- }
196
-
197
- /**
198
- */
199
-
200
- Token.statics.createToken = function(account, options, callback) {
201
-
202
- if(arguments.length === 2) {
203
- callback = options;
204
- options = {};
205
- }
206
-
207
- var item, collectionName, acc = options.access || access.all(false);
208
-
209
- if(options.item) {
210
- if(options.item._id) {
211
- item = options.item._id;
212
- collectionName = options.item.collection.name;
213
- }
214
- }
215
-
216
- var self = this, Token = this, on = outcome.error(callback);
217
- step(
218
-
219
- /**
220
- */
221
-
222
- function() {
223
- token = new Token({
224
- account: account._id,
225
- ttl: options.ttl || -1,
226
- scopes: [{
227
- item: item,
228
- collectionName: collectionName,
229
- access: acc
230
- }]
231
- });
232
- account.token = token;
233
- token.save(this);
234
- },
235
-
236
- /**
237
- */
238
-
239
- callback
240
- )
241
- }
242
-
243
- /**
244
- */
245
-
246
- Token.methods.authorized = function(item, acc) {
247
-
248
- if(!acc) acc = [access.SUPER];
249
-
250
- var collectionName = item.collection.name,
251
- itemId = String(item._id),
252
- acc2 = acc instanceof Array ? acc : [acc];
253
-
254
- return !!_.find(item.scopes, function(scope) {
255
-
256
- //no collection (all), OR the collection matches
257
- return (!!scope.collectionName || (scope.collectionName === collectionName)) &&
258
-
259
- //AND no item, OR the item matches the scoped item
260
- (!!scope.item || (String(scope.item) === itemId)) &&
261
-
262
- //AND the scope access intersects. This must intersect.
263
- !!_intersection(scope.access, acc2).length;
264
- })
265
- }
266
-
267
- /**
268
- * regenerates the key used to login
269
- */
270
-
271
- Token.methods.regenerateKey = function() {
272
- this.key = generateKey();
273
- }
274
-
275
- /**
276
- * make sure the grantee is set
277
- */
278
-
279
- Token.pre("save", function(next) {
280
- if(~this.ttl && !this.expiresAt) {
281
- this.expiresAt = Date.now() + this.ttl;
282
- }
283
- next();
284
- });
285
-
286
- /**
287
- */
288
-
289
- function generateKey() {
290
- return Date.now() + "_" + Math.round(Math.random() * 999999999999999);
291
- }
292
-
293
- /**
294
- */
295
-
296
- return database.model("tokens", Token);
297
- }
298
-
package/models.md DELETED
@@ -1,7 +0,0 @@
1
- ```javascript
2
-
3
- var Model = require("Model");
4
-
5
-
6
-
7
- ```