mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-01 16:45:40 +02:00
Merge branch 'main' of https://github.com/fosrl/pangolin
This commit is contained in:
commit
6942eeb7b4
9 changed files with 45 additions and 35 deletions
|
@ -20,9 +20,10 @@ export async function ensureActions() {
|
||||||
|
|
||||||
// Add new actions
|
// Add new actions
|
||||||
for (const actionId of actionsToAdd) {
|
for (const actionId of actionsToAdd) {
|
||||||
|
logger.debug(`Adding action: ${actionId}`);
|
||||||
await db.insert(actions).values({ actionId }).execute();
|
await db.insert(actions).values({ actionId }).execute();
|
||||||
// Add new actions to the Default role
|
// Add new actions to the Default role
|
||||||
if (defaultRoles.length === 0) {
|
if (defaultRoles.length != 0) {
|
||||||
await db.insert(roleActions)
|
await db.insert(roleActions)
|
||||||
.values(defaultRoles.map(role => ({ roleId: role.roleId!, actionId, orgId: role.orgId! })))
|
.values(defaultRoles.map(role => ({ roleId: role.roleId!, actionId, orgId: role.orgId! })))
|
||||||
.execute();
|
.execute();
|
||||||
|
@ -31,6 +32,7 @@ export async function ensureActions() {
|
||||||
|
|
||||||
// Remove deprecated actions
|
// Remove deprecated actions
|
||||||
if (actionsToRemove.length > 0) {
|
if (actionsToRemove.length > 0) {
|
||||||
|
logger.debug(`Removing actions: ${actionsToRemove.join(', ')}`);
|
||||||
await db.delete(actions).where(inArray(actions.actionId, actionsToRemove)).execute();
|
await db.delete(actions).where(inArray(actions.actionId, actionsToRemove)).execute();
|
||||||
await db.delete(roleActions).where(inArray(roleActions.actionId, actionsToRemove)).execute();
|
await db.delete(roleActions).where(inArray(roleActions.actionId, actionsToRemove)).execute();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,13 @@ import { eq, and } from "drizzle-orm";
|
||||||
import { __DIRNAME } from "@server/config";
|
import { __DIRNAME } from "@server/config";
|
||||||
|
|
||||||
// Load the names from the names.json file
|
// Load the names from the names.json file
|
||||||
const file = join(__DIRNAME, "names.json");
|
const dev = process.env.ENVIRONMENT !== "prod";
|
||||||
|
let file;
|
||||||
|
if (!dev) {
|
||||||
|
file = join(__DIRNAME, "names.json");
|
||||||
|
} else {
|
||||||
|
file = join(__DIRNAME, "/db/names.json");
|
||||||
|
}
|
||||||
export const names = JSON.parse(readFileSync(file, "utf-8"));
|
export const names = JSON.parse(readFileSync(file, "utf-8"));
|
||||||
|
|
||||||
export async function getUniqueSiteName(orgId: string): Promise<string> {
|
export async function getUniqueSiteName(orgId: string): Promise<string> {
|
||||||
|
|
|
@ -46,11 +46,11 @@ authenticated.put("/org/:orgId/site", verifyOrgAccess, site.createSite);
|
||||||
authenticated.get("/org/:orgId/sites", verifyOrgAccess, site.listSites);
|
authenticated.get("/org/:orgId/sites", verifyOrgAccess, site.listSites);
|
||||||
authenticated.get("/org/:orgId/site/:niceId", verifyOrgAccess, site.getSite);
|
authenticated.get("/org/:orgId/site/:niceId", verifyOrgAccess, site.getSite);
|
||||||
|
|
||||||
|
authenticated.get("/org/:orgId/pickSiteDefaults", verifyOrgAccess, site.pickSiteDefaults);
|
||||||
authenticated.get("/site/:siteId", verifySiteAccess, site.getSite);
|
authenticated.get("/site/:siteId", verifySiteAccess, site.getSite);
|
||||||
authenticated.get("/site/:siteId/roles", verifySiteAccess, site.listSiteRoles);
|
authenticated.get("/site/:siteId/roles", verifySiteAccess, site.listSiteRoles);
|
||||||
authenticated.post("/site/:siteId", verifySiteAccess, site.updateSite);
|
authenticated.post("/site/:siteId", verifySiteAccess, site.updateSite);
|
||||||
authenticated.delete("/site/:siteId", verifySiteAccess, site.deleteSite);
|
authenticated.delete("/site/:siteId", verifySiteAccess, site.deleteSite);
|
||||||
authenticated.delete("/site/pickSiteDefaults", site.pickSiteDefaults);
|
|
||||||
|
|
||||||
authenticated.put(
|
authenticated.put(
|
||||||
"/org/:orgId/site/:siteId/resource",
|
"/org/:orgId/site/:siteId/resource",
|
||||||
|
|
|
@ -27,7 +27,7 @@ export type GetConfigResponse = {
|
||||||
export async function getConfig(req: Request, res: Response, next: NextFunction): Promise<any> {
|
export async function getConfig(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
try {
|
try {
|
||||||
// Validate request parameters
|
// Validate request parameters
|
||||||
const parsedParams = getConfigSchema.safeParse(req.query);
|
const parsedParams = getConfigSchema.safeParse(req.body);
|
||||||
if (!parsedParams.success) {
|
if (!parsedParams.success) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
|
@ -44,9 +44,9 @@ export async function getConfig(req: Request, res: Response, next: NextFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch exit node
|
// Fetch exit node
|
||||||
let exitNode = await db.select().from(exitNodes).where(eq(exitNodes.publicKey, publicKey));
|
let exitNodeQuery = await db.select().from(exitNodes).where(eq(exitNodes.publicKey, publicKey));
|
||||||
|
let exitNode;
|
||||||
if (!exitNode) {
|
if (exitNodeQuery.length === 0) {
|
||||||
const address = await getNextAvailableSubnet();
|
const address = await getNextAvailableSubnet();
|
||||||
const listenPort = await getNextAvailablePort();
|
const listenPort = await getNextAvailablePort();
|
||||||
const subEndpoint = await getUniqueExitNodeEndpointName();
|
const subEndpoint = await getUniqueExitNodeEndpointName();
|
||||||
|
@ -61,6 +61,8 @@ export async function getConfig(req: Request, res: Response, next: NextFunction)
|
||||||
}).returning().execute();
|
}).returning().execute();
|
||||||
|
|
||||||
logger.info(`Created new exit node ${exitNode[0].name} with address ${exitNode[0].address} and port ${exitNode[0].listenPort}`);
|
logger.info(`Created new exit node ${exitNode[0].name} with address ${exitNode[0].address} and port ${exitNode[0].listenPort}`);
|
||||||
|
} else {
|
||||||
|
exitNode = exitNodeQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!exitNode) {
|
if (!exitNode) {
|
||||||
|
@ -98,16 +100,11 @@ export async function getConfig(req: Request, res: Response, next: NextFunction)
|
||||||
peers,
|
peers,
|
||||||
};
|
};
|
||||||
|
|
||||||
return response(res, {
|
logger.debug("Sending config: ", configResponse);
|
||||||
data: configResponse,
|
|
||||||
success: true,
|
|
||||||
error: false,
|
|
||||||
message: "Configuration retrieved successfully",
|
|
||||||
status: HttpCode.OK,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
return res.status(HttpCode.OK).send(configResponse);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Error from getConfig:', error);
|
logger.error(error);
|
||||||
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
|
return next(createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred..."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,10 +116,13 @@ async function getNextAvailableSubnet(): Promise<string> {
|
||||||
}).from(exitNodes);
|
}).from(exitNodes);
|
||||||
|
|
||||||
const addresses = existingAddresses.map(a => a.address);
|
const addresses = existingAddresses.map(a => a.address);
|
||||||
const subnet = findNextAvailableCidr(addresses, config.gerbil.block_size, config.gerbil.subnet_group);
|
let subnet = findNextAvailableCidr(addresses, config.gerbil.block_size, config.gerbil.subnet_group);
|
||||||
if (!subnet) {
|
if (!subnet) {
|
||||||
throw new Error('No available subnets remaining in space');
|
throw new Error('No available subnets remaining in space');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// replace the last octet with 1
|
||||||
|
subnet = subnet.split('.').slice(0, 3).join('.') + '.1' + subnet.split('/')[1];
|
||||||
return subnet;
|
return subnet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ internalRouter.get("/traefik-config", traefik.traefikConfigProvider);
|
||||||
const gerbilRouter = Router();
|
const gerbilRouter = Router();
|
||||||
internalRouter.use("/gerbil", gerbilRouter);
|
internalRouter.use("/gerbil", gerbilRouter);
|
||||||
|
|
||||||
gerbilRouter.get("/get-config", gerbil.getConfig);
|
gerbilRouter.post("/get-config", gerbil.getConfig);
|
||||||
gerbilRouter.post("/receive-bandwidth", gerbil.receiveBandwidth);
|
gerbilRouter.post("/receive-bandwidth", gerbil.receiveBandwidth);
|
||||||
|
|
||||||
// Badger routes
|
// Badger routes
|
||||||
|
|
|
@ -75,7 +75,7 @@ export async function createResource(req: Request, res: Response, next: NextFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a unique resourceId
|
// Generate a unique resourceId
|
||||||
const fullDomain = `${subdomain}.${org[0].orgId}.${org[0].domain}`;
|
const fullDomain = `${subdomain}.${org[0].domain}`;
|
||||||
|
|
||||||
// Create new resource in the database
|
// Create new resource in the database
|
||||||
const newResource = await db.insert(resources).values({
|
const newResource = await db.insert(resources).values({
|
||||||
|
|
|
@ -66,8 +66,10 @@ export async function pickSiteDefaults(
|
||||||
.where(eq(sites.exitNodeId, exitNode.exitNodeId));
|
.where(eq(sites.exitNodeId, exitNode.exitNodeId));
|
||||||
|
|
||||||
// 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
|
||||||
const subnets = sitesQuery.map((site) => site.subnet);
|
let subnets = sitesQuery.map((site) => site.subnet);
|
||||||
const newSubnet = findNextAvailableCidr(subnets, 28, exitNode.address);
|
// exclude the exit node address by replacing after the / with a /28
|
||||||
|
subnets.push(exitNode.address.replace(/\/\d+$/, "/29"));
|
||||||
|
const newSubnet = findNextAvailableCidr(subnets, 29, exitNode.address);
|
||||||
if (!newSubnet) {
|
if (!newSubnet) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
|
|
|
@ -68,18 +68,17 @@ export default async function ConfigurationLaytout(
|
||||||
}
|
}
|
||||||
|
|
||||||
let orgs: ListOrgsResponse["orgs"] = [];
|
let orgs: ListOrgsResponse["orgs"] = [];
|
||||||
try {
|
// try {
|
||||||
const res = await internal.get<AxiosResponse<ListOrgsResponse>>(
|
// const res = await internal.get<AxiosResponse<ListOrgsResponse>>(
|
||||||
`/orgs`,
|
// `/orgs`,
|
||||||
cookie
|
// cookie
|
||||||
);
|
// );
|
||||||
if (res && res.data.data.orgs) {
|
// if (res && res.data.data.orgs) {
|
||||||
orgs = res.data.data.orgs;
|
// orgs = res.data.data.orgs;
|
||||||
}
|
// }
|
||||||
} catch (e) {
|
// } catch (e) {
|
||||||
console.error("Error fetching orgs", e);
|
// console.error("Error fetching orgs", e);
|
||||||
}
|
// }
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="w-full bg-muted mb-6 select-none sm:px-0 px-3 pt-3">
|
<div className="w-full bg-muted mb-6 select-none sm:px-0 px-3 pt-3">
|
||||||
|
|
|
@ -76,7 +76,7 @@ export function CreateSiteForm() {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
|
|
||||||
api
|
api
|
||||||
.get(`/site/pickSiteDefaults`)
|
.get(`/org/${orgId}/pickSiteDefaults`)
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
toast({
|
toast({
|
||||||
title: "Error creating site..."
|
title: "Error creating site..."
|
||||||
|
@ -93,7 +93,8 @@ export function CreateSiteForm() {
|
||||||
const res = await api
|
const res = await api
|
||||||
.put(`/org/${orgId}/site/`, {
|
.put(`/org/${orgId}/site/`, {
|
||||||
name: data.name,
|
name: data.name,
|
||||||
// subdomain: data.subdomain,
|
subnet: siteDefaults?.subnet,
|
||||||
|
exitNodeId: siteDefaults?.exitNodeId,
|
||||||
pubKey: keypair?.publicKey,
|
pubKey: keypair?.publicKey,
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
|
@ -117,7 +118,7 @@ PrivateKey = ${keypair.privateKey}
|
||||||
|
|
||||||
[Peer]
|
[Peer]
|
||||||
PublicKey = ${siteDefaults.publicKey}
|
PublicKey = ${siteDefaults.publicKey}
|
||||||
AllowedIPs = ${siteDefaults.address}
|
AllowedIPs = ${siteDefaults.address.split("/")[0]}/32
|
||||||
Endpoint = ${siteDefaults.endpoint}:${siteDefaults.listenPort}
|
Endpoint = ${siteDefaults.endpoint}:${siteDefaults.listenPort}
|
||||||
PersistentKeepalive = 5`
|
PersistentKeepalive = 5`
|
||||||
: "";
|
: "";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue