@wxn0brp/vql 0.9.0 → 0.10.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.
- package/dist/cpu/relation.d.ts +2 -1
- package/dist/cpu/relation.js +3 -3
- package/dist/cpu/request.d.ts +2 -1
- package/dist/cpu/request.js +5 -5
- package/dist/helpers/apiAbstract.d.ts +23 -12
- package/dist/helpers/gw.js +2 -1
- package/dist/permissions/relation.js +1 -1
- package/dist/permissions/request.js +1 -1
- package/dist/permissions/resolver.d.ts +2 -2
- package/dist/permissions/resolver.js +26 -16
- package/dist/processor.d.ts +2 -2
- package/dist/processor.js +6 -6
- package/dist/types/perm.d.ts +3 -1
- package/dist/types/resolver.d.ts +4 -0
- package/package.json +1 -1
package/dist/cpu/relation.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { VQLConfig } from "../helpers/config.js";
|
|
1
2
|
import { VQLProcessor } from "../processor.js";
|
|
2
3
|
import { VQL_Query_Relation } from "../types/vql.js";
|
|
3
|
-
export declare function executeRelation(cpu: VQLProcessor, query: VQL_Query_Relation, user: any): Promise<any>;
|
|
4
|
+
export declare function executeRelation(cpu: VQLProcessor, query: VQL_Query_Relation, user: any, cfg: VQLConfig): Promise<any>;
|
package/dist/cpu/relation.js
CHANGED
|
@@ -17,15 +17,15 @@ function checkDBsExist(cpu, req) {
|
|
|
17
17
|
}
|
|
18
18
|
return { err: false };
|
|
19
19
|
}
|
|
20
|
-
export async function executeRelation(cpu, query, user) {
|
|
20
|
+
export async function executeRelation(cpu, query, user, cfg) {
|
|
21
21
|
const checkDb = checkDBsExist(cpu, query.r);
|
|
22
22
|
if (checkDb.err)
|
|
23
23
|
return checkDb;
|
|
24
|
-
if (!
|
|
24
|
+
if (!cfg.noCheckPermissions && !await checkRelationPermission(cfg, cpu.permValidFn, user, query)) {
|
|
25
25
|
return { err: true, msg: "Permission denied", c: 403 };
|
|
26
26
|
}
|
|
27
27
|
const req = query.r;
|
|
28
|
-
standardizeRelationRequest(
|
|
28
|
+
standardizeRelationRequest(cfg, req);
|
|
29
29
|
const { path, search, relations, select } = req;
|
|
30
30
|
if (req.many) {
|
|
31
31
|
return await cpu.relation.find(path, search, relations, select, req.options);
|
package/dist/cpu/request.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { VQLConfig } from "../helpers/config.js";
|
|
1
2
|
import { VQLProcessor } from "../processor.js";
|
|
2
3
|
import { VQL_Query_CRUD } from "../types/vql.js";
|
|
3
|
-
export declare function executeQuery(cpu: VQLProcessor, query: VQL_Query_CRUD, user: any): Promise<any>;
|
|
4
|
+
export declare function executeQuery(cpu: VQLProcessor, query: VQL_Query_CRUD, user: any, cfg: VQLConfig): Promise<any>;
|
package/dist/cpu/request.js
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
+
import { LowAdapter } from "../helpers/lowAdapter.js";
|
|
1
2
|
import { checkRequestPermission } from "../permissions/index.js";
|
|
2
3
|
import { parseSelect } from "./utils.js";
|
|
3
|
-
|
|
4
|
-
export async function executeQuery(cpu, query, user) {
|
|
4
|
+
export async function executeQuery(cpu, query, user, cfg) {
|
|
5
5
|
if (!query.db || !cpu.dbInstances[query.db])
|
|
6
6
|
return { err: true, msg: `Invalid query - db "${query.db || "undefined"}" not found`, c: 400 };
|
|
7
7
|
const db = cpu.dbInstances[query.db];
|
|
8
8
|
if (db instanceof LowAdapter)
|
|
9
9
|
return await db.resolver(query, user);
|
|
10
10
|
const operation = Object.keys(query.d)[0];
|
|
11
|
-
if (!
|
|
11
|
+
if (!cfg.noCheckPermissions && !await checkRequestPermission(cfg, cpu.permValidFn, user, query)) {
|
|
12
12
|
return { err: true, msg: "Permission denied", c: 403 };
|
|
13
13
|
}
|
|
14
14
|
if (operation === "find") {
|
|
15
15
|
const params = query.d[operation];
|
|
16
|
-
const select = parseSelect(
|
|
16
|
+
const select = parseSelect(cfg, params.fields || params.select || {});
|
|
17
17
|
if (select && typeof select === "object" && Object.keys(select).length !== 0)
|
|
18
18
|
params.searchOpts = { ...params.searchOpts, select };
|
|
19
19
|
return db.find(params.collection, params.search, params.options || {}, params.searchOpts);
|
|
20
20
|
}
|
|
21
21
|
else if (operation === "findOne" || operation === "f") {
|
|
22
22
|
const params = query.d[operation];
|
|
23
|
-
const select = parseSelect(
|
|
23
|
+
const select = parseSelect(cfg, params.fields || params.select || {});
|
|
24
24
|
if (select && typeof select === "object" && Object.keys(select).length !== 0)
|
|
25
25
|
params.searchOpts = { ...params.searchOpts, select };
|
|
26
26
|
return db.findOne(params.collection, params.search, params.searchOpts);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { VQL_Query_CRUD_Keys } from "../types/vql.js";
|
|
2
2
|
import { ValtheraCompatible } from "@wxn0brp/db-core";
|
|
3
|
-
type ResolverFn<TArgs extends any[] = any[], TReturn = any> = (...args: TArgs) => Promise<TReturn>;
|
|
3
|
+
export type ResolverFn<TArgs extends any[] = any[], TReturn = any> = (...args: TArgs) => Promise<TReturn>;
|
|
4
|
+
export type DropFirstFromTuple<T extends any[]> = T extends [any, ...infer Rest] ? Rest : never;
|
|
5
|
+
export type DropFirst<T> = T extends (...args: infer Args) => infer R ? (...args: DropFirstFromTuple<Args>) => R : never;
|
|
4
6
|
export interface ValtheraResolverMeta {
|
|
5
7
|
type: "valthera" | "api" | "wrapper" | (string & {});
|
|
6
8
|
version: string;
|
|
@@ -45,16 +47,25 @@ export declare class AdapterBuilder {
|
|
|
45
47
|
private collections;
|
|
46
48
|
constructor(catchCb?: (e: any, op: string, args: any[]) => void);
|
|
47
49
|
register(op: Operation, collection: string, fn: Function): this;
|
|
48
|
-
add(collection: string, fn: ValtheraResolver["add"]): this;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
50
|
+
add(collection: (string & {}), fn: DropFirst<ValtheraResolver["add"]>): this;
|
|
51
|
+
add(collection: "*", fn: ValtheraResolver["add"]): this;
|
|
52
|
+
find(collection: (string & {}), fn: DropFirst<ValtheraResolver["find"]>): this;
|
|
53
|
+
find(collection: "*", fn: ValtheraResolver["find"]): this;
|
|
54
|
+
findOne(collection: (string & {}), fn: DropFirst<ValtheraResolver["findOne"]>): this;
|
|
55
|
+
findOne(collection: "*", fn: ValtheraResolver["findOne"]): this;
|
|
56
|
+
update(collection: (string & {}), fn: DropFirst<ValtheraResolver["update"]>): this;
|
|
57
|
+
update(collection: "*", fn: ValtheraResolver["update"]): this;
|
|
58
|
+
updateOne(collection: (string & {}), fn: DropFirst<ValtheraResolver["updateOne"]>): this;
|
|
59
|
+
updateOne(collection: "*", fn: ValtheraResolver["updateOne"]): this;
|
|
60
|
+
updateOneOrAdd(collection: (string & {}), fn: DropFirst<ValtheraResolver["updateOneOrAdd"]>): this;
|
|
61
|
+
updateOneOrAdd(collection: "*", fn: ValtheraResolver["updateOneOrAdd"]): this;
|
|
62
|
+
toggleOne(collection: (string & {}), fn: DropFirst<ValtheraResolver["toggleOne"]>): this;
|
|
63
|
+
toggleOne(collection: "*", fn: ValtheraResolver["toggleOne"]): this;
|
|
64
|
+
remove(collection: (string & {}), fn: DropFirst<ValtheraResolver["remove"]>): this;
|
|
65
|
+
remove(collection: "*", fn: ValtheraResolver["remove"]): this;
|
|
66
|
+
removeOne(collection: (string & {}), fn: DropFirst<ValtheraResolver["removeOne"]>): this;
|
|
67
|
+
removeOne(collection: "*", fn: ValtheraResolver["removeOne"]): this;
|
|
68
|
+
removeCollection(collection: (string & {}), fn: DropFirst<ValtheraResolver["removeCollection"]>): this;
|
|
69
|
+
removeCollection(collection: "*", fn: ValtheraResolver["removeCollection"]): this;
|
|
58
70
|
getAdapter(extendedFind?: boolean): ValtheraCompatible;
|
|
59
71
|
}
|
|
60
|
-
export {};
|
package/dist/helpers/gw.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export function createGwValidFn(gw) {
|
|
2
2
|
return async (args) => {
|
|
3
|
-
|
|
3
|
+
const res = await gw.hasAccess(args.user._id, args.field, args.p);
|
|
4
|
+
return { granted: res.granted, via: `gate-warden`, reason: res.via };
|
|
4
5
|
};
|
|
5
6
|
}
|
|
@@ -18,7 +18,7 @@ export async function checkRelationPermission(config, permValidFn, user, query)
|
|
|
18
18
|
return true;
|
|
19
19
|
}
|
|
20
20
|
// If the result is "entity-404", check the next fallback level
|
|
21
|
-
if (!config.strictACL && result.
|
|
21
|
+
if (!config.strictACL && result.reason === "entity-404" && fallbackLevels.length > 0) {
|
|
22
22
|
const nextFallbackEntityId = await hashKey(config, fallbackLevels.slice(0, -1));
|
|
23
23
|
return checkPermissionRecursively(nextFallbackEntityId, fallbackLevels.slice(0, -2), fallbackLevels.slice(0, -2));
|
|
24
24
|
}
|
|
@@ -106,7 +106,7 @@ export async function checkRequestPermission(config, permValidFn, user, query) {
|
|
|
106
106
|
return true;
|
|
107
107
|
}
|
|
108
108
|
// If the result is "entity-404", check the next fallback level
|
|
109
|
-
if (!config.strictACL && result.
|
|
109
|
+
if (!config.strictACL && result.reason === "entity-404" && fallbackLevels.length > 0) {
|
|
110
110
|
const nextFallbackEntityId = await hashKey(config, fallbackLevels.slice(0, -1));
|
|
111
111
|
return checkPermissionRecursively(nextFallbackEntityId, fallbackLevels.slice(0, -2), requiredPerm, fallbackLevels.slice(0, -2));
|
|
112
112
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { PathMatcher, PermissionResolver } from "../types/resolver.js";
|
|
1
|
+
import { PathMatcher, PermissionResolver, ValidEngineOpts } from "../types/resolver.js";
|
|
2
2
|
import { PermValidFn } from "../types/perm.js";
|
|
3
3
|
import { GateWarden } from "@wxn0brp/gate-warden";
|
|
4
4
|
export declare class PermissionResolverEngine {
|
|
5
5
|
private resolvers;
|
|
6
|
-
addResolver(matcher: PathMatcher, resolver: PermissionResolver): void;
|
|
6
|
+
addResolver(matcher: PathMatcher, resolver: PermissionResolver, opts?: ValidEngineOpts | ValidEngineOpts["stringMode"]): void;
|
|
7
7
|
create(): PermValidFn;
|
|
8
8
|
createWithGw(gw: GateWarden): PermValidFn;
|
|
9
9
|
}
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
export class PermissionResolverEngine {
|
|
2
2
|
resolvers = [];
|
|
3
|
-
addResolver(matcher, resolver) {
|
|
4
|
-
|
|
3
|
+
addResolver(matcher, resolver, opts = {}) {
|
|
4
|
+
if (typeof opts === "string")
|
|
5
|
+
opts = { stringMode: opts };
|
|
6
|
+
this.resolvers.push({ matcher, resolver, opts });
|
|
5
7
|
}
|
|
6
8
|
create() {
|
|
7
9
|
return async (args) => {
|
|
8
10
|
const originalPath = args.path.join("/");
|
|
9
|
-
for (const { matcher, resolver } of this.resolvers) {
|
|
11
|
+
for (const { matcher, resolver, opts } of this.resolvers) {
|
|
10
12
|
let isMatch = false;
|
|
11
13
|
if (typeof matcher === "string") {
|
|
12
|
-
|
|
14
|
+
const { stringMode } = opts;
|
|
15
|
+
if (stringMode === "endsWith")
|
|
16
|
+
isMatch = originalPath.endsWith(matcher);
|
|
17
|
+
else if (stringMode === "startsWith")
|
|
18
|
+
isMatch = originalPath.startsWith(matcher);
|
|
19
|
+
else if (stringMode === "includes")
|
|
20
|
+
isMatch = originalPath.includes(matcher);
|
|
21
|
+
else
|
|
22
|
+
isMatch = originalPath === matcher;
|
|
13
23
|
}
|
|
14
24
|
else if (matcher instanceof RegExp) {
|
|
15
25
|
isMatch = matcher.test(originalPath);
|
|
@@ -17,18 +27,18 @@ export class PermissionResolverEngine {
|
|
|
17
27
|
else if (typeof matcher === "function") {
|
|
18
28
|
isMatch = await matcher(originalPath, args.path);
|
|
19
29
|
}
|
|
20
|
-
if (isMatch)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
30
|
+
if (!isMatch)
|
|
31
|
+
continue;
|
|
32
|
+
try {
|
|
33
|
+
const resolverGranted = await resolver(args);
|
|
34
|
+
return { granted: resolverGranted, via: `resolver`, reason: "resolver" };
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.error(`[Resolver Engine] Error in custom resolver for path ${originalPath}:`, error);
|
|
38
|
+
return { granted: false, via: `resolver`, reason: "resolver-error" };
|
|
29
39
|
}
|
|
30
40
|
}
|
|
31
|
-
return { granted: false, via: `no-resolver-match
|
|
41
|
+
return { granted: false, via: `resolver`, reason: "no-resolver-match" };
|
|
32
42
|
};
|
|
33
43
|
}
|
|
34
44
|
createWithGw(gw) {
|
|
@@ -37,10 +47,10 @@ export class PermissionResolverEngine {
|
|
|
37
47
|
const resolverResult = await resolver(args);
|
|
38
48
|
if (resolverResult.granted)
|
|
39
49
|
return resolverResult;
|
|
40
|
-
if (
|
|
50
|
+
if (resolverResult.reason !== `no-resolver-match`)
|
|
41
51
|
return resolverResult;
|
|
42
52
|
const gwResult = await gw.hasAccess(args.user.id, args.field, args.p);
|
|
43
|
-
return { granted: gwResult.granted, via: `gate-warden
|
|
53
|
+
return { granted: gwResult.granted, via: `gate-warden`, reason: gwResult.via };
|
|
44
54
|
};
|
|
45
55
|
}
|
|
46
56
|
}
|
package/dist/processor.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export declare class VQLProcessor {
|
|
|
8
8
|
relation: Relation;
|
|
9
9
|
config: VQLConfig;
|
|
10
10
|
constructor(dbInstances: Record<string, ValtheraCompatible>, config?: VQLConfig | Partial<VQLConfigInterface>, permValidFn?: PermValidFn);
|
|
11
|
-
execute<T = any>(queryRaw: VQLUQ<T>, user?: any): Promise<T | VQLError>;
|
|
11
|
+
execute<T = any>(queryRaw: VQLUQ<T>, user?: any, cfg?: VQLConfig): Promise<T | VQLError>;
|
|
12
12
|
_preProcessQuery(queryRaw: VQLUQ, user: any): {
|
|
13
13
|
err: VQLError;
|
|
14
14
|
query?: undefined;
|
|
@@ -20,5 +20,5 @@ export declare class VQLProcessor {
|
|
|
20
20
|
query?: VQL_Query;
|
|
21
21
|
err?: VQLError;
|
|
22
22
|
};
|
|
23
|
-
_runQuery(query: VQL_Query, user: any): Promise<any>;
|
|
23
|
+
_runQuery(query: VQL_Query, user: any, cfg?: VQLConfig): Promise<any>;
|
|
24
24
|
}
|
package/dist/processor.js
CHANGED
|
@@ -11,17 +11,17 @@ export class VQLProcessor {
|
|
|
11
11
|
permValidFn;
|
|
12
12
|
relation;
|
|
13
13
|
config;
|
|
14
|
-
constructor(dbInstances, config = new VQLConfig(), permValidFn = async () => ({ granted: true, via: "" })) {
|
|
14
|
+
constructor(dbInstances, config = new VQLConfig(), permValidFn = async () => ({ granted: true, via: "resolver", reason: "no-resolver-match" })) {
|
|
15
15
|
this.dbInstances = dbInstances;
|
|
16
16
|
this.permValidFn = permValidFn;
|
|
17
17
|
this.relation = new Relation(dbInstances);
|
|
18
18
|
this.config = config instanceof VQLConfig ? config : new VQLConfig(config);
|
|
19
19
|
}
|
|
20
|
-
async execute(queryRaw, user = { _id: "null-null-null" }) {
|
|
20
|
+
async execute(queryRaw, user = { _id: "null-null-null" }, cfg = this.config) {
|
|
21
21
|
const result = this._preProcessQuery(queryRaw, user);
|
|
22
22
|
if ("err" in result)
|
|
23
23
|
return result.err;
|
|
24
|
-
return await this._runQuery(result.query, user);
|
|
24
|
+
return await this._runQuery(result.query, user, cfg);
|
|
25
25
|
}
|
|
26
26
|
_preProcessQuery(queryRaw, user) {
|
|
27
27
|
const { query: parsedQuery, err: parseErr } = this._parseQuery(queryRaw);
|
|
@@ -68,12 +68,12 @@ export class VQLProcessor {
|
|
|
68
68
|
}
|
|
69
69
|
return { query: queryRaw };
|
|
70
70
|
}
|
|
71
|
-
async _runQuery(query, user) {
|
|
71
|
+
async _runQuery(query, user, cfg = this.config) {
|
|
72
72
|
if ("r" in query) {
|
|
73
|
-
return await executeRelation(this, query, user);
|
|
73
|
+
return await executeRelation(this, query, user, cfg);
|
|
74
74
|
}
|
|
75
75
|
else if ("d" in query) {
|
|
76
|
-
return await executeQuery(this, query, user);
|
|
76
|
+
return await executeQuery(this, query, user, cfg);
|
|
77
77
|
}
|
|
78
78
|
else {
|
|
79
79
|
return { err: true, msg: "Invalid query", c: 400 };
|
package/dist/types/perm.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AccessResult } from "@wxn0brp/gate-warden";
|
|
1
2
|
export declare enum PermCRUD {
|
|
2
3
|
CREATE = 1,
|
|
3
4
|
READ = 2,
|
|
@@ -7,7 +8,8 @@ export declare enum PermCRUD {
|
|
|
7
8
|
}
|
|
8
9
|
export interface ValidFnResult {
|
|
9
10
|
granted: boolean;
|
|
10
|
-
via?:
|
|
11
|
+
via?: "resolver" | "gate-warden";
|
|
12
|
+
reason?: AccessResult["via"] | "resolver" | "no-resolver-match" | "resolver-error";
|
|
11
13
|
}
|
|
12
14
|
export interface PermValidFnArgs {
|
|
13
15
|
/** sha256/json */
|
package/dist/types/resolver.d.ts
CHANGED
|
@@ -7,8 +7,12 @@ export type PermissionResolver = (args: PermValidFnArgs) => Promise<boolean>;
|
|
|
7
7
|
export interface ResolverEntry {
|
|
8
8
|
matcher: PathMatcher;
|
|
9
9
|
resolver: PermissionResolver;
|
|
10
|
+
opts: ValidEngineOpts;
|
|
10
11
|
}
|
|
11
12
|
export interface ResolverValidFnResult {
|
|
12
13
|
granted: boolean;
|
|
13
14
|
via: string;
|
|
14
15
|
}
|
|
16
|
+
export interface ValidEngineOpts {
|
|
17
|
+
stringMode?: "equal" | "startsWith" | "endsWith" | "includes";
|
|
18
|
+
}
|