From d81433a0f34d02aa15546015c922e60892c4846e Mon Sep 17 00:00:00 2001 From: jusax23 Date: Mon, 20 Mar 2023 16:26:06 +0100 Subject: [PATCH] remote passing --- .gitignore | 1 + package-lock.json | 8 +-- package.json | 3 +- src/api/acts/login.ts | 46 ++++++++++++- src/api/acts/rooms.ts | 154 ++++++++++++++++++++++++++++++++++-------- src/api/post.ts | 27 ++++++-- src/api/server.ts | 95 ++++++++++++++++++++++++++ src/api/user.ts | 37 +++++++--- src/sys/db.ts | 42 +++++++++--- src/sys/selfTag.ts | 2 +- tests/tests/post.js | 4 +- tests/tests/ws.js | 4 +- 12 files changed, 358 insertions(+), 65 deletions(-) create mode 100644 src/api/server.ts diff --git a/.gitignore b/.gitignore index e66b282..c761d7b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ node_modules dist config.juml +config2.juml .vscode test build diff --git a/package-lock.json b/package-lock.json index 9f0287d..166767f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "auth-header": "^1.0.0", "commander": "^10.0.0", "cors": "^2.8.5", - "dblang": "https://jusax.de/git/attachments/f23f8128-4fde-4ec6-a8cd-cfc5068b2cfd", + "dblang": "https://jusax.de/git/attachments/18f6a160-3695-4182-97a4-c2d9af97e60a", "express": "^4.18.2", "juml": "https://jusax.de/git/attachments/208913c5-2851-4b86-a53d-ca99fed168cc", "nman": "https://jusax.de/git/attachments/5333948b-fe6b-45d2-9230-ca388f6a89bc", @@ -1107,9 +1107,9 @@ } }, "node_modules/dblang": { - "version": "0.8.0", - "resolved": "https://jusax.de/git/attachments/f23f8128-4fde-4ec6-a8cd-cfc5068b2cfd", - "integrity": "sha512-hHfxa5iHD3fumMzH/LvVwB2kPUfs1TsxRdOS1veIppfgsJNUxqxPdEljd+EluWpHrPklfO3AJr2vWiZe4N0NBg==", + "version": "0.9.0", + "resolved": "https://jusax.de/git/attachments/18f6a160-3695-4182-97a4-c2d9af97e60a", + "integrity": "sha512-qDgygqUM1ykyKsy1IVdybzbBoBvQW1I9Qq6Sh8TS5rAcJnCHI7gyp2PxvqpK82bJsGL2NLBNBwKqhfetLdrJNw==", "license": "UNLICENSED", "dependencies": { "gitea-release": "git+https://jusax.de/git/jusax23/gitea-release.git", diff --git a/package.json b/package.json index 24415ef..ac567c5 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "prepublish": "tsc", "main": "tsc && node . -c config.juml", "debug": "tsc && node . -c config.juml -d -l 256", + "debug2": "tsc && node . -c config2.juml -d -l 256", "setup": "tsc && node . -c config.juml -s", "bundleRelease": "mkdir build/bundle & esbuild src/main.ts --platform=node --bundle --minify --outfile=build/bundle/main.js", "build-linux-x64": "mkdir build/bin & pkg -t node18-linux-x64 -o build/bin/outbag-linux-x64 build/bundle/main.js", @@ -54,7 +55,7 @@ "auth-header": "^1.0.0", "commander": "^10.0.0", "cors": "^2.8.5", - "dblang": "https://jusax.de/git/attachments/f23f8128-4fde-4ec6-a8cd-cfc5068b2cfd", + "dblang": "https://jusax.de/git/attachments/18f6a160-3695-4182-97a4-c2d9af97e60a", "express": "^4.18.2", "juml": "https://jusax.de/git/attachments/208913c5-2851-4b86-a53d-ca99fed168cc", "nman": "https://jusax.de/git/attachments/5333948b-fe6b-45d2-9230-ca388f6a89bc", diff --git a/src/api/acts/login.ts b/src/api/acts/login.ts index ebff4fc..1980b49 100644 --- a/src/api/acts/login.ts +++ b/src/api/acts/login.ts @@ -202,4 +202,48 @@ export const remote2 = { aws("error", "signature"); } } -}; \ No newline at end of file +}; + +export const remoteServer1 = { + state: STATE.no, + right: 0, + data: { + server: "string", + }, + func: async (client: Client, data: any, aws: (code: string, data: any) => void) => { + try { + let server = await outbagURLfromTag(data.server); + client.remoteKey = await getRemote(server); + client.server = server; + client.state = STATE.serverP; + let c = new postClient(client.ip, client); + let token = addTempToken(c); + let challenge = get64(64); + client.challenge = challenge; + aws("ok", { + token, + challenge + }); + } catch (e) { + client.suspect(); + aws("error", "existence"); + } + } +}; + +export const remoteServer2 = { + state: STATE.serverP, + right: 0, + data: { + sign: "string" + }, + func: async (client: Client, data: any, aws: (code: string, data: any) => void) => { + if (await verify(client.challenge, data.sign, client.remoteKey)) { + aws("ok", ""); + client.state = STATE.server; + } else { + client.suspect(); + aws("error", "signature"); + } + } +}; \ No newline at end of file diff --git a/src/api/acts/rooms.ts b/src/api/acts/rooms.ts index c955ca8..50322f6 100644 --- a/src/api/acts/rooms.ts +++ b/src/api/acts/rooms.ts @@ -1,11 +1,13 @@ import { alias, and, eq, exists, innerJoinOn, innerJoinUsing, insert, le, minus, naturalJoin, not, or, remove, select, update } from "dblang"; +import { checkSelfTag } from "../../server/outbagURL.js"; import { ROOM_RIGHTS } from "../../server/permissions.js"; -import { accounts, db, roomMembers, roomOTAs, rooms } from "../../sys/db.js"; +import { accounts, db, remoteRooms, roomMembers, roomOTAs, rooms } from "../../sys/db.js"; +import { selfTag } from "../../sys/selfTag.js"; import { uts } from "../../sys/tools.js"; import { isRoomFull } from "../helper.js"; import { Act, Client, STATE } from "../user.js"; -export const listLocalRooms: Act = { +export const listRooms: Act = { state: STATE.client | STATE.remote, right: 0, data: {}, @@ -36,11 +38,30 @@ export const listLocalRooms: Act = { let title = d[rooms.title]; let description = d[rooms.description]; let icon = d[rooms.icon]; + let server = selfTag.tag; if (name != null && owner != null && rights != null && visibility != null && title != null && description != null && icon != null) { - return { name, owner, rights, visibility, title, description, icon }; + return { name, server, owner, rights, visibility, title, description, icon }; } return null; - }); + }) + if (client.state == STATE.client) { + let query = await select([remoteRooms.server], remoteRooms) + .where(eq(remoteRooms.accID, client.accID)) + .query(db); + for (let i = 0; i < query.length; i++) { + const server = query[i]; + let resp = await client.pass(server[remoteRooms.server], "listRooms", {}); + if (resp.state == "ok" && Array.isArray(resp.data)) { + out.push(...resp.data.map(d => { + let { name, owner, rights, visibility, title, description, icon, server } = d; + if (name != null && owner != null && rights != null && visibility != null && title != null && description != null && icon != null) { + return { name, server, owner, rights, visibility, title, description, icon }; + } + return null; + })) + } + } + } aws("ok", out.filter(d => d != null)); } }; @@ -50,10 +71,17 @@ export const getRoomMembers: Act = { right: 0, data: { room: "name", - server: "string", // Unused at the Moment + server: "string", }, func: async (client: Client, data: any, aws: (code: string, data: any) => void) => { + if (!checkSelfTag(data.server)) { + let resp = await client.pass(data.server, "getRoomMembers", data); + aws(resp.state, resp.data); + return; + } + let roomID = await client.isInRoom(data.room); + console.log(data, client.server.tag, client.name, roomID); if (roomID == -1) { aws("error", "existence"); return; @@ -63,12 +91,13 @@ export const getRoomMembers: Act = { roomMembers.server, roomMembers.admin ], roomMembers) - .where(eq(rooms.roomID, roomID)) + .where(eq(roomMembers.roomID, roomID)) .query(db); let out = req.map(d => { let name = d[roomMembers.name]; let server = d[roomMembers.server]; let admin = d[roomMembers.admin]; + server = server == "local" ? selfTag.tag : server; if (name != null && server != null && admin != null) { return { name, server, admin }; } @@ -83,15 +112,27 @@ export const joinRoom: Act = { right: 0, data: { room: "string", - server: "string", // Unused at the Moment + server: "string", token: "string" //OTA }, func: async (client: Client, data: any, aws: (code: string, data: any) => void) => { + if (!checkSelfTag(data.server)) { + let resp = await client.pass(data.server, "joinRoom", data); + if (resp.state == "ok") { + //TODO: add server to personal list + } else if (resp.data == "ota") { + client.suspect(); + client.suspect(); + } + aws(resp.state, resp.data); + return; + } let query = await select([rooms.roomID], rooms) .where(eq(rooms.name, data.room)) .query(db); let roomID = (query[0] ?? {})[rooms.roomID]; if (typeof roomID != "number" || roomID < 0) { + client.suspect(); return void aws("error", "ota"); } if (await isRoomFull(roomID)) return void aws("error", "limit"); @@ -107,20 +148,26 @@ export const joinRoom: Act = { .where(eq(roomOTAs.usesLeft, 0)) .query(db); if (req.affectedRows == 0) { + client.suspect(); return void aws("error", "ota"); } - let queryx = await insert( - roomMembers.roomID, - roomMembers.name, - roomMembers.server, - roomMembers.admin - ).add(roomID, client.name, client.server.tag, 0) - .query(db); - if (queryx.affectedRows > 0) { - aws("ok", ""); - } else { - aws("error", "server"); + try { + let queryx = await insert( + roomMembers.roomID, + roomMembers.name, + roomMembers.server, + roomMembers.admin + ).add(roomID, client.name, client.server.tag, 0) + .query(db); + if (queryx.affectedRows > 0) { + aws("ok", ""); + } else { + aws("error", "duplicate"); + } + } catch (error) { + aws("error", "duplicate"); } + } }; @@ -129,9 +176,17 @@ export const joinPublicRoom: Act = { right: 0, data: { room: "string", - server: "string", // Unused at the Moment + server: "string", }, func: async (client: Client, data: any, aws: (code: string, data: any) => void) => { + if (!checkSelfTag(data.server)) { + let resp = await client.pass(data.server, "joinPublicRoom", data); + if (resp.state == "ok") { + //TODO: add server to personal list + } + aws(resp.state, resp.data); + return; + } let query = await select([rooms.roomID, rooms.visibility], rooms) .where(eq(rooms.name, data.room)) .query(db); @@ -164,9 +219,14 @@ export const getRoomOTAs: Act = { right: 0, data: { room: "string", - server: "string", // Unused at the Moment + server: "string", }, func: async (client: Client, data: any, aws: (code: string, data: any) => void) => { + if (!checkSelfTag(data.server)) { + let resp = await client.pass(data.server, "getRoomOTAs", data); + aws(resp.state, resp.data); + return; + } let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.OTA); if (roomID == -1) return void aws("error", "roomAdmin"); let req = await select([roomOTAs.token, roomOTAs.expires, roomOTAs.usesLeft], roomOTAs) @@ -185,12 +245,17 @@ export const addRoomOTA: Act = { right: 0, data: { room: "string", - server: "string", // Unused at the Moment + server: "string", token: "string-255", expires: "number", usesLeft: "number", }, func: async (client: Client, data: any, aws: (code: string, data: any) => void) => { + if (!checkSelfTag(data.server)) { + let resp = await client.pass(data.server, "addRoomOTA", data); + aws(resp.state, resp.data); + return; + } let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.OTA); if (roomID == -1) return void aws("error", "roomAdmin"); try { @@ -215,10 +280,15 @@ export const deleteRoomOTA: Act = { right: 0, data: { room: "string", - server: "string", // Unused at the Moment + server: "string", token: "string" }, func: async (client: Client, data: any, aws: (code: string, data: any) => void) => { + if (!checkSelfTag(data.server)) { + let resp = await client.pass(data.server, "deleteRoomOTA", data); + aws(resp.state, resp.data); + return; + } let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.OTA); if (roomID == -1) return void aws("error", "roomAdmin"); await remove(roomOTAs) @@ -235,11 +305,16 @@ export const kickMember: Act = { right: 0, data: { room: "string", - roomServer: "string", // Unused at the Moment + roomServer: "string", name: "string", server: "string", }, func: async (client: Client, data: any, aws: (code: string, data: any) => void) => { + if (!checkSelfTag(data.server)) { + let resp = await client.pass(data.server, "kickMember", data); + aws(resp.state, resp.data); + return; + } let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.MANAGE_MEMBERS); if (roomID == -1) return void aws("error", "roomAdmin"); let req = await remove(roomMembers) @@ -271,12 +346,17 @@ export const setAdminStatus: Act = { right: 0, data: { room: "string", - roomServer: "string", // Unused at the Moment + roomServer: "string", name: "string", server: "string", admin: "boolean", }, func: async (client: Client, data: any, aws: (code: string, data: any) => void) => { + if (!checkSelfTag(data.server)) { + let resp = await client.pass(data.roomServer, "setAdminStatus", data); + aws(resp.state, resp.data); + return; + } let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.MANAGE_MEMBERS); if (roomID == -1) return void aws("error", "roomAdmin"); let req = await update(roomMembers) @@ -299,9 +379,19 @@ export const leaveRoom: Act = { right: 0, data: { room: "string", - server: "string", // Unused at the Moment + server: "string", }, func: async (client: Client, data: any, aws: (code: string, data: any) => void) => { + if (!checkSelfTag(data.server)) { + let resp = await client.pass(data.server, "leaveRoom", data); + if (resp.state == "ok") { + //TODO: remove server from personal list + } else if (resp.data == "ota") { + client.suspect(); + } + aws(resp.state, resp.data); + return; + } let roomID = await client.isInRoom(data.room); if (roomID == -1) return void aws("error", "existence"); let req = await remove(roomMembers) @@ -333,11 +423,16 @@ export const roomSettings: Act = { right: 0, data: { room: "string", - server: "string", // Unused at the Moment + server: "string", rights: "number", //see permissions.ts visibility: "number" //0 is not, 1 only to clients, 2 or bigger everywhere }, func: async (client, data, aws) => { + if (!checkSelfTag(data.server)) { + let resp = await client.pass(data.server, "roomSettings", data); + aws(resp.state, resp.data); + return; + } let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.CHANGE_SETTINGS); if (roomID == -1) return void aws("error", "roomAdmin"); let req = await update(rooms) @@ -359,7 +454,12 @@ export const roomMeta: Act = { description: "string-255", icon: "string-255" }, - func: async (client: Client, data: any, aws: (code: string, data: any) => void) =>{ + func: async (client: Client, data: any, aws: (code: string, data: any) => void) => { + if (!checkSelfTag(data.server)) { + let resp = await client.pass(data.server, "roomMeta", data); + aws(resp.state, resp.data); + return; + } let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.CHANGE_META); if (roomID == -1) return void aws("error", "roomAdmin"); let req = await update(rooms) diff --git a/src/api/post.ts b/src/api/post.ts index ce6ba89..61ad730 100644 --- a/src/api/post.ts +++ b/src/api/post.ts @@ -40,7 +40,21 @@ export const addPostMethods = (server: express.Express) => { let auth = authorization.parse(req.headers["authorization"] ?? ""); if (auth.scheme == "outbagServer") { debug("POST", "auth: outbag Server"); - throw new Error("not implemented"); + if ( + typeof auth.token == "string" + && tempTokens[auth.token] != null + && typeof auth?.params?.as == "string" + ) { + let serverClient = tempTokens[auth.token]; + client = new postClient(req.socket.remoteAddress ?? ""); + client.client.name = auth.params.as; + client.client.server = serverClient.client.server; + client.client.state = STATE.remote; + } else { + if (req.suspect) req.suspect(); + aws("error", "serverToken"); + return; + } } else if (auth.token != null && typeof auth.token == "string") { debug("POST", "auth: temp Token"); if (tempTokens[auth.token] != null) { @@ -51,10 +65,7 @@ export const addPostMethods = (server: express.Express) => { return; } } else if ( - auth?.params?.name != null - && auth?.params?.server != null - && auth?.params?.accountKey != null - && typeof auth?.params?.name == "string" + typeof auth?.params?.name == "string" && typeof auth?.params?.server == "string" && typeof auth?.params?.accountKey == "string" ) { @@ -161,7 +172,7 @@ export const addTempToken = (client: postClient) => { return token; }; -addShutdownTask(() => { +let cancleClear = setInterval(() => { let keys = Object.keys(tempTokens); for (let i = 0; i < keys.length; i++) { const c = tempTokens[keys[i]]; @@ -169,4 +180,6 @@ addShutdownTask(() => { delete tempTokens[keys[i]]; } } -}, 1000); \ No newline at end of file +}, 1000); + +addShutdownTask(() => void clearInterval(cancleClear)); \ No newline at end of file diff --git a/src/api/server.ts b/src/api/server.ts new file mode 100644 index 0000000..741e7ea --- /dev/null +++ b/src/api/server.ts @@ -0,0 +1,95 @@ +import { addShutdownTask } from "nman"; +import { sign } from "../sys/crypto.js"; +import { outbagServer } from "../server/outbagURL.js"; +import { uts } from "../sys/tools.js"; +import { getSettings, SETTINGS } from "../sys/settings.js"; +import { selfTag } from "../sys/selfTag.js"; + +let remoteTempTokens: { [key: string]: { lastReq: number, token: string } } = {}; + +async function sendPost(server: outbagServer, header: object, act: string, data: any) { + let fetchResp = await fetch(server.httpsURL + "api/" + act, { + method: "POST", + headers: Object.assign({ + "Content-Type": "application/json" + }, header), + body: JSON.stringify({ data }) + }); + + return { + state: fetchResp.status == 200 ? "ok" : "error", + data: (await fetchResp.json()).data + }; +} + +export const getServerToken = async (server: outbagServer, force = false) => { + if ( + !force + && remoteTempTokens[server.tag] != null + && remoteTempTokens[server.tag].lastReq + 60 * 60 * 1 > uts() + ) return remoteTempTokens[server.tag].token; + try { + let resp = await sendPost(server, {}, "remoteServer1", { + server: selfTag.tag + }); + if (resp.state != "ok") return false; + let token = resp.data.token; + let challenge = resp.data.challenge; + resp = await sendPost( + server, + { "authorization": `Bearer ${token}` }, + "remoteServer2", + { sign: await sign(challenge, await getSettings(SETTINGS.privateKey)) } + ); + if (resp.state != "ok") return false; + remoteTempTokens[server.tag] = { lastReq: uts(), token }; + return token; + } catch (error) { + return false; + } + +} + +export const fetchRemoteAs = async (server: outbagServer, name: string, act: string, data: any) => { + try { + let token = await getServerToken(server); + if (token === false) throw new Error("remote"); + let resp = await sendPost( + server, + { "authorization": `outbagServer ${token} as=${name}` }, + act, + data + ); + if (resp.state != "error" || resp.data != "serverToken") return resp; + token = await getServerToken(server, true); + if (token === false) throw new Error("remote"); + resp = await sendPost( + server, + { "authorization": `outbagServer ${token} as=${name}` }, + act, + data + ); + if (resp.state == "error" && resp.data == "serverToken") return { + state: "error", + data: "remote" + } + return resp; + } catch (error) { + return { + state: "error", + data: "remote" + } + } +} + +let cancleClear = setInterval(() => { + let keys = Object.keys(remoteTempTokens); + for (let i = 0; i < keys.length; i++) { + const c = remoteTempTokens[keys[i]]; + if (c.lastReq + 60 * 60 * 1 < uts()) { + delete remoteTempTokens[keys[i]]; + } + } +}, 1000); + +addShutdownTask(() => void clearInterval(cancleClear)); \ No newline at end of file diff --git a/src/api/user.ts b/src/api/user.ts index 2d0c27a..bd7649d 100644 --- a/src/api/user.ts +++ b/src/api/user.ts @@ -1,14 +1,17 @@ -import { and, eq, naturalJoin, select, update } from "dblang"; +import { and, eq, innerJoinUsing, naturalJoin, select, update } from "dblang"; import { accounts, db, roomMembers, rooms } from "../sys/db.js"; import { addBruteforcePotantial } from "../sys/bruteforce.js"; -import { outbagServer } from "../server/outbagURL.js"; +import { outbagServer, outbagURLfromTag } from "../server/outbagURL.js"; +import { fetchRemoteAs } from "./server.js"; +import { debug } from "../sys/log.js"; export const STATE = { no: 0b00001, - remoteP: 0b00010, - remote: 0b00100, - client: 0b01000, - server: 0b10000, + remoteP: 0b000010, + remote: 0b000100, + client: 0b001000, + serverP: 0b010000, + server: 0b100000, }; export const MODE = { @@ -45,9 +48,23 @@ export class Client { addBruteforcePotantial(this.ip); } + async pass(server: string, act: string, data: any) { + debug("Client", "passing act to remote:", server); + try { + let s = await outbagURLfromTag(server); + return await fetchRemoteAs(s, this.name, act, data); + } catch (error) { + return { + state: "error", + data: "remote" + } + } + + } + async isInRoom(name: string): Promise { - if (this.state != STATE.client) return -1; - let query = await select([rooms.roomID], naturalJoin(rooms, roomMembers)) + if (this.state != STATE.client && this.state != STATE.remote) return -1; + let query = await select([rooms.roomID], innerJoinUsing(rooms, roomMembers, rooms.roomID, roomMembers.roomID)) .where(and( eq(rooms.name, name), eq(roomMembers.name, this.name), @@ -58,8 +75,8 @@ export class Client { return query[0][rooms.roomID]; } async isRoomAdmin(name: string, roomRightRequires: number): Promise { - if (this.state != STATE.client) return -1; - let query = await select([rooms.roomID, rooms.owner, rooms.rights, roomMembers.admin], naturalJoin(rooms, roomMembers)) + if (this.state != STATE.client && this.state != STATE.remote) return -1; + let query = await select([rooms.roomID, rooms.owner, rooms.rights, roomMembers.admin], innerJoinUsing(rooms, roomMembers, rooms.roomID, roomMembers.roomID)) .where(and( eq(rooms.name, name), eq(roomMembers.admin, true), diff --git a/src/sys/db.ts b/src/sys/db.ts index f689911..b2196a3 100644 --- a/src/sys/db.ts +++ b/src/sys/db.ts @@ -1,4 +1,4 @@ -import { BIGINT, BOOL, DB, INT, onAction, SMALLINT, TEXT, TINYINT, VARCHAR } from "dblang" +import { BIGINT, BOOL, DB, INT, onAction, SMALLINT, TEXT, TINYINT, uniqueKey, VARCHAR } from "dblang" import { oConf } from "./config.js" import { PERMISSIONS } from "../server/permissions.js" import nMan from "nman"; @@ -46,7 +46,7 @@ nMan.addShutdownTask(db.close, 3000, 10); export const accounts = db.newTable("accounts"); accounts.addAttributes({ accID: { type: INT, primaryKey: true, autoIncrement: true }, - name: { type: VARCHAR(100), unique: true, default: PERMISSIONS.DEFAULT }, + name: { type: VARCHAR(100), unique: true, notNull: true }, rights: { type: INT, default: PERMISSIONS.DEFAULT }, @@ -62,6 +62,23 @@ accounts.addAttributes({ maxUsersPerRoom: { type: INT }, }); +export const remoteRooms = db.newTable("remoteRooms"); +remoteRooms.addAttributes({ + accID: { + type: INT, + primaryKey: true, + foreignKey: { + link: accounts.accID, + onUpdate: onAction.cascade, + onDelete: onAction.cascade + } + }, + server: { + type: VARCHAR(256), + primaryKey: true, + } +}); + export const settings = db.newTable("settings"); settings.addAttributes({ type: { type: VARCHAR(255), primaryKey: true }, @@ -89,7 +106,7 @@ rooms.addAttributes({ name: { type: VARCHAR(255), unique: true }, owner: { type: INT, - foreginKey: { + foreignKey: { link: accounts.accID } }, @@ -105,23 +122,28 @@ roomMembers.addAttributes({ roomMemberID: { type: INT, primaryKey: true, autoIncrement: true }, roomID: { type: INT, - foreginKey: { + foreignKey: { link: rooms.roomID, onDelete: onAction.cascade, onUpdate: onAction.cascade } }, - name: { type: TEXT }, - server: { type: TEXT }, + name: { type: VARCHAR(256) }, + server: { type: VARCHAR(256) }, admin: { type: BOOL, default: false } }); +roomMembers.addConstraint(uniqueKey([ + roomMembers.roomID, + roomMembers.name, + roomMembers.server +])); export const roomOTAs = db.newTable("roomOTAs"); roomOTAs.addAttributes({ roomID: { type: INT, primaryKey: true, - foreginKey: { + foreignKey: { link: rooms.roomID, onDelete: onAction.cascade, onUpdate: onAction.cascade @@ -141,7 +163,7 @@ listCategories.addAttributes({ roomID: { type: INT, primaryKey: true, - foreginKey: { + foreignKey: { link: rooms.roomID, onDelete: onAction.cascade, onUpdate: onAction.cascade @@ -158,7 +180,7 @@ articles.addAttributes({ roomID: { type: INT, primaryKey: true, - foreginKey: { + foreignKey: { link: rooms.roomID, onDelete: onAction.cascade, onUpdate: onAction.cascade @@ -170,7 +192,7 @@ articles.addAttributes({ category: { type: INT, - foreginKey: { + foreignKey: { link: listCategories.listCatID, onDelete: onAction.setNull, onUpdate: onAction.cascade diff --git a/src/sys/selfTag.ts b/src/sys/selfTag.ts index 209961d..cef9c3a 100644 --- a/src/sys/selfTag.ts +++ b/src/sys/selfTag.ts @@ -1,5 +1,5 @@ import { outbagServer, outbagURLfromTag } from "../server/outbagURL.js"; -import {oConf} from "./config.js" +import { oConf } from "./config.js" import { debug } from "./log.js"; export let selfTag: outbagServer = new outbagServer( diff --git a/tests/tests/post.js b/tests/tests/post.js index 0b56637..5cd0b49 100644 --- a/tests/tests/post.js +++ b/tests/tests/post.js @@ -183,7 +183,7 @@ const list = [ await req({ "authorization": `Digest name=${name1} server=localhost:7224 accountKey=${accountKey}` - }, "listLocalRooms", {}, "ok", [ + }, "listRooms", {}, "ok", [ { name: room1, owner: name1, @@ -225,7 +225,7 @@ const list = [ await req({ "authorization": `Digest name=${name1} server=localhost:7224 accountKey=${accountKey}` - }, "listLocalRooms", {}, "ok", [ + }, "listRooms", {}, "ok", [ { name: room1, owner: name1, diff --git a/tests/tests/ws.js b/tests/tests/ws.js index c941f35..3c9ea6c 100644 --- a/tests/tests/ws.js +++ b/tests/tests/ws.js @@ -177,7 +177,7 @@ const list = [ icon: "" }, "error", "limit"); - await req(handler, "listLocalRooms", {}, "ok", [ + await req(handler, "listRooms", {}, "ok", [ { name: room1, owner: name1, @@ -208,7 +208,7 @@ const list = [ room: room2, server: "localhost:7224" }, "error", "existence"); - await req(handler, "listLocalRooms", {}, "ok", [ + await req(handler, "listRooms", {}, "ok", [ { name: room1, owner: name1,