mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-01 08:34:53 +02:00
add openapi registers
This commit is contained in:
parent
a76e3e00f7
commit
d260450a84
50 changed files with 852 additions and 60 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -32,3 +32,4 @@ installer
|
||||||
bin
|
bin
|
||||||
.secrets
|
.secrets
|
||||||
test_event.json
|
test_event.json
|
||||||
|
swagger.ts
|
||||||
|
|
44
package-lock.json
generated
44
package-lock.json
generated
|
@ -67,6 +67,7 @@
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"rebuild": "0.1.2",
|
"rebuild": "0.1.2",
|
||||||
"semver": "7.6.3",
|
"semver": "7.6.3",
|
||||||
|
"swagger-ui-express": "^5.0.1",
|
||||||
"tailwind-merge": "2.6.0",
|
"tailwind-merge": "2.6.0",
|
||||||
"tailwindcss-animate": "1.0.7",
|
"tailwindcss-animate": "1.0.7",
|
||||||
"vaul": "1.1.2",
|
"vaul": "1.1.2",
|
||||||
|
@ -89,6 +90,7 @@
|
||||||
"@types/react": "19.0.2",
|
"@types/react": "19.0.2",
|
||||||
"@types/react-dom": "19.0.2",
|
"@types/react-dom": "19.0.2",
|
||||||
"@types/semver": "7.5.8",
|
"@types/semver": "7.5.8",
|
||||||
|
"@types/swagger-ui-express": "^4.1.8",
|
||||||
"@types/ws": "8.5.13",
|
"@types/ws": "8.5.13",
|
||||||
"@types/yargs": "17.0.33",
|
"@types/yargs": "17.0.33",
|
||||||
"drizzle-kit": "0.30.1",
|
"drizzle-kit": "0.30.1",
|
||||||
|
@ -4164,6 +4166,13 @@
|
||||||
"integrity": "sha512-kkKUDVlII2DQiKy7UstOR1ErJP8kUKAQ4oa+SQtM0K+lPdmmjj0YnnxBgtTVYH7mUKtbsxeFC9y0AmK7Yb78/A==",
|
"integrity": "sha512-kkKUDVlII2DQiKy7UstOR1ErJP8kUKAQ4oa+SQtM0K+lPdmmjj0YnnxBgtTVYH7mUKtbsxeFC9y0AmK7Yb78/A==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@scarf/scarf": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
"node_modules/@selderee/plugin-htmlparser2": {
|
"node_modules/@selderee/plugin-htmlparser2": {
|
||||||
"version": "0.11.0",
|
"version": "0.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz",
|
||||||
|
@ -4442,6 +4451,17 @@
|
||||||
"@types/send": "*"
|
"@types/send": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/swagger-ui-express": {
|
||||||
|
"version": "4.1.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-4.1.8.tgz",
|
||||||
|
"integrity": "sha512-AhZV8/EIreHFmBV5wAs0gzJUNq9JbbSXgJLQubCC0jtIo6prnI9MIRRxnU4MZX9RB9yXxF1V4R7jtLl/Wcj31g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/express": "*",
|
||||||
|
"@types/serve-static": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/triple-beam": {
|
"node_modules/@types/triple-beam": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
|
||||||
|
@ -15562,6 +15582,30 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/swagger-ui-dist": {
|
||||||
|
"version": "5.20.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.20.6.tgz",
|
||||||
|
"integrity": "sha512-q/1dwcCOQb+qsNkb+1VWRdGEEVdBtOTH4vv9rICjPwJXOwq/JSRkBbuEMjMe161Oxsp589+8Ff5nE4HTPLWIAw==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@scarf/scarf": "=1.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/swagger-ui-express": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"swagger-ui-dist": ">=5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= v0.10.32"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"express": ">=4.0.0 || >=5.0.0-beta"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tailwind-merge": {
|
"node_modules/tailwind-merge": {
|
||||||
"version": "2.6.0",
|
"version": "2.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.0.tgz",
|
||||||
|
|
|
@ -78,6 +78,7 @@
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"rebuild": "0.1.2",
|
"rebuild": "0.1.2",
|
||||||
"semver": "7.6.3",
|
"semver": "7.6.3",
|
||||||
|
"swagger-ui-express": "^5.0.1",
|
||||||
"tailwind-merge": "2.6.0",
|
"tailwind-merge": "2.6.0",
|
||||||
"tailwindcss-animate": "1.0.7",
|
"tailwindcss-animate": "1.0.7",
|
||||||
"vaul": "1.1.2",
|
"vaul": "1.1.2",
|
||||||
|
@ -100,6 +101,7 @@
|
||||||
"@types/react": "19.0.2",
|
"@types/react": "19.0.2",
|
||||||
"@types/react-dom": "19.0.2",
|
"@types/react-dom": "19.0.2",
|
||||||
"@types/semver": "7.5.8",
|
"@types/semver": "7.5.8",
|
||||||
|
"@types/swagger-ui-express": "^4.1.8",
|
||||||
"@types/ws": "8.5.13",
|
"@types/ws": "8.5.13",
|
||||||
"@types/yargs": "17.0.33",
|
"@types/yargs": "17.0.33",
|
||||||
"drizzle-kit": "0.30.1",
|
"drizzle-kit": "0.30.1",
|
||||||
|
|
|
@ -2,16 +2,13 @@ import { OpenAPIRegistry } from "@asteasolutions/zod-to-openapi";
|
||||||
|
|
||||||
export const registry = new OpenAPIRegistry();
|
export const registry = new OpenAPIRegistry();
|
||||||
|
|
||||||
export const bearerAuth = registry.registerComponent(
|
|
||||||
"securitySchemes",
|
|
||||||
"Bearer Auth",
|
|
||||||
{
|
|
||||||
type: "http",
|
|
||||||
scheme: "bearer"
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export enum OpenAPITags {
|
export enum OpenAPITags {
|
||||||
Site = "Site",
|
Site = "Site",
|
||||||
Org = "Organization"
|
Org = "Organization",
|
||||||
|
Resource = "Resource",
|
||||||
|
Role = "Role",
|
||||||
|
User = "User",
|
||||||
|
Target = "Target",
|
||||||
|
Rule = "Rule",
|
||||||
|
AccessToken = "Access Token"
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { fromError } from "zod-validation-error";
|
||||||
import { resourceAccessToken } from "@server/db/schemas";
|
import { resourceAccessToken } from "@server/db/schemas";
|
||||||
import { and, eq } from "drizzle-orm";
|
import { and, eq } from "drizzle-orm";
|
||||||
import db from "@server/db";
|
import db from "@server/db";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const deleteAccessTokenParamsSchema = z
|
const deleteAccessTokenParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -15,6 +16,17 @@ const deleteAccessTokenParamsSchema = z
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "delete",
|
||||||
|
path: "/access-token/{accessTokenId}",
|
||||||
|
description: "Delete a access token.",
|
||||||
|
tags: [OpenAPITags.AccessToken],
|
||||||
|
request: {
|
||||||
|
params: deleteAccessTokenParamsSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function deleteAccessToken(
|
export async function deleteAccessToken(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -22,6 +22,7 @@ import { createDate, TimeSpan } from "oslo";
|
||||||
import { hashPassword } from "@server/auth/password";
|
import { hashPassword } from "@server/auth/password";
|
||||||
import { encodeHexLowerCase } from "@oslojs/encoding";
|
import { encodeHexLowerCase } from "@oslojs/encoding";
|
||||||
import { sha256 } from "@oslojs/crypto/sha2";
|
import { sha256 } from "@oslojs/crypto/sha2";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
export const generateAccessTokenBodySchema = z
|
export const generateAccessTokenBodySchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -45,6 +46,24 @@ export type GenerateAccessTokenResponse = Omit<
|
||||||
"tokenHash"
|
"tokenHash"
|
||||||
> & { accessToken: string };
|
> & { accessToken: string };
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "post",
|
||||||
|
path: "/resource/{resourceId}/access-token",
|
||||||
|
description: "Generate a new access token for a resource.",
|
||||||
|
tags: [OpenAPITags.Resource, OpenAPITags.AccessToken],
|
||||||
|
request: {
|
||||||
|
params: generateAccssTokenParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: generateAccessTokenBodySchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function generateAccessToken(
|
export async function generateAccessToken(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { sql, eq, or, inArray, and, count, isNull, lt, gt } from "drizzle-orm";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import stoi from "@server/lib/stoi";
|
import stoi from "@server/lib/stoi";
|
||||||
import { fromZodError } from "zod-validation-error";
|
import { fromZodError } from "zod-validation-error";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const listAccessTokensParamsSchema = z
|
const listAccessTokensParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -73,10 +74,7 @@ function queryAccessTokens(
|
||||||
resources,
|
resources,
|
||||||
eq(resourceAccessToken.resourceId, resources.resourceId)
|
eq(resourceAccessToken.resourceId, resources.resourceId)
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(sites, eq(resources.resourceId, sites.siteId))
|
||||||
sites,
|
|
||||||
eq(resources.resourceId, sites.siteId)
|
|
||||||
)
|
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
inArray(
|
inArray(
|
||||||
|
@ -98,10 +96,7 @@ function queryAccessTokens(
|
||||||
resources,
|
resources,
|
||||||
eq(resourceAccessToken.resourceId, resources.resourceId)
|
eq(resourceAccessToken.resourceId, resources.resourceId)
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(sites, eq(resources.resourceId, sites.siteId))
|
||||||
sites,
|
|
||||||
eq(resources.resourceId, sites.siteId)
|
|
||||||
)
|
|
||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
inArray(
|
inArray(
|
||||||
|
@ -123,6 +118,34 @@ export type ListAccessTokensResponse = {
|
||||||
pagination: { total: number; limit: number; offset: number };
|
pagination: { total: number; limit: number; offset: number };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/org/{orgId}/access-tokens",
|
||||||
|
description: "List all access tokens in an organization.",
|
||||||
|
tags: [OpenAPITags.Org, OpenAPITags.AccessToken],
|
||||||
|
request: {
|
||||||
|
params: z.object({
|
||||||
|
orgId: z.string()
|
||||||
|
}),
|
||||||
|
query: listAccessTokensSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/resource/{resourceId}/access-tokens",
|
||||||
|
description: "List all access tokens in an organization.",
|
||||||
|
tags: [OpenAPITags.Resource, OpenAPITags.AccessToken],
|
||||||
|
request: {
|
||||||
|
params: z.object({
|
||||||
|
resourceId: z.number()
|
||||||
|
}),
|
||||||
|
query: listAccessTokensSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function listAccessTokens(
|
export async function listAccessTokens(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import createHttpError from "http-errors";
|
||||||
import { eq, sql } from "drizzle-orm";
|
import { eq, sql } from "drizzle-orm";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const listDomainsParamsSchema = z
|
const listDomainsParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -51,6 +52,20 @@ export type ListDomainsResponse = {
|
||||||
pagination: { total: number; limit: number; offset: number };
|
pagination: { total: number; limit: number; offset: number };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/org/{orgId}/domains",
|
||||||
|
description: "List all domains for a organization.",
|
||||||
|
tags: [OpenAPITags.Org],
|
||||||
|
request: {
|
||||||
|
params: z.object({
|
||||||
|
orgId: z.string()
|
||||||
|
}),
|
||||||
|
query: listDomainsSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function listDomains(
|
export async function listDomains(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -19,6 +19,7 @@ import { createAdminRole } from "@server/setup/ensureActions";
|
||||||
import config from "@server/lib/config";
|
import config from "@server/lib/config";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import { defaultRoleAllowedActions } from "../role";
|
import { defaultRoleAllowedActions } from "../role";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const createOrgSchema = z
|
const createOrgSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -29,6 +30,23 @@ const createOrgSchema = z
|
||||||
|
|
||||||
// const MAX_ORGS = 5;
|
// const MAX_ORGS = 5;
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "put",
|
||||||
|
path: "/org",
|
||||||
|
description: "Create a new organization",
|
||||||
|
tags: [OpenAPITags.Org],
|
||||||
|
request: {
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: createOrgSchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function createOrg(
|
export async function createOrg(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -17,6 +17,7 @@ import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import { sendToClient } from "../ws";
|
import { sendToClient } from "../ws";
|
||||||
import { deletePeer } from "../gerbil/peers";
|
import { deletePeer } from "../gerbil/peers";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const deleteOrgSchema = z
|
const deleteOrgSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -26,6 +27,17 @@ const deleteOrgSchema = z
|
||||||
|
|
||||||
export type DeleteOrgResponse = {};
|
export type DeleteOrgResponse = {};
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "delete",
|
||||||
|
path: "/org/{orgId}",
|
||||||
|
description: "Delete an organization",
|
||||||
|
tags: [OpenAPITags.Org],
|
||||||
|
request: {
|
||||||
|
params: deleteOrgSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function deleteOrg(
|
export async function deleteOrg(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromZodError } from "zod-validation-error";
|
import { fromZodError } from "zod-validation-error";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const getOrgSchema = z
|
const getOrgSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -19,6 +20,17 @@ export type GetOrgResponse = {
|
||||||
org: Org;
|
org: Org;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/org/{orgId}",
|
||||||
|
description: "Get an organization",
|
||||||
|
tags: [OpenAPITags.Org],
|
||||||
|
request: {
|
||||||
|
params: getOrgSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function getOrg(
|
export async function getOrg(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import createHttpError from "http-errors";
|
||||||
import { sql, inArray } from "drizzle-orm";
|
import { sql, inArray } from "drizzle-orm";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromZodError } from "zod-validation-error";
|
import { fromZodError } from "zod-validation-error";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const listOrgsSchema = z.object({
|
const listOrgsSchema = z.object({
|
||||||
limit: z
|
limit: z
|
||||||
|
@ -21,7 +22,18 @@ const listOrgsSchema = z.object({
|
||||||
.optional()
|
.optional()
|
||||||
.default("0")
|
.default("0")
|
||||||
.transform(Number)
|
.transform(Number)
|
||||||
.pipe(z.number().int().nonnegative()),
|
.pipe(z.number().int().nonnegative())
|
||||||
|
});
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/orgs",
|
||||||
|
description: "List all organizations in the system",
|
||||||
|
tags: [OpenAPITags.Org],
|
||||||
|
request: {
|
||||||
|
query: listOrgsSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
});
|
});
|
||||||
|
|
||||||
export type ListOrgsResponse = {
|
export type ListOrgsResponse = {
|
||||||
|
@ -57,13 +69,13 @@ export async function listOrgs(
|
||||||
pagination: {
|
pagination: {
|
||||||
total: 0,
|
total: 0,
|
||||||
limit,
|
limit,
|
||||||
offset,
|
offset
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
success: true,
|
success: true,
|
||||||
error: false,
|
error: false,
|
||||||
message: "No organizations found for the user",
|
message: "No organizations found for the user",
|
||||||
status: HttpCode.OK,
|
status: HttpCode.OK
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,13 +98,13 @@ export async function listOrgs(
|
||||||
pagination: {
|
pagination: {
|
||||||
total: totalCount,
|
total: totalCount,
|
||||||
limit,
|
limit,
|
||||||
offset,
|
offset
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
success: true,
|
success: true,
|
||||||
error: false,
|
error: false,
|
||||||
message: "Organizations retrieved successfully",
|
message: "Organizations retrieved successfully",
|
||||||
status: HttpCode.OK,
|
status: HttpCode.OK
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
|
|
|
@ -8,6 +8,7 @@ import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const updateOrgParamsSchema = z
|
const updateOrgParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -17,7 +18,7 @@ const updateOrgParamsSchema = z
|
||||||
|
|
||||||
const updateOrgBodySchema = z
|
const updateOrgBodySchema = z
|
||||||
.object({
|
.object({
|
||||||
name: z.string().min(1).max(255).optional(),
|
name: z.string().min(1).max(255).optional()
|
||||||
// domain: z.string().min(1).max(255).optional(),
|
// domain: z.string().min(1).max(255).optional(),
|
||||||
})
|
})
|
||||||
.strict()
|
.strict()
|
||||||
|
@ -25,6 +26,24 @@ const updateOrgBodySchema = z
|
||||||
message: "At least one field must be provided for update"
|
message: "At least one field must be provided for update"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "post",
|
||||||
|
path: "/org/{orgId}",
|
||||||
|
description: "Update an organization",
|
||||||
|
tags: [OpenAPITags.Org],
|
||||||
|
request: {
|
||||||
|
params: updateOrgParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: updateOrgBodySchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function updateOrg(
|
export async function updateOrg(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { fromError } from "zod-validation-error";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { subdomainSchema } from "@server/lib/schemas";
|
import { subdomainSchema } from "@server/lib/schemas";
|
||||||
import config from "@server/lib/config";
|
import config from "@server/lib/config";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const createResourceParamsSchema = z
|
const createResourceParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -90,6 +91,26 @@ const createRawResourceSchema = z
|
||||||
|
|
||||||
export type CreateResourceResponse = Resource;
|
export type CreateResourceResponse = Resource;
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "put",
|
||||||
|
path: "/org/{orgId}/site/{siteId}/resource",
|
||||||
|
description: "Create a resource.",
|
||||||
|
tags: [OpenAPITags.Org, OpenAPITags.Resource],
|
||||||
|
request: {
|
||||||
|
params: createResourceParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: createHttpResourceSchema.or(
|
||||||
|
createRawResourceSchema
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function createResource(
|
export async function createResource(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {
|
||||||
isValidIP,
|
isValidIP,
|
||||||
isValidUrlGlobPattern
|
isValidUrlGlobPattern
|
||||||
} from "@server/lib/validators";
|
} from "@server/lib/validators";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const createResourceRuleSchema = z
|
const createResourceRuleSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -33,6 +34,24 @@ const createResourceRuleParamsSchema = z
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "put",
|
||||||
|
path: "/resource/{resourceId}/rule",
|
||||||
|
description: "Create a resource rule.",
|
||||||
|
tags: [OpenAPITags.Resource, OpenAPITags.Rule],
|
||||||
|
request: {
|
||||||
|
params: createResourceRuleParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: createResourceRuleSchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function createResourceRule(
|
export async function createResourceRule(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { fromError } from "zod-validation-error";
|
||||||
import { addPeer } from "../gerbil/peers";
|
import { addPeer } from "../gerbil/peers";
|
||||||
import { removeTargets } from "../newt/targets";
|
import { removeTargets } from "../newt/targets";
|
||||||
import { getAllowedIps } from "../target/helpers";
|
import { getAllowedIps } from "../target/helpers";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
// Define Zod schema for request parameters validation
|
// Define Zod schema for request parameters validation
|
||||||
const deleteResourceSchema = z
|
const deleteResourceSchema = z
|
||||||
|
@ -22,6 +23,17 @@ const deleteResourceSchema = z
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "delete",
|
||||||
|
path: "/resource/{resourceId}",
|
||||||
|
description: "Delete a resource.",
|
||||||
|
tags: [OpenAPITags.Resource],
|
||||||
|
request: {
|
||||||
|
params: deleteResourceSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function deleteResource(
|
export async function deleteResource(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
@ -88,7 +100,11 @@ export async function deleteResource(
|
||||||
.where(eq(newts.siteId, site.siteId))
|
.where(eq(newts.siteId, site.siteId))
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
removeTargets(newt.newtId, targetsToBeRemoved, deletedResource.protocol);
|
removeTargets(
|
||||||
|
newt.newtId,
|
||||||
|
targetsToBeRemoved,
|
||||||
|
deletedResource.protocol
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,11 @@ import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const deleteResourceRuleSchema = z
|
const deleteResourceRuleSchema = z
|
||||||
.object({
|
.object({
|
||||||
ruleId: z
|
ruleId: z.string().transform(Number).pipe(z.number().int().positive()),
|
||||||
.string()
|
|
||||||
.transform(Number)
|
|
||||||
.pipe(z.number().int().positive()),
|
|
||||||
resourceId: z
|
resourceId: z
|
||||||
.string()
|
.string()
|
||||||
.transform(Number)
|
.transform(Number)
|
||||||
|
@ -22,6 +20,17 @@ const deleteResourceRuleSchema = z
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "delete",
|
||||||
|
path: "/resource/{resourceId}/rule/{ruleId}",
|
||||||
|
description: "Delete a resource rule.",
|
||||||
|
tags: [OpenAPITags.Resource, OpenAPITags.Rule],
|
||||||
|
request: {
|
||||||
|
params: deleteResourceRuleSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function deleteResourceRule(
|
export async function deleteResourceRule(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const getResourceSchema = z
|
const getResourceSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -22,6 +23,17 @@ export type GetResourceResponse = Resource & {
|
||||||
siteName: string;
|
siteName: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/resource/{resourceId}",
|
||||||
|
description: "Get a resource.",
|
||||||
|
tags: [OpenAPITags.Resource],
|
||||||
|
request: {
|
||||||
|
params: getResourceSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function getResource(
|
export async function getResource(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const getResourceWhitelistSchema = z
|
const getResourceWhitelistSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -31,6 +32,17 @@ export type GetResourceWhitelistResponse = {
|
||||||
whitelist: NonNullable<Awaited<ReturnType<typeof queryWhitelist>>>;
|
whitelist: NonNullable<Awaited<ReturnType<typeof queryWhitelist>>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/resource/{resourceId}/whitelist",
|
||||||
|
description: "Get the whitelist of emails for a specific resource.",
|
||||||
|
tags: [OpenAPITags.Resource],
|
||||||
|
request: {
|
||||||
|
params: getResourceWhitelistSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function getResourceWhitelist(
|
export async function getResourceWhitelist(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const listResourceRolesSchema = z
|
const listResourceRolesSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -35,6 +36,17 @@ export type ListResourceRolesResponse = {
|
||||||
roles: NonNullable<Awaited<ReturnType<typeof query>>>;
|
roles: NonNullable<Awaited<ReturnType<typeof query>>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/resource/{resourceId}/roles",
|
||||||
|
description: "List all roles for a resource.",
|
||||||
|
tags: [OpenAPITags.Resource, OpenAPITags.Role],
|
||||||
|
request: {
|
||||||
|
params: listResourceRolesSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function listResourceRoles(
|
export async function listResourceRoles(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -8,6 +8,7 @@ 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 logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const listResourceRulesParamsSchema = z
|
const listResourceRulesParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -56,6 +57,18 @@ export type ListResourceRulesResponse = {
|
||||||
pagination: { total: number; limit: number; offset: number };
|
pagination: { total: number; limit: number; offset: number };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/resource/{resourceId}/rules",
|
||||||
|
description: "List rules for a resource.",
|
||||||
|
tags: [OpenAPITags.Resource, OpenAPITags.Rule],
|
||||||
|
request: {
|
||||||
|
params: listResourceRulesParamsSchema,
|
||||||
|
query: listResourceRulesSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function listResourceRules(
|
export async function listResourceRules(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const listResourceUsersSchema = z
|
const listResourceUsersSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -33,6 +34,17 @@ export type ListResourceUsersResponse = {
|
||||||
users: NonNullable<Awaited<ReturnType<typeof queryUsers>>>;
|
users: NonNullable<Awaited<ReturnType<typeof queryUsers>>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/resource/{resourceId}/users",
|
||||||
|
description: "List all users for a resource.",
|
||||||
|
tags: [OpenAPITags.Resource, OpenAPITags.User],
|
||||||
|
request: {
|
||||||
|
params: listResourceUsersSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function listResourceUsers(
|
export async function listResourceUsers(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { sql, eq, or, inArray, and, count } from "drizzle-orm";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import stoi from "@server/lib/stoi";
|
import stoi from "@server/lib/stoi";
|
||||||
import { fromZodError } from "zod-validation-error";
|
import { fromZodError } from "zod-validation-error";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const listResourcesParamsSchema = z
|
const listResourcesParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -128,6 +129,34 @@ export type ListResourcesResponse = {
|
||||||
pagination: { total: number; limit: number; offset: number };
|
pagination: { total: number; limit: number; offset: number };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/site/{siteId}/resources",
|
||||||
|
description: "List resources for a site.",
|
||||||
|
tags: [OpenAPITags.Site, OpenAPITags.Resource],
|
||||||
|
request: {
|
||||||
|
params: z.object({
|
||||||
|
siteId: z.number()
|
||||||
|
}),
|
||||||
|
query: listResourcesSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/org/{orgId}/resources",
|
||||||
|
description: "List resources for an organization.",
|
||||||
|
tags: [OpenAPITags.Org, OpenAPITags.Resource],
|
||||||
|
request: {
|
||||||
|
params: z.object({
|
||||||
|
orgId: z.string()
|
||||||
|
}),
|
||||||
|
query: listResourcesSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function listResources(
|
export async function listResources(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { hash } from "@node-rs/argon2";
|
||||||
import { response } from "@server/lib";
|
import { response } from "@server/lib";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { hashPassword } from "@server/auth/password";
|
import { hashPassword } from "@server/auth/password";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const setResourceAuthMethodsParamsSchema = z.object({
|
const setResourceAuthMethodsParamsSchema = z.object({
|
||||||
resourceId: z.string().transform(Number).pipe(z.number().int().positive())
|
resourceId: z.string().transform(Number).pipe(z.number().int().positive())
|
||||||
|
@ -21,6 +22,25 @@ const setResourceAuthMethodsBodySchema = z
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "post",
|
||||||
|
path: "/resource/{resourceId}/password",
|
||||||
|
description:
|
||||||
|
"Set the password for a resource. Setting the password to null will remove it.",
|
||||||
|
tags: [OpenAPITags.Resource],
|
||||||
|
request: {
|
||||||
|
params: setResourceAuthMethodsParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: setResourceAuthMethodsBodySchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function setResourcePassword(
|
export async function setResourcePassword(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -11,9 +11,10 @@ import { response } from "@server/lib";
|
||||||
import stoi from "@server/lib/stoi";
|
import stoi from "@server/lib/stoi";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { hashPassword } from "@server/auth/password";
|
import { hashPassword } from "@server/auth/password";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const setResourceAuthMethodsParamsSchema = z.object({
|
const setResourceAuthMethodsParamsSchema = z.object({
|
||||||
resourceId: z.string().transform(Number).pipe(z.number().int().positive()),
|
resourceId: z.string().transform(Number).pipe(z.number().int().positive())
|
||||||
});
|
});
|
||||||
|
|
||||||
const setResourceAuthMethodsBodySchema = z
|
const setResourceAuthMethodsBodySchema = z
|
||||||
|
@ -21,25 +22,44 @@ const setResourceAuthMethodsBodySchema = z
|
||||||
pincode: z
|
pincode: z
|
||||||
.string()
|
.string()
|
||||||
.regex(/^\d{6}$/)
|
.regex(/^\d{6}$/)
|
||||||
.or(z.null()),
|
.or(z.null())
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "post",
|
||||||
|
path: "/resource/{resourceId}/pincode",
|
||||||
|
description:
|
||||||
|
"Set the PIN code for a resource. Setting the PIN code to null will remove it.",
|
||||||
|
tags: [OpenAPITags.Resource],
|
||||||
|
request: {
|
||||||
|
params: setResourceAuthMethodsParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: setResourceAuthMethodsBodySchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function setResourcePincode(
|
export async function setResourcePincode(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
next: NextFunction,
|
next: NextFunction
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const parsedParams = setResourceAuthMethodsParamsSchema.safeParse(
|
const parsedParams = setResourceAuthMethodsParamsSchema.safeParse(
|
||||||
req.params,
|
req.params
|
||||||
);
|
);
|
||||||
if (!parsedParams.success) {
|
if (!parsedParams.success) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.BAD_REQUEST,
|
HttpCode.BAD_REQUEST,
|
||||||
fromError(parsedParams.error).toString(),
|
fromError(parsedParams.error).toString()
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,8 +68,8 @@ export async function setResourcePincode(
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.BAD_REQUEST,
|
HttpCode.BAD_REQUEST,
|
||||||
fromError(parsedBody.error).toString(),
|
fromError(parsedBody.error).toString()
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,15 +95,12 @@ export async function setResourcePincode(
|
||||||
success: true,
|
success: true,
|
||||||
error: false,
|
error: false,
|
||||||
message: "Resource PIN code set successfully",
|
message: "Resource PIN code set successfully",
|
||||||
status: HttpCode.CREATED,
|
status: HttpCode.CREATED
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
|
||||||
HttpCode.INTERNAL_SERVER_ERROR,
|
|
||||||
"An error occurred",
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import createHttpError from "http-errors";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import { eq, and, ne } from "drizzle-orm";
|
import { eq, and, ne } from "drizzle-orm";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const setResourceRolesBodySchema = z
|
const setResourceRolesBodySchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -24,6 +25,25 @@ const setResourceRolesParamsSchema = z
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "post",
|
||||||
|
path: "/resource/{resourceId}/roles",
|
||||||
|
description:
|
||||||
|
"Set roles for a resource. This will replace all existing roles.",
|
||||||
|
tags: [OpenAPITags.Resource, OpenAPITags.Role],
|
||||||
|
request: {
|
||||||
|
params: setResourceRolesParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: setResourceRolesBodySchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function setResourceRoles(
|
export async function setResourceRoles(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import createHttpError from "http-errors";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const setUserResourcesBodySchema = z
|
const setUserResourcesBodySchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -24,6 +25,25 @@ const setUserResourcesParamsSchema = z
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "post",
|
||||||
|
path: "/resource/{resourceId}/users",
|
||||||
|
description:
|
||||||
|
"Set users for a resource. This will replace all existing users.",
|
||||||
|
tags: [OpenAPITags.Resource, OpenAPITags.User],
|
||||||
|
request: {
|
||||||
|
params: setUserResourcesParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: setUserResourcesBodySchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function setResourceUsers(
|
export async function setResourceUsers(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import createHttpError from "http-errors";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import { and, eq } from "drizzle-orm";
|
import { and, eq } from "drizzle-orm";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const setResourceWhitelistBodySchema = z
|
const setResourceWhitelistBodySchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -37,6 +38,25 @@ const setResourceWhitelistParamsSchema = z
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "post",
|
||||||
|
path: "/resource/{resourceId}/whitelist",
|
||||||
|
description:
|
||||||
|
"Set email whitelist for a resource. This will replace all existing emails.",
|
||||||
|
tags: [OpenAPITags.Resource],
|
||||||
|
request: {
|
||||||
|
params: setResourceWhitelistParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: setResourceWhitelistBodySchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function setResourceWhitelist(
|
export async function setResourceWhitelist(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { fromError } from "zod-validation-error";
|
||||||
import { addPeer } from "../gerbil/peers";
|
import { addPeer } from "../gerbil/peers";
|
||||||
import { addTargets, removeTargets } from "../newt/targets";
|
import { addTargets, removeTargets } from "../newt/targets";
|
||||||
import { getAllowedIps } from "../target/helpers";
|
import { getAllowedIps } from "../target/helpers";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const transferResourceParamsSchema = z
|
const transferResourceParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -27,6 +28,25 @@ const transferResourceBodySchema = z
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "post",
|
||||||
|
path: "/resource/{resourceId}/transfer",
|
||||||
|
description:
|
||||||
|
"Transfer a resource to a different site. This will also transfer the targets associated with the resource.",
|
||||||
|
tags: [OpenAPITags.Resource],
|
||||||
|
request: {
|
||||||
|
params: transferResourceParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: transferResourceBodySchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function transferResource(
|
export async function transferResource(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -17,6 +17,8 @@ import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import config from "@server/lib/config";
|
import config from "@server/lib/config";
|
||||||
import { subdomainSchema } from "@server/lib/schemas";
|
import { subdomainSchema } from "@server/lib/schemas";
|
||||||
|
import { registry } from "@server/openApi";
|
||||||
|
import { OpenAPITags } from "@server/openApi";
|
||||||
|
|
||||||
const updateResourceParamsSchema = z
|
const updateResourceParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -93,6 +95,26 @@ const updateRawResourceBodySchema = z
|
||||||
{ message: "Cannot update proxyPort" }
|
{ message: "Cannot update proxyPort" }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "post",
|
||||||
|
path: "/resource/{resourceId}",
|
||||||
|
description: "Update a resource.",
|
||||||
|
tags: [OpenAPITags.Resource],
|
||||||
|
request: {
|
||||||
|
params: updateResourceParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: updateHttpResourceBodySchema.and(
|
||||||
|
updateRawResourceBodySchema
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function updateResource(
|
export async function updateResource(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {
|
||||||
isValidIP,
|
isValidIP,
|
||||||
isValidUrlGlobPattern
|
isValidUrlGlobPattern
|
||||||
} from "@server/lib/validators";
|
} from "@server/lib/validators";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
// Define Zod schema for request parameters validation
|
// Define Zod schema for request parameters validation
|
||||||
const updateResourceRuleParamsSchema = z
|
const updateResourceRuleParamsSchema = z
|
||||||
|
@ -39,6 +40,24 @@ const updateResourceRuleSchema = z
|
||||||
message: "At least one field must be provided for update"
|
message: "At least one field must be provided for update"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "post",
|
||||||
|
path: "/resource/{resourceId}/rule/{ruleId}",
|
||||||
|
description: "Update a resource rule.",
|
||||||
|
tags: [OpenAPITags.Resource, OpenAPITags.Rule],
|
||||||
|
request: {
|
||||||
|
params: updateResourceRuleParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: updateResourceRuleSchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function updateResourceRule(
|
export async function updateResourceRule(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -9,6 +9,7 @@ import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import { ActionsEnum } from "@server/auth/actions";
|
import { ActionsEnum } from "@server/auth/actions";
|
||||||
import { eq, and } from "drizzle-orm";
|
import { eq, and } from "drizzle-orm";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const createRoleParamsSchema = z
|
const createRoleParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -33,6 +34,24 @@ export type CreateRoleBody = z.infer<typeof createRoleSchema>;
|
||||||
|
|
||||||
export type CreateRoleResponse = Role;
|
export type CreateRoleResponse = Role;
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "put",
|
||||||
|
path: "/org/{orgId}/role",
|
||||||
|
description: "Create a role.",
|
||||||
|
tags: [OpenAPITags.Org, OpenAPITags.Role],
|
||||||
|
request: {
|
||||||
|
params: createRoleParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: createRoleSchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function createRole(
|
export async function createRole(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const deleteRoleSchema = z
|
const deleteRoleSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -21,6 +22,24 @@ const deelteRoleBodySchema = z
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "delete",
|
||||||
|
path: "/role/{roleId}",
|
||||||
|
description: "Delete a role.",
|
||||||
|
tags: [OpenAPITags.Role],
|
||||||
|
request: {
|
||||||
|
params: deleteRoleSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: deelteRoleBodySchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function deleteRole(
|
export async function deleteRole(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { sql, eq } from "drizzle-orm";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import stoi from "@server/lib/stoi";
|
import stoi from "@server/lib/stoi";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const listRolesParamsSchema = z
|
const listRolesParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -57,6 +58,18 @@ export type ListRolesResponse = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/orgs/{orgId}/roles",
|
||||||
|
description: "List roles.",
|
||||||
|
tags: [OpenAPITags.Org, OpenAPITags.Role],
|
||||||
|
request: {
|
||||||
|
params: listRolesParamsSchema,
|
||||||
|
query: listRolesSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function listRoles(
|
export async function listRoles(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -13,29 +13,30 @@ import { fromError } from "zod-validation-error";
|
||||||
import { hash } from "@node-rs/argon2";
|
import { hash } from "@node-rs/argon2";
|
||||||
import { newts } from "@server/db/schemas";
|
import { newts } from "@server/db/schemas";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { bearerAuth, OpenAPITags, registry } from "@server/openApi";
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
import { hashPassword } from "@server/auth/password";
|
||||||
|
|
||||||
const createSiteParamsSchema = z
|
const createSiteParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
orgId: z.string().openapi({})
|
orgId: z.string()
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
const createSiteSchema = z
|
const createSiteSchema = z
|
||||||
.object({
|
.object({
|
||||||
name: z.string().min(1).max(255).openapi({}),
|
name: z.string().min(1).max(255),
|
||||||
exitNodeId: z.number().int().positive().optional().openapi({}),
|
exitNodeId: z.number().int().positive().optional(),
|
||||||
// subdomain: z
|
// subdomain: z
|
||||||
// .string()
|
// .string()
|
||||||
// .min(1)
|
// .min(1)
|
||||||
// .max(255)
|
// .max(255)
|
||||||
// .transform((val) => val.toLowerCase())
|
// .transform((val) => val.toLowerCase())
|
||||||
// .optional(),
|
// .optional(),
|
||||||
pubKey: z.string().optional().openapi({}),
|
pubKey: z.string().optional(),
|
||||||
subnet: z.string().optional().openapi({}),
|
subnet: z.string().optional(),
|
||||||
newtId: z.string().optional().openapi({}),
|
newtId: z.string().optional(),
|
||||||
secret: z.string().optional().openapi({}),
|
secret: z.string().optional(),
|
||||||
type: z.enum(["newt", "wireguard", "local"]).openapi({})
|
type: z.enum(["newt", "wireguard", "local"])
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
@ -46,8 +47,7 @@ export type CreateSiteResponse = Site;
|
||||||
registry.registerPath({
|
registry.registerPath({
|
||||||
method: "put",
|
method: "put",
|
||||||
path: "/org/{orgId}/site",
|
path: "/org/{orgId}/site",
|
||||||
description: "Create a new site",
|
description: "Create a new site.",
|
||||||
security: [{ [bearerAuth.name]: [] }],
|
|
||||||
tags: [OpenAPITags.Site, OpenAPITags.Org],
|
tags: [OpenAPITags.Site, OpenAPITags.Org],
|
||||||
request: {
|
request: {
|
||||||
params: createSiteParamsSchema,
|
params: createSiteParamsSchema,
|
||||||
|
|
|
@ -10,6 +10,7 @@ import logger from "@server/logger";
|
||||||
import { deletePeer } from "../gerbil/peers";
|
import { deletePeer } from "../gerbil/peers";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import { sendToClient } from "../ws";
|
import { sendToClient } from "../ws";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const deleteSiteSchema = z
|
const deleteSiteSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -17,6 +18,17 @@ const deleteSiteSchema = z
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "delete",
|
||||||
|
path: "/site/{siteId}",
|
||||||
|
description: "Delete a site and all its associated data.",
|
||||||
|
tags: [OpenAPITags.Site],
|
||||||
|
request: {
|
||||||
|
params: deleteSiteSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function deleteSite(
|
export async function deleteSite(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -9,6 +9,7 @@ import createHttpError from "http-errors";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import stoi from "@server/lib/stoi";
|
import stoi from "@server/lib/stoi";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const getSiteSchema = z
|
const getSiteSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -43,6 +44,34 @@ async function query(siteId?: number, niceId?: string, orgId?: string) {
|
||||||
|
|
||||||
export type GetSiteResponse = NonNullable<Awaited<ReturnType<typeof query>>>;
|
export type GetSiteResponse = NonNullable<Awaited<ReturnType<typeof query>>>;
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/org/{orgId}/site/{niceId}",
|
||||||
|
description:
|
||||||
|
"Get a site by orgId and niceId. NiceId is a readable ID for the site and unique on a per org basis.",
|
||||||
|
tags: [OpenAPITags.Org, OpenAPITags.Site],
|
||||||
|
request: {
|
||||||
|
params: z.object({
|
||||||
|
orgId: z.string(),
|
||||||
|
niceId: z.string()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/site/{siteId}",
|
||||||
|
description: "Get a site by siteId.",
|
||||||
|
tags: [OpenAPITags.Site],
|
||||||
|
request: {
|
||||||
|
params: z.object({
|
||||||
|
siteId: z.number()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function getSite(
|
export async function getSite(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { NextFunction, Request, Response } from "express";
|
||||||
import createHttpError from "http-errors";
|
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 { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const listSitesParamsSchema = z
|
const listSitesParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -59,6 +60,18 @@ export type ListSitesResponse = {
|
||||||
pagination: { total: number; limit: number; offset: number };
|
pagination: { total: number; limit: number; offset: number };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/org/{orgId}/sites",
|
||||||
|
description: "List all sites in an organization",
|
||||||
|
tags: [OpenAPITags.Org, OpenAPITags.Site],
|
||||||
|
request: {
|
||||||
|
params: listSitesParamsSchema,
|
||||||
|
query: listSitesSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function listSites(
|
export async function listSites(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -9,6 +9,8 @@ import logger from "@server/logger";
|
||||||
import { findNextAvailableCidr } from "@server/lib/ip";
|
import { findNextAvailableCidr } from "@server/lib/ip";
|
||||||
import { generateId } from "@server/auth/sessions/app";
|
import { generateId } from "@server/auth/sessions/app";
|
||||||
import config from "@server/lib/config";
|
import config from "@server/lib/config";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
export type PickSiteDefaultsResponse = {
|
export type PickSiteDefaultsResponse = {
|
||||||
exitNodeId: number;
|
exitNodeId: number;
|
||||||
|
@ -22,6 +24,20 @@ export type PickSiteDefaultsResponse = {
|
||||||
newtSecret: string;
|
newtSecret: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/org/{orgId}/pick-site-defaults",
|
||||||
|
description:
|
||||||
|
"Return pre-requisite data for creating a site, such as the exit node, subnet, Newt credentials, etc.",
|
||||||
|
tags: [OpenAPITags.Org, OpenAPITags.Site],
|
||||||
|
request: {
|
||||||
|
params: z.object({
|
||||||
|
orgId: z.string()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function pickSiteDefaults(
|
export async function pickSiteDefaults(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
@ -45,7 +61,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 +69,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 +102,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);
|
||||||
|
|
|
@ -8,6 +8,7 @@ import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const updateSiteParamsSchema = z
|
const updateSiteParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -35,6 +36,25 @@ const updateSiteBodySchema = z
|
||||||
message: "At least one field must be provided for update"
|
message: "At least one field must be provided for update"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "post",
|
||||||
|
path: "/site/{siteId}",
|
||||||
|
description:
|
||||||
|
"Update a site.",
|
||||||
|
tags: [OpenAPITags.Site],
|
||||||
|
request: {
|
||||||
|
params: updateSiteParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: updateSiteBodySchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function updateSite(
|
export async function updateSite(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { addTargets } from "../newt/targets";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { pickPort } from "./helpers";
|
import { pickPort } from "./helpers";
|
||||||
import { isTargetValid } from "@server/lib/validators";
|
import { isTargetValid } from "@server/lib/validators";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const createTargetParamsSchema = z
|
const createTargetParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -34,6 +35,24 @@ const createTargetSchema = z
|
||||||
|
|
||||||
export type CreateTargetResponse = Target;
|
export type CreateTargetResponse = Target;
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "put",
|
||||||
|
path: "/resource/{resourceId}/target",
|
||||||
|
description: "Create a target for a resource.",
|
||||||
|
tags: [OpenAPITags.Resource, OpenAPITags.Target],
|
||||||
|
request: {
|
||||||
|
params: createTargetParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: createTargetSchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function createTarget(
|
export async function createTarget(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { addPeer } from "../gerbil/peers";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import { removeTargets } from "../newt/targets";
|
import { removeTargets } from "../newt/targets";
|
||||||
import { getAllowedIps } from "./helpers";
|
import { getAllowedIps } from "./helpers";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const deleteTargetSchema = z
|
const deleteTargetSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -18,6 +19,17 @@ const deleteTargetSchema = z
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "delete",
|
||||||
|
path: "/target/{targetId}",
|
||||||
|
description: "Delete a target.",
|
||||||
|
tags: [OpenAPITags.Target],
|
||||||
|
request: {
|
||||||
|
params: deleteTargetSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function deleteTarget(
|
export async function deleteTarget(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const getTargetSchema = z
|
const getTargetSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -15,6 +16,17 @@ const getTargetSchema = z
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/target/{targetId}",
|
||||||
|
description: "Get a target.",
|
||||||
|
tags: [OpenAPITags.Target],
|
||||||
|
request: {
|
||||||
|
params: getTargetSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function getTarget(
|
export async function getTarget(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -8,6 +8,7 @@ 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 logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const listTargetsParamsSchema = z
|
const listTargetsParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -56,6 +57,18 @@ export type ListTargetsResponse = {
|
||||||
pagination: { total: number; limit: number; offset: number };
|
pagination: { total: number; limit: number; offset: number };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/resource/{resourceId}/targets",
|
||||||
|
description: "List targets for a resource.",
|
||||||
|
tags: [OpenAPITags.Resource, OpenAPITags.Target],
|
||||||
|
request: {
|
||||||
|
params: listTargetsParamsSchema,
|
||||||
|
query: listTargetsSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function listTargets(
|
export async function listTargets(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { addPeer } from "../gerbil/peers";
|
||||||
import { addTargets } from "../newt/targets";
|
import { addTargets } from "../newt/targets";
|
||||||
import { pickPort } from "./helpers";
|
import { pickPort } from "./helpers";
|
||||||
import { isTargetValid } from "@server/lib/validators";
|
import { isTargetValid } from "@server/lib/validators";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const updateTargetParamsSchema = z
|
const updateTargetParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -31,6 +32,24 @@ const updateTargetBodySchema = z
|
||||||
message: "At least one field must be provided for update"
|
message: "At least one field must be provided for update"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "post",
|
||||||
|
path: "/target/{targetId}",
|
||||||
|
description: "Update a target.",
|
||||||
|
tags: [OpenAPITags.Target],
|
||||||
|
request: {
|
||||||
|
params: updateTargetParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: updateTargetBodySchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function updateTarget(
|
export async function updateTarget(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -9,6 +9,7 @@ import createHttpError from "http-errors";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import stoi from "@server/lib/stoi";
|
import stoi from "@server/lib/stoi";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const addUserRoleParamsSchema = z
|
const addUserRoleParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -19,6 +20,17 @@ const addUserRoleParamsSchema = z
|
||||||
|
|
||||||
export type AddUserRoleResponse = z.infer<typeof addUserRoleParamsSchema>;
|
export type AddUserRoleResponse = z.infer<typeof addUserRoleParamsSchema>;
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "post",
|
||||||
|
path: "/role/{roleId}/add/{userId}",
|
||||||
|
description: "Add a role to a user.",
|
||||||
|
tags: [OpenAPITags.Role, OpenAPITags.User],
|
||||||
|
request: {
|
||||||
|
params: addUserRoleParamsSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function addUserRole(
|
export async function addUserRole(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -9,6 +9,7 @@ import createHttpError from "http-errors";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
|
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
async function queryUser(orgId: string, userId: string) {
|
async function queryUser(orgId: string, userId: string) {
|
||||||
const [user] = await db
|
const [user] = await db
|
||||||
|
@ -40,6 +41,17 @@ const getOrgUserParamsSchema = z
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/org/{orgId}/user/{userId}",
|
||||||
|
description: "Get a user in an organization.",
|
||||||
|
tags: [OpenAPITags.Org, OpenAPITags.User],
|
||||||
|
request: {
|
||||||
|
params: getOrgUserParamsSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function getOrgUser(
|
export async function getOrgUser(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { hashPassword } from "@server/auth/password";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import { sendEmail } from "@server/emails";
|
import { sendEmail } from "@server/emails";
|
||||||
import SendInviteLink from "@server/emails/templates/SendInviteLink";
|
import SendInviteLink from "@server/emails/templates/SendInviteLink";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const inviteUserParamsSchema = z
|
const inviteUserParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -42,6 +43,24 @@ export type InviteUserResponse = {
|
||||||
|
|
||||||
const inviteTracker: Record<string, { timestamps: number[] }> = {};
|
const inviteTracker: Record<string, { timestamps: number[] }> = {};
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "post",
|
||||||
|
path: "/org/{orgId}/create-invite",
|
||||||
|
description: "Invite a user to join an organization.",
|
||||||
|
tags: [OpenAPITags.Org],
|
||||||
|
request: {
|
||||||
|
params: inviteUserParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: inviteUserBodySchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function inviteUser(
|
export async function inviteUser(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import createHttpError from "http-errors";
|
||||||
import { sql } from "drizzle-orm";
|
import { sql } from "drizzle-orm";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromZodError } from "zod-validation-error";
|
import { fromZodError } from "zod-validation-error";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const listUsersParamsSchema = z
|
const listUsersParamsSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -57,6 +58,18 @@ export type ListUsersResponse = {
|
||||||
pagination: { total: number; limit: number; offset: number };
|
pagination: { total: number; limit: number; offset: number };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "get",
|
||||||
|
path: "/org/{orgId}/users",
|
||||||
|
description: "List users in an organization.",
|
||||||
|
tags: [OpenAPITags.Org, OpenAPITags.User],
|
||||||
|
request: {
|
||||||
|
params: listUsersParamsSchema,
|
||||||
|
query: listUsersSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function listUsers(
|
export async function listUsers(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
|
||||||
const removeUserSchema = z
|
const removeUserSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
@ -16,6 +17,17 @@ const removeUserSchema = z
|
||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "delete",
|
||||||
|
path: "/org/{orgId}/user/{userId}",
|
||||||
|
description: "Remove a user from an organization.",
|
||||||
|
tags: [OpenAPITags.Org, OpenAPITags.User],
|
||||||
|
request: {
|
||||||
|
params: removeUserSchema
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
export async function removeUserOrg(
|
export async function removeUserOrg(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue