remote passing
This commit is contained in:
parent
98d2aef68d
commit
d81433a0f3
12 changed files with 358 additions and 65 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -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
8
package-lock.json
generated
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -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)
|
||||||
|
@ -360,6 +455,11 @@ export const roomMeta: Act = {
|
||||||
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)
|
||||||
|
|
|
@ -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
95
src/api/server.ts
Normal 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));
|
|
@ -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),
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue