querysub 0.2.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/.dependency-cruiser.js +304 -0
- package/.eslintrc.js +51 -0
- package/.github/copilot-instructions.md +1 -0
- package/.vscode/settings.json +25 -0
- package/bin/deploy.js +4 -0
- package/bin/function.js +4 -0
- package/bin/server.js +4 -0
- package/costsBenefits.txt +112 -0
- package/deploy.ts +3 -0
- package/inject.ts +1 -0
- package/package.json +60 -0
- package/prompts.txt +54 -0
- package/spec.txt +820 -0
- package/src/-a-archives/archiveCache.ts +913 -0
- package/src/-a-archives/archives.ts +148 -0
- package/src/-a-archives/archivesBackBlaze.ts +792 -0
- package/src/-a-archives/archivesDisk.ts +418 -0
- package/src/-a-archives/copyLocalToBackblaze.ts +24 -0
- package/src/-a-auth/certs.ts +517 -0
- package/src/-a-auth/der.ts +122 -0
- package/src/-a-auth/ed25519.ts +1015 -0
- package/src/-a-auth/node-forge-ed25519.d.ts +17 -0
- package/src/-b-authorities/dnsAuthority.ts +203 -0
- package/src/-b-authorities/emailAuthority.ts +57 -0
- package/src/-c-identity/IdentityController.ts +200 -0
- package/src/-d-trust/NetworkTrust2.ts +150 -0
- package/src/-e-certs/EdgeCertController.ts +288 -0
- package/src/-e-certs/certAuthority.ts +192 -0
- package/src/-f-node-discovery/NodeDiscovery.ts +543 -0
- package/src/-g-core-values/NodeCapabilities.ts +134 -0
- package/src/-g-core-values/oneTimeForward.ts +91 -0
- package/src/-h-path-value-serialize/PathValueSerializer.ts +769 -0
- package/src/-h-path-value-serialize/stringSerializer.ts +176 -0
- package/src/0-path-value-core/LoggingClient.tsx +24 -0
- package/src/0-path-value-core/NodePathAuthorities.ts +978 -0
- package/src/0-path-value-core/PathController.ts +1 -0
- package/src/0-path-value-core/PathValueCommitter.ts +565 -0
- package/src/0-path-value-core/PathValueController.ts +231 -0
- package/src/0-path-value-core/archiveLocks/ArchiveLocks.ts +154 -0
- package/src/0-path-value-core/archiveLocks/ArchiveLocks2.ts +820 -0
- package/src/0-path-value-core/archiveLocks/archiveSnapshots.ts +180 -0
- package/src/0-path-value-core/debugLogs.ts +90 -0
- package/src/0-path-value-core/pathValueArchives.ts +483 -0
- package/src/0-path-value-core/pathValueCore.ts +2217 -0
- package/src/1-path-client/RemoteWatcher.ts +558 -0
- package/src/1-path-client/pathValueClientWatcher.ts +702 -0
- package/src/2-proxy/PathValueProxyWatcher.ts +1857 -0
- package/src/2-proxy/archiveMoveHarness.ts +376 -0
- package/src/2-proxy/garbageCollection.ts +753 -0
- package/src/2-proxy/pathDatabaseProxyBase.ts +37 -0
- package/src/2-proxy/pathValueProxy.ts +139 -0
- package/src/2-proxy/schema2.ts +518 -0
- package/src/3-path-functions/PathFunctionHelpers.ts +129 -0
- package/src/3-path-functions/PathFunctionRunner.ts +619 -0
- package/src/3-path-functions/PathFunctionRunnerMain.ts +67 -0
- package/src/3-path-functions/deployBlock.ts +10 -0
- package/src/3-path-functions/deployCheck.ts +7 -0
- package/src/3-path-functions/deployMain.ts +160 -0
- package/src/3-path-functions/pathFunctionLoader.ts +282 -0
- package/src/3-path-functions/syncSchema.ts +475 -0
- package/src/3-path-functions/tests/functionsTest.ts +135 -0
- package/src/3-path-functions/tests/rejectTest.ts +77 -0
- package/src/4-dom/css.tsx +29 -0
- package/src/4-dom/cssTypes.d.ts +212 -0
- package/src/4-dom/qreact.tsx +2322 -0
- package/src/4-dom/qreactTest.tsx +417 -0
- package/src/4-querysub/Querysub.ts +877 -0
- package/src/4-querysub/QuerysubController.ts +620 -0
- package/src/4-querysub/copyEvent.ts +0 -0
- package/src/4-querysub/permissions.ts +289 -0
- package/src/4-querysub/permissionsShared.ts +1 -0
- package/src/4-querysub/querysubPrediction.ts +525 -0
- package/src/5-diagnostics/FullscreenModal.tsx +67 -0
- package/src/5-diagnostics/GenericFormat.tsx +165 -0
- package/src/5-diagnostics/Modal.tsx +79 -0
- package/src/5-diagnostics/Table.tsx +183 -0
- package/src/5-diagnostics/TimeGrouper.tsx +114 -0
- package/src/5-diagnostics/diskValueAudit.ts +216 -0
- package/src/5-diagnostics/memoryValueAudit.ts +442 -0
- package/src/5-diagnostics/nodeMetadata.ts +135 -0
- package/src/5-diagnostics/qreactDebug.tsx +309 -0
- package/src/5-diagnostics/shared.ts +26 -0
- package/src/5-diagnostics/synchronousLagTracking.ts +47 -0
- package/src/TestController.ts +35 -0
- package/src/allowclient.flag +0 -0
- package/src/bits.ts +86 -0
- package/src/buffers.ts +69 -0
- package/src/config.ts +53 -0
- package/src/config2.ts +48 -0
- package/src/diagnostics/ActionsHistory.ts +56 -0
- package/src/diagnostics/NodeViewer.tsx +503 -0
- package/src/diagnostics/SizeLimiter.ts +62 -0
- package/src/diagnostics/TimeDebug.tsx +18 -0
- package/src/diagnostics/benchmark.ts +139 -0
- package/src/diagnostics/errorLogs/ErrorLogController.ts +515 -0
- package/src/diagnostics/errorLogs/ErrorLogCore.ts +274 -0
- package/src/diagnostics/errorLogs/LogClassifiers.tsx +302 -0
- package/src/diagnostics/errorLogs/LogFilterUI.tsx +84 -0
- package/src/diagnostics/errorLogs/LogNotify.tsx +101 -0
- package/src/diagnostics/errorLogs/LogTimeSelector.tsx +724 -0
- package/src/diagnostics/errorLogs/LogViewer.tsx +757 -0
- package/src/diagnostics/errorLogs/hookErrors.ts +60 -0
- package/src/diagnostics/errorLogs/logFiltering.tsx +149 -0
- package/src/diagnostics/heapTag.ts +13 -0
- package/src/diagnostics/listenOnDebugger.ts +77 -0
- package/src/diagnostics/logs/DiskLoggerPage.tsx +572 -0
- package/src/diagnostics/logs/ObjectDisplay.tsx +165 -0
- package/src/diagnostics/logs/ansiFormat.ts +108 -0
- package/src/diagnostics/logs/diskLogGlobalContext.ts +38 -0
- package/src/diagnostics/logs/diskLogger.ts +305 -0
- package/src/diagnostics/logs/diskShimConsoleLogs.ts +32 -0
- package/src/diagnostics/logs/injectFileLocationToConsole.ts +50 -0
- package/src/diagnostics/logs/logGitHashes.ts +30 -0
- package/src/diagnostics/managementPages.tsx +289 -0
- package/src/diagnostics/periodic.ts +89 -0
- package/src/diagnostics/runSaturationTest.ts +416 -0
- package/src/diagnostics/satSchema.ts +64 -0
- package/src/diagnostics/trackResources.ts +82 -0
- package/src/diagnostics/watchdog.ts +55 -0
- package/src/errors.ts +132 -0
- package/src/forceProduction.ts +3 -0
- package/src/fs.ts +72 -0
- package/src/heapDumps.ts +666 -0
- package/src/https.ts +2 -0
- package/src/inject.ts +1 -0
- package/src/library-components/ATag.tsx +84 -0
- package/src/library-components/Button.tsx +344 -0
- package/src/library-components/ButtonSelector.tsx +64 -0
- package/src/library-components/DropdownCustom.tsx +151 -0
- package/src/library-components/DropdownSelector.tsx +32 -0
- package/src/library-components/Input.tsx +334 -0
- package/src/library-components/InputLabel.tsx +198 -0
- package/src/library-components/InputPicker.tsx +125 -0
- package/src/library-components/LazyComponent.tsx +62 -0
- package/src/library-components/MeasureHeightCSS.tsx +48 -0
- package/src/library-components/MeasuredDiv.tsx +47 -0
- package/src/library-components/ShowMore.tsx +51 -0
- package/src/library-components/SyncedController.ts +171 -0
- package/src/library-components/TimeRangeSelector.tsx +407 -0
- package/src/library-components/URLParam.ts +263 -0
- package/src/library-components/colors.tsx +14 -0
- package/src/library-components/drag.ts +114 -0
- package/src/library-components/icons.tsx +692 -0
- package/src/library-components/niceStringify.ts +50 -0
- package/src/library-components/renderToString.ts +52 -0
- package/src/misc/PromiseRace.ts +101 -0
- package/src/misc/color.ts +30 -0
- package/src/misc/getParentProcessId.cs +53 -0
- package/src/misc/getParentProcessId.ts +53 -0
- package/src/misc/hash.ts +83 -0
- package/src/misc/ipPong.js +13 -0
- package/src/misc/networking.ts +2 -0
- package/src/misc/random.ts +45 -0
- package/src/misc.ts +19 -0
- package/src/noserverhotreload.flag +0 -0
- package/src/path.ts +226 -0
- package/src/persistentLocalStore.ts +37 -0
- package/src/promise.ts +15 -0
- package/src/server.ts +73 -0
- package/src/src.d.ts +1 -0
- package/src/test/heapProcess.ts +36 -0
- package/src/test/mongoSatTest.tsx +55 -0
- package/src/test/satTest.ts +193 -0
- package/src/test/test.tsx +552 -0
- package/src/zip.ts +92 -0
- package/src/zipThreaded.ts +106 -0
- package/src/zipThreadedWorker.js +19 -0
- package/tsconfig.json +27 -0
- package/yarnSpec.txt +56 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { cache, cacheLimited } from "socket-function/src/caching";
|
|
2
|
+
import { measureFnc, measureWrap, nameFunction } from "socket-function/src/profiling/measure";
|
|
3
|
+
import { getPathSuffix, getPathDepth, trimPathStrToDepth, getPathFromStr, rootPathStr, getPathIndex, getPathStr1, joinPathStres, appendToPathStr, getPathStr } from "../path";
|
|
4
|
+
import { atomic, atomicObjectRead, isSynced, proxyWatcher } from "../2-proxy/PathValueProxyWatcher";
|
|
5
|
+
import { SchemaObject, getSchemaObject, hasWildcardMatch, getWildcardMatches, PERMISSIONS_FUNCTION_ID, PermissionsCheckResult } from "../3-path-functions/syncSchema";
|
|
6
|
+
import { getModuleFromConfig } from "../3-path-functions/pathFunctionLoader";
|
|
7
|
+
import { getSchemaPartsFromPath, functionSchema, DEPTH_TO_DATA, overrideCurrentCall, CallSpec, FunctionSpec, DOMAIN_INDEX, MODULE_INDEX } from "../3-path-functions/PathFunctionRunner";
|
|
8
|
+
import debugbreak from "debugbreak";
|
|
9
|
+
import { blue, red, yellow } from "socket-function/src/formatting/logColors";
|
|
10
|
+
import { ignoreErrors } from "../errors";
|
|
11
|
+
import { epochTime } from "../0-path-value-core/pathValueCore";
|
|
12
|
+
import { isClient } from "../config2";
|
|
13
|
+
import { sort } from "socket-function/src/misc";
|
|
14
|
+
import { Querysub } from "./QuerysubController";
|
|
15
|
+
import { CALL_PERMISSIONS_KEY } from "./permissionsShared";
|
|
16
|
+
|
|
17
|
+
function watchModule(config: FunctionSpec): NodeJS.Module | undefined {
|
|
18
|
+
let module = getModuleFromConfig(config);
|
|
19
|
+
if (module && typeof module === "object" && module instanceof Promise) {
|
|
20
|
+
// NOTE: The errors should throw correctly when proxyWatch is triggered (which will be immediately
|
|
21
|
+
// after our ignore handler runs), because the underlying implementation should convert promises
|
|
22
|
+
// to throws (or undefined, if errors are ignored).
|
|
23
|
+
ignoreErrors(module);
|
|
24
|
+
proxyWatcher.triggerOnPromiseFinish(module, { waitReason: "waitForModuleToLoad" });
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
return module;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const callPermissionsPath = getPathStr1(CALL_PERMISSIONS_KEY);
|
|
31
|
+
|
|
32
|
+
/** NOTE: This can only be used synchronously, and must be recreated after the current
|
|
33
|
+
* synchronous code is finished.
|
|
34
|
+
*/
|
|
35
|
+
export class PermissionsCheck {
|
|
36
|
+
private dead = false;
|
|
37
|
+
public static skippingChecks = false;
|
|
38
|
+
|
|
39
|
+
public static DEBUG = false;
|
|
40
|
+
|
|
41
|
+
constructor(private callerConfig: { callerMachineId: string; callerIP: string; }) {
|
|
42
|
+
setImmediate(() => this.dead = true);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private perSchema = cache((schema: SchemaObject) => {
|
|
46
|
+
return new PermissionsCheckSchema({ machineID: this.callerConfig.callerMachineId, IP: this.callerConfig.callerIP }, schema);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
private getModulePermissions = cache((domainName: string) => {
|
|
50
|
+
return cache((moduleId: string) => {
|
|
51
|
+
let functionConfigProxy = PermissionsCheck.skipPermissionsChecks(() =>
|
|
52
|
+
functionSchema()[domainName].PathFunctionRunner[moduleId].Sources[PERMISSIONS_FUNCTION_ID],
|
|
53
|
+
);
|
|
54
|
+
const functionConfig = PermissionsCheck.skipPermissionsChecks(() => atomic(functionConfigProxy));
|
|
55
|
+
if (!functionConfig) {
|
|
56
|
+
if (isSynced(functionConfigProxy)) {
|
|
57
|
+
console.warn(red(`Missing path to permissions. You might need to rerun "yarn deploy", ensuring all schemas are imported in a file called "/deploy.ts". Path ${domainName}.${moduleId}.${PERMISSIONS_FUNCTION_ID}`));
|
|
58
|
+
}
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
let module: NodeJS.Module | undefined;
|
|
62
|
+
try {
|
|
63
|
+
module = watchModule(functionConfig);
|
|
64
|
+
} catch (e: any) {
|
|
65
|
+
console.warn(yellow(`Rejecting permissions due to error when loading module ${functionConfig.gitURL}#${functionConfig.gitRef}:${functionConfig.FilePath}\n${e.stack}`));
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!module) return undefined;
|
|
70
|
+
return getSchemaObject(module);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
pathPartsCache = new Map<string, {
|
|
75
|
+
domainName: string;
|
|
76
|
+
moduleId: string;
|
|
77
|
+
pathPrefix: string;
|
|
78
|
+
rootKey: string;
|
|
79
|
+
callExamplePath: string;
|
|
80
|
+
emptyKeyPath: string;
|
|
81
|
+
}>();
|
|
82
|
+
// IMPORTANT! This function USED TO BE a major hotspot for function evaluation, and so is heavily optimized.
|
|
83
|
+
public checkPermissions(path: string): { permissionsPath: string; allowed: boolean; } {
|
|
84
|
+
if (this.dead) throw new Error("PermissionsCheck MUST be used synchronously, after which it cannot be reused");
|
|
85
|
+
if (PermissionsCheck.skippingChecks) return { permissionsPath: rootPathStr, allowed: true };
|
|
86
|
+
|
|
87
|
+
let pathPrefix = trimPathStrToDepth(path, DEPTH_TO_DATA);
|
|
88
|
+
let pathParts = this.pathPartsCache.get(pathPrefix);
|
|
89
|
+
if (!pathParts) {
|
|
90
|
+
const domainName = getPathIndex(path, DOMAIN_INDEX) || "";
|
|
91
|
+
const moduleId = getPathIndex(path, MODULE_INDEX) || "";
|
|
92
|
+
let rootKey = getPathIndex(path, DEPTH_TO_DATA - 1) || "";
|
|
93
|
+
|
|
94
|
+
pathParts = {
|
|
95
|
+
domainName,
|
|
96
|
+
moduleId,
|
|
97
|
+
pathPrefix,
|
|
98
|
+
rootKey,
|
|
99
|
+
callExamplePath: appendToPathStr(pathPrefix, "ExampleCallId"),
|
|
100
|
+
emptyKeyPath: appendToPathStr(pathPrefix, ""),
|
|
101
|
+
};
|
|
102
|
+
this.pathPartsCache.set(pathPrefix, pathParts);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!pathParts.domainName) return { permissionsPath: trimPathStrToDepth(path, DOMAIN_INDEX + 1), allowed: false };
|
|
106
|
+
if (!pathParts.moduleId) return { permissionsPath: trimPathStrToDepth(path, MODULE_INDEX + 1), allowed: false };
|
|
107
|
+
if (!pathParts.rootKey) return { permissionsPath: trimPathStrToDepth(path, DEPTH_TO_DATA), allowed: false };
|
|
108
|
+
|
|
109
|
+
const schema = this.getModulePermissions(pathParts.domainName)(pathParts.moduleId);
|
|
110
|
+
if (!schema) return { permissionsPath: trimPathStrToDepth(path, MODULE_INDEX + 1), allowed: false };
|
|
111
|
+
|
|
112
|
+
let instance = this.perSchema(schema);
|
|
113
|
+
instance.pathPrefix = pathPrefix;
|
|
114
|
+
|
|
115
|
+
const rootKey = pathParts.rootKey;
|
|
116
|
+
|
|
117
|
+
if (rootKey === "Module" || rootKey === "Sources") {
|
|
118
|
+
return instance.checkPermissionsBase(callPermissionsPath);
|
|
119
|
+
}
|
|
120
|
+
if (rootKey === "Calls" || rootKey === "Results") {
|
|
121
|
+
// Don't allow "" call to be read, as this would allow running Object.values() to read all calls.
|
|
122
|
+
if (path === pathParts.emptyKeyPath) return { permissionsPath: path, allowed: false };
|
|
123
|
+
// NOTE: A lot of the time, anyone will technically be able to read calls, as we don't inspect the call.
|
|
124
|
+
// However... they would need to know the id, which will be very hard to guess.
|
|
125
|
+
// - Also inspecting the call adds a lot of call overhead, so we would prefer not to do that.
|
|
126
|
+
let result = instance.checkPermissionsBase(callPermissionsPath);
|
|
127
|
+
return {
|
|
128
|
+
// Make sure the path is specific, so when we are called again callId is not undefined
|
|
129
|
+
permissionsPath: pathParts.callExamplePath,
|
|
130
|
+
allowed: result.allowed
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
if (rootKey === "Data") {
|
|
134
|
+
let dataPath = getPathSuffix(path, DEPTH_TO_DATA);
|
|
135
|
+
return instance.checkPermissionsBase(dataPath);
|
|
136
|
+
}
|
|
137
|
+
return { permissionsPath: path, allowed: false };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
public static ignorePermissionsChecks = this.skipPermissionsChecks;
|
|
141
|
+
public static skipPermissionsChecks<T>(code: () => T) {
|
|
142
|
+
let prev = this.skippingChecks;
|
|
143
|
+
this.skippingChecks = true;
|
|
144
|
+
try {
|
|
145
|
+
return code();
|
|
146
|
+
} finally {
|
|
147
|
+
this.skippingChecks = prev;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
class PermissionsCheckSchema {
|
|
152
|
+
public pathPrefix = rootPathStr;
|
|
153
|
+
|
|
154
|
+
constructor(private callerConfig: { machineID: string; IP: string }, private schema: SchemaObject) { }
|
|
155
|
+
private exampleCall: CallSpec = {
|
|
156
|
+
callerMachineId: this.callerConfig.machineID,
|
|
157
|
+
callerIP: this.callerConfig.IP,
|
|
158
|
+
CallId: "",
|
|
159
|
+
DomainName: "",
|
|
160
|
+
FunctionId: "",
|
|
161
|
+
ModuleId: "",
|
|
162
|
+
runAtTime: epochTime,
|
|
163
|
+
argsEncoded: "",
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/** Converts a specific path to a more general path. All paths which map to this general path
|
|
167
|
+
* will have identical permissions checks.
|
|
168
|
+
*/
|
|
169
|
+
private getCachePermissionsPath(path: string): string {
|
|
170
|
+
if (this.schema.permissionsNonWildcards.has(path)) {
|
|
171
|
+
return path;
|
|
172
|
+
}
|
|
173
|
+
let depth = getPathDepth(path);
|
|
174
|
+
for (let i = depth - 1; i > 0; i--) {
|
|
175
|
+
let ancestorPath = trimPathStrToDepth(path, i);
|
|
176
|
+
if (this.schema.permissionsNonWildcards.has(ancestorPath)) {
|
|
177
|
+
return ancestorPath;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (this.schema.permissionsWildcards.length > 0) {
|
|
181
|
+
let valuePath = getPathFromStr(path);
|
|
182
|
+
// Using a tree would be algorithmically faster, but... might not even be faster in practice?
|
|
183
|
+
// (at least for a small number of checks, which there should almost always be)
|
|
184
|
+
for (let wildcardCheck of this.schema.permissionsWildcards) {
|
|
185
|
+
if (hasWildcardMatch(wildcardCheck.pathParts, valuePath)) {
|
|
186
|
+
return trimPathStrToDepth(path, wildcardCheck.pathParts.length);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return rootPathStr;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// NOTE: For our trivial "127.0.0.1" check this cache isn't needed. But permissions checks might be A LOT slower,
|
|
195
|
+
// so it is important to cache it based on the permissionsPath.
|
|
196
|
+
private checkCache = cacheLimited(1000 * 1000, measureWrap((permissionsPath: string) => {
|
|
197
|
+
let checks = this.getChecks(permissionsPath);
|
|
198
|
+
let allowed = overrideCurrentCall(this.exampleCall, () => {
|
|
199
|
+
// NOTE: If we read inside of a permissions check we don't want to ALSO check
|
|
200
|
+
// permissions checks on those because:
|
|
201
|
+
// 1) It might infinitely loop
|
|
202
|
+
// 2) When checking permissions we need to be allowed to read all values!
|
|
203
|
+
return PermissionsCheck.skipPermissionsChecks(() => {
|
|
204
|
+
for (let check of checks) {
|
|
205
|
+
try {
|
|
206
|
+
let result = check();
|
|
207
|
+
if (!result && PermissionsCheck.DEBUG) {
|
|
208
|
+
let anyUnsynced = false;
|
|
209
|
+
try {
|
|
210
|
+
anyUnsynced = Querysub.anyUnsynced();
|
|
211
|
+
} catch { }
|
|
212
|
+
if (!anyUnsynced) {
|
|
213
|
+
// NOTE: This gets loud, as it happens EVERY TIME we check permissions. We already have a check in QuerysubController,
|
|
214
|
+
// which should be enough.
|
|
215
|
+
//console.log(blue(`Denied permissions for ${joinPathStres(this.pathPrefix, permissionsPath)} due to check at ${(check as any).debugName}`));
|
|
216
|
+
check();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (typeof result === "object") {
|
|
220
|
+
if (!result.allowed) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
if (result.skipParentChecks) {
|
|
224
|
+
return result.allowed;
|
|
225
|
+
}
|
|
226
|
+
} else if (!result) {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
} catch {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return true;
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
return { permissionsPath: joinPathStres(this.pathPrefix, permissionsPath), allowed };
|
|
237
|
+
}, "permissionsCheckInsideCache"));
|
|
238
|
+
|
|
239
|
+
public checkPermissionsBase(dataPath: string): { permissionsPath: string; allowed: boolean; } {
|
|
240
|
+
let permissionsPath = this.getCachePermissionsPath(dataPath);
|
|
241
|
+
return this.checkCache(permissionsPath);
|
|
242
|
+
}
|
|
243
|
+
// NOTE: We don't cache the result of a permissions check, because it might change while
|
|
244
|
+
// a function is evaluating. If they need to be skipped for the purposes of speed (which is hard
|
|
245
|
+
// to believe, considering all the other sources of overhead we have), skipPermissionsChecks
|
|
246
|
+
// can be used to quickly skip them.
|
|
247
|
+
private getChecks = cacheLimited(1000 * 1000, ((path: string): (() => PermissionsCheckResult)[] => {
|
|
248
|
+
let checks: {
|
|
249
|
+
check: () => PermissionsCheckResult;
|
|
250
|
+
path: string;
|
|
251
|
+
}[] = [];
|
|
252
|
+
let depth = getPathDepth(path);
|
|
253
|
+
for (let i = depth; i >= 0; i--) {
|
|
254
|
+
let ancestorPath = trimPathStrToDepth(path, i);
|
|
255
|
+
const permissions = this.schema.permissionsNonWildcards.get(ancestorPath);
|
|
256
|
+
if (permissions) {
|
|
257
|
+
let check = () => permissions({
|
|
258
|
+
callerMachineId: this.callerConfig.machineID,
|
|
259
|
+
matchedPath: ancestorPath,
|
|
260
|
+
pathWildcards: [],
|
|
261
|
+
});
|
|
262
|
+
if (PermissionsCheck.DEBUG) {
|
|
263
|
+
Object.assign(check, { debugName: ancestorPath });
|
|
264
|
+
}
|
|
265
|
+
checks.push({ check, path: ancestorPath });
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
// Using a tree would be algorithmically faster, but... might not even be faster in practice?
|
|
269
|
+
// (at least for a small number of checks, which there should almost always be)
|
|
270
|
+
for (let wildcardCheck of this.schema.permissionsWildcards) {
|
|
271
|
+
let matches = getWildcardMatches(wildcardCheck.pathParts, getPathFromStr(path));
|
|
272
|
+
if (!matches) continue;
|
|
273
|
+
let matchedPath = trimPathStrToDepth(path, wildcardCheck.pathParts.length);
|
|
274
|
+
let check = () => wildcardCheck.callback({
|
|
275
|
+
callerMachineId: this.callerConfig.machineID,
|
|
276
|
+
matchedPath,
|
|
277
|
+
pathWildcards: matches || [],
|
|
278
|
+
});
|
|
279
|
+
if (PermissionsCheck.DEBUG) {
|
|
280
|
+
Object.assign(check, { debugName: wildcardCheck.pathParts.join(".") });
|
|
281
|
+
}
|
|
282
|
+
checks.push({ check, path: matchedPath });
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
sort(checks, x => -x.path.length);
|
|
286
|
+
|
|
287
|
+
return checks.map(x => x.check);
|
|
288
|
+
}));
|
|
289
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const CALL_PERMISSIONS_KEY = "CALL_PERMISSIONS_KEY" as "CALL_PERMISSIONS_KEY";
|