2024-10-01 19:09:35 +07:00
|
|
|
import { dotenvLoad } from "dotenv-mono";
|
|
|
|
|
const dotenv = dotenvLoad();
|
|
|
|
|
|
2025-01-02 14:48:19 +07:00
|
|
|
import { Elysia, error, t } from "elysia";
|
2024-09-21 13:28:02 +07:00
|
|
|
import { swagger } from "@elysiajs/swagger";
|
2025-01-02 14:48:19 +07:00
|
|
|
import { prisma, ServerType } from "@minikura/db";
|
|
|
|
|
|
|
|
|
|
import { ServerService } from "./services/server";
|
|
|
|
|
import { UserService } from "./services/user";
|
|
|
|
|
import argon2 from "argon2";
|
|
|
|
|
import { SessionService } from "./services/session";
|
|
|
|
|
|
|
|
|
|
enum ReturnError {
|
|
|
|
|
INVALID_USERNAME_OR_PASSWORD = "INVALID_USERNAME_OR_PASSWORD",
|
|
|
|
|
MISSING_TOKEN = "MISSING_TOKEN",
|
|
|
|
|
REVOKED_TOKEN = "REVOKED_TOKEN",
|
|
|
|
|
EXPIRED_TOKEN = "EXPIRED_TOKEN",
|
|
|
|
|
INVALID_TOKEN = "INVALID_TOKEN",
|
|
|
|
|
SERVER_NAME_IN_USE = "SERVER_NAME_IN_USE",
|
|
|
|
|
SERVER_NOT_FOUND = "SERVER_NOT_FOUND",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const bootstrap = async () => {
|
|
|
|
|
const users = await prisma.user.findMany();
|
|
|
|
|
if (users.length !== 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await prisma.user.create({
|
|
|
|
|
data: {
|
|
|
|
|
username: "admin",
|
|
|
|
|
password: await argon2.hash("admin"),
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
console.log("Default user created");
|
|
|
|
|
};
|
2024-09-21 13:28:02 +07:00
|
|
|
|
|
|
|
|
const app = new Elysia()
|
2025-05-12 12:37:35 +07:00
|
|
|
.use(swagger({
|
|
|
|
|
path: '/swagger',
|
|
|
|
|
documentation: {
|
|
|
|
|
info: {
|
|
|
|
|
title: 'Minikura API Documentation',
|
|
|
|
|
version: '1.0.0'
|
2025-01-02 14:48:19 +07:00
|
|
|
}
|
|
|
|
|
}
|
2025-05-12 12:37:35 +07:00
|
|
|
}))
|
|
|
|
|
.group('/api', app => app
|
|
|
|
|
.derive(async ({ headers, cookie: { session_token }, path }) => {
|
|
|
|
|
// Skip token validation for login route
|
|
|
|
|
if (path === '/api/login') {
|
2025-01-02 14:48:19 +07:00
|
|
|
return {
|
2025-05-12 12:37:35 +07:00
|
|
|
server: null,
|
2025-01-02 14:48:19 +07:00
|
|
|
session: null,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-12 12:37:35 +07:00
|
|
|
const auth = session_token.value;
|
|
|
|
|
const token = headers.authorization?.split(" ")[1];
|
2025-01-02 14:48:19 +07:00
|
|
|
|
2025-05-12 12:37:35 +07:00
|
|
|
if (!auth && !token)
|
|
|
|
|
return error("Unauthorized", {
|
2025-01-02 14:48:19 +07:00
|
|
|
success: false,
|
2025-05-12 12:37:35 +07:00
|
|
|
message: ReturnError.MISSING_TOKEN,
|
2025-01-02 14:48:19 +07:00
|
|
|
});
|
2025-05-12 12:37:35 +07:00
|
|
|
|
|
|
|
|
if (auth) {
|
|
|
|
|
const session = await SessionService.validate(auth);
|
|
|
|
|
if (session.status === SessionService.SESSION_STATUS.REVOKED) {
|
|
|
|
|
return error("Unauthorized", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: ReturnError.REVOKED_TOKEN,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if (session.status === SessionService.SESSION_STATUS.EXPIRED) {
|
|
|
|
|
return error("Unauthorized", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: ReturnError.EXPIRED_TOKEN,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if (
|
|
|
|
|
session.status === SessionService.SESSION_STATUS.INVALID ||
|
|
|
|
|
session.status !== SessionService.SESSION_STATUS.VALID ||
|
|
|
|
|
!session.session
|
|
|
|
|
) {
|
|
|
|
|
return error("Unauthorized", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: ReturnError.INVALID_TOKEN,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
server: null,
|
|
|
|
|
session: session.session,
|
|
|
|
|
};
|
2025-01-02 14:48:19 +07:00
|
|
|
}
|
|
|
|
|
|
2025-05-12 12:37:35 +07:00
|
|
|
if (token) {
|
|
|
|
|
const session = await SessionService.validateApiKey(token);
|
|
|
|
|
if (session.status === SessionService.SESSION_STATUS.INVALID) {
|
|
|
|
|
return error("Unauthorized", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: ReturnError.INVALID_TOKEN,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if (
|
|
|
|
|
session.status === SessionService.SESSION_STATUS.VALID &&
|
|
|
|
|
session.server
|
|
|
|
|
) {
|
|
|
|
|
return {
|
|
|
|
|
session: null,
|
|
|
|
|
server: session.server,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Should never reach here
|
|
|
|
|
return error("Unauthorized", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: ReturnError.INVALID_TOKEN,
|
2025-01-02 14:48:19 +07:00
|
|
|
});
|
2025-05-12 12:37:35 +07:00
|
|
|
})
|
|
|
|
|
.post(
|
|
|
|
|
"/login",
|
|
|
|
|
async ({ body, cookie: { session_token } }) => {
|
|
|
|
|
const user = await UserService.getUserByUsername(body.username);
|
|
|
|
|
const valid = await argon2.verify(user?.password || "fake", body.password);
|
|
|
|
|
|
|
|
|
|
if (!user || !valid) {
|
|
|
|
|
return error("Unauthorized", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: ReturnError.INVALID_USERNAME_OR_PASSWORD,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const session = await SessionService.create(user.id);
|
|
|
|
|
|
|
|
|
|
session_token.httpOnly = true;
|
|
|
|
|
session_token.value = session.token;
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
body: t.Object({
|
|
|
|
|
username: t.String({ minLength: 1 }),
|
|
|
|
|
password: t.String({ minLength: 1 }),
|
|
|
|
|
}),
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
.ws("/ws", {
|
|
|
|
|
body: t.Object({
|
|
|
|
|
message: t.String(),
|
|
|
|
|
}),
|
|
|
|
|
message(ws, { message }) {
|
|
|
|
|
const { id } = ws.data.query;
|
|
|
|
|
ws.send({
|
|
|
|
|
id,
|
|
|
|
|
message,
|
|
|
|
|
time: Date.now(),
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
.post("/logout", async ({ session, cookie: { session_token } }) => {
|
|
|
|
|
if (!session) return { success: true };
|
|
|
|
|
|
|
|
|
|
await SessionService.revoke(session.token);
|
|
|
|
|
|
|
|
|
|
session_token.remove();
|
2025-01-02 14:48:19 +07:00
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
};
|
2025-05-12 12:37:35 +07:00
|
|
|
})
|
|
|
|
|
.get("/servers", async ({ session }) => {
|
|
|
|
|
return await ServerService.getAllServers(!session);
|
|
|
|
|
})
|
|
|
|
|
.get("/servers/:id", async ({ session, params: { id } }) => {
|
|
|
|
|
return await ServerService.getServerById(id, !session);
|
|
|
|
|
})
|
|
|
|
|
.post(
|
|
|
|
|
"/servers",
|
|
|
|
|
async ({ body, error }) => {
|
|
|
|
|
// Must be a-z, A-Z, 0-9, and -_ only
|
|
|
|
|
if (!/^[a-zA-Z0-9-_]+$/.test(body.id)) {
|
|
|
|
|
return error("Bad Request", "ID must be a-z, A-Z, 0-9, and -_ only");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const _server = await ServerService.getServerById(body.id);
|
|
|
|
|
if (_server) {
|
|
|
|
|
return error("Conflict", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: ReturnError.SERVER_NAME_IN_USE,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const server = await ServerService.createServer({
|
|
|
|
|
id: body.id,
|
|
|
|
|
description: body.description,
|
|
|
|
|
listen_port: body.listen_port,
|
|
|
|
|
type: body.type,
|
|
|
|
|
env_variables: body.env_variables,
|
|
|
|
|
memory: body.memory,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
data: {
|
|
|
|
|
server,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
body: t.Object({
|
|
|
|
|
id: t.String({ minLength: 1 }),
|
|
|
|
|
description: t.Nullable(t.String({ minLength: 1 })),
|
|
|
|
|
listen_port: t.Integer({ minimum: 1, maximum: 65535 }),
|
|
|
|
|
type: t.Enum(ServerType),
|
|
|
|
|
env_variables: t.Optional(t.Array(t.Object({
|
|
|
|
|
key: t.String({ minLength: 1 }),
|
|
|
|
|
value: t.String(),
|
|
|
|
|
}))),
|
|
|
|
|
memory: t.Optional(t.String({ minLength: 1 })),
|
|
|
|
|
}),
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
.patch(
|
|
|
|
|
"/servers/:id",
|
|
|
|
|
async ({ session, params: { id }, body }) => {
|
|
|
|
|
const server = await ServerService.getServerById(id);
|
|
|
|
|
if (!server) {
|
|
|
|
|
return error("Not Found", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: ReturnError.SERVER_NOT_FOUND,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create update data with only fields that exist in the model
|
|
|
|
|
const data: any = {};
|
|
|
|
|
|
|
|
|
|
if (body.description !== undefined) data.description = body.description;
|
|
|
|
|
if (body.listen_port !== undefined) data.listen_port = body.listen_port;
|
|
|
|
|
if (body.memory !== undefined) data.memory = body.memory;
|
|
|
|
|
// Don't allow service_type to be updated through API
|
|
|
|
|
|
|
|
|
|
await prisma.server.update({
|
|
|
|
|
where: { id },
|
|
|
|
|
data,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const newServer = await ServerService.getServerById(id, !session);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
data: {
|
|
|
|
|
server: newServer,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
body: t.Object({
|
|
|
|
|
description: t.Optional(t.Nullable(t.String({ minLength: 1 }))),
|
|
|
|
|
listen_port: t.Optional(t.Integer({ minimum: 1, maximum: 65535 })),
|
|
|
|
|
memory: t.Optional(t.String({ minLength: 1 })),
|
|
|
|
|
}),
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
.delete("/servers/:id", async ({ params: { id } }) => {
|
2025-01-02 14:48:19 +07:00
|
|
|
const server = await ServerService.getServerById(id);
|
|
|
|
|
if (!server) {
|
|
|
|
|
return error("Not Found", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: ReturnError.SERVER_NOT_FOUND,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-12 12:37:35 +07:00
|
|
|
await prisma.server.delete({
|
|
|
|
|
where: { id },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
};
|
|
|
|
|
})
|
|
|
|
|
.get("/reverse_proxy_servers", async ({ session }) => {
|
|
|
|
|
return await ServerService.getAllReverseProxyServers(!session);
|
|
|
|
|
})
|
|
|
|
|
.post(
|
|
|
|
|
"/reverse_proxy_servers",
|
|
|
|
|
async ({ body, error }) => {
|
|
|
|
|
// Must be a-z, A-Z, 0-9, and -_ only
|
|
|
|
|
if (!/^[a-zA-Z0-9-_]+$/.test(body.id)) {
|
|
|
|
|
return error("Bad Request", "ID must be a-z, A-Z, 0-9, and -_ only");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const _server = await ServerService.getReverseProxyServerById(body.id);
|
|
|
|
|
if (_server) {
|
2025-01-02 14:48:19 +07:00
|
|
|
return error("Conflict", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: ReturnError.SERVER_NAME_IN_USE,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-12 12:37:35 +07:00
|
|
|
const server = await ServerService.createReverseProxyServer({
|
|
|
|
|
id: body.id,
|
|
|
|
|
description: body.description,
|
|
|
|
|
external_address: body.external_address,
|
|
|
|
|
external_port: body.external_port,
|
|
|
|
|
listen_port: body.listen_port,
|
|
|
|
|
type: body.type,
|
|
|
|
|
env_variables: body.env_variables,
|
|
|
|
|
memory: body.memory,
|
2025-01-02 14:48:19 +07:00
|
|
|
});
|
2025-05-12 12:37:35 +07:00
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
data: {
|
|
|
|
|
server,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
body: t.Object({
|
|
|
|
|
id: t.String({ minLength: 1 }),
|
|
|
|
|
description: t.Nullable(t.String({ minLength: 1 })),
|
|
|
|
|
external_address: t.String({ minLength: 1 }),
|
|
|
|
|
external_port: t.Integer({ minimum: 1, maximum: 65535 }),
|
|
|
|
|
listen_port: t.Optional(t.Integer({ minimum: 1, maximum: 65535 })),
|
|
|
|
|
type: t.Optional(t.Enum({ VELOCITY: "VELOCITY", BUNGEECORD: "BUNGEECORD" })),
|
|
|
|
|
env_variables: t.Optional(t.Array(t.Object({
|
|
|
|
|
key: t.String({ minLength: 1 }),
|
|
|
|
|
value: t.String(),
|
|
|
|
|
}))),
|
|
|
|
|
memory: t.Optional(t.String({ minLength: 1 })),
|
|
|
|
|
}),
|
2025-01-02 14:48:19 +07:00
|
|
|
}
|
2025-05-12 12:37:35 +07:00
|
|
|
)
|
|
|
|
|
.patch(
|
|
|
|
|
"/reverse_proxy_servers/:id",
|
|
|
|
|
async ({ session, params: { id }, body }) => {
|
|
|
|
|
const server = await prisma.reverseProxyServer.findUnique({
|
|
|
|
|
where: { id },
|
|
|
|
|
});
|
|
|
|
|
if (!server) {
|
|
|
|
|
return error("Not Found", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: ReturnError.SERVER_NOT_FOUND,
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-01-02 14:48:19 +07:00
|
|
|
|
2025-05-12 12:37:35 +07:00
|
|
|
// Create update data with only fields that exist in the model
|
|
|
|
|
const data: any = {};
|
|
|
|
|
|
|
|
|
|
if (body.description !== undefined) data.description = body.description;
|
|
|
|
|
if (body.external_address !== undefined) data.external_address = body.external_address;
|
|
|
|
|
if (body.external_port !== undefined) data.external_port = body.external_port;
|
|
|
|
|
if (body.listen_port !== undefined) data.listen_port = body.listen_port;
|
|
|
|
|
if (body.type !== undefined) data.type = body.type;
|
|
|
|
|
if (body.memory !== undefined) data.memory = body.memory;
|
|
|
|
|
// Don't allow service_type to be updated through API
|
2025-01-02 14:48:19 +07:00
|
|
|
|
2025-05-12 12:37:35 +07:00
|
|
|
await prisma.reverseProxyServer.update({
|
|
|
|
|
where: { id },
|
|
|
|
|
data,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const newServer = await ServerService.getReverseProxyServerById(
|
|
|
|
|
id,
|
|
|
|
|
!session
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
data: {
|
|
|
|
|
server: newServer,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
body: t.Object({
|
|
|
|
|
description: t.Optional(t.Nullable(t.String({ minLength: 1 }))),
|
|
|
|
|
external_address: t.Optional(t.String({ minLength: 1 })),
|
|
|
|
|
external_port: t.Optional(t.Integer({ minimum: 1, maximum: 65535 })),
|
|
|
|
|
listen_port: t.Optional(t.Integer({ minimum: 1, maximum: 65535 })),
|
|
|
|
|
type: t.Optional(t.Enum({ VELOCITY: "VELOCITY", BUNGEECORD: "BUNGEECORD" })),
|
|
|
|
|
memory: t.Optional(t.String({ minLength: 1 })),
|
|
|
|
|
}),
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
.delete("/reverse_proxy_servers/:id", async ({ params: { id } }) => {
|
2025-01-02 14:48:19 +07:00
|
|
|
const server = await prisma.reverseProxyServer.findUnique({
|
|
|
|
|
where: { id },
|
|
|
|
|
});
|
|
|
|
|
if (!server) {
|
|
|
|
|
return error("Not Found", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: ReturnError.SERVER_NOT_FOUND,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-12 12:37:35 +07:00
|
|
|
await prisma.reverseProxyServer.delete({
|
2025-01-02 14:48:19 +07:00
|
|
|
where: { id },
|
|
|
|
|
});
|
|
|
|
|
|
2025-05-12 12:37:35 +07:00
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
};
|
|
|
|
|
})
|
|
|
|
|
.get("/servers/:id/env", async ({ params: { id } }) => {
|
|
|
|
|
const server = await ServerService.getServerById(id);
|
|
|
|
|
if (!server) {
|
|
|
|
|
return error("Not Found", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: ReturnError.SERVER_NOT_FOUND,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-02 14:48:19 +07:00
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
data: {
|
2025-05-12 12:37:35 +07:00
|
|
|
env_variables: server.env_variables,
|
2025-01-02 14:48:19 +07:00
|
|
|
},
|
|
|
|
|
};
|
2025-05-12 12:37:35 +07:00
|
|
|
})
|
|
|
|
|
.post(
|
|
|
|
|
"/servers/:id/env",
|
|
|
|
|
async ({ params: { id }, body }) => {
|
|
|
|
|
const server = await ServerService.getServerById(id);
|
|
|
|
|
if (!server) {
|
|
|
|
|
return error("Not Found", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: ReturnError.SERVER_NOT_FOUND,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const envVar = await prisma.customEnvironmentVariable.upsert({
|
|
|
|
|
where: {
|
|
|
|
|
key_server_id: {
|
|
|
|
|
key: body.key,
|
|
|
|
|
server_id: id,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
update: {
|
|
|
|
|
value: body.value,
|
|
|
|
|
},
|
|
|
|
|
create: {
|
|
|
|
|
key: body.key,
|
|
|
|
|
value: body.value,
|
|
|
|
|
server_id: id,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
data: {
|
|
|
|
|
env_var: envVar,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
body: t.Object({
|
|
|
|
|
key: t.String({ minLength: 1 }),
|
|
|
|
|
value: t.String(),
|
|
|
|
|
}),
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
.delete("/servers/:id/env/:key", async ({ params: { id, key } }) => {
|
|
|
|
|
const server = await ServerService.getServerById(id);
|
|
|
|
|
if (!server) {
|
|
|
|
|
return error("Not Found", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: ReturnError.SERVER_NOT_FOUND,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await prisma.customEnvironmentVariable.delete({
|
|
|
|
|
where: {
|
|
|
|
|
key_server_id: {
|
|
|
|
|
key,
|
|
|
|
|
server_id: id,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
};
|
|
|
|
|
} catch (err) {
|
|
|
|
|
return error("Not Found", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: "Environment variable not found",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.get("/reverse_proxy_servers/:id/env", async ({ params: { id } }) => {
|
|
|
|
|
const server = await ServerService.getReverseProxyServerById(id);
|
|
|
|
|
if (!server) {
|
|
|
|
|
return error("Not Found", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: ReturnError.SERVER_NOT_FOUND,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
data: {
|
|
|
|
|
env_variables: server.env_variables,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
})
|
|
|
|
|
.post(
|
|
|
|
|
"/reverse_proxy_servers/:id/env",
|
|
|
|
|
async ({ params: { id }, body }) => {
|
|
|
|
|
const server = await ServerService.getReverseProxyServerById(id);
|
|
|
|
|
if (!server) {
|
|
|
|
|
return error("Not Found", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: ReturnError.SERVER_NOT_FOUND,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const envVar = await prisma.customEnvironmentVariable.upsert({
|
|
|
|
|
where: {
|
|
|
|
|
key_reverse_proxy_id: {
|
|
|
|
|
key: body.key,
|
|
|
|
|
reverse_proxy_id: id,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
update: {
|
|
|
|
|
value: body.value,
|
|
|
|
|
},
|
|
|
|
|
create: {
|
|
|
|
|
key: body.key,
|
|
|
|
|
value: body.value,
|
|
|
|
|
reverse_proxy_id: id,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
data: {
|
|
|
|
|
env_var: envVar,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
body: t.Object({
|
|
|
|
|
key: t.String({ minLength: 1 }),
|
|
|
|
|
value: t.String(),
|
|
|
|
|
}),
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
.delete("/reverse_proxy_servers/:id/env/:key", async ({ params: { id, key } }) => {
|
|
|
|
|
const server = await ServerService.getReverseProxyServerById(id);
|
|
|
|
|
if (!server) {
|
|
|
|
|
return error("Not Found", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: ReturnError.SERVER_NOT_FOUND,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await prisma.customEnvironmentVariable.delete({
|
|
|
|
|
where: {
|
|
|
|
|
key_reverse_proxy_id: {
|
|
|
|
|
key,
|
|
|
|
|
reverse_proxy_id: id,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
};
|
|
|
|
|
} catch (err) {
|
|
|
|
|
return error("Not Found", {
|
|
|
|
|
success: false,
|
|
|
|
|
message: "Environment variable not found",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
})
|
2025-01-02 14:48:19 +07:00
|
|
|
)
|
2024-09-21 13:28:02 +07:00
|
|
|
.listen(3000, async () => {
|
|
|
|
|
console.log("Server is running on port 3000");
|
2025-01-02 14:48:19 +07:00
|
|
|
bootstrap();
|
2024-09-21 13:28:02 +07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export type App = typeof app;
|