server Tag

This commit is contained in:
jusax23 2023-03-05 18:00:03 +01:00
parent 8accb3fd2f
commit 60069c86af
Signed by: jusax23
GPG key ID: 499E2AA870C1CD41
10 changed files with 183 additions and 110 deletions

View file

@ -1,7 +1,6 @@
import { eq, select, update } from "dblang";
import { outbagURLshort } from "../../server/outbagURL.js";
import { PERMISSIONS } from "../../server/permissions.js";
import { oConf } from "../../sys/config.js";
import { selfTag } from "../../sys/config.js";
import { sha256, sign } from "../../sys/crypto.js";
import { accounts, db } from "../../sys/db.js";
import { getSettings, SETTINGS } from "../../sys/settings.js";
@ -30,8 +29,8 @@ export const createSignature = {
publicKey: "string"
},
func: async (client: Client, data: any, aws: (code: string, data: any) => void) => {
const server = await outbagURLshort(oConf.get("System", "URL") + ":" + oConf.get("System", "PORTexposed"));
const tag = client.name + "@" + server + "-" + data.publicKey;
const server = selfTag;
const tag = `${client.name}@${server.host}:${server.port}-${data.publicKey}`;
var signature = await sign(tag, await getSettings(SETTINGS.privateKey));
aws("ok", signature);
}

View file

@ -1,8 +1,8 @@
import { select, count, alias, insert, remove, le, update, minus, eq, and } from "dblang";
import { outbagURLshort } from "../../server/outbagURL.js";
import { outbagURLfromTag } from "../../server/outbagURL.js";
import { PERMISSIONS } from "../../server/permissions.js";
import { getRemote } from "../../server/serverCerts.js";
import { oConf } from "../../sys/config.js";
import { localhostTag, oConf } from "../../sys/config.js";
import { sha256, verify } from "../../sys/crypto.js";
import { accounts, db, signupOTA as signupOTATable } from "../../sys/db.js";
import { get64, uts } from "../../sys/tools.js";
@ -50,7 +50,7 @@ export const signup: Act = {
client.state = STATE.client;
client.accID = accID;
client.name = data.name;
client.server = "localhost";
client.server = localhostTag;
}
} else {
client.suspect();
@ -92,7 +92,7 @@ export const signupOTA = {
client.state = STATE.client;
client.accID = accID;
client.name = data.name;
client.server = "localhost";
client.server = localhostTag;
}
} else {
client.suspect();
@ -126,7 +126,7 @@ export const signin = {
client.state = STATE.client;
client.accID = accID;
client.name = data.name;
client.server = "localhost";
client.server = localhostTag;
}
}
};
@ -141,9 +141,9 @@ export const remote1 = {
sign: "string",
},
func: async (client: Client, data: any, aws: (code: string, data: any) => void) => {
data.server = await outbagURLshort(data.server);
let server = await outbagURLfromTag(data.server);
try {
var cert = await getRemote(data.server);
var cert = await getRemote(server);
var tagAcert = data.name + "@" + data.server + "-" + data.key;
if (!(await verify(tagAcert, data.sign, cert))) {
client.suspect();
@ -152,7 +152,7 @@ export const remote1 = {
}
client.name = data.name;
client.server = data.server;
client.server = server;
client.challenge = get64(64);
client.state = STATE.remoteP;
client.remoteKey = data.key;

View file

@ -10,15 +10,24 @@ import { sha256 } from "../sys/crypto.js";
import { get64, uts } from "../sys/tools.js";
import { addShutdownTask } from "nman";
import { suspectRequest } from "../sys/bruteforce.js";
import { localhostTag } from "../sys/config.js";
let acts = importActs as { [key: string]: Act };
let tempTokens: { [key: string]: postClient } = {};
let activePost = false;
export const activatePost = () => { activePost = true; };
export const addPostMethods = (server: express.Express) => {
for (const act in acts) {
let methode = acts[act];
server.post("/api/" + act, async (req: suspectRequest, res) => {
if (!activePost) {
res.status(500);
res.send("not active");
return;
}
debug("POST", "reveived:", req.body);
const aws = (state: string, data: any) => {
res.status(state == "error" ? 400 : 200);
@ -29,7 +38,7 @@ export const addPostMethods = (server: express.Express) => {
try {
let auth = authorization.parse(req.headers["authorization"] ?? "");
if (auth.scheme == "outbagServer") {
} else if (auth.token != null && typeof auth.token == "string") {
if (tempTokens[auth.token] != null) {
client = tempTokens[auth.token];
@ -41,7 +50,7 @@ export const addPostMethods = (server: express.Express) => {
} else if (auth?.params?.name != null && auth?.params?.accountKey != null && typeof auth?.params?.name == "string" && typeof auth?.params?.accountKey == "string") {
client = new postClient(req.ip);
client.name = auth?.params?.name;
client.server = "localhost";
client.server = localhostTag;
let accountKey = auth?.params?.accountKey;
let query = await select([accounts.accID, accounts.accountKey, accounts.accountKeySalt], accounts)

View file

@ -1,17 +1,18 @@
import { and, eq, 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";
export const STATE = {
no: 0b00001,
no: 0b00001,
remoteP: 0b00010,
remote: 0b00100,
client: 0b01000,
server: 0b10000,
remote: 0b00100,
client: 0b01000,
server: 0b10000,
};
export const MODE = {
ws: 0b01,
ws: 0b01,
post: 0b10,
both: 0b11,
};
@ -27,7 +28,7 @@ export type Act = {
export class Client {
name: string = "";
server: string = "";
server: outbagServer;
ip: string = "";
state: number = STATE.no;
@ -36,6 +37,7 @@ export class Client {
remoteKey: string = "";
constructor(ip: string) {
this.server = new outbagServer("", "", "", "");
this.ip = ip;
}
@ -49,7 +51,7 @@ export class Client {
.where(and(
eq(rooms.name, name),
eq(roomMembers.name, this.name),
eq(roomMembers.server, this.server)
eq(roomMembers.server, this.server.tag)
))
.query(db);
if (query.length == 0) return -1;
@ -62,7 +64,7 @@ export class Client {
eq(rooms.name, name),
eq(roomMembers.admin, true),
eq(roomMembers.name, this.name),
eq(roomMembers.server, this.server)
eq(roomMembers.server, this.server.tag)
))
.query(db);
if (query.length == 0) return -1;

View file

@ -7,9 +7,12 @@ import * as importActs from "./acts.js"
let acts = importActs as { [key: string]: Act };
let activeWS = false;
export const activatePost = () => { activeWS = true; };
export const wsOnConnection = (socket: ws.WebSocket, req: http.IncomingMessage) => {
let ip = req.socket.remoteAddress;
if (bruteforcecheck(ip ?? "")) return void socket.close();
if (!activeWS || bruteforcecheck(ip ?? "")) return void socket.close();
new wsClient(socket, req);
}

View file

@ -8,15 +8,15 @@ import nman from "nman";
import cors from "cors";
import { WebSocketServer } from "ws";
import { Command } from "commander";
import { oConf } from "./sys/config.js";
import { generateTag, oConf } from "./sys/config.js";
import { error, log } from "./sys/log.js";
import { connectToDB } from "./sys/db.js";
import bruteforce, { suspectRequest } from "./sys/bruteforce.js";
import bruteforce from "./sys/bruteforce.js";
import { fullSetup, partiellSetup } from "./setup/config.js";
import { addGetMethods } from "./api/get.js";
import { addPostMethods } from "./api/post.js";
import { wsOnConnection } from "./api/ws.js";
import { startUpdateCerts } from "./server/serverCerts.js";
import { startUpdateCert } from "./server/serverCerts.js";
const config = {
@ -52,6 +52,8 @@ program
program.parse();
const activeRequest = false;
var serverclose = { close: (d: () => void) => d() };
nman.addShutdownTask(() => new Promise(async (res, rej) => {
//await closeWebSocket();
@ -96,6 +98,9 @@ async function startServer() {
}
function complete_loaded() {
startUpdateCerts();
}
async function complete_loaded() {
startUpdateCert();
let succ = await generateTag();
if(!succ) error("System", "Could not resolve own Server Tag. Remote-Auth will not work! Check if the Server is reachable and the config ist correct!");
}

View file

@ -1,59 +1,55 @@
const WELL_KNOWN_PATH = "/.well-known/outbag/server";
const DEFAULT_PORT = 7223;
const DEFAULT_PORT = "7223";
export const outbagURL = (url: string, prefix = "https") => new Promise((res, rej) => {
const fetchWellknown = async (uri: URL) => {
uri = new URL(uri);
let resp = await fetch(uri);
let json = await resp.json();
if (json.path == null || json.port == null) throw new Error("NotAValidWellKnown");
return { host: uri.hostname, path: json.path as string, port: json.port as string };
};
export const outbagURLfromTag = async (tag: string) => {
let uri: URL;
try {
uri = new URL("/", url);
uri = new URL("/", tag);
uri.protocol = "https";
} catch (_) {
uri = new URL("https://" + url);
uri = new URL("https://" + tag);
}
uri.pathname = WELL_KNOWN_PATH;
fetch(uri)
.then(resp => resp.json())
.then(({ path = "/", port = 7223 }) => {
uri.pathname = path;
uri.port = port;
uri.protocol = prefix;
res(uri.toString());
})
.catch(_ => {
if (uri.port == '') {
uri.port = DEFAULT_PORT + "";
outbagURL(uri.toString(), prefix)
.then(url => res(url))
.catch(_ => rej());
} else {
rej();
}
});
});
export const outbagURLshort = (url: string) => new Promise((res, rej) => {
let uri: URL;
let isMain = uri.port == '';
try {
uri = new URL("/", url);
uri.protocol = "https";
let { host, path, port } = await fetchWellknown(uri);
return new outbagServer(isMain ? host : host + ":" + port, host, path, port);
} catch (_) {
uri = new URL("https://" + url);
if (isMain) {
try {
uri.port = DEFAULT_PORT;
let { host, path, port } = await fetchWellknown(uri);
return new outbagServer(isMain ? host : host + ":" + port, host, path, port);
} catch (_) { }
}
throw new Error("InvalidOutbagServer");
}
uri.pathname = WELL_KNOWN_PATH;
fetch(uri)
.then(resp => resp.json())
.then(({ path = "/", port = 7223 }) => {
uri.pathname = path;
uri.port = port;
res(uri.hostname + ":" + uri.port);
})
.catch(_ => {
if (uri.port == '') {
uri.port = DEFAULT_PORT + "";
outbagURLshort(uri.toString())
.then(url => res(url))
.catch(_ => rej());
} else {
rej();
}
});
});
};
export class outbagServer {
host: string;
port: string;
path: string;
tag: string;
constructor(tag: string, host: string, path: string, port: string) {
this.host = host;
this.port = port;
if (!path.startsWith("/")) this.path = "/" + path;
else this.path = path;
this.tag = tag;
}
get httpsURL() {
return `https://${this.host}:${this.port}${this.path}/`;
}
get wsURL() {
return `wss://${this.host}:${this.port}${this.path}/`;
}
};

View file

@ -1,14 +1,14 @@
import { outbagURL, outbagURLshort } from "./outbagURL.js";
import { db, serverCerts } from "../sys/db.js"
import { eq, insert, select, update } from "dblang";
import { error, log } from "../sys/log.js";
import { outbagServer } from "./outbagURL.js";
import { debug, log } from "../sys/log.js";
import { uts } from "../sys/tools.js";
import { getSettings, setSettings, SETTINGS } from "../sys/settings.js"
import { generateSigningKey } from "../sys/crypto.js"
import { oConf } from "../sys/config.js";
import nman from "nman";
import nman, { addShutdownTask } from "nman";
import { insert } from "dblang";
import { db, servers } from "../sys/db.js";
export const startUpdateCerts = () => {
export const startUpdateCert = () => {
const update = async () => {
var exp = parseInt(await getSettings(SETTINGS.certExpires));
if (uts() - 60 >= (exp || 0)) {
@ -27,26 +27,25 @@ export const startUpdateCerts = () => {
}, 100);
}
async function updateRemote(url: string, pKey: string = ""): Promise<boolean | string> {
var urlP = await outbagURL(url);
/*async function updateRemote(server: outbagServer): Promise<boolean> {
return new Promise((res, rej) => {
fetch(urlP + "api/server/publicKey")
fetch(server.httpsURL + "api/server/publicKey")
.then(d => d.json())
.then(async json => {
let { publicKey, expires } = json;
if (typeof publicKey == "string" && typeof expires == "string") {
try {
await insert(serverCerts.url, serverCerts.publicKey, serverCerts.expires)
.add(url, publicKey, expires)
await insert(servers.url, servers.publicKey, servers.expires)
.add(server.tag, publicKey, expires)
.query(db);
} catch (error) {
await update(serverCerts)
.set(serverCerts.publicKey, publicKey)
.set(serverCerts.expires, expires)
.where(eq(serverCerts.url, url))
await update(servers)
.set(servers.publicKey, publicKey)
.set(servers.expires, expires)
.where(eq(servers.url, server.tag))
.query(db);
}
res(publicKey);
res(true);
} else {
if (publicKey.length > 0) {
res(publicKey);
@ -57,20 +56,53 @@ async function updateRemote(url: string, pKey: string = ""): Promise<boolean | s
})
.catch((e) => {
error("serverCert", "fetch error:", e);
if (pKey.length > 0) {
res(pKey);
return;
}
res(false);
});
});
};
export const getRemote = async (url: string) => {
let query = await select([serverCerts.publicKey, serverCerts.expires], serverCerts)
.where(eq(serverCerts.url, url))
export const getRemote = async (server: outbagServer) => {
await updateRemote(server);
let query = await select([servers.publicKey, servers.expires], servers)
.where(eq(servers.url, server.tag))
.query(db);
if (query.length == 0 || query[0][serverCerts.expires] < uts() - 60)
return await updateRemote(url, query[0][serverCerts.publicKey]);
return query[0][serverCerts.publicKey];
return query[0][servers.publicKey];
};*/
const deleteafter = 60 * 60;
const certList: { [key: string]: { exp: number, cert: string } } = {};
var certListCleaner = setInterval(async () => {
var utst = uts();
let keys = Object.keys(certList);
for (var i = 0; i < keys.length; i++) {
if (utst >= certList[keys[i]].exp) {
debug("Certificate List", "remove Cert: ", keys[i]);
delete certList[keys[i]];
}
}
}, 1000 * 60);
addShutdownTask(() => clearInterval(certListCleaner), 5000);
const updateCert = async (server: outbagServer) => {
try {
let resp = await fetch(server.httpsURL + "api/server/publicKey")
let json = await resp.json();
let { publicKey, expires } = json;
certList[server.tag] = { exp: Math.min(expires, deleteafter), cert: publicKey };
try {
await insert(servers.tag)
.add(server.tag)
.query(db);
} catch (error) {}
return true;
} catch (error) {
return false;
}
};
export const getRemote = async (server: outbagServer) => {
if (certList[server.tag] == null || certList[server.tag].exp >= uts()) await updateCert(server);
if (certList[server.tag] != null) return certList[server.tag].cert;
else throw new Error("Cert Error");
};

View file

@ -1,4 +1,5 @@
import juml from "juml";
import { outbagServer, outbagURLfromTag } from "../server/outbagURL.js";
const conf_struct = {
System: {
@ -29,4 +30,31 @@ const conf_struct = {
}
};
export const oConf = new juml(conf_struct);
export const oConf = new juml(conf_struct);
export let localhostTag: outbagServer = new outbagServer(
"localhost",
oConf.get("System", "URL")+"",
oConf.get("System", "PATHexposed")+"",
oConf.get("System", "PORTexposed")+"",
);
export let selfTag: outbagServer = localhostTag;
export const generateTag = async () => {
try {
let mainServerHost: outbagServer | null = null;
try {
mainServerHost = await outbagURLfromTag(oConf.get("System", "URL"));
} catch (error) {}
let serverHostPort = await outbagURLfromTag(
oConf.get("System", "URL") + ":" + oConf.get("System", "PORTexposed"));
if(mainServerHost == null || mainServerHost != serverHostPort){
selfTag = serverHostPort;
}else selfTag = mainServerHost;
return true;
} catch (error) {
return false;
}
};

View file

@ -67,12 +67,11 @@ settings.addAttributes({
data: { type: TEXT },
})
export const serverCerts = db.newTable("serverCerts");
serverCerts.addAttributes({
serverCertID: { type: INT, primaryKey: true, autoIncrement: true },
url: { type: TEXT },
publicKey: { type: TEXT },
expires: { type: BIGINT },
export const servers = db.newTable("servers");
servers.addAttributes({
tag: { type: VARCHAR(255), primaryKey: true },
//publicKey: { type: TEXT },
//expires: { type: BIGINT },
token: { type: TEXT, notNull: false },
});