auth 0.0.8 → 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +19 -162
- package/index.js +75 -0
- package/package.json +22 -27
- package/.cupboard +0 -2
- package/.npmignore +0 -2
- package/browser/account.js +0 -72
- package/browser/index.js +0 -13
- package/docs/issues.md +0 -4
- package/docs/pseudo-1.js +0 -19
- package/examples/ex1.js +0 -72
- package/examples/ex2.js +0 -62
- package/examples/models.js +0 -17
- package/examples/plugin-1.js +0 -14
- package/examples/pseduo.js +0 -6
- package/examples/pseudo-2.js +0 -2
- package/examples/pseudo-3.js +0 -61
- package/lib/access.js +0 -18
- package/lib/http/middleware/index.js +0 -31
- package/lib/http/routes/index.js +0 -152
- package/lib/http/routes/lostPassword.js +0 -121
- package/lib/http/routes/reqOutcome.js +0 -10
- package/lib/index.js +0 -65
- package/lib/mixin/ownableModel.js +0 -118
- package/lib/models/account.js +0 -275
- package/lib/models/lostPassword.js +0 -28
- package/lib/models/token.js +0 -298
- package/models.md +0 -7
package/examples/pseudo-3.js
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
var db;
|
|
2
|
-
|
|
3
|
-
//how do we handle permissions for super users?
|
|
4
|
-
//simple answer is - user permissions have root privileges - there's only ONE root
|
|
5
|
-
//level, which is the user itself. a "super" tag maybe applied, but after that, privileges
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
var user1 = user(),
|
|
9
|
-
|
|
10
|
-
//user2 can be a registered user, or it can be a
|
|
11
|
-
//public user that's automatically logged in. This could be the
|
|
12
|
-
//default option.
|
|
13
|
-
user2 = user();
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
//this sort of thing isn't necessary since authentication would be bubbled
|
|
17
|
-
//up to the top-most item. in which case, "comments", is owned by post. "Post" is owned
|
|
18
|
-
//by user. The authentication would work as follows:
|
|
19
|
-
//auth -> posts -> comments
|
|
20
|
-
db.collection("post").owns("comments");
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
//in this case, post is owned by community. HOWEVER, "post" can still be shared with
|
|
24
|
-
//other users. this use case just follows a different authentication path.
|
|
25
|
-
//auth -> community -> post -> comments
|
|
26
|
-
//where the post looks to see if the community is its owner - in which case
|
|
27
|
-
//modifications can be made against the given post. Before that, community
|
|
28
|
-
//checks if a user is the given owner.
|
|
29
|
-
//how do we give permissions for the owner of given community to make changes
|
|
30
|
-
//to any post? We could modify the query such that if the owner is of the community,
|
|
31
|
-
//q = { community: _id }, but if the owner is of the poist, then q = { u: u, p: p }
|
|
32
|
-
//In other words, think of this as a faster method short of adding super users in each item which... fndskfsfklds
|
|
33
|
-
db.collection("community").owns("post").owns("");
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
//here's a different use case. This would require watching "repositories" for any
|
|
37
|
-
//NEW repository that comes in, instead of one shot.
|
|
38
|
-
db.collection("repositories").owns("repository");
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
//1 queue job
|
|
42
|
-
//2 check if u1 owns someId
|
|
43
|
-
//3. add user2 under "owners" in the given item
|
|
44
|
-
user1.shareItem("someId", user2, function() {
|
|
45
|
-
//on share
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
//1 add job that gets triggered when a new repository is inserted
|
|
49
|
-
//2. follow step "shareItem" when a new item is added
|
|
50
|
-
user1.shareCollection("repositories", user2, function() {
|
|
51
|
-
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
//takes permissions away from the given user
|
|
55
|
-
user1.takeAwayItem("someId", user2);
|
|
56
|
-
//cron.addJob({ from: user1, update: { $set: permissions: [] }}, to: user2 })
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
//takes away privileges for a particular user
|
|
60
|
-
user1.takeAwayCollection("repositories", user2);
|
|
61
|
-
//cron.removeJob({ from: user1, collection: "repositories", to: user2 })
|
package/lib/access.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
var all = [];
|
|
3
|
-
|
|
4
|
-
["GET", "POST", "PUT", "DELETE"].forEach(function(method) {
|
|
5
|
-
all.push(exports[method] = method);
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
//don't want the array to be altered
|
|
9
|
-
exports.all = function(isSuper) {
|
|
10
|
-
var acc = all.concat();
|
|
11
|
-
if(isSuper) {
|
|
12
|
-
acc.push(exports.SUPER);
|
|
13
|
-
}
|
|
14
|
-
return acc;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
//outside of all - must be manually set.
|
|
18
|
-
exports.SUPER = "SUPER";
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
var vine = require("vine"),
|
|
2
|
-
comerr = require("comerr");
|
|
3
|
-
|
|
4
|
-
exports.plugin = function(auth) {
|
|
5
|
-
|
|
6
|
-
var Account = auth.Account;
|
|
7
|
-
|
|
8
|
-
return {
|
|
9
|
-
authCheckpoint: function(req, res, next) {
|
|
10
|
-
if(req.session.token) {
|
|
11
|
-
q = { token: req.session.token };
|
|
12
|
-
} else {
|
|
13
|
-
q = req.query.token || req.query.email ? req.query : req.body || req.query;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
Account.login(q, function(err, account) {
|
|
17
|
-
|
|
18
|
-
if(err) {
|
|
19
|
-
|
|
20
|
-
if(/\.json$/.test(req.path)) return res.send(vine.error(new comerr.Unauthorized("you must be logged in to view this page")));
|
|
21
|
-
|
|
22
|
-
return res.redirect("/login?redirect_to=" + encodeURIComponent(req.originalUrl));
|
|
23
|
-
// return res.send(vine.error(err));
|
|
24
|
-
}
|
|
25
|
-
req.account = account;
|
|
26
|
-
next();
|
|
27
|
-
});
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
}
|
package/lib/http/routes/index.js
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
var step = require("step"),
|
|
2
|
-
vine = require("vine"),
|
|
3
|
-
reqOutcome = require("./reqOutcome"),
|
|
4
|
-
dust = require("dustjs-linkedin"),
|
|
5
|
-
step = require("step"),
|
|
6
|
-
fs = require("fs");
|
|
7
|
-
|
|
8
|
-
exports.plugin = function(httpServer, emailer, auth, loader) {
|
|
9
|
-
|
|
10
|
-
var Account = auth.Account,
|
|
11
|
-
InvitedAccount = auth.InvitedAccount,
|
|
12
|
-
privateMode = loader.params("privateMode") || false,
|
|
13
|
-
domain = loader.params("domain"),
|
|
14
|
-
serviceName = loader.params("serviceName");
|
|
15
|
-
|
|
16
|
-
eval(dust.compile(fs.readFileSync(loader.params("http.validateEmailTpl"), "utf8"), "validateEmailTpl"));
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
function getToken(req, res, account, render, redirect) {
|
|
20
|
-
account.getMainToken(function(err, token) {
|
|
21
|
-
|
|
22
|
-
req.session.token = token.key;
|
|
23
|
-
|
|
24
|
-
if(!render) {
|
|
25
|
-
if(err) {
|
|
26
|
-
return res.send(vine.error(err));
|
|
27
|
-
} else {
|
|
28
|
-
var obj = account.toObject();
|
|
29
|
-
delete obj.password; //why is this still here??
|
|
30
|
-
obj.token = token;
|
|
31
|
-
res.send(vine.result(obj));
|
|
32
|
-
}
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if(err) return res.render(render, {
|
|
37
|
-
error: err.message
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
res.redirect(redirect || req.query.redirect_to || loader.params("http.loginRedirect") || "/");
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
httpServer.get("/account.json", auth.middleware.authCheckpoint, function(req, res) {
|
|
46
|
-
getToken(req, res, req.account);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
httpServer.post("/account.json", function(req, res) {
|
|
50
|
-
Account.signup(req.body, function(err, account) {
|
|
51
|
-
if(err) return res.send(vine.error(err));
|
|
52
|
-
getToken(req, res, account);
|
|
53
|
-
})
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
httpServer.get("/login", function(req, res) {
|
|
58
|
-
|
|
59
|
-
if(!req.secure && req.headers["x-forwarded-proto"] != "https" && !/127.0.0.1|localhost/.test(String(req.headers.host))) {
|
|
60
|
-
return res.redirect("https://" + (req.headers.host || loader.params("domain") || loader.params("http.host")) + req.url);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
res.render("login", {
|
|
64
|
-
redirect_to: req.query.redirect_to
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
httpServer.get("/logout", function(req, res) {
|
|
69
|
-
delete req.session.token;
|
|
70
|
-
res.redirect("/login");
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
httpServer.post("/login", function(req, res) {
|
|
74
|
-
Account.login(req.body, reqOutcome(req, res, "login").success(function(acc) {
|
|
75
|
-
getToken(req, res, acc, "login");
|
|
76
|
-
}));
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
httpServer.get("/signup", function(req, res) {
|
|
80
|
-
res.render("signup");
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
httpServer.get("/validate_account", function(req, res) {
|
|
85
|
-
var on = reqOutcome(req, res, "validate_account");
|
|
86
|
-
|
|
87
|
-
step(
|
|
88
|
-
function() {
|
|
89
|
-
Account.findOne({ _id: req.query.account }, this);
|
|
90
|
-
},
|
|
91
|
-
on.success(function(account) {
|
|
92
|
-
if(!account) return on(new Error("account does not exist"));
|
|
93
|
-
// if(account.validated) return on(new Error("this account has already been validated"));
|
|
94
|
-
|
|
95
|
-
if(account.validationKey != req.query.validationKey) return on(new Error("incorrect validation key"));
|
|
96
|
-
account.validatedAt = new Date();
|
|
97
|
-
account.validated = true;
|
|
98
|
-
account.save(this);
|
|
99
|
-
Account.emit("validated", account);
|
|
100
|
-
}),
|
|
101
|
-
on.success(function(account) {
|
|
102
|
-
res.render("validate_account", {
|
|
103
|
-
account: account
|
|
104
|
-
});
|
|
105
|
-
})
|
|
106
|
-
);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
Account.on("signup", function(acc) {
|
|
110
|
-
step(
|
|
111
|
-
function() {
|
|
112
|
-
dust.render("validateEmailTpl", { validationKey: acc.validationKey, accountId: acc._id }, this);
|
|
113
|
-
},
|
|
114
|
-
function(err, tpl) {
|
|
115
|
-
if(err) return console.error(err);
|
|
116
|
-
var next = this;
|
|
117
|
-
console.log("sending validation email");
|
|
118
|
-
emailer.send({
|
|
119
|
-
to: acc.email,
|
|
120
|
-
subject: "Validate Account",
|
|
121
|
-
htmlBody: tpl
|
|
122
|
-
}, function(err) {
|
|
123
|
-
if(err) console.error(err)
|
|
124
|
-
next();
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
},
|
|
128
|
-
function() {
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
httpServer.post("/signup", function(req, res) {
|
|
136
|
-
|
|
137
|
-
console.log("signing up")
|
|
138
|
-
var on = reqOutcome(req, res, "signup");
|
|
139
|
-
|
|
140
|
-
/*if(privateMode && !req.body.referredBy) {
|
|
141
|
-
on(new Error("You cannot signup unless you've been invited by someone"));
|
|
142
|
-
}*/
|
|
143
|
-
|
|
144
|
-
Account.signup(req.body, reqOutcome(req, res, "signup").success(function(acc) {
|
|
145
|
-
getToken(req, res, acc, "signup", loader.params("http.signupRedirect"));
|
|
146
|
-
}));
|
|
147
|
-
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
require("./lostPassword").plugin(Account, auth.LostPassword, httpServer, emailer, getToken, loader);
|
|
152
|
-
}
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
var vine = require("vine"),
|
|
2
|
-
reqOutcome = require("./reqOutcome"),
|
|
3
|
-
step = require("step"),
|
|
4
|
-
dust = require("dustjs-linkedin"),
|
|
5
|
-
fs = require("fs");
|
|
6
|
-
|
|
7
|
-
exports.plugin = function(Account, LostPassword, httpServer, emailer, getToken, loader) {
|
|
8
|
-
|
|
9
|
-
if(!emailer) return;
|
|
10
|
-
|
|
11
|
-
//register the dust tpl ~ fugly >.>
|
|
12
|
-
eval(dust.compile(fs.readFileSync(loader.params("http.lostPasswordEmailTpl"), "utf8"), "lostPasswordEmailTpl"));
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
httpServer.get("/lost_password", function(req, res) {
|
|
16
|
-
res.render("lost_password");
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
httpServer.post("/lost_password", function(req, res) {
|
|
20
|
-
var on = reqOutcome(req, res, "lost_password");
|
|
21
|
-
|
|
22
|
-
step(
|
|
23
|
-
function() {
|
|
24
|
-
Account.findOne({ email: req.body.email }, this);
|
|
25
|
-
},
|
|
26
|
-
on.success(function(account) {
|
|
27
|
-
if(!account) return on(new Error("account does not exist"));
|
|
28
|
-
this.account = account;
|
|
29
|
-
|
|
30
|
-
var lostPassword = new LostPassword({ account: account._id });
|
|
31
|
-
|
|
32
|
-
lostPassword.save(this);
|
|
33
|
-
}),
|
|
34
|
-
on.success(function(lostPassword) {
|
|
35
|
-
var next = this;
|
|
36
|
-
|
|
37
|
-
dust.render("lostPasswordEmailTpl", { email: req.body.email, token: lostPassword._id }, this);
|
|
38
|
-
|
|
39
|
-
}),
|
|
40
|
-
on.success(function(tpl) {
|
|
41
|
-
var next = this;
|
|
42
|
-
emailer.send({
|
|
43
|
-
to: this.account.email,
|
|
44
|
-
subject: "Reset Password",
|
|
45
|
-
htmlBody: tpl
|
|
46
|
-
}, function(err) {
|
|
47
|
-
if(err) return on(new Error("Unable to send password recovery email"));
|
|
48
|
-
next();
|
|
49
|
-
})
|
|
50
|
-
}),
|
|
51
|
-
on.success(function() {
|
|
52
|
-
res.render("lost_password_sent", {
|
|
53
|
-
email: this.account.email
|
|
54
|
-
});
|
|
55
|
-
})
|
|
56
|
-
);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
function lostPasswordExists(req, res, next) {
|
|
60
|
-
var on = reqOutcome(req, res, "lost_password");
|
|
61
|
-
|
|
62
|
-
step(
|
|
63
|
-
function() {
|
|
64
|
-
LostPassword.findOne({ _id: req.query.token || req.body.token }, this);
|
|
65
|
-
},
|
|
66
|
-
on.success(function(lostPassword) {
|
|
67
|
-
if(!lostPassword) {
|
|
68
|
-
return on(new Error("The reset password token does not exist."));
|
|
69
|
-
} else
|
|
70
|
-
if(lostPassword.expiresAt.getTime() < Date.now()) {
|
|
71
|
-
lostPassword.remove();
|
|
72
|
-
return on(new Error("The reset password link has expired."));
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
req.lostPassword = lostPassword;
|
|
76
|
-
this();
|
|
77
|
-
}),
|
|
78
|
-
next
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
httpServer.get("/reset_password", lostPasswordExists, function(req, res) {
|
|
83
|
-
res.render("reset_password", {
|
|
84
|
-
token: req.query.token
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
httpServer.post("/reset_password", lostPasswordExists, function(req, res) {
|
|
89
|
-
var on = reqOutcome(req, res, "reset_password");
|
|
90
|
-
|
|
91
|
-
step(
|
|
92
|
-
function() {
|
|
93
|
-
if(req.body.password.length < 6) {
|
|
94
|
-
console.log(vine.error(new Error("password must be at least 6 characters")).data)
|
|
95
|
-
|
|
96
|
-
return on(new Error("password must be at least 6 characters"));
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if(req.body.password != req.body.password2) {
|
|
100
|
-
return on(new Error("passwords don't match"));
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
this();
|
|
104
|
-
},
|
|
105
|
-
function() {
|
|
106
|
-
Account.findOne({ _id: req.lostPassword.account }, this);
|
|
107
|
-
},
|
|
108
|
-
on.success(function(account) {
|
|
109
|
-
if(!account) return on(new Error("account doesn't exist"));
|
|
110
|
-
account.password = req.body.password;
|
|
111
|
-
account.save(this);
|
|
112
|
-
}),
|
|
113
|
-
on.success(function(account) {
|
|
114
|
-
|
|
115
|
-
getToken(req, res, account, "reset_password");
|
|
116
|
-
// res.render("login", vine.message("Please re-login with your new password").data);
|
|
117
|
-
// req.lostPassword.remove();
|
|
118
|
-
})
|
|
119
|
-
);
|
|
120
|
-
});
|
|
121
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
vine = require("vine"),
|
|
2
|
-
outcome = require("outcome"),
|
|
3
|
-
_ = require("underscore");
|
|
4
|
-
|
|
5
|
-
module.exports = function(req, res, render) {
|
|
6
|
-
var on = outcome.error(function(err) {
|
|
7
|
-
res.render(render, _.extend(req.query, vine.error(err).data));
|
|
8
|
-
});
|
|
9
|
-
return on;
|
|
10
|
-
}
|
package/lib/index.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
var structr = require("structr"),
|
|
2
|
-
ownableModel = require("./mixin/ownableModel"),
|
|
3
|
-
Account = require("./models/account"),
|
|
4
|
-
LostPassword = require("./models/lostPassword"),
|
|
5
|
-
_ = require("underscore"),
|
|
6
|
-
middleware = require("./http/middleware");
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
var Auth = structr({
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
publicKeys: ["login", "signup"],
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
"__construct": function(options) {
|
|
20
|
-
this.connection = options.connection;
|
|
21
|
-
this.Account = Account.model(options);
|
|
22
|
-
this.LostPassword = LostPassword.model(options.connection);
|
|
23
|
-
this.middleware = middleware.plugin(this);
|
|
24
|
-
this.ownable = function(schema) {
|
|
25
|
-
return ownableModel(schema, options.connection);
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* logs the user in
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
"login": function(credentials, callback) {
|
|
34
|
-
this.Account.login.apply(this.Account, arguments);
|
|
35
|
-
},
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* signs a user up
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
|
-
"signup": function() {
|
|
42
|
-
this.Account.signup.apply(this.Account, arguments);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
exports.access = require("./access");
|
|
47
|
-
|
|
48
|
-
exports.connect = function(options) {
|
|
49
|
-
return new Auth(options);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
exports.require = [["auth.middleware.*"], "emailer", "plugin-mongodb", "plugin-express"];
|
|
54
|
-
exports.plugin = function(authMiddleware, emailer, mongodb, httpServer, loader) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
var auth = exports.connect(_.extend({
|
|
58
|
-
connection: mongodb
|
|
59
|
-
}, loader.params("auth")));
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
require("./http/routes").plugin(httpServer, emailer, auth, loader);
|
|
63
|
-
|
|
64
|
-
return auth;
|
|
65
|
-
}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
var _ = require("underscore"),
|
|
2
|
-
access = require("../access"),
|
|
3
|
-
comerr = require("comerr");
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
module.exports = function(schema, connection) {
|
|
10
|
-
|
|
11
|
-
var Schema = connection.base.Schema,
|
|
12
|
-
ObjectId = Schema.ObjectId;
|
|
13
|
-
|
|
14
|
-
var Owner = new Schema({
|
|
15
|
-
account: ObjectId,
|
|
16
|
-
access: [ String ]
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
var Account = connection.model("accounts").schema,
|
|
20
|
-
collectionName;
|
|
21
|
-
|
|
22
|
-
//add owners schema to the item
|
|
23
|
-
schema.add({
|
|
24
|
-
owners: [ Owner ],
|
|
25
|
-
|
|
26
|
-
//is the item visible to the public?
|
|
27
|
-
isPublic: { type: Boolean, default: false }
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
//add a method to all
|
|
31
|
-
schema.methods.fetchOwner = function(callback) {
|
|
32
|
-
var owner = _.find(this.owners, function(owner) {
|
|
33
|
-
return ~owner.access.indexOf(access.SUPER);
|
|
34
|
-
});
|
|
35
|
-
if(!owner) return callback(new Error("item doesn't have an owner"));
|
|
36
|
-
this.model("accounts").findOne({ _id: owner.account }, function(err, account) {
|
|
37
|
-
if(err) return callback(err);
|
|
38
|
-
if(!account) return callback(new comerr.NotFound("account does't exist"));
|
|
39
|
-
callback(err, account);
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
//plucks any access to shared
|
|
45
|
-
schema.statics.revokeShared = function(account, callback) {
|
|
46
|
-
this.collection.update(account.ownQuery(), {$pull:{ owners:{ account: account._id }}}, { multi: true }, callback);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
//model is needed to remove the item if the account is deleted.
|
|
50
|
-
//NOTE - database might not be present, so we just grab the name for reference
|
|
51
|
-
//later on
|
|
52
|
-
schema.once("init", function(m) {
|
|
53
|
-
collectionName = m.collection.name;
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
//on remove, remove the item as well.
|
|
57
|
-
Account.pre("remove", function(next) {
|
|
58
|
-
if(!collectionName) {
|
|
59
|
-
console.warn("model is not provided with an ownable schema");
|
|
60
|
-
return next();
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
var model = this.model(collectionName),
|
|
64
|
-
self = this;
|
|
65
|
-
|
|
66
|
-
//first remove ALL items that belong to this acocunt
|
|
67
|
-
model.collection.remove(this.ownQuery(access.SUPER), { multi: true }, function() {
|
|
68
|
-
|
|
69
|
-
//next, pluck ANY items that maybe associated with this account
|
|
70
|
-
model.revokeShared(self, function(){});
|
|
71
|
-
});
|
|
72
|
-
next();
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
schema.pre("save", function(next) {
|
|
76
|
-
if(!this._account) {
|
|
77
|
-
return next();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if(this.authorized([this.isNew ? access.POST : access.PUT])) {
|
|
81
|
-
next();
|
|
82
|
-
} else {
|
|
83
|
-
this._account.unauthorized(next);
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
schema.methods.authorized = function(acc, callback) {
|
|
88
|
-
|
|
89
|
-
if(typeof access == "function") {
|
|
90
|
-
callback = null;
|
|
91
|
-
acc = null;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if(!acc) {
|
|
95
|
-
acc = access.all();
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
var authorized = !this._account || this._account.authorized(this, acc);
|
|
99
|
-
|
|
100
|
-
return !callback ? authorized : callback(null, authorized);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
var oldToJson = schema.methods.toJSON;
|
|
104
|
-
|
|
105
|
-
//lockdown serialization
|
|
106
|
-
schema.methods.toJSON = function() {
|
|
107
|
-
|
|
108
|
-
//locked down?
|
|
109
|
-
if(this.authorized([access.GET])) {
|
|
110
|
-
return this.toObject();
|
|
111
|
-
} else {
|
|
112
|
-
return { error: this._account.unauthorized().message };
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return schema;
|
|
118
|
-
}
|