mirror of
https://github.com/fosrl/pangolin.git
synced 2026-03-04 01:36:39 +00:00
Merge branch 'clients-user' into refactor/separate-tables
This commit is contained in:
@@ -8,7 +8,7 @@ import logger from "@server/logger";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
import { rebuildClientAssociations } from "@server/lib/rebuildClientAssociations";
|
||||
import { rebuildClientAssociationsFromSiteResource } from "@server/lib/rebuildClientAssociations";
|
||||
|
||||
const addClientToSiteResourceBodySchema = z
|
||||
.object({
|
||||
@@ -136,7 +136,7 @@ export async function addClientToSiteResource(
|
||||
siteResourceId
|
||||
});
|
||||
|
||||
await rebuildClientAssociations(siteResource, trx);
|
||||
await rebuildClientAssociationsFromSiteResource(siteResource, trx);
|
||||
});
|
||||
|
||||
return response(res, {
|
||||
|
||||
@@ -9,7 +9,7 @@ import logger from "@server/logger";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
import { rebuildClientAssociations } from "@server/lib/rebuildClientAssociations";
|
||||
import { rebuildClientAssociationsFromSiteResource } from "@server/lib/rebuildClientAssociations";
|
||||
|
||||
const addRoleToSiteResourceBodySchema = z
|
||||
.object({
|
||||
@@ -146,7 +146,7 @@ export async function addRoleToSiteResource(
|
||||
siteResourceId
|
||||
});
|
||||
|
||||
await rebuildClientAssociations(siteResource, trx);
|
||||
await rebuildClientAssociationsFromSiteResource(siteResource, trx);
|
||||
});
|
||||
|
||||
return response(res, {
|
||||
|
||||
@@ -9,7 +9,7 @@ import logger from "@server/logger";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
import { rebuildClientAssociations } from "@server/lib/rebuildClientAssociations";
|
||||
import { rebuildClientAssociationsFromSiteResource } from "@server/lib/rebuildClientAssociations";
|
||||
|
||||
const addUserToSiteResourceBodySchema = z
|
||||
.object({
|
||||
@@ -115,7 +115,7 @@ export async function addUserToSiteResource(
|
||||
siteResourceId
|
||||
});
|
||||
|
||||
await rebuildClientAssociations(siteResource, trx);
|
||||
await rebuildClientAssociationsFromSiteResource(siteResource, trx);
|
||||
});
|
||||
|
||||
return response(res, {
|
||||
|
||||
@@ -17,7 +17,8 @@ import { fromError } from "zod-validation-error";
|
||||
import logger from "@server/logger";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
import { getUniqueSiteResourceName } from "@server/db/names";
|
||||
import { rebuildClientAssociations } from "@server/lib/rebuildClientAssociations";
|
||||
import { rebuildClientAssociationsFromSiteResource } from "@server/lib/rebuildClientAssociations";
|
||||
import { getNextAvailableAliasAddress } from "@server/lib/ip";
|
||||
|
||||
const createSiteResourceParamsSchema = z.strictObject({
|
||||
siteId: z.string().transform(Number).pipe(z.int().positive()),
|
||||
@@ -193,6 +194,10 @@ export async function createSiteResource(
|
||||
// }
|
||||
|
||||
const niceId = await getUniqueSiteResourceName(orgId);
|
||||
let aliasAddress: string | null = null;
|
||||
if (mode == "host") { // we can only have an alias on a host
|
||||
aliasAddress = await getNextAvailableAliasAddress(orgId);
|
||||
}
|
||||
|
||||
let newSiteResource: SiteResource | undefined;
|
||||
await db.transaction(async (trx) => {
|
||||
@@ -210,7 +215,8 @@ export async function createSiteResource(
|
||||
// destinationPort: mode === "port" ? destinationPort : null,
|
||||
destination,
|
||||
enabled,
|
||||
alias: alias || null
|
||||
alias,
|
||||
aliasAddress
|
||||
})
|
||||
.returning();
|
||||
|
||||
@@ -272,7 +278,7 @@ export async function createSiteResource(
|
||||
);
|
||||
}
|
||||
|
||||
await rebuildClientAssociations(newSiteResource, trx); // we need to call this because we added to the admin role
|
||||
await rebuildClientAssociationsFromSiteResource(newSiteResource, trx); // we need to call this because we added to the admin role
|
||||
});
|
||||
|
||||
if (!newSiteResource) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import { eq, and } from "drizzle-orm";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import logger from "@server/logger";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
import { rebuildClientAssociations } from "@server/lib/rebuildClientAssociations";
|
||||
import { rebuildClientAssociationsFromSiteResource } from "@server/lib/rebuildClientAssociations";
|
||||
|
||||
const deleteSiteResourceParamsSchema = z.strictObject({
|
||||
siteResourceId: z.string().transform(Number).pipe(z.int().positive()),
|
||||
@@ -106,7 +106,7 @@ export async function deleteSiteResource(
|
||||
);
|
||||
}
|
||||
|
||||
await rebuildClientAssociations(removedSiteResource, trx);
|
||||
await rebuildClientAssociationsFromSiteResource(removedSiteResource, trx);
|
||||
});
|
||||
|
||||
logger.info(
|
||||
|
||||
@@ -8,7 +8,7 @@ import logger from "@server/logger";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
import { rebuildClientAssociations } from "@server/lib/rebuildClientAssociations";
|
||||
import { rebuildClientAssociationsFromSiteResource } from "@server/lib/rebuildClientAssociations";
|
||||
|
||||
const removeClientFromSiteResourceBodySchema = z
|
||||
.object({
|
||||
@@ -142,7 +142,7 @@ export async function removeClientFromSiteResource(
|
||||
)
|
||||
);
|
||||
|
||||
await rebuildClientAssociations(siteResource, trx);
|
||||
await rebuildClientAssociationsFromSiteResource(siteResource, trx);
|
||||
});
|
||||
|
||||
return response(res, {
|
||||
|
||||
@@ -9,7 +9,7 @@ import logger from "@server/logger";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
import { rebuildClientAssociations } from "@server/lib/rebuildClientAssociations";
|
||||
import { rebuildClientAssociationsFromSiteResource } from "@server/lib/rebuildClientAssociations";
|
||||
|
||||
const removeRoleFromSiteResourceBodySchema = z
|
||||
.object({
|
||||
@@ -151,7 +151,7 @@ export async function removeRoleFromSiteResource(
|
||||
)
|
||||
);
|
||||
|
||||
await rebuildClientAssociations(siteResource, trx);
|
||||
await rebuildClientAssociationsFromSiteResource(siteResource, trx);
|
||||
});
|
||||
|
||||
return response(res, {
|
||||
|
||||
@@ -9,7 +9,7 @@ import logger from "@server/logger";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
import { rebuildClientAssociations } from "@server/lib/rebuildClientAssociations";
|
||||
import { rebuildClientAssociationsFromSiteResource } from "@server/lib/rebuildClientAssociations";
|
||||
|
||||
const removeUserFromSiteResourceBodySchema = z
|
||||
.object({
|
||||
@@ -121,7 +121,7 @@ export async function removeUserFromSiteResource(
|
||||
)
|
||||
);
|
||||
|
||||
await rebuildClientAssociations(siteResource, trx);
|
||||
await rebuildClientAssociationsFromSiteResource(siteResource, trx);
|
||||
});
|
||||
|
||||
return response(res, {
|
||||
|
||||
@@ -8,7 +8,7 @@ import logger from "@server/logger";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { eq, inArray } from "drizzle-orm";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
import { rebuildClientAssociations } from "@server/lib/rebuildClientAssociations";
|
||||
import { rebuildClientAssociationsFromSiteResource } from "@server/lib/rebuildClientAssociations";
|
||||
|
||||
const setSiteResourceClientsBodySchema = z
|
||||
.object({
|
||||
@@ -124,7 +124,7 @@ export async function setSiteResourceClients(
|
||||
.values(clientIds.map((clientId) => ({ clientId, siteResourceId })));
|
||||
}
|
||||
|
||||
await rebuildClientAssociations(siteResource, trx);
|
||||
await rebuildClientAssociationsFromSiteResource(siteResource, trx);
|
||||
});
|
||||
|
||||
return response(res, {
|
||||
|
||||
@@ -9,7 +9,7 @@ import logger from "@server/logger";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { eq, and, ne, inArray } from "drizzle-orm";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
import { rebuildClientAssociations } from "@server/lib/rebuildClientAssociations";
|
||||
import { rebuildClientAssociationsFromSiteResource } from "@server/lib/rebuildClientAssociations";
|
||||
|
||||
const setSiteResourceRolesBodySchema = z
|
||||
.object({
|
||||
@@ -147,7 +147,7 @@ export async function setSiteResourceRoles(
|
||||
.values(roleIds.map((roleId) => ({ roleId, siteResourceId })));
|
||||
}
|
||||
|
||||
await rebuildClientAssociations(siteResource, trx);
|
||||
await rebuildClientAssociationsFromSiteResource(siteResource, trx);
|
||||
});
|
||||
|
||||
return response(res, {
|
||||
|
||||
@@ -9,7 +9,7 @@ import logger from "@server/logger";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
import { rebuildClientAssociations } from "@server/lib/rebuildClientAssociations";
|
||||
import { rebuildClientAssociationsFromSiteResource } from "@server/lib/rebuildClientAssociations";
|
||||
|
||||
const setSiteResourceUsersBodySchema = z
|
||||
.object({
|
||||
@@ -102,7 +102,7 @@ export async function setSiteResourceUsers(
|
||||
.values(userIds.map((userId) => ({ userId, siteResourceId })));
|
||||
}
|
||||
|
||||
await rebuildClientAssociations(siteResource, trx);
|
||||
await rebuildClientAssociationsFromSiteResource(siteResource, trx);
|
||||
});
|
||||
|
||||
return response(res, {
|
||||
|
||||
@@ -17,17 +17,15 @@ import { eq, and, ne } from "drizzle-orm";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import logger from "@server/logger";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
import { updatePeerData, updateTargets } from "@server/routers/client/targets";
|
||||
import {
|
||||
updateRemoteSubnets,
|
||||
updateTargets
|
||||
} from "@server/routers/client/targets";
|
||||
import {
|
||||
generateAliasConfig,
|
||||
generateRemoteSubnets,
|
||||
generateSubnetProxyTargets
|
||||
} from "@server/lib/ip";
|
||||
import {
|
||||
getClientSiteResourceAccess,
|
||||
rebuildClientAssociations
|
||||
rebuildClientAssociationsFromSiteResource
|
||||
} from "@server/lib/rebuildClientAssociations";
|
||||
|
||||
const updateSiteResourceParamsSchema = z.strictObject({
|
||||
@@ -51,7 +49,44 @@ const updateSiteResourceSchema = z
|
||||
roleIds: z.array(z.int()),
|
||||
clientIds: z.array(z.int())
|
||||
})
|
||||
.strict();
|
||||
.strict()
|
||||
.refine(
|
||||
(data) => {
|
||||
if (data.mode === "host" && data.destination) {
|
||||
// Check if it's a valid IP address using zod (v4 or v6)
|
||||
const isValidIP = z
|
||||
.union([z.ipv4(), z.ipv6()])
|
||||
.safeParse(data.destination).success;
|
||||
|
||||
// Check if it's a valid domain (hostname pattern, TLD not required)
|
||||
const domainRegex =
|
||||
/^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)*[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/;
|
||||
const isValidDomain = domainRegex.test(data.destination);
|
||||
|
||||
return isValidIP || isValidDomain;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
{
|
||||
message:
|
||||
"Destination must be a valid IP address or domain name for host mode"
|
||||
}
|
||||
)
|
||||
.refine(
|
||||
(data) => {
|
||||
if (data.mode === "cidr" && data.destination) {
|
||||
// Check if it's a valid CIDR (v4 or v6)
|
||||
const isValidCIDR = z
|
||||
.union([z.cidrv4(), z.cidrv6()])
|
||||
.safeParse(data.destination).success;
|
||||
return isValidCIDR;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
{
|
||||
message: "Destination must be a valid CIDR notation for cidr mode"
|
||||
}
|
||||
);
|
||||
|
||||
export type UpdateSiteResourceBody = z.infer<typeof updateSiteResourceSchema>;
|
||||
export type UpdateSiteResourceResponse = SiteResource;
|
||||
@@ -226,16 +261,20 @@ export async function updateSiteResource(
|
||||
);
|
||||
}
|
||||
|
||||
const { mergedAllClients } = await rebuildClientAssociations(
|
||||
existingSiteResource, // we want to rebuild based on the existing resource then we will apply the change to the destination below
|
||||
trx
|
||||
);
|
||||
const { mergedAllClients } =
|
||||
await rebuildClientAssociationsFromSiteResource(
|
||||
existingSiteResource, // we want to rebuild based on the existing resource then we will apply the change to the destination below
|
||||
trx
|
||||
);
|
||||
|
||||
// after everything is rebuilt above we still need to update the targets and remote subnets if the destination changed
|
||||
if (
|
||||
const destinationChanged =
|
||||
existingSiteResource.destination !==
|
||||
updatedSiteResource.destination
|
||||
) {
|
||||
updatedSiteResource.destination;
|
||||
const aliasChanged =
|
||||
existingSiteResource.alias !== updatedSiteResource.alias;
|
||||
|
||||
if (destinationChanged || aliasChanged) {
|
||||
const [newt] = await trx
|
||||
.select()
|
||||
.from(newts)
|
||||
@@ -248,25 +287,28 @@ export async function updateSiteResource(
|
||||
);
|
||||
}
|
||||
|
||||
const oldTargets = generateSubnetProxyTargets(
|
||||
existingSiteResource,
|
||||
mergedAllClients
|
||||
);
|
||||
const newTargets = generateSubnetProxyTargets(
|
||||
updatedSiteResource,
|
||||
mergedAllClients
|
||||
);
|
||||
// Only update targets on newt if destination changed
|
||||
if (destinationChanged) {
|
||||
const oldTargets = generateSubnetProxyTargets(
|
||||
existingSiteResource,
|
||||
mergedAllClients
|
||||
);
|
||||
const newTargets = generateSubnetProxyTargets(
|
||||
updatedSiteResource,
|
||||
mergedAllClients
|
||||
);
|
||||
|
||||
await updateTargets(newt.newtId, {
|
||||
oldTargets: oldTargets,
|
||||
newTargets: newTargets
|
||||
});
|
||||
await updateTargets(newt.newtId, {
|
||||
oldTargets: oldTargets,
|
||||
newTargets: newTargets
|
||||
});
|
||||
}
|
||||
|
||||
const olmJobs: Promise<void>[] = [];
|
||||
for (const client of mergedAllClients) {
|
||||
// we also need to update the remote subnets on the olms for each client that has access to this site
|
||||
olmJobs.push(
|
||||
updateRemoteSubnets(
|
||||
updatePeerData(
|
||||
client.clientId,
|
||||
updatedSiteResource.siteId,
|
||||
{
|
||||
@@ -276,8 +318,22 @@ export async function updateSiteResource(
|
||||
newRemoteSubnets: generateRemoteSubnets([
|
||||
updatedSiteResource
|
||||
])
|
||||
},
|
||||
{
|
||||
oldAliases: generateAliasConfig([
|
||||
existingSiteResource
|
||||
]),
|
||||
newAliases: generateAliasConfig([
|
||||
updatedSiteResource
|
||||
])
|
||||
}
|
||||
)
|
||||
).catch((error) => {
|
||||
// this is okay because sometimes the olm is not online to receive the update or associated with the client yet
|
||||
logger.warn(
|
||||
`Error updating peer data for client ${client.clientId}:`,
|
||||
error
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user