feature: Adds start and stop routes.
This commit is contained in:
parent
5bfbf5cb05
commit
18b13d4aa3
6 changed files with 203 additions and 4 deletions
28
routes/NextNet API/Forward/Start.bru
Normal file
28
routes/NextNet API/Forward/Start.bru
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
meta {
|
||||||
|
name: Start
|
||||||
|
type: http
|
||||||
|
seq: 4
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
url: http://127.0.0.1:3000/api/v1/forward/create
|
||||||
|
body: json
|
||||||
|
auth: none
|
||||||
|
}
|
||||||
|
|
||||||
|
body:json {
|
||||||
|
{
|
||||||
|
"token": "914abf2223f84375eed884671bfaefd7755d378af496b345f322214e75b51ed4465f11e26c944914c9b4fcc35c53250325fbc6530853ddfed8f72976d6fc5",
|
||||||
|
"name": "Test Route",
|
||||||
|
"description": "This is a test route for SSH",
|
||||||
|
|
||||||
|
"protocol": "tcp",
|
||||||
|
|
||||||
|
"sourceIP": "127.0.0.1",
|
||||||
|
"sourcePort": "8000",
|
||||||
|
|
||||||
|
"destinationPort": "9000",
|
||||||
|
|
||||||
|
"providerID": "1"
|
||||||
|
}
|
||||||
|
}
|
18
routes/NextNet API/Forward/Stop.bru
Normal file
18
routes/NextNet API/Forward/Stop.bru
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
meta {
|
||||||
|
name: Stop
|
||||||
|
type: http
|
||||||
|
seq: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
url: http://127.0.0.1:3000/api/v1/forward/start
|
||||||
|
body: json
|
||||||
|
auth: none
|
||||||
|
}
|
||||||
|
|
||||||
|
body:json {
|
||||||
|
{
|
||||||
|
"token": "914abf2223f84375eed884671bfaefd7755d378af496b345f322214e75b51ed4465f11e26c944914c9b4fcc35c53250325fbc6530853ddfed8f72976d6fc5",
|
||||||
|
"id": "1"
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,10 @@ import { Socket } from "node:net";
|
||||||
|
|
||||||
import type { BackendBaseClass, ForwardRule, ConnectedClient, ParameterReturnedValue } from "./base.js";
|
import type { BackendBaseClass, ForwardRule, ConnectedClient, ParameterReturnedValue } from "./base.js";
|
||||||
|
|
||||||
|
type ForwardRuleExt = ForwardRule & {
|
||||||
|
enabled: boolean
|
||||||
|
}
|
||||||
|
|
||||||
// Fight me (for better naming)
|
// Fight me (for better naming)
|
||||||
type BackendParsedProviderString = {
|
type BackendParsedProviderString = {
|
||||||
ip: string,
|
ip: string,
|
||||||
|
@ -40,7 +44,7 @@ export class SSHBackendProvider implements BackendBaseClass {
|
||||||
state: "stopped" | "stopping" | "started" | "starting";
|
state: "stopped" | "stopping" | "started" | "starting";
|
||||||
|
|
||||||
clients: ConnectedClient[];
|
clients: ConnectedClient[];
|
||||||
proxies: ForwardRule[];
|
proxies: ForwardRuleExt[];
|
||||||
logs: string[];
|
logs: string[];
|
||||||
|
|
||||||
sshInstance: NodeSSH;
|
sshInstance: NodeSSH;
|
||||||
|
@ -118,6 +122,7 @@ export class SSHBackendProvider implements BackendBaseClass {
|
||||||
await this.sshInstance.forwardIn("0.0.0.0", destPort, (info, accept, reject) => {
|
await this.sshInstance.forwardIn("0.0.0.0", destPort, (info, accept, reject) => {
|
||||||
const foundProxyEntry = this.proxies.find((i) => i.sourceIP == sourceIP && i.sourcePort == sourcePort && i.destPort == destPort);
|
const foundProxyEntry = this.proxies.find((i) => i.sourceIP == sourceIP && i.sourcePort == sourcePort && i.destPort == destPort);
|
||||||
if (!foundProxyEntry) return reject();
|
if (!foundProxyEntry) return reject();
|
||||||
|
if (!foundProxyEntry.enabled) return reject();
|
||||||
|
|
||||||
const client: ConnectedClient = {
|
const client: ConnectedClient = {
|
||||||
ip: info.srcIP,
|
ip: info.srcIP,
|
||||||
|
@ -161,7 +166,9 @@ export class SSHBackendProvider implements BackendBaseClass {
|
||||||
this.proxies.push({
|
this.proxies.push({
|
||||||
sourceIP,
|
sourceIP,
|
||||||
sourcePort,
|
sourcePort,
|
||||||
destPort
|
destPort,
|
||||||
|
|
||||||
|
enabled: true
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -172,8 +179,7 @@ export class SSHBackendProvider implements BackendBaseClass {
|
||||||
const foundProxyEntry = this.proxies.find((i) => i.sourceIP == sourceIP && i.sourcePort == sourcePort && i.destPort == destPort);
|
const foundProxyEntry = this.proxies.find((i) => i.sourceIP == sourceIP && i.sourcePort == sourcePort && i.destPort == destPort);
|
||||||
if (!foundProxyEntry) return;
|
if (!foundProxyEntry) return;
|
||||||
|
|
||||||
const proxyIndex = this.proxies.indexOf(foundProxyEntry);
|
foundProxyEntry.enabled = false;
|
||||||
this.proxies.splice(proxyIndex, 1);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
getAllConnections(): ConnectedClient[] {
|
getAllConnections(): ConnectedClient[] {
|
||||||
|
|
|
@ -15,11 +15,14 @@ import { route as backendLookup } from "./routes/backends/lookup.js";
|
||||||
import { route as forwardCreate } from "./routes/forward/create.js";
|
import { route as forwardCreate } from "./routes/forward/create.js";
|
||||||
import { route as forwardRemove } from "./routes/forward/remove.js";
|
import { route as forwardRemove } from "./routes/forward/remove.js";
|
||||||
import { route as forwardLookup } from "./routes/forward/lookup.js";
|
import { route as forwardLookup } from "./routes/forward/lookup.js";
|
||||||
|
import { route as forwardStart } from "./routes/forward/start.js";
|
||||||
|
import { route as forwardStop } from "./routes/forward/stop.js";
|
||||||
|
|
||||||
import { route as userCreate } from "./routes/user/create.js";
|
import { route as userCreate } from "./routes/user/create.js";
|
||||||
import { route as userRemove } from "./routes/user/remove.js";
|
import { route as userRemove } from "./routes/user/remove.js";
|
||||||
import { route as userLookup } from "./routes/user/lookup.js";
|
import { route as userLookup } from "./routes/user/lookup.js";
|
||||||
import { route as userLogin } from "./routes/user/login.js";
|
import { route as userLogin } from "./routes/user/login.js";
|
||||||
|
|
||||||
import { backendInit } from "./libs/backendInit.js";
|
import { backendInit } from "./libs/backendInit.js";
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
|
@ -78,6 +81,8 @@ backendLookup(routeOptions);
|
||||||
forwardCreate(routeOptions);
|
forwardCreate(routeOptions);
|
||||||
forwardRemove(routeOptions);
|
forwardRemove(routeOptions);
|
||||||
forwardLookup(routeOptions);
|
forwardLookup(routeOptions);
|
||||||
|
forwardStart(routeOptions);
|
||||||
|
forwardStop(routeOptions);
|
||||||
|
|
||||||
userCreate(routeOptions);
|
userCreate(routeOptions);
|
||||||
userRemove(routeOptions);
|
userRemove(routeOptions);
|
||||||
|
|
72
src/routes/forward/start.ts
Normal file
72
src/routes/forward/start.ts
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
import { hasPermissionByToken } from "../../libs/permissions.js";
|
||||||
|
import type { RouteOptions } from "../../libs/types.js";
|
||||||
|
|
||||||
|
export function route(routeOptions: RouteOptions) {
|
||||||
|
const {
|
||||||
|
fastify,
|
||||||
|
prisma,
|
||||||
|
tokens,
|
||||||
|
backends
|
||||||
|
} = routeOptions;
|
||||||
|
|
||||||
|
function hasPermission(token: string, permissionList: string[]): Promise<boolean> {
|
||||||
|
return hasPermissionByToken(permissionList, token, tokens, prisma);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new route to use
|
||||||
|
*/
|
||||||
|
fastify.post("/api/v1/forward/start", {
|
||||||
|
schema: {
|
||||||
|
body: {
|
||||||
|
type: "object",
|
||||||
|
required: ["token", "id"],
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
token: { type: "string" },
|
||||||
|
id: { type: "number" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}, async(req, res) => {
|
||||||
|
// @ts-ignore
|
||||||
|
const body: {
|
||||||
|
token: string,
|
||||||
|
id: number
|
||||||
|
} = req.body;
|
||||||
|
|
||||||
|
console.log(body);
|
||||||
|
|
||||||
|
if (!await hasPermission(body.token, [
|
||||||
|
"routes.start"
|
||||||
|
])) {
|
||||||
|
return res.status(403).send({
|
||||||
|
error: "Unauthorized"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const forward = await prisma.forwardRule.findUnique({
|
||||||
|
where: {
|
||||||
|
id: body.id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!forward) return res.status(400).send({
|
||||||
|
error: "Could not find forward entry"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!backends[forward.destProviderID]) return res.status(400).send({
|
||||||
|
error: "Backend not found"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Other restrictions in place make it so that it MUST be either TCP or UDP
|
||||||
|
// @ts-ignore
|
||||||
|
const protocol: "tcp" | "udp" = forward.protocol;
|
||||||
|
|
||||||
|
backends[forward.destProviderID].addConnection(forward.sourceIP, forward.sourcePort, forward.destPort, protocol);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
70
src/routes/forward/stop.ts
Normal file
70
src/routes/forward/stop.ts
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import { hasPermissionByToken } from "../../libs/permissions.js";
|
||||||
|
import type { RouteOptions } from "../../libs/types.js";
|
||||||
|
|
||||||
|
export function route(routeOptions: RouteOptions) {
|
||||||
|
const {
|
||||||
|
fastify,
|
||||||
|
prisma,
|
||||||
|
tokens,
|
||||||
|
backends
|
||||||
|
} = routeOptions;
|
||||||
|
|
||||||
|
function hasPermission(token: string, permissionList: string[]): Promise<boolean> {
|
||||||
|
return hasPermissionByToken(permissionList, token, tokens, prisma);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new route to use
|
||||||
|
*/
|
||||||
|
fastify.post("/api/v1/forward/stop", {
|
||||||
|
schema: {
|
||||||
|
body: {
|
||||||
|
type: "object",
|
||||||
|
required: ["token", "id"],
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
token: { type: "string" },
|
||||||
|
id: { type: "number" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}, async(req, res) => {
|
||||||
|
// @ts-ignore
|
||||||
|
const body: {
|
||||||
|
token: string,
|
||||||
|
id: number
|
||||||
|
} = req.body;
|
||||||
|
|
||||||
|
if (!await hasPermission(body.token, [
|
||||||
|
"routes.stop"
|
||||||
|
])) {
|
||||||
|
return res.status(403).send({
|
||||||
|
error: "Unauthorized"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const forward = await prisma.forwardRule.findUnique({
|
||||||
|
where: {
|
||||||
|
id: body.id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!forward) return res.status(400).send({
|
||||||
|
error: "Could not find forward entry"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!backends[forward.destProviderID]) return res.status(400).send({
|
||||||
|
error: "Backend not found"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Other restrictions in place make it so that it MUST be either TCP or UDP
|
||||||
|
// @ts-ignore
|
||||||
|
const protocol: "tcp" | "udp" = forward.protocol;
|
||||||
|
|
||||||
|
backends[forward.destProviderID].removeConnection(forward.sourceIP, forward.sourcePort, forward.destPort, protocol);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue