acts framework
This commit is contained in:
parent
adf061f7dd
commit
1fbe8d69cb
11 changed files with 442 additions and 35 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
config.juml
|
config.juml
|
||||||
.vscode
|
.vscode
|
||||||
|
test
|
13
package-lock.json
generated
13
package-lock.json
generated
|
@ -9,6 +9,7 @@
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"auth-header": "^1.0.0",
|
||||||
"commander": "^10.0.0",
|
"commander": "^10.0.0",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"dblang": "https://jusax.de/git/attachments/c13552b7-c9f0-4f50-bcce-96a124c1c286",
|
"dblang": "https://jusax.de/git/attachments/c13552b7-c9f0-4f50-bcce-96a124c1c286",
|
||||||
|
@ -19,6 +20,7 @@
|
||||||
"ws": "^8.12.1"
|
"ws": "^8.12.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/auth-header": "^1.0.2",
|
||||||
"@types/cors": "^2.8.13",
|
"@types/cors": "^2.8.13",
|
||||||
"@types/express": "^4.17.17",
|
"@types/express": "^4.17.17",
|
||||||
"@types/node": "^18.11.18",
|
"@types/node": "^18.11.18",
|
||||||
|
@ -513,6 +515,12 @@
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/auth-header": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/auth-header/-/auth-header-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-KWpTfyz+F5GtURfp7W9c4ubFSXaPAvb1dUN5MlU3xSvlNIYhFrmrTNE7vd6SUOfSOO7FI/ePe03Y/KCPM/YOoA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/body-parser": {
|
"node_modules/@types/body-parser": {
|
||||||
"version": "1.19.2",
|
"version": "1.19.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
|
||||||
|
@ -725,6 +733,11 @@
|
||||||
"node": ">= 4.0.0"
|
"node": ">= 4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/auth-header": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/auth-header/-/auth-header-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-CPPazq09YVDUNNVWo4oSPTQmtwIzHusZhQmahCKvIsk0/xH6U3QsMAv3sM+7+Q0B1K2KJ/Q38OND317uXs4NHA=="
|
||||||
|
},
|
||||||
"node_modules/base64-js": {
|
"node_modules/base64-js": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"main": "tsc && node . -c config.juml",
|
"main": "tsc && node . -c config.juml",
|
||||||
|
"debug": "tsc && node . -c config.juml -d",
|
||||||
"setup": "tsc && node . -c config.juml -s"
|
"setup": "tsc && node . -c config.juml -s"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -18,6 +19,7 @@
|
||||||
"author": "jusax23, comcloudway",
|
"author": "jusax23, comcloudway",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/auth-header": "^1.0.2",
|
||||||
"@types/cors": "^2.8.13",
|
"@types/cors": "^2.8.13",
|
||||||
"@types/express": "^4.17.17",
|
"@types/express": "^4.17.17",
|
||||||
"@types/node": "^18.11.18",
|
"@types/node": "^18.11.18",
|
||||||
|
@ -29,6 +31,7 @@
|
||||||
"typescript": "^4.9.4"
|
"typescript": "^4.9.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"auth-header": "^1.0.0",
|
||||||
"commander": "^10.0.0",
|
"commander": "^10.0.0",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"dblang": "https://jusax.de/git/attachments/c13552b7-c9f0-4f50-bcce-96a124c1c286",
|
"dblang": "https://jusax.de/git/attachments/c13552b7-c9f0-4f50-bcce-96a124c1c286",
|
||||||
|
|
1
src/api/acts.ts
Normal file
1
src/api/acts.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from "./acts/login.js"
|
14
src/api/acts/login.ts
Normal file
14
src/api/acts/login.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { Act, Client, STATE } from "../user.js";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const dummy:Act = {
|
||||||
|
state: STATE.no,
|
||||||
|
right: 0,
|
||||||
|
data: {
|
||||||
|
sign: "string"
|
||||||
|
},
|
||||||
|
func: async (client: Client, data, aws) => {
|
||||||
|
aws("ok","dummy");
|
||||||
|
}
|
||||||
|
};
|
146
src/api/post.ts
146
src/api/post.ts
|
@ -1,5 +1,149 @@
|
||||||
import express from "express";
|
import express from "express";
|
||||||
|
import { Act, checktype, Client, STATE } from "./user.js";
|
||||||
|
import { debug, error } from "../sys/log.js";
|
||||||
|
import * as authorization from 'auth-header';
|
||||||
|
import * as importActs from "./acts.js"
|
||||||
|
import { and, eq, select } from "dblang";
|
||||||
|
import { accounts } from "../sys/db.js";
|
||||||
|
import { db } from "../sys/db.js"
|
||||||
|
import { sha256 } from "../sys/crypto.js";
|
||||||
|
import { get64, uts } from "../sys/tools.js";
|
||||||
|
import { addShutdownTask } from "nman";
|
||||||
|
|
||||||
|
let acts = importActs as { [key: string]: Act };
|
||||||
|
|
||||||
|
let tempTokens: { [key: string]: postClient } = {};
|
||||||
|
|
||||||
export const addPostMethods = (server: express.Express) => {
|
export const addPostMethods = (server: express.Express) => {
|
||||||
|
for (const act in acts) {
|
||||||
|
let methode = acts[act];
|
||||||
|
server.post("/api/" + act, async (req, res) => {
|
||||||
|
debug("POST", "reveived:", req.body);
|
||||||
|
const aws = (state: string, data: any) => {
|
||||||
|
res.status(state == "error" ? 400 : 200);
|
||||||
|
if (typeof data == "string") res.send(data);
|
||||||
|
else res.json(data);
|
||||||
|
};
|
||||||
|
let client: postClient | null = null;
|
||||||
|
try {
|
||||||
|
let auth = authorization.parse(req.headers["authorization"] ?? "");
|
||||||
|
if (auth.token != null && typeof auth.token == "string") {
|
||||||
|
if (tempTokens[auth.token] != null) {
|
||||||
|
client = tempTokens[auth.token];
|
||||||
|
} else {
|
||||||
|
aws("error", "token");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (auth?.params?.name != null && auth?.params?.accountKey != null && typeof auth?.params?.name == "string" && typeof auth?.params?.accountKey == "string") {
|
||||||
|
client = new postClient(req.socket.remoteAddress ?? "");
|
||||||
|
client.name = auth?.params?.name;
|
||||||
|
client.server = "localhost";
|
||||||
|
let accountKey = auth?.params?.accountKey;
|
||||||
|
|
||||||
}
|
let query = await select([accounts.accID, accounts.accountKey, accounts.accountKeySalt], accounts)
|
||||||
|
.where(and(
|
||||||
|
eq(accounts.name, client.name),
|
||||||
|
eq(accounts.deleted, 0)
|
||||||
|
))
|
||||||
|
.query(db);
|
||||||
|
|
||||||
|
if (query.length == 0 || query[0].accountKey != sha256((query[0].accountKeySalt ?? '') + accountKey)) {
|
||||||
|
client.suspect();
|
||||||
|
aws("error", "auth");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
client.accID = query[0][accounts.accID];
|
||||||
|
client.state = STATE.client;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client == null) client = new postClient(req.socket.remoteAddress ?? "");
|
||||||
|
let send = false;
|
||||||
|
await client.runAct(methode, req.body, (state: string, data: any) => {
|
||||||
|
aws(state, data);
|
||||||
|
send = true;
|
||||||
|
});
|
||||||
|
if (!send) aws("error", "server");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class postClient extends Client {
|
||||||
|
lastReq = uts();
|
||||||
|
constructor(ip: string) {
|
||||||
|
super(ip);
|
||||||
|
}
|
||||||
|
async runAct(act: Act, json: any, aws: (state: string, data: any) => void) {
|
||||||
|
this.lastReq = uts();
|
||||||
|
try {
|
||||||
|
let { state, data, right, func } = act;
|
||||||
|
if (!(state & this.state)) {
|
||||||
|
aws("error", "wrongstate");
|
||||||
|
debug("POST", "send:", "error", "wrongstate");
|
||||||
|
this.suspect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (json.data === null) {
|
||||||
|
aws("error", "data");
|
||||||
|
debug("POST", "send:", "error", "data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (data) {
|
||||||
|
for (let d in data) {
|
||||||
|
if (!checktype(json.data[d], data[d])) {
|
||||||
|
aws("error", "data");
|
||||||
|
debug("POST", "Data check error. Key: ", d, "; Type:", data[d], "; Value:", json.data[d]);
|
||||||
|
debug("POST", "send:", "error", "data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (right && !(await this.checkRight(right))) {
|
||||||
|
aws("error", "right");
|
||||||
|
debug("POST", "send:", "error", "right");
|
||||||
|
this.suspect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var send = false;
|
||||||
|
try {
|
||||||
|
await func(this, json.data, (state, data = "") => {
|
||||||
|
debug("POST", "send:", state, data);
|
||||||
|
aws(state, data);
|
||||||
|
send = true;
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
error("POST", "act error:", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!send) {
|
||||||
|
debug("POST", "send:", "error", "server");
|
||||||
|
aws("error", "server");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
debug("POST", "error:", error);
|
||||||
|
aws("error", "server");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const addTempToken = (client: Client) => {
|
||||||
|
if (!(client instanceof postClient)) return false;
|
||||||
|
let token = get64(128);
|
||||||
|
if (tempTokens[token] != null) token = get64(128);
|
||||||
|
if (tempTokens[token] != null) token = get64(128);
|
||||||
|
if (tempTokens[token] != null) return false;
|
||||||
|
tempTokens[token] = client;
|
||||||
|
return token;
|
||||||
|
};
|
||||||
|
|
||||||
|
addShutdownTask(() => {
|
||||||
|
let keys = Object.keys(tempTokens);
|
||||||
|
for (let i = 0; i < keys.length; i++) {
|
||||||
|
const c = tempTokens[keys[i]];
|
||||||
|
if (c.lastReq + 60 * 60 * 3 < uts()) {
|
||||||
|
delete tempTokens[keys[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 1000);
|
117
src/api/user.ts
117
src/api/user.ts
|
@ -1,16 +1,115 @@
|
||||||
|
import { and, eq, naturalJoin, select, update } from "dblang";
|
||||||
|
import { accounts, db, roomMembers, rooms } from "../sys/db.js";
|
||||||
|
import { addBruteforcePotantial } from "../sys/bruteforce.js";
|
||||||
|
|
||||||
export const STATE = {
|
export const STATE = {
|
||||||
no: 0b0001,
|
no: 0b0001,
|
||||||
remoteP: 0b0010,
|
remoteP: 0b0010,
|
||||||
remote: 0b0100,
|
remote: 0b0100,
|
||||||
client: 0b1000,
|
client: 0b1000
|
||||||
};
|
};
|
||||||
|
|
||||||
export abstract class Client{
|
export const MODE = {
|
||||||
name: String;
|
ws: 0b01,
|
||||||
server: String;
|
post: 0b10,
|
||||||
ip: String;
|
both: 0b11,
|
||||||
rights: number;
|
};
|
||||||
state: number;
|
|
||||||
accID = -1;
|
export type Act = {
|
||||||
|
state: number,
|
||||||
|
right: number,
|
||||||
|
data: {
|
||||||
|
[key: string]: any
|
||||||
|
},
|
||||||
|
func: (client: Client, data: any, aws: (code: string, data: any) => void) => Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class Client {
|
||||||
|
name: string = "";
|
||||||
|
server: string = "";
|
||||||
|
ip: string = "";
|
||||||
|
state: number = STATE.no;
|
||||||
|
|
||||||
|
accID: number = -1;
|
||||||
|
|
||||||
|
constructor(ip: string) {
|
||||||
|
this.ip = ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
suspect() {
|
||||||
|
addBruteforcePotantial(this.ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
async isInRoom(name: string): Promise<number> {
|
||||||
|
if (this.state != STATE.client) return -1;
|
||||||
|
let query = await select([rooms.roomID], naturalJoin(rooms, roomMembers))
|
||||||
|
.where(and(
|
||||||
|
eq(rooms.name, name),
|
||||||
|
eq(roomMembers.name, this.name),
|
||||||
|
eq(roomMembers.server, this.server)
|
||||||
|
))
|
||||||
|
.query(db);
|
||||||
|
if (query.length == 0) return -1;
|
||||||
|
return query[0][rooms.roomID];
|
||||||
|
}
|
||||||
|
async isRoomAdmin(name: string, roomRightRequires: number): Promise<number> {
|
||||||
|
if (this.state != STATE.client) return -1;
|
||||||
|
let query = await select([rooms.roomID, rooms.owner, rooms.rights, roomMembers.admin], naturalJoin(rooms, roomMembers))
|
||||||
|
.where(and(
|
||||||
|
eq(rooms.name, name),
|
||||||
|
eq(roomMembers.admin, true),
|
||||||
|
eq(roomMembers.name, this.name),
|
||||||
|
eq(roomMembers.server, this.server)
|
||||||
|
))
|
||||||
|
.query(db);
|
||||||
|
if (query.length == 0) return -1;
|
||||||
|
if (
|
||||||
|
query[0][roomMembers.admin] == 0
|
||||||
|
&& query[0][rooms.owner] != this.accID
|
||||||
|
&& !(query[0][rooms.rights] & roomRightRequires)
|
||||||
|
) return -1;
|
||||||
|
return query[0][rooms.roomID];
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkRight(right: number) {
|
||||||
|
try {
|
||||||
|
if (right == 0) return true;
|
||||||
|
let data = await select([accounts.rights], accounts)
|
||||||
|
.where(eq(accounts.accID, this.accID))
|
||||||
|
.query(db);
|
||||||
|
return ((data[0][accounts.rights]) & right) == right;
|
||||||
|
} catch (e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
async setRights(rights: number) {
|
||||||
|
await update(accounts)
|
||||||
|
.set(accounts.rights, rights)
|
||||||
|
.where(eq(accounts.accID, this.accID))
|
||||||
|
.query(db);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function checktype(data: any, type: string) {
|
||||||
|
const re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||||
|
if (typeof data == type) {
|
||||||
|
return true;
|
||||||
|
} else if (type == "int" && typeof data == "number" && Number.isInteger(data)) {
|
||||||
|
return true;
|
||||||
|
} else if (type == "email" && typeof data == "string" && re.test(data)) {
|
||||||
|
return true;
|
||||||
|
} else if (type == "name" && typeof data == "string" && /^[a-zA-Z0-9\-_.]+$/.test(data)) {
|
||||||
|
return true;
|
||||||
|
} else if (type.startsWith("name-") && typeof data == "string" && /^[a-zA-Z0-9\-_.]+$/.test(data)) {
|
||||||
|
return parseInt(type.split("-")[1]) >= data.length;
|
||||||
|
} else if (type.startsWith("string-") && typeof data == "string") {
|
||||||
|
return parseInt(type.split("-")[1]) >= data.length;
|
||||||
|
} else if (type == "any") {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
153
src/api/ws.ts
153
src/api/ws.ts
|
@ -1,6 +1,155 @@
|
||||||
import ws from "ws";
|
import ws from "ws";
|
||||||
import http from "http";
|
import http from "http";
|
||||||
|
import { bruteforcecheck } from "../sys/bruteforce.js";
|
||||||
|
import { Act, checktype, Client } from "./user.js";
|
||||||
|
import { debug, error } from "../sys/log.js";
|
||||||
|
import * as importActs from "./acts.js"
|
||||||
|
|
||||||
export const wsOnConnection = (socket:ws.WebSocket, req: http.IncomingMessage) => {
|
let acts = importActs as { [key: string]: Act };
|
||||||
|
|
||||||
}
|
export const wsOnConnection = (socket: ws.WebSocket, req: http.IncomingMessage) => {
|
||||||
|
let ip = req.socket.remoteAddress;
|
||||||
|
if (bruteforcecheck(ip ?? "")) return void socket.close();
|
||||||
|
new wsClient(socket, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
let clients: wsClient[] = [];
|
||||||
|
|
||||||
|
class wsClient extends Client {
|
||||||
|
socket: ws.WebSocket;
|
||||||
|
open = true;
|
||||||
|
activeRequests = 0;
|
||||||
|
constructor(socket: ws.WebSocket, req: http.IncomingMessage) {
|
||||||
|
super(req.socket.remoteAddress ?? "");
|
||||||
|
this.socket = socket;
|
||||||
|
|
||||||
|
socket.on("message", async (msg: any) => {
|
||||||
|
try {
|
||||||
|
this.activeRequests++;
|
||||||
|
let msgStr = msg.toString();
|
||||||
|
debug("WebSocket", "reveived:", msgStr);
|
||||||
|
let json = JSON.parse(msgStr) as { act: string, id: number, data: any };
|
||||||
|
if (closed) {
|
||||||
|
socket.send(JSON.stringify({
|
||||||
|
id: json.id,
|
||||||
|
state: "error",
|
||||||
|
data: "closed"
|
||||||
|
}));
|
||||||
|
debug("WebSocket", "send:", "error", "closed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof json.act != "string") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (acts[json.act] == null) {
|
||||||
|
socket.send(JSON.stringify({
|
||||||
|
id: json.id,
|
||||||
|
state: "error",
|
||||||
|
data: "notfound"
|
||||||
|
}));
|
||||||
|
debug("WebSocket", "send:", "error", "notfound");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let { state, data, right, func } = acts[json.act];
|
||||||
|
if (!(state & this.state)) {
|
||||||
|
socket.send(JSON.stringify({
|
||||||
|
id: json.id,
|
||||||
|
state: "error",
|
||||||
|
data: "wrongstate"
|
||||||
|
}));
|
||||||
|
debug("WebSocket", "send:", "error", "wrongstate");
|
||||||
|
this.suspect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (json.data === null) {
|
||||||
|
socket.send(JSON.stringify({
|
||||||
|
id: json.id,
|
||||||
|
state: "error",
|
||||||
|
data: "data"
|
||||||
|
}));
|
||||||
|
debug("POST", "send:", "error", "data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (data) {
|
||||||
|
for (let d in data) {
|
||||||
|
if (!checktype(json.data[d], data[d])) {
|
||||||
|
socket.send(JSON.stringify({
|
||||||
|
id: json.id,
|
||||||
|
state: "error",
|
||||||
|
data: "data"
|
||||||
|
}));
|
||||||
|
debug("WebSocket", "Data check error. Key: ", d, "; Type:", data[d], "; Value:", json.data[d]);
|
||||||
|
debug("WebSocket", "send:", "error", "data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (right && !(await this.checkRight(right))) {
|
||||||
|
socket.send(JSON.stringify({
|
||||||
|
id: json.id,
|
||||||
|
state: "error",
|
||||||
|
data: "right"
|
||||||
|
}));
|
||||||
|
debug("WebSocket", "send:", "error", "right");
|
||||||
|
this.suspect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var send = false;
|
||||||
|
try {
|
||||||
|
await func(this, json.data, (state, data = "") => {
|
||||||
|
debug("WebSocket", "send:", state, data);
|
||||||
|
socket.send(JSON.stringify({ id: json.id, state, data }));
|
||||||
|
send = true;
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
error("WebSocket", "act error:", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!send) {
|
||||||
|
debug("WebSocket", "send:", "error", "server");
|
||||||
|
socket.send(JSON.stringify({
|
||||||
|
id: json.id,
|
||||||
|
state: "error",
|
||||||
|
data: "server"
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
debug("WebSocket", "error:", error);
|
||||||
|
socket.send("error");
|
||||||
|
} finally {
|
||||||
|
this.activeRequests--;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('close', () => {
|
||||||
|
var i = clients.indexOf(this);
|
||||||
|
delete clients[i];
|
||||||
|
if (i >= 0) {
|
||||||
|
clients.splice(i, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
close(ms: number) {
|
||||||
|
return new Promise<void>(res => {
|
||||||
|
if (this.activeRequests == 0) {
|
||||||
|
this.socket.close();
|
||||||
|
return void res();
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
this.socket.close();
|
||||||
|
res();
|
||||||
|
}, Math.max(100, ms));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const closeWebSocket = async () => {
|
||||||
|
for (let i = 0; i < clients.length; i++) {
|
||||||
|
clients[i].open = false;
|
||||||
|
}
|
||||||
|
var now = performance.now();
|
||||||
|
for (let i = 0; i < clients.length; i++) {
|
||||||
|
await clients[i].close(now - performance.now() + 25000);
|
||||||
|
}
|
||||||
|
};
|
|
@ -17,23 +17,3 @@ export const PERMISSIONS = {
|
||||||
EDIT_USERS: 0b1000000000000000,
|
EDIT_USERS: 0b1000000000000000,
|
||||||
ALL: 0b1111111111111111,
|
ALL: 0b1111111111111111,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const checkRight = async (accID: number, right: number) => {
|
|
||||||
try {
|
|
||||||
if (right == 0) return true;
|
|
||||||
let data = await select([accounts.rights], accounts)
|
|
||||||
.where(eq(accounts.accID, accID))
|
|
||||||
.query(db);
|
|
||||||
return ((data[0][accounts.rights]) & right) == right;
|
|
||||||
} catch (e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const setRights = async (accID: number, rights: number) => {
|
|
||||||
await update(accounts)
|
|
||||||
.set(accounts.rights, rights)
|
|
||||||
.where(eq(accounts.accID, accID))
|
|
||||||
.query(db);
|
|
||||||
};
|
|
|
@ -28,7 +28,7 @@ const loading = () => {
|
||||||
process.stdout.write("\r\x1b[1m" + P[(x++) % P.length]+" ");
|
process.stdout.write("\r\x1b[1m" + P[(x++) % P.length]+" ");
|
||||||
}, 150);
|
}, 150);
|
||||||
return () => {
|
return () => {
|
||||||
process.stdout.write("\r");
|
process.stdout.write("\r\x1b[0m");
|
||||||
clearInterval(intID)
|
clearInterval(intID)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -109,7 +109,10 @@ roomMembers.addAttributes({
|
||||||
onDelete: onAction.cascade,
|
onDelete: onAction.cascade,
|
||||||
onUpdate: onAction.cascade
|
onUpdate: onAction.cascade
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
name: { type: TEXT },
|
||||||
|
server: { type: TEXT },
|
||||||
|
admin: { type: BOOL, default: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
export const roomOTAs = db.newTable("roomOTAs");
|
export const roomOTAs = db.newTable("roomOTAs");
|
||||||
|
|
Loading…
Reference in a new issue