Skip to content

Commit cdbc51f

Browse files
committed
feat(permissions): Add new operators '$storage', '$database', '$array', '$index'
- Introduce operators to define permissions more precisely across different data structures. - Enable support for applying complex queries within these operators to filter and return data based on specified conditions.
1 parent 3355635 commit cdbc51f

File tree

1 file changed

+96
-30
lines changed

1 file changed

+96
-30
lines changed

src/index.js

Lines changed: 96 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@
165165

166166
let status = await checkMethod(data, authorized.actions, data.method)
167167

168-
// console.log(data.method, status)
168+
// console.log(data.method, data.array, status)
169169

170170
if (!status) {
171171
return false
@@ -217,50 +217,117 @@
217217
status = await checkMethodMatch(data, authorized[i], newmatch)
218218
}
219219
} else if (typeof authorized === 'object') {
220-
let keys = Object.keys(authorized);
221-
222-
for (const key of keys) {
223-
if (key.includes('$'))
224-
status = await checkMethodOperators(data, key, authorized[key])
225-
else if (newmatch && (authorized[newmatch] || authorized['*'])) {
226-
status = await checkMethodMatch(data, authorized[newmatch] || authorized['*'], newmatch)
220+
for (const key of Object.keys(authorized)) {
221+
if (key.includes('$')) {
222+
if (['$storage', '$database', '$array', '$index'].includes(key)) {
223+
let opStatus = await checkMethodOperators(data, key, authorized[key])
224+
if (opStatus === true || opStatus === false)
225+
status = opStatus
226+
} else {
227+
let isFilter = applyFilter(data, authorized[key], key)
228+
console.log('isFIlter', isFilter)
229+
}
227230
}
228231
}
229232
}
233+
if (newmatch) {
234+
if (!status && authorized[newmatch]) {
235+
status = await checkMethodMatch(data, authorized[newmatch], newmatch)
236+
}
237+
if (!status && authorized['*']) {
238+
status = await checkMethodMatch(data, authorized['*'], newmatch)
239+
}
240+
}
241+
230242
return status
231243
}
232244
}
233245

234-
async function checkMethodOperators(data, key, value) {
235-
if (value === '$user_Id' && data.socket)
236-
value = data.socket.user_id || data.user_id
246+
async function checkMethodOperators(data, key, authorization) {
247+
try {
248+
// Adjust authorization if it's based on a dynamic user ID from sockets
249+
if (authorization === '$user_id' && data.socket) {
250+
authorization = data.socket.user_id || data.user_id;
251+
}
237252

238-
// TODO: support our standard query system
239-
let keys = key.split('.')
240-
if (['$eq', '$ne', '$lt', '$lte', '$gt', '$gte', '$in', '$nin', '$or', '$and', '$not', '$nor', '$exists', '$type', '$mod', '$regex', '$text', '$where', '$all', '$elemMatch', '$size'].includes(keys[0])) {
253+
if (key.startsWith('$')) {
254+
let type = key.substring(1);
255+
256+
if (!data[type]) {
257+
return undefined;
258+
}
259+
260+
if (typeof data[type] === 'string') {
261+
return checkAuthorizationData(data, authorization, data[type])
262+
} else if (Array.isArray(data[type])) {
263+
if (!data[type].length)
264+
return undefined
265+
// ToDo: Current stratergy checks if all items match else false will be returned
266+
let allAuthorized = true;
267+
for (let i = 0; i < data[type].length; i++) {
268+
const itemData = typeof data[type][i] === 'object' ? data[type][i].name : data[type][i];
269+
const authResult = checkAuthorizationData(data, authorization, itemData);
270+
if (authResult === false) {
271+
return false; // Return false as soon as one item is unauthorized
272+
} else if (authResult === undefined) {
273+
allAuthorized = undefined
274+
}
275+
}
276+
return allAuthorized;
277+
} else if (typeof data[type] === 'object') {
278+
return checkAuthorizationData(data, authorization, data[type].name)
279+
}
280+
}
281+
return undefined;
282+
} catch (e) {
283+
console.log(e);
284+
return undefined;
285+
}
286+
}
287+
288+
function checkAuthorizationData(data, authorization, key) {
289+
if (typeof authorization === 'string') {
290+
if (key === authorization)
291+
return true
292+
else
293+
return undefined
294+
} else if (Array.isArray(authorization)) {
295+
if (authorization.includes(key))
296+
return true
297+
else
298+
return undefined
299+
} else if (typeof authorization === 'object') {
300+
if (typeof authorization[key] === 'object') {
301+
for (const queryKey of Object.keys(authorization[key])) {
302+
return applyFilter(data, authorization[key], queryKey)
303+
}
304+
} else if (authorization[key] === false || authorization[key] === 'false')
305+
return false
306+
else if (authorization[key])
307+
return true
308+
else
309+
return undefined
310+
}
311+
}
312+
313+
function applyFilter(data, authorization, authorizationKey) {
314+
let keyParts = authorizationKey.split('.');
315+
let operator = keyParts.pop();
316+
let key = keyParts.join('.');
317+
if (['$eq', '$ne', '$lt', '$lte', '$gt', '$gte', '$in', '$nin', '$or', '$and', '$not', '$nor', '$exists', '$type', '$mod', '$regex', '$text', '$where', '$all', '$elemMatch', '$size'].includes(operator)) {
241318
if (!data.$filter)
242319
data.$filter = { query: {} }
243320
else if (!data.$filter.query)
244321
data.$filter.query = {}
245322

246-
data.$filter.query[keys[1]] = { [keys[0]]: value }
323+
if (authorization[authorizationKey] === '$user_id' && data.socket) {
324+
authorization[authorizationKey] = data.socket.user_id || data.user_id;
325+
}
247326

248-
} else {
249-
if (key === '$array' && value === 'questions') {
250-
if (typeof data.array === 'string') {
251-
if (typeof value === 'string') {
252-
return data.array === value
253-
} else if (Array.isArray(value)) {
254-
return value.includes(data.array)
255-
}
256-
} else if (Array.isArray(data.array)) {
327+
data.$filter.query[key] = { [operator]: authorization[authorizationKey] }
257328

258-
}
259-
}
260-
// TODO: sanitize data by removing items user does not have access to.
261-
// console.log('key is a query operator', key)
329+
return true
262330
}
263-
return true
264331
}
265332

266333
async function checkFilter(authorized, data, apikey, unauthorize) {
@@ -287,7 +354,6 @@
287354
}
288355
}
289356

290-
291357
function deleteKey(data, path) {
292358
if (!data || !path) return
293359
if (path.includes('._id'))

0 commit comments

Comments
 (0)