Get new api endpoints working

This commit is contained in:
Owen 2025-02-21 16:12:21 -05:00
parent 6e1bfdac58
commit b1f4971f25
No known key found for this signature in database
GPG key ID: 8271FDFFD9E0CCBD
13 changed files with 79 additions and 51 deletions

View file

@ -35,7 +35,8 @@ gerbil:
wg_site: wg_site:
start_port: 51820 start_port: 51820
block_size: 24 block_size: 24
subnet_group: 100.89.137.0/20 subnet_group: 100.89.138.0/20
site_block_size: 30
rate_limits: rate_limits:
global: global:

View file

@ -173,7 +173,7 @@ export const olmSessions = sqliteTable("clientSession", {
sessionId: text("id").primaryKey(), sessionId: text("id").primaryKey(),
olmId: text("olmId") olmId: text("olmId")
.notNull() .notNull()
.references(() => newts.newtId, { onDelete: "cascade" }), .references(() => olms.olmId, { onDelete: "cascade" }),
expiresAt: integer("expiresAt").notNull() expiresAt: integer("expiresAt").notNull()
}); });

View file

@ -113,7 +113,8 @@ const configSchema = z.object({
wg_site: z.object({ wg_site: z.object({
block_size: z.number().positive().gt(0), block_size: z.number().positive().gt(0),
subnet_group: z.string(), subnet_group: z.string(),
start_port: portSchema start_port: portSchema,
site_block_size: z.number().positive().gt(0)
}), }),
rate_limits: z.object({ rate_limits: z.object({
global: z.object({ global: z.object({

View file

@ -37,10 +37,10 @@ const createClientSchema = z
.object({ .object({
name: z.string().min(1).max(255), name: z.string().min(1).max(255),
siteId: z.number().int().positive(), siteId: z.number().int().positive(),
pubKey: z.string(), pubKey: z.string().optional(),
subnet: z.string(), subnet: z.string().optional(),
olmId: z.string(), olmId: z.string().optional(),
secret: z.string(), secret: z.string().optional(),
type: z.enum(["olm"]) type: z.enum(["olm"])
}) })
.strict(); .strict();

View file

@ -14,7 +14,7 @@ import { fromError } from "zod-validation-error";
const getSiteSchema = z const getSiteSchema = z
.object({ .object({
siteId: z.number().int().positive() siteId: z.string().transform(Number).pipe(z.number())
}) })
.strict(); .strict();
@ -92,12 +92,16 @@ export async function pickClientDefaults(
subnets.push( subnets.push(
address.replace( address.replace(
/\/\d+$/, /\/\d+$/,
`/${config.getRawConfig().wg_site.block_size}` `/${config.getRawConfig().wg_site.site_block_size}`
) )
); );
logger.debug(`Subnets: ${subnets}`);
logger.debug(`Address: ${address}`);
logger.debug(`Block size: ${config.getRawConfig().wg_site.block_size}`);
logger.debug(`Site block size: ${config.getRawConfig().wg_site.site_block_size}`);
const newSubnet = findNextAvailableCidr( const newSubnet = findNextAvailableCidr(
subnets, subnets,
config.getRawConfig().wg_site.block_size, config.getRawConfig().wg_site.site_block_size,
address address
); );
if (!newSubnet) { if (!newSubnet) {

View file

@ -28,7 +28,8 @@ import {
import { verifyUserHasAction } from "../middlewares/verifyUserHasAction"; import { verifyUserHasAction } from "../middlewares/verifyUserHasAction";
import { ActionsEnum } from "@server/auth/actions"; import { ActionsEnum } from "@server/auth/actions";
import { verifyUserIsOrgOwner } from "../middlewares/verifyUserIsOrgOwner"; import { verifyUserIsOrgOwner } from "../middlewares/verifyUserIsOrgOwner";
import { createNewt, getToken } from "./newt"; import { createNewt, getNewtToken } from "./newt";
import { getOlmToken } from "./olm";
import rateLimit from "express-rate-limit"; import rateLimit from "express-rate-limit";
import createHttpError from "http-errors"; import createHttpError from "http-errors";
@ -501,7 +502,8 @@ authRouter.use(
authRouter.put("/signup", auth.signup); authRouter.put("/signup", auth.signup);
authRouter.post("/login", auth.login); authRouter.post("/login", auth.login);
authRouter.post("/logout", auth.logout); authRouter.post("/logout", auth.logout);
authRouter.post("/newt/get-token", getToken); authRouter.post("/newt/get-token", getNewtToken);
authRouter.post("/olm/get-token", getOlmToken);
authRouter.post("/2fa/enable", verifySessionUserMiddleware, auth.verifyTotp); authRouter.post("/2fa/enable", verifySessionUserMiddleware, auth.verifyTotp);
authRouter.post( authRouter.post(

View file

@ -24,7 +24,7 @@ export const newtGetTokenBodySchema = z.object({
export type NewtGetTokenBody = z.infer<typeof newtGetTokenBodySchema>; export type NewtGetTokenBody = z.infer<typeof newtGetTokenBodySchema>;
export async function getToken( export async function getNewtToken(
req: Request, req: Request,
res: Response, res: Response,
next: NextFunction next: NextFunction

View file

@ -10,8 +10,7 @@ import config from "@server/lib/config";
const inputSchema = z.object({ const inputSchema = z.object({
publicKey: z.string(), publicKey: z.string(),
endpoint: z.string(), endpoint: z.string()
listenPort: z.number()
}); });
type Input = z.infer<typeof inputSchema>; type Input = z.infer<typeof inputSchema>;
@ -20,6 +19,9 @@ export const handleGetConfigMessage: MessageHandler = async (context) => {
const { message, client, sendToClient } = context; const { message, client, sendToClient } = context;
const newt = client as Newt; const newt = client as Newt;
logger.debug(JSON.stringify(message.data));
logger.debug("Handling Newt get config message!"); logger.debug("Handling Newt get config message!");
if (!newt) { if (!newt) {
@ -99,8 +101,8 @@ export const handleGetConfigMessage: MessageHandler = async (context) => {
); );
const configResponse = { const configResponse = {
listenPort: site.listenPort, // ????? listenPort: site.listenPort,
// ipAddress: exitNode[0].address, ipAddress: site.address,
peers peers
}; };

View file

@ -12,9 +12,12 @@ interface PeerBandwidth {
export const handleReceiveBandwidthMessage: MessageHandler = async (context) => { export const handleReceiveBandwidthMessage: MessageHandler = async (context) => {
const { message, client, sendToClient } = context; const { message, client, sendToClient } = context;
const newt = client as Newt;
const bandwidthData: PeerBandwidth[] = message.data; if (!message.data.bandwidthData) {
logger.warn("No bandwidth data provided");
}
const bandwidthData: PeerBandwidth[] = message.data.bandwidthData;
if (!Array.isArray(bandwidthData)) { if (!Array.isArray(bandwidthData)) {
throw new Error("Invalid bandwidth data"); throw new Error("Invalid bandwidth data");
@ -63,6 +66,4 @@ export const handleReceiveBandwidthMessage: MessageHandler = async (context) =>
.where(eq(clients.clientId, client.clientId)); .where(eq(clients.clientId, client.clientId));
} }
}); });
logger.info("Handling register olm message!");
}; };

View file

@ -1,4 +1,4 @@
export * from "./createNewt"; export * from "./createNewt";
export * from "./getToken"; export * from "./getNewtToken";
export * from "./handleNewtRegisterMessage"; export * from "./handleNewtRegisterMessage";
export* from "./handleReceiveBandwidthMessage"; export* from "./handleReceiveBandwidthMessage";

View file

@ -1,6 +1,6 @@
import { generateSessionToken } from "@server/auth/sessions/app"; import { generateSessionToken } from "@server/auth/sessions/app";
import db from "@server/db"; import db from "@server/db";
import { newts } from "@server/db/schema"; import { olms } from "@server/db/schema";
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 { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
@ -9,27 +9,27 @@ import createHttpError from "http-errors";
import { z } from "zod"; import { z } from "zod";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import { import {
createNewtSession, createOlmSession,
validateNewtSessionToken validateOlmSessionToken
} from "@server/auth/sessions/newt"; } from "@server/auth/sessions/olm";
import { verifyPassword } from "@server/auth/password"; import { verifyPassword } from "@server/auth/password";
import logger from "@server/logger"; import logger from "@server/logger";
import config from "@server/lib/config"; import config from "@server/lib/config";
export const newtGetTokenBodySchema = z.object({ export const olmGetTokenBodySchema = z.object({
newtId: z.string(), olmId: z.string(),
secret: z.string(), secret: z.string(),
token: z.string().optional() token: z.string().optional()
}); });
export type NewtGetTokenBody = z.infer<typeof newtGetTokenBodySchema>; export type OlmGetTokenBody = z.infer<typeof olmGetTokenBodySchema>;
export async function getToken( export async function getOlmToken(
req: Request, req: Request,
res: Response, res: Response,
next: NextFunction next: NextFunction
): Promise<any> { ): Promise<any> {
const parsedBody = newtGetTokenBodySchema.safeParse(req.body); const parsedBody = olmGetTokenBodySchema.safeParse(req.body);
if (!parsedBody.success) { if (!parsedBody.success) {
return next( return next(
@ -40,15 +40,15 @@ export async function getToken(
); );
} }
const { newtId, secret, token } = parsedBody.data; const { olmId, secret, token } = parsedBody.data;
try { try {
if (token) { if (token) {
const { session, newt } = await validateNewtSessionToken(token); const { session, olm } = await validateOlmSessionToken(token);
if (session) { if (session) {
if (config.getRawConfig().app.log_failed_attempts) { if (config.getRawConfig().app.log_failed_attempts) {
logger.info( logger.info(
`Newt session already valid. Newt ID: ${newtId}. IP: ${req.ip}.` `Olm session already valid. Olm ID: ${olmId}. IP: ${req.ip}.`
); );
} }
return response<null>(res, { return response<null>(res, {
@ -61,29 +61,31 @@ export async function getToken(
} }
} }
const existingNewtRes = await db const existingOlmRes = await db
.select() .select()
.from(newts) .from(olms)
.where(eq(newts.newtId, newtId)); .where(eq(olms.olmId, olmId));
if (!existingNewtRes || !existingNewtRes.length) { if (!existingOlmRes || !existingOlmRes.length) {
return next( return next(
createHttpError( createHttpError(
HttpCode.BAD_REQUEST, HttpCode.BAD_REQUEST,
"No newt found with that newtId" "No olm found with that olmId"
) )
); );
} }
const existingNewt = existingNewtRes[0]; logger.debug("Existing olm: ", existingOlmRes);
const existingOlm = existingOlmRes[0];
const validSecret = await verifyPassword( const validSecret = await verifyPassword(
secret, secret,
existingNewt.secretHash existingOlm.secretHash
); );
if (!validSecret) { if (!validSecret) {
if (config.getRawConfig().app.log_failed_attempts) { if (config.getRawConfig().app.log_failed_attempts) {
logger.info( logger.info(
`Newt id or secret is incorrect. Newt: ID ${newtId}. IP: ${req.ip}.` `Olm id or secret is incorrect. Olm: ID ${olmId}. IP: ${req.ip}.`
); );
} }
return next( return next(
@ -91,8 +93,12 @@ export async function getToken(
); );
} }
logger.debug("Creating new olm session token");
const resToken = generateSessionToken(); const resToken = generateSessionToken();
await createNewtSession(resToken, existingNewt.newtId); await createOlmSession(resToken, existingOlm.olmId);
logger.debug("Token created successfully");
return response<{ token: string }>(res, { return response<{ token: string }>(res, {
data: { data: {
@ -103,12 +109,12 @@ export async function getToken(
message: "Token created successfully", message: "Token created successfully",
status: HttpCode.OK status: HttpCode.OK
}); });
} catch (e) { } catch (error) {
console.error(e); logger.error(error);
return next( return next(
createHttpError( createHttpError(
HttpCode.INTERNAL_SERVER_ERROR, HttpCode.INTERNAL_SERVER_ERROR,
"Failed to authenticate newt" "Failed to authenticate olm"
) )
); );
} }

View file

@ -1 +1,3 @@
export * from "./handleOlmRegisterMessage"; export * from "./handleOlmRegisterMessage";
export * from "./getOlmToken";
export * from "./createOlm";

View file

@ -45,7 +45,7 @@ export async function pickSiteDefaults(
// list all of the sites on that exit node // list all of the sites on that exit node
const sitesQuery = await db const sitesQuery = await db
.select({ .select({
subnet: sites.subnet, subnet: sites.subnet
}) })
.from(sites) .from(sites)
.where(eq(sites.exitNodeId, exitNode.exitNodeId)); .where(eq(sites.exitNodeId, exitNode.exitNodeId));
@ -53,8 +53,17 @@ export async function pickSiteDefaults(
// TODO: we need to lock this subnet for some time so someone else does not take it // TODO: we need to lock this subnet for some time so someone else does not take it
let subnets = sitesQuery.map((site) => site.subnet); let subnets = sitesQuery.map((site) => site.subnet);
// exclude the exit node address by replacing after the / with a site block size // exclude the exit node address by replacing after the / with a site block size
subnets.push(exitNode.address.replace(/\/\d+$/, `/${config.getRawConfig().gerbil.site_block_size}`)); subnets.push(
const newSubnet = findNextAvailableCidr(subnets, config.getRawConfig().gerbil.site_block_size, exitNode.address); exitNode.address.replace(
/\/\d+$/,
`/${config.getRawConfig().gerbil.site_block_size}`
)
);
const newSubnet = findNextAvailableCidr(
subnets,
config.getRawConfig().gerbil.site_block_size,
exitNode.address
);
if (!newSubnet) { if (!newSubnet) {
return next( return next(
createHttpError( createHttpError(
@ -77,12 +86,12 @@ export async function pickSiteDefaults(
endpoint: exitNode.endpoint, endpoint: exitNode.endpoint,
subnet: newSubnet, subnet: newSubnet,
newtId, newtId,
newtSecret: secret, newtSecret: secret
}, },
success: true, success: true,
error: false, error: false,
message: "Organization retrieved successfully", message: "Organization retrieved successfully",
status: HttpCode.OK, status: HttpCode.OK
}); });
} catch (error) { } catch (error) {
logger.error(error); logger.error(error);