fosrl.pangolin/server/routers/olm/handleOlmRegisterMessage.ts

128 lines
3.5 KiB
TypeScript
Raw Normal View History

2025-02-21 10:13:41 -05:00
import db from "@server/db";
import { MessageHandler } from "../ws";
import { clients, exitNodes, Olm, olms, sites } from "@server/db/schema";
2025-03-14 09:18:13 -04:00
import { eq } from "drizzle-orm";
2025-02-21 10:55:38 -05:00
import { addPeer, deletePeer } from "../newt/peers";
2025-02-21 10:13:41 -05:00
import logger from "@server/logger";
export const handleOlmRegisterMessage: MessageHandler = async (context) => {
2025-02-21 12:17:56 -05:00
const { message, client: c, sendToClient } = context;
const olm = c as Olm;
2025-02-21 10:13:41 -05:00
2025-02-21 10:55:38 -05:00
logger.info("Handling register olm message!");
2025-02-21 10:13:41 -05:00
if (!olm) {
logger.warn("Olm not found");
return;
}
2025-02-21 12:17:56 -05:00
if (!olm.clientId) {
2025-02-21 10:13:41 -05:00
logger.warn("Olm has no site!"); // TODO: Maybe we create the site here?
return;
}
2025-02-21 12:17:56 -05:00
const clientId = olm.clientId;
2025-02-21 10:13:41 -05:00
const { publicKey } = message.data;
if (!publicKey) {
logger.warn("Public key not provided");
return;
}
2025-02-21 12:17:56 -05:00
const [client] = await db
.select()
.from(clients)
.where(eq(clients.clientId, clientId))
.limit(1);
if (!client || !client.siteId) {
logger.warn("Site not found or does not have exit node");
return;
}
2025-02-21 10:13:41 -05:00
const [site] = await db
.select()
.from(sites)
2025-02-21 12:17:56 -05:00
.where(eq(sites.siteId, client.siteId))
2025-02-21 10:13:41 -05:00
.limit(1);
if (!site) {
2025-02-21 10:13:41 -05:00
logger.warn("Site not found or does not have exit node");
return;
}
if (!site.exitNodeId) {
logger.warn("Site does not have exit node");
2025-02-22 11:20:56 -05:00
return;
}
const [exitNode] = await db
.select()
.from(exitNodes)
.where(eq(exitNodes.exitNodeId, site.exitNodeId))
.limit(1);
2025-03-14 09:18:13 -04:00
sendToClient(olm.olmId, {
type: "olm/wg/holepunch",
data: {
serverPubKey: exitNode.publicKey,
2025-03-14 09:18:13 -04:00
}
});
// make sure we hand endpoints for both the site and the client and the lastHolePunch is not too old
if (!site.endpoint || !client.endpoint) {
logger.warn("Site or client has no endpoint or listen port");
return;
}
2025-02-22 11:20:56 -05:00
const now = new Date().getTime() / 1000;
if (site.lastHolePunch && now - site.lastHolePunch > 6) {
logger.warn("Site last hole punch is too old");
return;
}
if (client.lastHolePunch && now - client.lastHolePunch > 6) {
logger.warn("Client last hole punch is too old");
return;
}
2025-02-21 10:13:41 -05:00
await db
2025-02-21 12:17:56 -05:00
.update(clients)
2025-02-21 10:13:41 -05:00
.set({
pubKey: publicKey
})
2025-02-21 12:17:56 -05:00
.where(eq(clients.clientId, olm.clientId))
2025-02-21 10:13:41 -05:00
.returning();
2025-02-21 12:17:56 -05:00
if (client.pubKey && client.pubKey !== publicKey) {
2025-02-21 10:13:41 -05:00
logger.info("Public key mismatch. Deleting old peer...");
2025-02-21 12:17:56 -05:00
await deletePeer(site.siteId, client.pubKey);
2025-02-21 10:13:41 -05:00
}
if (!site.subnet) {
logger.warn("Site has no subnet");
return;
}
2025-03-14 09:18:13 -04:00
2025-02-21 10:13:41 -05:00
// add the peer to the exit node
2025-02-21 10:55:38 -05:00
await addPeer(site.siteId, {
2025-02-21 10:13:41 -05:00
publicKey: publicKey,
2025-02-22 11:20:56 -05:00
allowedIps: [client.subnet],
endpoint: client.endpoint
2025-02-21 10:13:41 -05:00
});
return {
message: {
type: "olm/wg/connect",
data: {
2025-02-22 11:20:56 -05:00
endpoint: site.endpoint,
2025-02-21 10:55:38 -05:00
publicKey: site.publicKey,
serverIP: site.address!.split("/")[0],
2025-03-14 09:18:13 -04:00
tunnelIP: `${client.subnet.split("/")[0]}/${site.address!.split("/")[1]}` // put the client ip in the same subnet as the site. TODO: Is this right? Maybe we need th make .subnet work properly!
2025-02-21 10:13:41 -05:00
}
},
broadcast: false, // Send to all olms
excludeSender: false // Include sender in broadcast
};
};