Make easier to run in dev - fix a couple of things

This commit is contained in:
Owen
2025-10-12 16:23:38 -07:00
parent f17a957058
commit a50c0d84e9
10 changed files with 265 additions and 123 deletions

View File

@@ -14,10 +14,10 @@
import Stripe from "stripe";
import privateConfig from "#private/lib/config";
import logger from "@server/logger";
import { build } from "@server/build";
import { noop } from "@server/lib/billing/usageService";
let stripe: Stripe | undefined = undefined;
if (build == "saas") {
if (!noop()) {
const stripeApiKey = privateConfig.getRawPrivateConfig().stripe?.secret_key;
if (!stripeApiKey) {
logger.error("Stripe secret key is not configured");

View File

@@ -33,10 +33,11 @@ import rateLimit, { ipKeyGenerator } from "express-rate-limit";
import createHttpError from "http-errors";
import HttpCode from "@server/types/HttpCode";
import { unauthenticated as ua, authenticated as a } from "@server/routers/external";
import { unauthenticated as ua, authenticated as a, authRouter as aa } from "@server/routers/external";
export const authenticated = a;
export const unauthenticated = ua;
export const authRouter = aa;
unauthenticated.post(
"/quick-start",
@@ -227,8 +228,6 @@ authenticated.get(
loginPage.getLoginPage
);
export const authRouter = Router();
authRouter.post(
"/remoteExitNode/get-token",
rateLimit({

View File

@@ -68,10 +68,11 @@ import { decryptData } from "@server/lib/encryption";
import config from "@server/lib/config";
import privateConfig from "#private/lib/config";
import * as fs from "fs";
import { exchangeSession } from "@server/routers/badger";
import { exchangeSession } from "@server/routers/badger";
import { validateResourceSessionToken } from "@server/auth/sessions/resource";
import { checkExitNodeOrg, resolveExitNodes } from "#private/lib/exitNodes";
import { maxmindLookup } from "@server/db/maxmind";
import { verifyResourceAccessToken } from "@server/auth/verifyResourceAccessToken";
// Zod schemas for request validation
const getResourceByDomainParamsSchema = z
@@ -162,6 +163,14 @@ const validateResourceSessionTokenBodySchema = z
})
.strict();
const validateResourceAccessTokenBodySchema = z
.object({
accessTokenId: z.string().optional(),
resourceId: z.number().optional(),
accessToken: z.string()
})
.strict();
// Certificates by domains query validation
const getCertificatesByDomainsQuerySchema = z
.object({
@@ -215,6 +224,33 @@ export type UserSessionWithUser = {
export const hybridRouter = Router();
hybridRouter.use(verifySessionRemoteExitNodeMiddleware);
hybridRouter.get(
"/general-config",
async (req: Request, res: Response, next: NextFunction) => {
return response(res, {
data: {
resource_session_request_param:
config.getRawConfig().server.resource_session_request_param,
resource_access_token_headers:
config.getRawConfig().server.resource_access_token_headers,
resource_access_token_param:
config.getRawConfig().server.resource_access_token_param,
session_cookie_name:
config.getRawConfig().server.session_cookie_name,
require_email_verification:
config.getRawConfig().flags?.require_email_verification ||
false,
resource_session_length_hours:
config.getRawConfig().server.resource_session_length_hours
},
success: true,
error: false,
message: "General config retrieved successfully",
status: HttpCode.OK
});
}
);
hybridRouter.get(
"/traefik-config",
async (req: Request, res: Response, next: NextFunction) => {
@@ -1101,6 +1137,52 @@ hybridRouter.post(
}
);
// Validate resource session token
hybridRouter.post(
"/resource/:resourceId/access-token/verify",
async (req: Request, res: Response, next: NextFunction) => {
try {
const parsedBody = validateResourceAccessTokenBodySchema.safeParse(
req.body
);
if (!parsedBody.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedBody.error).toString()
)
);
}
const { accessToken, resourceId, accessTokenId } = parsedBody.data;
const result = await verifyResourceAccessToken({
accessTokenId,
accessToken,
resourceId
});
return response(res, {
data: result,
success: true,
error: false,
message: result.valid
? "Resource access token is valid"
: "Resource access token is invalid or expired",
status: HttpCode.OK
});
} catch (error) {
logger.error(error);
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"Failed to validate resource session token"
)
);
}
}
);
const geoIpLookupParamsSchema = z.object({
ip: z.string().ip()
});
@@ -1489,4 +1571,4 @@ hybridRouter.post(
);
}
}
);
);

View File

@@ -84,30 +84,25 @@ export async function createRemoteExitNode(
orgId,
FeatureId.REMOTE_EXIT_NODES
);
if (!usage) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
"No usage data found for this organization"
)
);
}
const rejectRemoteExitNodes = await usageService.checkLimitSet(
orgId,
false,
FeatureId.REMOTE_EXIT_NODES,
{
...usage,
instantaneousValue: (usage.instantaneousValue || 0) + 1
} // We need to add one to know if we are violating the limit
);
if (rejectRemoteExitNodes) {
return next(
createHttpError(
HttpCode.FORBIDDEN,
"Remote exit node limit exceeded. Please upgrade your plan or contact us at support@fossorial.io"
)
if (usage) {
const rejectRemoteExitNodes = await usageService.checkLimitSet(
orgId,
false,
FeatureId.REMOTE_EXIT_NODES,
{
...usage,
instantaneousValue: (usage.instantaneousValue || 0) + 1
} // We need to add one to know if we are violating the limit
);
if (rejectRemoteExitNodes) {
return next(
createHttpError(
HttpCode.FORBIDDEN,
"Remote exit node limit exceeded. Please upgrade your plan or contact us at support@fossorial.io"
)
);
}
}
const secretHash = await hashPassword(secret);