mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-28 07:46:36 +00:00
Merge branch 'dev' into feat/login-page-customization
This commit is contained in:
@@ -31,7 +31,6 @@ import {
|
||||
verifyUserIsServerAdmin,
|
||||
verifySiteAccess,
|
||||
verifyClientAccess,
|
||||
verifyClientsEnabled,
|
||||
} from "@server/middlewares";
|
||||
import { ActionsEnum } from "@server/auth/actions";
|
||||
import {
|
||||
@@ -437,7 +436,6 @@ authenticated.get(
|
||||
|
||||
authenticated.post(
|
||||
"/re-key/:clientId/regenerate-client-secret",
|
||||
verifyClientsEnabled,
|
||||
verifyClientAccess,
|
||||
verifyUserHasAction(ActionsEnum.reGenerateSecret),
|
||||
reKey.reGenerateClientSecret
|
||||
|
||||
@@ -1043,7 +1043,7 @@ hybridRouter.get(
|
||||
);
|
||||
}
|
||||
|
||||
let rules = await db
|
||||
const rules = await db
|
||||
.select()
|
||||
.from(resourceRules)
|
||||
.where(eq(resourceRules.resourceId, resourceId));
|
||||
@@ -1369,7 +1369,7 @@ const updateHolePunchSchema = z.object({
|
||||
port: z.number(),
|
||||
timestamp: z.number(),
|
||||
reachableAt: z.string().optional(),
|
||||
publicKey: z.string().optional()
|
||||
publicKey: z.string() // this is the client public key
|
||||
});
|
||||
hybridRouter.post(
|
||||
"/gerbil/update-hole-punch",
|
||||
@@ -1408,7 +1408,7 @@ hybridRouter.post(
|
||||
);
|
||||
}
|
||||
|
||||
const { olmId, newtId, ip, port, timestamp, token, reachableAt } =
|
||||
const { olmId, newtId, ip, port, timestamp, token, publicKey, reachableAt } =
|
||||
parsedParams.data;
|
||||
|
||||
const destinations = await updateAndGenerateEndpointDestinations(
|
||||
@@ -1418,6 +1418,7 @@ hybridRouter.post(
|
||||
port,
|
||||
timestamp,
|
||||
token,
|
||||
publicKey,
|
||||
exitNode,
|
||||
true
|
||||
);
|
||||
@@ -1742,7 +1743,12 @@ hybridRouter.post(
|
||||
tls: logEntry.tls
|
||||
}));
|
||||
|
||||
await db.insert(requestAuditLog).values(logEntries);
|
||||
// batch them into inserts of 100 to avoid exceeding parameter limits
|
||||
const batchSize = 100;
|
||||
for (let i = 0; i < logEntries.length; i += batchSize) {
|
||||
const batch = logEntries.slice(i, i + batchSize);
|
||||
await db.insert(requestAuditLog).values(batch);
|
||||
}
|
||||
|
||||
return response(res, {
|
||||
data: null,
|
||||
|
||||
@@ -13,13 +13,17 @@
|
||||
|
||||
import * as orgIdp from "#private/routers/orgIdp";
|
||||
import * as org from "#private/routers/org";
|
||||
import * as logs from "#private/routers/auditLogs";
|
||||
|
||||
import { Router } from "express";
|
||||
import {
|
||||
verifyApiKey,
|
||||
verifyApiKeyHasAction,
|
||||
verifyApiKeyIsRoot,
|
||||
verifyApiKeyOrgAccess,
|
||||
} from "@server/middlewares";
|
||||
import {
|
||||
verifyValidSubscription,
|
||||
verifyValidLicense
|
||||
} from "#private/middlewares";
|
||||
import { ActionsEnum } from "@server/auth/actions";
|
||||
|
||||
import { unauthenticated as ua, authenticated as a } from "@server/routers/integration";
|
||||
@@ -42,4 +46,42 @@ authenticated.delete(
|
||||
verifyApiKeyHasAction(ActionsEnum.deleteIdp),
|
||||
logActionAudit(ActionsEnum.deleteIdp),
|
||||
orgIdp.deleteOrgIdp,
|
||||
);
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/logs/action",
|
||||
verifyValidLicense,
|
||||
verifyValidSubscription,
|
||||
verifyApiKeyOrgAccess,
|
||||
verifyApiKeyHasAction(ActionsEnum.exportLogs),
|
||||
logs.queryActionAuditLogs
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/logs/action/export",
|
||||
verifyValidLicense,
|
||||
verifyValidSubscription,
|
||||
verifyApiKeyOrgAccess,
|
||||
verifyApiKeyHasAction(ActionsEnum.exportLogs),
|
||||
logActionAudit(ActionsEnum.exportLogs),
|
||||
logs.exportActionAuditLogs
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/logs/access",
|
||||
verifyValidLicense,
|
||||
verifyValidSubscription,
|
||||
verifyApiKeyOrgAccess,
|
||||
verifyApiKeyHasAction(ActionsEnum.exportLogs),
|
||||
logs.queryAccessAuditLogs
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/logs/access/export",
|
||||
verifyValidLicense,
|
||||
verifyValidSubscription,
|
||||
verifyApiKeyOrgAccess,
|
||||
verifyApiKeyHasAction(ActionsEnum.exportLogs),
|
||||
logActionAudit(ActionsEnum.exportLogs),
|
||||
logs.exportAccessAuditLogs
|
||||
);
|
||||
|
||||
@@ -164,7 +164,7 @@ export async function createLoginPage(
|
||||
.select()
|
||||
.from(exitNodes)
|
||||
.where(and(eq(exitNodes.type, "gerbil"), eq(exitNodes.online, true)))
|
||||
.limit(10);
|
||||
.limit(10);
|
||||
}
|
||||
|
||||
// select a random exit node
|
||||
|
||||
@@ -38,6 +38,7 @@ import { rateLimitService } from "#private/lib/rateLimit";
|
||||
import { messageHandlers } from "@server/routers/ws/messageHandlers";
|
||||
import { messageHandlers as privateMessageHandlers } from "#private/routers/ws/messageHandlers";
|
||||
import { AuthenticatedWebSocket, ClientType, WSMessage, TokenPayload, WebSocketRequest, RedisMessage } from "@server/routers/ws";
|
||||
import { validateSessionToken } from "@server/auth/sessions/app";
|
||||
|
||||
// Merge public and private message handlers
|
||||
Object.assign(messageHandlers, privateMessageHandlers);
|
||||
@@ -370,6 +371,9 @@ const sendToClientLocal = async (
|
||||
client.send(messageString);
|
||||
}
|
||||
});
|
||||
|
||||
logger.debug(`sendToClient: Message type ${message.type} sent to clientId ${clientId}`);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -478,7 +482,8 @@ const getActiveNodes = async (
|
||||
// Token verification middleware
|
||||
const verifyToken = async (
|
||||
token: string,
|
||||
clientType: ClientType
|
||||
clientType: ClientType,
|
||||
userToken: string
|
||||
): Promise<TokenPayload | null> => {
|
||||
try {
|
||||
if (clientType === "newt") {
|
||||
@@ -506,6 +511,17 @@ const verifyToken = async (
|
||||
if (!existingOlm || !existingOlm[0]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (olm.userId) { // this is a user device and we need to check the user token
|
||||
const { session: userSession, user } = await validateSessionToken(userToken);
|
||||
if (!userSession || !user) {
|
||||
return null;
|
||||
}
|
||||
if (user.userId !== olm.userId) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return { client: existingOlm[0], session, clientType };
|
||||
} else if (clientType === "remoteExitNode") {
|
||||
const { session, remoteExitNode } =
|
||||
@@ -652,6 +668,7 @@ const handleWSUpgrade = (server: HttpServer): void => {
|
||||
url.searchParams.get("token") ||
|
||||
request.headers["sec-websocket-protocol"] ||
|
||||
"";
|
||||
const userToken = url.searchParams.get('userToken') || '';
|
||||
let clientType = url.searchParams.get(
|
||||
"clientType"
|
||||
) as ClientType;
|
||||
@@ -673,7 +690,7 @@ const handleWSUpgrade = (server: HttpServer): void => {
|
||||
return;
|
||||
}
|
||||
|
||||
const tokenPayload = await verifyToken(token, clientType);
|
||||
const tokenPayload = await verifyToken(token, clientType, userToken);
|
||||
if (!tokenPayload) {
|
||||
logger.debug(
|
||||
"Unauthorized connection attempt: invalid token..."
|
||||
@@ -792,6 +809,28 @@ if (redisManager.isRedisEnabled()) {
|
||||
);
|
||||
}
|
||||
|
||||
// Disconnect a specific client and force them to reconnect
|
||||
const disconnectClient = async (clientId: string): Promise<boolean> => {
|
||||
const mapKey = getClientMapKey(clientId);
|
||||
const clients = connectedClients.get(mapKey);
|
||||
|
||||
if (!clients || clients.length === 0) {
|
||||
logger.debug(`No connections found for client ID: ${clientId}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
logger.info(`Disconnecting client ID: ${clientId} (${clients.length} connection(s))`);
|
||||
|
||||
// Close all connections for this client
|
||||
clients.forEach((client) => {
|
||||
if (client.readyState === WebSocket.OPEN) {
|
||||
client.close(1000, "Disconnected by server");
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// Cleanup function for graceful shutdown
|
||||
const cleanup = async (): Promise<void> => {
|
||||
try {
|
||||
@@ -829,6 +868,7 @@ export {
|
||||
connectedClients,
|
||||
hasActiveConnections,
|
||||
getActiveNodes,
|
||||
disconnectClient,
|
||||
NODE_ID,
|
||||
cleanup
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user