Skip to content

Commit 47889b1

Browse files
committed
Allow permissions to be embedded in saved documents
Use a post save hook to insert the new permissions into the document
1 parent 9eee1a9 commit 47889b1

3 files changed

Lines changed: 21 additions & 9 deletions

File tree

.vscode/settings.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
"cSpell.words": [
33
"adhoc",
44
"authz",
5-
"nodeunit"
5+
"nodeunit",
6+
"permissioned",
7+
"subpath",
8+
"upsert"
69
]
710
}

index.js

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ const getEmbeddedPermission = require('./src/getEmbeddedPermission');
99
const PermissionDeniedError = require('./src/PermissionDeniedError');
1010
const IncompatibleMethodError = require('./src/IncompatibleMethodError');
1111

12+
const docOptionsSymbol = Symbol('documentOptions');
13+
1214
module.exports = (schema, installationOptions) => {
1315
async function save(doc, options) {
1416
let authorizedFields = getEmbeddedPermission(doc, options, 'write');
@@ -110,11 +112,25 @@ module.exports = (schema, installationOptions) => {
110112
// is to have arguments to the middleware function. If we have arguments, mongoose
111113
// assume we want to use a `next()` function. FML
112114
schema.pre('save', function preSave(next, options) {
115+
// Embed the options into the doc so we have access to them in post save hooks
116+
this[docOptionsSymbol] = options;
113117
if (authIsDisabled(options)) { return next(); }
118+
114119
return save(this, options)
115120
.then(() => next())
116121
.catch(next);
117122
});
123+
schema.post('save', (doc, next) => {
124+
const options = doc[docOptionsSymbol];
125+
if (authIsDisabled(options)) { return next(); }
126+
127+
// Nothing will likely be removed, but this allows people to specify that
128+
// permissions should be returned, so this will recalculate permissions
129+
// with the new document data (after changes) and embed it if asked for
130+
return sanitizeDocumentList(schema, options, doc)
131+
.then(() => next())
132+
.catch(next);
133+
});
118134
// TODO, WTF, how to prevent someone from Model.find().remove().exec(); That doesn't
119135
// fire any remove hooks. Does it fire a find hook?
120136
schema.pre('remove', function preRemove(next, options) {
@@ -149,13 +165,6 @@ module.exports = (schema, installationOptions) => {
149165
return this;
150166
};
151167

152-
// TODO add tests for this function
153-
schema.statics.canCreate = async function canCreate(options) {
154-
// Check just the blank document since nothing exists yet
155-
const authLevels = await resolveAuthLevel(schema, options, {});
156-
return hasPermission(this.schema, authLevels, 'create');
157-
};
158-
159168
const allowedMethods = _.get(installationOptions, 'allowedMethods');
160169
if (!_.includes(allowedMethods, 'create')) {
161170
schema.statics.create = function cannotCreate() {

src/sanitizeDocumentList.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const embedPermissions = require('./embedPermissions');
66
async function sanitizeDocument(schema, options, doc) {
77
if (!doc) { return; }
88

9-
// If there are subschemas that need to be authorized, store a reference to the top
9+
// If there are sub-schemas that need to be authorized, store a reference to the top
1010
// level doc so they have context when doing their authorization checks
1111
const optionAddition = {};
1212
if (!options.originalDoc && !_.isEmpty(schema.pathsWithPermissionedSchemas)) {

0 commit comments

Comments
 (0)