remote passing

This commit is contained in:
jusax23 2023-03-20 16:26:06 +01:00
parent 98d2aef68d
commit d81433a0f3
Signed by: jusax23
GPG key ID: 499E2AA870C1CD41
12 changed files with 358 additions and 65 deletions

1
.gitignore vendored
View file

@ -1,6 +1,7 @@
node_modules node_modules
dist dist
config.juml config.juml
config2.juml
.vscode .vscode
test test
build build

8
package-lock.json generated
View file

@ -12,7 +12,7 @@
"auth-header": "^1.0.0", "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/f23f8128-4fde-4ec6-a8cd-cfc5068b2cfd", "dblang": "https://jusax.de/git/attachments/18f6a160-3695-4182-97a4-c2d9af97e60a",
"express": "^4.18.2", "express": "^4.18.2",
"juml": "https://jusax.de/git/attachments/208913c5-2851-4b86-a53d-ca99fed168cc", "juml": "https://jusax.de/git/attachments/208913c5-2851-4b86-a53d-ca99fed168cc",
"nman": "https://jusax.de/git/attachments/5333948b-fe6b-45d2-9230-ca388f6a89bc", "nman": "https://jusax.de/git/attachments/5333948b-fe6b-45d2-9230-ca388f6a89bc",
@ -1107,9 +1107,9 @@
} }
}, },
"node_modules/dblang": { "node_modules/dblang": {
"version": "0.8.0", "version": "0.9.0",
"resolved": "https://jusax.de/git/attachments/f23f8128-4fde-4ec6-a8cd-cfc5068b2cfd", "resolved": "https://jusax.de/git/attachments/18f6a160-3695-4182-97a4-c2d9af97e60a",
"integrity": "sha512-hHfxa5iHD3fumMzH/LvVwB2kPUfs1TsxRdOS1veIppfgsJNUxqxPdEljd+EluWpHrPklfO3AJr2vWiZe4N0NBg==", "integrity": "sha512-qDgygqUM1ykyKsy1IVdybzbBoBvQW1I9Qq6Sh8TS5rAcJnCHI7gyp2PxvqpK82bJsGL2NLBNBwKqhfetLdrJNw==",
"license": "UNLICENSED", "license": "UNLICENSED",
"dependencies": { "dependencies": {
"gitea-release": "git+https://jusax.de/git/jusax23/gitea-release.git", "gitea-release": "git+https://jusax.de/git/jusax23/gitea-release.git",

View file

@ -18,6 +18,7 @@
"prepublish": "tsc", "prepublish": "tsc",
"main": "tsc && node . -c config.juml", "main": "tsc && node . -c config.juml",
"debug": "tsc && node . -c config.juml -d -l 256", "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", "setup": "tsc && node . -c config.juml -s",
"bundleRelease": "mkdir build/bundle & esbuild src/main.ts --platform=node --bundle --minify --outfile=build/bundle/main.js", "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", "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", "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/f23f8128-4fde-4ec6-a8cd-cfc5068b2cfd", "dblang": "https://jusax.de/git/attachments/18f6a160-3695-4182-97a4-c2d9af97e60a",
"express": "^4.18.2", "express": "^4.18.2",
"juml": "https://jusax.de/git/attachments/208913c5-2851-4b86-a53d-ca99fed168cc", "juml": "https://jusax.de/git/attachments/208913c5-2851-4b86-a53d-ca99fed168cc",
"nman": "https://jusax.de/git/attachments/5333948b-fe6b-45d2-9230-ca388f6a89bc", "nman": "https://jusax.de/git/attachments/5333948b-fe6b-45d2-9230-ca388f6a89bc",

View file

@ -203,3 +203,47 @@ export const remote2 = {
} }
} }
}; };
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");
}
}
};

View file

@ -1,11 +1,13 @@
import { alias, and, eq, exists, innerJoinOn, innerJoinUsing, insert, le, minus, naturalJoin, not, or, remove, select, update } from "dblang"; 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 { 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 { uts } from "../../sys/tools.js";
import { isRoomFull } from "../helper.js"; import { isRoomFull } from "../helper.js";
import { Act, Client, STATE } from "../user.js"; import { Act, Client, STATE } from "../user.js";
export const listLocalRooms: Act = { export const listRooms: Act = {
state: STATE.client | STATE.remote, state: STATE.client | STATE.remote,
right: 0, right: 0,
data: {}, data: {},
@ -36,11 +38,30 @@ export const listLocalRooms: Act = {
let title = d[rooms.title]; let title = d[rooms.title];
let description = d[rooms.description]; let description = d[rooms.description];
let icon = d[rooms.icon]; let icon = d[rooms.icon];
let server = selfTag.tag;
if (name != null && owner != null && rights != null && visibility != null && title != null && description != null && icon != null) { 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; 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)); aws("ok", out.filter(d => d != null));
} }
}; };
@ -50,10 +71,17 @@ export const getRoomMembers: Act = {
right: 0, right: 0,
data: { data: {
room: "name", room: "name",
server: "string", // Unused at the Moment server: "string",
}, },
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, "getRoomMembers", data);
aws(resp.state, resp.data);
return;
}
let roomID = await client.isInRoom(data.room); let roomID = await client.isInRoom(data.room);
console.log(data, client.server.tag, client.name, roomID);
if (roomID == -1) { if (roomID == -1) {
aws("error", "existence"); aws("error", "existence");
return; return;
@ -63,12 +91,13 @@ export const getRoomMembers: Act = {
roomMembers.server, roomMembers.server,
roomMembers.admin roomMembers.admin
], roomMembers) ], roomMembers)
.where(eq(rooms.roomID, roomID)) .where(eq(roomMembers.roomID, roomID))
.query(db); .query(db);
let out = req.map(d => { let out = req.map(d => {
let name = d[roomMembers.name]; let name = d[roomMembers.name];
let server = d[roomMembers.server]; let server = d[roomMembers.server];
let admin = d[roomMembers.admin]; let admin = d[roomMembers.admin];
server = server == "local" ? selfTag.tag : server;
if (name != null && server != null && admin != null) { if (name != null && server != null && admin != null) {
return { name, server, admin }; return { name, server, admin };
} }
@ -83,15 +112,27 @@ export const joinRoom: Act = {
right: 0, right: 0,
data: { data: {
room: "string", room: "string",
server: "string", // Unused at the Moment server: "string",
token: "string" //OTA token: "string" //OTA
}, },
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, "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) let query = await select([rooms.roomID], rooms)
.where(eq(rooms.name, data.room)) .where(eq(rooms.name, data.room))
.query(db); .query(db);
let roomID = (query[0] ?? {})[rooms.roomID]; let roomID = (query[0] ?? {})[rooms.roomID];
if (typeof roomID != "number" || roomID < 0) { if (typeof roomID != "number" || roomID < 0) {
client.suspect();
return void aws("error", "ota"); return void aws("error", "ota");
} }
if (await isRoomFull(roomID)) return void aws("error", "limit"); if (await isRoomFull(roomID)) return void aws("error", "limit");
@ -107,8 +148,10 @@ export const joinRoom: Act = {
.where(eq(roomOTAs.usesLeft, 0)) .where(eq(roomOTAs.usesLeft, 0))
.query(db); .query(db);
if (req.affectedRows == 0) { if (req.affectedRows == 0) {
client.suspect();
return void aws("error", "ota"); return void aws("error", "ota");
} }
try {
let queryx = await insert( let queryx = await insert(
roomMembers.roomID, roomMembers.roomID,
roomMembers.name, roomMembers.name,
@ -119,8 +162,12 @@ export const joinRoom: Act = {
if (queryx.affectedRows > 0) { if (queryx.affectedRows > 0) {
aws("ok", ""); aws("ok", "");
} else { } else {
aws("error", "server"); aws("error", "duplicate");
} }
} catch (error) {
aws("error", "duplicate");
}
} }
}; };
@ -129,9 +176,17 @@ export const joinPublicRoom: Act = {
right: 0, right: 0,
data: { data: {
room: "string", room: "string",
server: "string", // Unused at the Moment server: "string",
}, },
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, "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) let query = await select([rooms.roomID, rooms.visibility], rooms)
.where(eq(rooms.name, data.room)) .where(eq(rooms.name, data.room))
.query(db); .query(db);
@ -164,9 +219,14 @@ export const getRoomOTAs: Act = {
right: 0, right: 0,
data: { data: {
room: "string", room: "string",
server: "string", // Unused at the Moment server: "string",
}, },
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, "getRoomOTAs", data);
aws(resp.state, resp.data);
return;
}
let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.OTA); let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.OTA);
if (roomID == -1) return void aws("error", "roomAdmin"); if (roomID == -1) return void aws("error", "roomAdmin");
let req = await select([roomOTAs.token, roomOTAs.expires, roomOTAs.usesLeft], roomOTAs) let req = await select([roomOTAs.token, roomOTAs.expires, roomOTAs.usesLeft], roomOTAs)
@ -185,12 +245,17 @@ export const addRoomOTA: Act = {
right: 0, right: 0,
data: { data: {
room: "string", room: "string",
server: "string", // Unused at the Moment server: "string",
token: "string-255", token: "string-255",
expires: "number", expires: "number",
usesLeft: "number", usesLeft: "number",
}, },
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, "addRoomOTA", data);
aws(resp.state, resp.data);
return;
}
let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.OTA); let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.OTA);
if (roomID == -1) return void aws("error", "roomAdmin"); if (roomID == -1) return void aws("error", "roomAdmin");
try { try {
@ -215,10 +280,15 @@ export const deleteRoomOTA: Act = {
right: 0, right: 0,
data: { data: {
room: "string", room: "string",
server: "string", // Unused at the Moment server: "string",
token: "string" token: "string"
}, },
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, "deleteRoomOTA", data);
aws(resp.state, resp.data);
return;
}
let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.OTA); let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.OTA);
if (roomID == -1) return void aws("error", "roomAdmin"); if (roomID == -1) return void aws("error", "roomAdmin");
await remove(roomOTAs) await remove(roomOTAs)
@ -235,11 +305,16 @@ export const kickMember: Act = {
right: 0, right: 0,
data: { data: {
room: "string", room: "string",
roomServer: "string", // Unused at the Moment roomServer: "string",
name: "string", name: "string",
server: "string", server: "string",
}, },
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, "kickMember", data);
aws(resp.state, resp.data);
return;
}
let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.MANAGE_MEMBERS); let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.MANAGE_MEMBERS);
if (roomID == -1) return void aws("error", "roomAdmin"); if (roomID == -1) return void aws("error", "roomAdmin");
let req = await remove(roomMembers) let req = await remove(roomMembers)
@ -271,12 +346,17 @@ export const setAdminStatus: Act = {
right: 0, right: 0,
data: { data: {
room: "string", room: "string",
roomServer: "string", // Unused at the Moment roomServer: "string",
name: "string", name: "string",
server: "string", server: "string",
admin: "boolean", admin: "boolean",
}, },
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.roomServer, "setAdminStatus", data);
aws(resp.state, resp.data);
return;
}
let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.MANAGE_MEMBERS); let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.MANAGE_MEMBERS);
if (roomID == -1) return void aws("error", "roomAdmin"); if (roomID == -1) return void aws("error", "roomAdmin");
let req = await update(roomMembers) let req = await update(roomMembers)
@ -299,9 +379,19 @@ export const leaveRoom: Act = {
right: 0, right: 0,
data: { data: {
room: "string", room: "string",
server: "string", // Unused at the Moment server: "string",
}, },
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, "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); let roomID = await client.isInRoom(data.room);
if (roomID == -1) return void aws("error", "existence"); if (roomID == -1) return void aws("error", "existence");
let req = await remove(roomMembers) let req = await remove(roomMembers)
@ -333,11 +423,16 @@ export const roomSettings: Act = {
right: 0, right: 0,
data: { data: {
room: "string", room: "string",
server: "string", // Unused at the Moment server: "string",
rights: "number", //see permissions.ts rights: "number", //see permissions.ts
visibility: "number" //0 is not, 1 only to clients, 2 or bigger everywhere visibility: "number" //0 is not, 1 only to clients, 2 or bigger everywhere
}, },
func: async (client, data, aws) => { 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); let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.CHANGE_SETTINGS);
if (roomID == -1) return void aws("error", "roomAdmin"); if (roomID == -1) return void aws("error", "roomAdmin");
let req = await update(rooms) let req = await update(rooms)
@ -359,7 +454,12 @@ export const roomMeta: Act = {
description: "string-255", description: "string-255",
icon: "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); let roomID = await client.isRoomAdmin(data.room, ROOM_RIGHTS.CHANGE_META);
if (roomID == -1) return void aws("error", "roomAdmin"); if (roomID == -1) return void aws("error", "roomAdmin");
let req = await update(rooms) let req = await update(rooms)

View file

@ -40,7 +40,21 @@ export const addPostMethods = (server: express.Express) => {
let auth = authorization.parse(req.headers["authorization"] ?? ""); let auth = authorization.parse(req.headers["authorization"] ?? "");
if (auth.scheme == "outbagServer") { if (auth.scheme == "outbagServer") {
debug("POST", "auth: outbag Server"); 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") { } else if (auth.token != null && typeof auth.token == "string") {
debug("POST", "auth: temp Token"); debug("POST", "auth: temp Token");
if (tempTokens[auth.token] != null) { if (tempTokens[auth.token] != null) {
@ -51,10 +65,7 @@ export const addPostMethods = (server: express.Express) => {
return; return;
} }
} else if ( } else if (
auth?.params?.name != null typeof auth?.params?.name == "string"
&& auth?.params?.server != null
&& auth?.params?.accountKey != null
&& typeof auth?.params?.name == "string"
&& typeof auth?.params?.server == "string" && typeof auth?.params?.server == "string"
&& typeof auth?.params?.accountKey == "string" && typeof auth?.params?.accountKey == "string"
) { ) {
@ -161,7 +172,7 @@ export const addTempToken = (client: postClient) => {
return token; return token;
}; };
addShutdownTask(() => { let cancleClear = setInterval(() => {
let keys = Object.keys(tempTokens); let keys = Object.keys(tempTokens);
for (let i = 0; i < keys.length; i++) { for (let i = 0; i < keys.length; i++) {
const c = tempTokens[keys[i]]; const c = tempTokens[keys[i]];
@ -170,3 +181,5 @@ addShutdownTask(() => {
} }
} }
}, 1000); }, 1000);
addShutdownTask(() => void clearInterval(cancleClear));

95
src/api/server.ts Normal file
View file

@ -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));

View file

@ -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 { accounts, db, roomMembers, rooms } from "../sys/db.js";
import { addBruteforcePotantial } from "../sys/bruteforce.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 = { export const STATE = {
no: 0b00001, no: 0b00001,
remoteP: 0b00010, remoteP: 0b000010,
remote: 0b00100, remote: 0b000100,
client: 0b01000, client: 0b001000,
server: 0b10000, serverP: 0b010000,
server: 0b100000,
}; };
export const MODE = { export const MODE = {
@ -45,9 +48,23 @@ export class Client {
addBruteforcePotantial(this.ip); 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<number> { async isInRoom(name: string): Promise<number> {
if (this.state != STATE.client) return -1; if (this.state != STATE.client && this.state != STATE.remote) return -1;
let query = await select([rooms.roomID], naturalJoin(rooms, roomMembers)) let query = await select([rooms.roomID], innerJoinUsing(rooms, roomMembers, rooms.roomID, roomMembers.roomID))
.where(and( .where(and(
eq(rooms.name, name), eq(rooms.name, name),
eq(roomMembers.name, this.name), eq(roomMembers.name, this.name),
@ -58,8 +75,8 @@ export class Client {
return query[0][rooms.roomID]; return query[0][rooms.roomID];
} }
async isRoomAdmin(name: string, roomRightRequires: number): Promise<number> { async isRoomAdmin(name: string, roomRightRequires: number): Promise<number> {
if (this.state != STATE.client) return -1; if (this.state != STATE.client && this.state != STATE.remote) return -1;
let query = await select([rooms.roomID, rooms.owner, rooms.rights, roomMembers.admin], naturalJoin(rooms, roomMembers)) let query = await select([rooms.roomID, rooms.owner, rooms.rights, roomMembers.admin], innerJoinUsing(rooms, roomMembers, rooms.roomID, roomMembers.roomID))
.where(and( .where(and(
eq(rooms.name, name), eq(rooms.name, name),
eq(roomMembers.admin, true), eq(roomMembers.admin, true),

View file

@ -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 { oConf } from "./config.js"
import { PERMISSIONS } from "../server/permissions.js" import { PERMISSIONS } from "../server/permissions.js"
import nMan from "nman"; import nMan from "nman";
@ -46,7 +46,7 @@ nMan.addShutdownTask(db.close, 3000, 10);
export const accounts = db.newTable("accounts"); export const accounts = db.newTable("accounts");
accounts.addAttributes({ accounts.addAttributes({
accID: { type: INT, primaryKey: true, autoIncrement: true }, 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 }, rights: { type: INT, default: PERMISSIONS.DEFAULT },
@ -62,6 +62,23 @@ accounts.addAttributes({
maxUsersPerRoom: { type: INT }, 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"); export const settings = db.newTable("settings");
settings.addAttributes({ settings.addAttributes({
type: { type: VARCHAR(255), primaryKey: true }, type: { type: VARCHAR(255), primaryKey: true },
@ -89,7 +106,7 @@ rooms.addAttributes({
name: { type: VARCHAR(255), unique: true }, name: { type: VARCHAR(255), unique: true },
owner: { owner: {
type: INT, type: INT,
foreginKey: { foreignKey: {
link: accounts.accID link: accounts.accID
} }
}, },
@ -105,23 +122,28 @@ roomMembers.addAttributes({
roomMemberID: { type: INT, primaryKey: true, autoIncrement: true }, roomMemberID: { type: INT, primaryKey: true, autoIncrement: true },
roomID: { roomID: {
type: INT, type: INT,
foreginKey: { foreignKey: {
link: rooms.roomID, link: rooms.roomID,
onDelete: onAction.cascade, onDelete: onAction.cascade,
onUpdate: onAction.cascade onUpdate: onAction.cascade
} }
}, },
name: { type: TEXT }, name: { type: VARCHAR(256) },
server: { type: TEXT }, server: { type: VARCHAR(256) },
admin: { type: BOOL, default: false } admin: { type: BOOL, default: false }
}); });
roomMembers.addConstraint(uniqueKey([
roomMembers.roomID,
roomMembers.name,
roomMembers.server
]));
export const roomOTAs = db.newTable("roomOTAs"); export const roomOTAs = db.newTable("roomOTAs");
roomOTAs.addAttributes({ roomOTAs.addAttributes({
roomID: { roomID: {
type: INT, type: INT,
primaryKey: true, primaryKey: true,
foreginKey: { foreignKey: {
link: rooms.roomID, link: rooms.roomID,
onDelete: onAction.cascade, onDelete: onAction.cascade,
onUpdate: onAction.cascade onUpdate: onAction.cascade
@ -141,7 +163,7 @@ listCategories.addAttributes({
roomID: { roomID: {
type: INT, type: INT,
primaryKey: true, primaryKey: true,
foreginKey: { foreignKey: {
link: rooms.roomID, link: rooms.roomID,
onDelete: onAction.cascade, onDelete: onAction.cascade,
onUpdate: onAction.cascade onUpdate: onAction.cascade
@ -158,7 +180,7 @@ articles.addAttributes({
roomID: { roomID: {
type: INT, type: INT,
primaryKey: true, primaryKey: true,
foreginKey: { foreignKey: {
link: rooms.roomID, link: rooms.roomID,
onDelete: onAction.cascade, onDelete: onAction.cascade,
onUpdate: onAction.cascade onUpdate: onAction.cascade
@ -170,7 +192,7 @@ articles.addAttributes({
category: { category: {
type: INT, type: INT,
foreginKey: { foreignKey: {
link: listCategories.listCatID, link: listCategories.listCatID,
onDelete: onAction.setNull, onDelete: onAction.setNull,
onUpdate: onAction.cascade onUpdate: onAction.cascade

View file

@ -1,5 +1,5 @@
import { outbagServer, outbagURLfromTag } from "../server/outbagURL.js"; import { outbagServer, outbagURLfromTag } from "../server/outbagURL.js";
import {oConf} from "./config.js" import { oConf } from "./config.js"
import { debug } from "./log.js"; import { debug } from "./log.js";
export let selfTag: outbagServer = new outbagServer( export let selfTag: outbagServer = new outbagServer(

View file

@ -183,7 +183,7 @@ const list = [
await req({ await req({
"authorization": `Digest name=${name1} server=localhost:7224 accountKey=${accountKey}` "authorization": `Digest name=${name1} server=localhost:7224 accountKey=${accountKey}`
}, "listLocalRooms", {}, "ok", [ }, "listRooms", {}, "ok", [
{ {
name: room1, name: room1,
owner: name1, owner: name1,
@ -225,7 +225,7 @@ const list = [
await req({ await req({
"authorization": `Digest name=${name1} server=localhost:7224 accountKey=${accountKey}` "authorization": `Digest name=${name1} server=localhost:7224 accountKey=${accountKey}`
}, "listLocalRooms", {}, "ok", [ }, "listRooms", {}, "ok", [
{ {
name: room1, name: room1,
owner: name1, owner: name1,

View file

@ -177,7 +177,7 @@ const list = [
icon: "" icon: ""
}, "error", "limit"); }, "error", "limit");
await req(handler, "listLocalRooms", {}, "ok", [ await req(handler, "listRooms", {}, "ok", [
{ {
name: room1, name: room1,
owner: name1, owner: name1,
@ -208,7 +208,7 @@ const list = [
room: room2, room: room2,
server: "localhost:7224" server: "localhost:7224"
}, "error", "existence"); }, "error", "existence");
await req(handler, "listLocalRooms", {}, "ok", [ await req(handler, "listRooms", {}, "ok", [
{ {
name: room1, name: room1,
owner: name1, owner: name1,