Add auth to gerbil calls

This commit is contained in:
Owen 2025-08-15 16:53:30 -07:00
parent e043d0e654
commit e73383cc79
No known key found for this signature in database
GPG key ID: 8271FDFFD9E0CCBD
3 changed files with 67 additions and 7 deletions

View file

@ -53,3 +53,10 @@ export function selectBestExitNode(
return pingResults[0]; return pingResults[0];
} }
export async function checkExitNodeOrg(
exitNodeId: number,
orgId: string
) {
return false;
}

View file

@ -6,6 +6,7 @@ import logger from "@server/logger";
import createHttpError from "http-errors"; import createHttpError from "http-errors";
import HttpCode from "@server/types/HttpCode"; import HttpCode from "@server/types/HttpCode";
import response from "@server/lib/response"; import response from "@server/lib/response";
import { checkExitNodeOrg } from "@server/lib/exitNodes";
// Track sites that are already offline to avoid unnecessary queries // Track sites that are already offline to avoid unnecessary queries
const offlineSites = new Set<string>(); const offlineSites = new Set<string>();
@ -48,7 +49,10 @@ export const receiveBandwidth = async (
} }
}; };
export async function updateSiteBandwidth(bandwidthData: PeerBandwidth[]) { export async function updateSiteBandwidth(
bandwidthData: PeerBandwidth[],
exitNodeId?: number
) {
const currentTime = new Date(); const currentTime = new Date();
const oneMinuteAgo = new Date(currentTime.getTime() - 60000); // 1 minute ago const oneMinuteAgo = new Date(currentTime.getTime() - 60000); // 1 minute ago
@ -69,7 +73,7 @@ export async function updateSiteBandwidth(bandwidthData: PeerBandwidth[]) {
// Update all active sites with bandwidth data and get the site data in one operation // Update all active sites with bandwidth data and get the site data in one operation
const updatedSites = []; const updatedSites = [];
for (const peer of activePeers) { for (const peer of activePeers) {
const updatedSite = await trx const [updatedSite] = await trx
.update(sites) .update(sites)
.set({ .set({
megabytesOut: sql`${sites.megabytesOut} + ${peer.bytesIn}`, megabytesOut: sql`${sites.megabytesOut} + ${peer.bytesIn}`,
@ -85,8 +89,19 @@ export async function updateSiteBandwidth(bandwidthData: PeerBandwidth[]) {
lastBandwidthUpdate: sites.lastBandwidthUpdate lastBandwidthUpdate: sites.lastBandwidthUpdate
}); });
if (updatedSite.length > 0) { if (exitNodeId) {
updatedSites.push({ ...updatedSite[0], peer }); if (await checkExitNodeOrg(exitNodeId, updatedSite.orgId)) {
// not allowed
logger.warn(
`Exit node ${exitNodeId} is not allowed for org ${updatedSite.orgId}`
);
// THIS SHOULD TRIGGER THE TRANSACTION TO FAIL?
throw new Error("Exit node not allowed");
}
}
if (updatedSite) {
updatedSites.push({ ...updatedSite, peer });
} }
} }
@ -138,12 +153,29 @@ export async function updateSiteBandwidth(bandwidthData: PeerBandwidth[]) {
// Always update lastBandwidthUpdate to show this instance is receiving reports // Always update lastBandwidthUpdate to show this instance is receiving reports
// Only update online status if it changed // Only update online status if it changed
if (site.online !== newOnlineStatus) { if (site.online !== newOnlineStatus) {
await trx const [updatedSite] = await trx
.update(sites) .update(sites)
.set({ .set({
online: newOnlineStatus online: newOnlineStatus
}) })
.where(eq(sites.siteId, site.siteId)); .where(eq(sites.siteId, site.siteId))
.returning();
if (exitNodeId) {
if (
await checkExitNodeOrg(
exitNodeId,
updatedSite.orgId
)
) {
// not allowed
logger.warn(
`Exit node ${exitNodeId} is not allowed for org ${updatedSite.orgId}`
);
// THIS SHOULD TRIGGER THE TRANSACTION TO FAIL?
throw new Error("Exit node not allowed");
}
}
// If site went offline, add it to our tracking set // If site went offline, add it to our tracking set
if (!newOnlineStatus && site.pubKey) { if (!newOnlineStatus && site.pubKey) {

View file

@ -19,6 +19,7 @@ import { fromError } from "zod-validation-error";
import { validateNewtSessionToken } from "@server/auth/sessions/newt"; import { validateNewtSessionToken } from "@server/auth/sessions/newt";
import { validateOlmSessionToken } from "@server/auth/sessions/olm"; import { validateOlmSessionToken } from "@server/auth/sessions/olm";
import axios from "axios"; import axios from "axios";
import { checkExitNodeOrg } from "@server/lib/exitNodes";
// Define Zod schema for request validation // Define Zod schema for request validation
const updateHolePunchSchema = z.object({ const updateHolePunchSchema = z.object({
@ -157,7 +158,13 @@ export async function updateAndGenerateEndpointDestinations(
.where(eq(clients.clientId, olm.clientId)) .where(eq(clients.clientId, olm.clientId))
.returning(); .returning();
if (await checkExitNodeOrg(exitNode.exitNodeId, client.orgId)) {
// not allowed
logger.warn(
`Exit node ${exitNode.exitNodeId} is not allowed for org ${client.orgId}`
);
throw new Error("Exit node not allowed");
}
// Get sites that are on this specific exit node and connected to this client // Get sites that are on this specific exit node and connected to this client
const sitesOnExitNode = await db const sitesOnExitNode = await db
@ -240,6 +247,20 @@ export async function updateAndGenerateEndpointDestinations(
throw new Error("Newt not found"); throw new Error("Newt not found");
} }
const [site] = await db
.select()
.from(sites)
.where(eq(sites.siteId, newt.siteId))
.limit(1);
if (await checkExitNodeOrg(exitNode.exitNodeId, site.orgId)) {
// not allowed
logger.warn(
`Exit node ${exitNode.exitNodeId} is not allowed for org ${site.orgId}`
);
throw new Error("Exit node not allowed");
}
currentSiteId = newt.siteId; currentSiteId = newt.siteId;
// Update the current site with the new endpoint // Update the current site with the new endpoint