This repository has been archived on 2021-06-02. You can view files and clone it, but cannot push or open issues or pull requests.
RealtimeDB-OLD/src/database/rules.ts

126 lines
2.8 KiB
TypeScript

import Session from "./session";
import Logging from "@hibas123/nodelogging";
interface IRule<T> {
".write"?: T;
".read"?: T;
}
type IRuleConfig<T> =
| IRule<T>
| {
[segment: string]: IRuleConfig<T>;
};
type IRuleRaw = IRuleConfig<string>;
type IRuleParsed = IRuleConfig<boolean>;
const resolve = (value: any) => {
if (value === true) {
return true;
} else if (typeof value === "string") {
}
return undefined;
};
export class Rules {
rules: IRuleParsed;
constructor(private config: string) {
let parsed: IRuleRaw = JSON.parse(config);
const analyse = (raw: IRuleRaw) => {
let r: IRuleParsed = {};
if (raw[".read"]) {
let res = resolve(raw[".read"]);
if (res) {
r[".read"] = res;
}
delete raw[".read"];
}
if (raw[".write"]) {
let res = resolve(raw[".write"]);
if (res) {
r[".write"] = res;
}
delete raw[".write"];
}
for (let segment in raw) {
if (segment.startsWith(".")) continue;
r[segment] = analyse(raw[segment]);
}
return r;
};
this.rules = analyse(parsed);
}
hasPermission(
path: string[],
session: Session
): { read: boolean; write: boolean; path: string[] } {
if (session.root)
return {
read: true,
write: true,
path: path
};
let read = this.rules[".read"] || false;
let write = this.rules[".write"] || false;
let rules = this.rules;
for (let idx in path) {
let segment = path[idx];
if (segment.startsWith(".")) {
read = false;
write = false;
Logging.log("Invalid query path (started with '$' or '.'):", path);
break;
}
let k = Object.keys(rules)
.filter(e => e.startsWith("$"))
.find(e => {
switch (e) {
case "$uid":
if (segment === "$uid") {
path[idx] = session.uid;
return true;
}
if (segment === session.uid) return true;
break;
}
return false;
});
rules = (k ? rules[k] : undefined) || rules[segment] || rules["*"];
if (rules) {
if (rules[".read"]) {
read = rules[".read"];
}
if (rules[".write"]) {
read = rules[".write"];
}
} else {
break;
}
}
return {
read: read as boolean,
write: write as boolean,
path
};
}
toJSON() {
return this.config;
}
}