mirror of
https://github.com/fosrl/pangolin.git
synced 2026-05-30 04:32:53 +00:00
Simplify create site
This commit is contained in:
@@ -243,7 +243,7 @@ registry.registerPath({
|
|||||||
path: "/org/{orgId}/client/{niceId}",
|
path: "/org/{orgId}/client/{niceId}",
|
||||||
description:
|
description:
|
||||||
"Get a client by orgId and niceId. NiceId is a readable ID for the site and unique on a per org basis.",
|
"Get a client by orgId and niceId. NiceId is a readable ID for the site and unique on a per org basis.",
|
||||||
tags: [OpenAPITags.Site],
|
tags: [OpenAPITags.Client],
|
||||||
request: {
|
request: {
|
||||||
params: z.object({
|
params: z.object({
|
||||||
orgId: z.string(),
|
orgId: z.string(),
|
||||||
|
|||||||
@@ -15,11 +15,12 @@ import moment from "moment";
|
|||||||
import { OpenAPITags, registry } from "@server/openApi";
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
import { hashPassword } from "@server/auth/password";
|
import { hashPassword } from "@server/auth/password";
|
||||||
import { isValidIP } from "@server/lib/validators";
|
import { isValidIP } from "@server/lib/validators";
|
||||||
import { isIpInCidr } from "@server/lib/ip";
|
import { getNextAvailableClientSubnet, isIpInCidr } from "@server/lib/ip";
|
||||||
import { verifyExitNodeOrgAccess } from "#dynamic/lib/exitNodes";
|
import { verifyExitNodeOrgAccess } from "#dynamic/lib/exitNodes";
|
||||||
import { build } from "@server/build";
|
import { build } from "@server/build";
|
||||||
import { usageService } from "@server/lib/billing/usageService";
|
import { usageService } from "@server/lib/billing/usageService";
|
||||||
import { FeatureId } from "@server/lib/billing";
|
import { FeatureId } from "@server/lib/billing";
|
||||||
|
import { generateId } from "@server/auth/sessions/app";
|
||||||
|
|
||||||
const createSiteParamsSchema = z.strictObject({
|
const createSiteParamsSchema = z.strictObject({
|
||||||
orgId: z.string()
|
orgId: z.string()
|
||||||
@@ -28,6 +29,7 @@ const createSiteParamsSchema = z.strictObject({
|
|||||||
const createSiteSchema = z.strictObject({
|
const createSiteSchema = z.strictObject({
|
||||||
name: z.string().min(1).max(255),
|
name: z.string().min(1).max(255),
|
||||||
exitNodeId: z.int().positive().optional(),
|
exitNodeId: z.int().positive().optional(),
|
||||||
|
niceId: z.string().min(1).max(255).optional(),
|
||||||
// subdomain: z
|
// subdomain: z
|
||||||
// .string()
|
// .string()
|
||||||
// .min(1)
|
// .min(1)
|
||||||
@@ -52,7 +54,10 @@ const createSiteSchema = z.strictObject({
|
|||||||
|
|
||||||
export type CreateSiteBody = z.infer<typeof createSiteSchema>;
|
export type CreateSiteBody = z.infer<typeof createSiteSchema>;
|
||||||
|
|
||||||
export type CreateSiteResponse = Site;
|
export type CreateSiteResponse = Site & {
|
||||||
|
newtId?: string;
|
||||||
|
secret?: string;
|
||||||
|
};
|
||||||
|
|
||||||
registry.registerPath({
|
registry.registerPath({
|
||||||
method: "put",
|
method: "put",
|
||||||
@@ -64,7 +69,11 @@ registry.registerPath({
|
|||||||
body: {
|
body: {
|
||||||
content: {
|
content: {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
schema: createSiteSchema
|
schema: createSiteSchema,
|
||||||
|
example: {
|
||||||
|
name: "My Site",
|
||||||
|
type: "newt"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,9 +105,13 @@ export async function createSite(
|
|||||||
subnet,
|
subnet,
|
||||||
newtId,
|
newtId,
|
||||||
secret,
|
secret,
|
||||||
address
|
address,
|
||||||
|
niceId
|
||||||
} = parsedBody.data;
|
} = parsedBody.data;
|
||||||
|
|
||||||
|
const updatedNewtSecret = secret || generateId(48);
|
||||||
|
const updatedNewtId = newtId || generateId(15);
|
||||||
|
|
||||||
const parsedParams = createSiteParamsSchema.safeParse(req.params);
|
const parsedParams = createSiteParamsSchema.safeParse(req.params);
|
||||||
if (!parsedParams.success) {
|
if (!parsedParams.success) {
|
||||||
return next(
|
return next(
|
||||||
@@ -111,7 +124,10 @@ export async function createSite(
|
|||||||
|
|
||||||
const { orgId } = parsedParams.data;
|
const { orgId } = parsedParams.data;
|
||||||
|
|
||||||
if (req.user && (!req.userOrgRoleIds || req.userOrgRoleIds.length === 0)) {
|
if (
|
||||||
|
req.user &&
|
||||||
|
(!req.userOrgRoleIds || req.userOrgRoleIds.length === 0)
|
||||||
|
) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(HttpCode.FORBIDDEN, "User does not have a role")
|
createHttpError(HttpCode.FORBIDDEN, "User does not have a role")
|
||||||
);
|
);
|
||||||
@@ -227,6 +243,18 @@ export async function createSite(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
const newClientAddress = await getNextAvailableClientSubnet(orgId);
|
||||||
|
if (!newClientAddress) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.INTERNAL_SERVER_ERROR,
|
||||||
|
"No available address found"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedAddress = newClientAddress.split("/")[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subnet && exitNodeId) {
|
if (subnet && exitNodeId) {
|
||||||
@@ -285,7 +313,31 @@ export async function createSite(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const niceId = await getUniqueSiteName(orgId);
|
let updatedNiceId = niceId;
|
||||||
|
if (!niceId) {
|
||||||
|
updatedNiceId = await getUniqueSiteName(orgId);
|
||||||
|
} else {
|
||||||
|
// make sure the niceId is unique
|
||||||
|
const existingSite = await db
|
||||||
|
.select()
|
||||||
|
.from(sites)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(sites.niceId, niceId),
|
||||||
|
eq(sites.orgId, orgId)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (existingSite.length > 0) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.CONFLICT,
|
||||||
|
`Nice ID ${niceId} already exists. Please choose a different one.`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let newSite: Site | undefined;
|
let newSite: Site | undefined;
|
||||||
await db.transaction(async (trx) => {
|
await db.transaction(async (trx) => {
|
||||||
@@ -295,7 +347,7 @@ export async function createSite(
|
|||||||
.values({ // NOTE: NO SUBNET OR EXIT NODE ID PASSED IN HERE BECAUSE ITS NOW CHOSEN ON CONNECT
|
.values({ // NOTE: NO SUBNET OR EXIT NODE ID PASSED IN HERE BECAUSE ITS NOW CHOSEN ON CONNECT
|
||||||
orgId,
|
orgId,
|
||||||
name,
|
name,
|
||||||
niceId,
|
niceId: updatedNiceId!,
|
||||||
address: updatedAddress || null,
|
address: updatedAddress || null,
|
||||||
type,
|
type,
|
||||||
dockerSocketEnabled: true,
|
dockerSocketEnabled: true,
|
||||||
@@ -353,7 +405,7 @@ export async function createSite(
|
|||||||
orgId,
|
orgId,
|
||||||
exitNodeId,
|
exitNodeId,
|
||||||
name,
|
name,
|
||||||
niceId,
|
niceId: updatedNiceId!,
|
||||||
subnet,
|
subnet,
|
||||||
type,
|
type,
|
||||||
pubKey: pubKey || null,
|
pubKey: pubKey || null,
|
||||||
@@ -367,8 +419,7 @@ export async function createSite(
|
|||||||
exitNodeId: exitNodeId || null,
|
exitNodeId: exitNodeId || null,
|
||||||
orgId,
|
orgId,
|
||||||
name,
|
name,
|
||||||
niceId,
|
niceId: updatedNiceId!,
|
||||||
address: updatedAddress || null,
|
|
||||||
type,
|
type,
|
||||||
dockerSocketEnabled: false,
|
dockerSocketEnabled: false,
|
||||||
online: true,
|
online: true,
|
||||||
@@ -402,7 +453,10 @@ export async function createSite(
|
|||||||
siteId: newSite.siteId
|
siteId: newSite.siteId
|
||||||
});
|
});
|
||||||
|
|
||||||
if (req.user && !req.userOrgRoleIds?.includes(adminRole[0].roleId)) {
|
if (
|
||||||
|
req.user &&
|
||||||
|
!req.userOrgRoleIds?.includes(adminRole[0].roleId)
|
||||||
|
) {
|
||||||
// make sure the user can access the site
|
// make sure the user can access the site
|
||||||
trx.insert(userSites).values({
|
trx.insert(userSites).values({
|
||||||
userId: req.user?.userId!,
|
userId: req.user?.userId!,
|
||||||
@@ -412,10 +466,10 @@ export async function createSite(
|
|||||||
|
|
||||||
// add the peer to the exit node
|
// add the peer to the exit node
|
||||||
if (type == "newt") {
|
if (type == "newt") {
|
||||||
const secretHash = await hashPassword(secret!);
|
const secretHash = await hashPassword(updatedNewtSecret);
|
||||||
|
|
||||||
await trx.insert(newts).values({
|
await trx.insert(newts).values({
|
||||||
newtId: newtId!,
|
newtId: updatedNewtId,
|
||||||
secretHash,
|
secretHash,
|
||||||
siteId: newSite.siteId,
|
siteId: newSite.siteId,
|
||||||
dateCreated: moment().toISOString()
|
dateCreated: moment().toISOString()
|
||||||
@@ -458,7 +512,11 @@ export async function createSite(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return response<CreateSiteResponse>(res, {
|
return response<CreateSiteResponse>(res, {
|
||||||
data: newSite,
|
data: {
|
||||||
|
...newSite,
|
||||||
|
newtId: type == "newt" ? updatedNewtId : undefined,
|
||||||
|
secret: type == "newt" ? updatedNewtSecret : undefined
|
||||||
|
},
|
||||||
success: true,
|
success: true,
|
||||||
error: false,
|
error: false,
|
||||||
message: "Site created successfully",
|
message: "Site created successfully",
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ export async function pickSiteDefaults(
|
|||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.INTERNAL_SERVER_ERROR,
|
HttpCode.INTERNAL_SERVER_ERROR,
|
||||||
"No available subnet found"
|
"No available address"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user