Web interface #525
@@ -92,6 +92,14 @@ export class Bedrock<P extends platforms> extends customEvent<bedrockEvents> {
 | 
			
		||||
    Object.defineProperty(this, "platform", { writable: false });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getVersion(version: string | number) {
 | 
			
		||||
    if (this.platform === "mojang") return bedrockVersions.mojangCache.get(version);
 | 
			
		||||
    else if (this.platform === "pocketmine") return bedrockVersions.pocketmineCache.get(version);
 | 
			
		||||
    else if (this.platform === "cloudburst") return bedrockVersions.cloudburstCache.get(version);
 | 
			
		||||
    else if (this.platform === "nukkit") return bedrockVersions.nukkitCache.get(version);
 | 
			
		||||
    else return bedrockVersions.powernukkitCache.get(version);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async installServer(version: string | number) {
 | 
			
		||||
    const { platform } = this;
 | 
			
		||||
    if (!(await extendsFS.exists(this.serverFolder))) await fs.mkdir(this.serverFolder, { recursive: true });
 | 
			
		||||
 
 | 
			
		||||
@@ -5,12 +5,12 @@ import semver from "semver";
 | 
			
		||||
import { bdsFilesBucket } from "../../internalClouds.js";
 | 
			
		||||
import { versionsStorages } from "../../serverRun.js";
 | 
			
		||||
 | 
			
		||||
interface baseDownload {
 | 
			
		||||
export interface baseDownload {
 | 
			
		||||
  URL: string;
 | 
			
		||||
  releaseDate: Date;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface mojangInfo extends baseDownload {
 | 
			
		||||
export interface mojangInfo extends baseDownload {
 | 
			
		||||
  release: "oficial" | "snapshot" | "beta" | "alpha";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -41,6 +41,16 @@ export class Java<P extends platform> extends customEvent<javaEvents> {
 | 
			
		||||
    Object.defineProperty(this, "platform", { writable: false });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getVersion(version: number|string) {
 | 
			
		||||
    if (this.platform === "mojang") return javaVersions.mojangCache.get(version);
 | 
			
		||||
    else if (this.platform === "spigot") return javaVersions.spigotCache.get(version);
 | 
			
		||||
    else if (this.platform === "paper") return javaVersions.paperCache.get(version);
 | 
			
		||||
    else if (this.platform === "purpur") return javaVersions.purpurCache.get(version);
 | 
			
		||||
    else if (this.platform === "folia") return javaVersions.foliaCache.get(version);
 | 
			
		||||
    else if (this.platform === "cuberite") return javaVersions.cuberiteCache.get(version);
 | 
			
		||||
    else return javaVersions.glowstoneCache.get(version);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async installServer(version: string | number) {
 | 
			
		||||
    const { platform } = this;
 | 
			
		||||
    if (!(await extendsFS.exists(this.serverFolder))) await fs.mkdir(this.serverFolder, { recursive: true });
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
import session from "express-session";
 | 
			
		||||
import express from "express";
 | 
			
		||||
import crypto from "node:crypto";
 | 
			
		||||
import { localConfig } from "./config.js";
 | 
			
		||||
import { mongoDatabase } from "./databaseConnect.js";
 | 
			
		||||
@@ -131,7 +132,7 @@ export async function createSSHKey(): Promise<{privateKey: string, publicKey: st
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type userSorage = {
 | 
			
		||||
type userStorage = {
 | 
			
		||||
  /** Unique user ID */
 | 
			
		||||
  readonly userID: string;
 | 
			
		||||
 | 
			
		||||
@@ -142,7 +143,7 @@ type userSorage = {
 | 
			
		||||
  email: string;
 | 
			
		||||
 | 
			
		||||
  /** Auth password */
 | 
			
		||||
  password: string;
 | 
			
		||||
  password: {hash: string, salt: string};
 | 
			
		||||
 | 
			
		||||
  /** API Token auth */
 | 
			
		||||
  tokens: string[];
 | 
			
		||||
@@ -153,16 +154,16 @@ type userSorage = {
 | 
			
		||||
    Java: string;
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
export const usersCollection = mongoDatabase.collection<userSorage>("usersAuth");
 | 
			
		||||
export const usersCollection = mongoDatabase.collection<userStorage>("usersAuth");
 | 
			
		||||
 | 
			
		||||
export const random = () => {
 | 
			
		||||
  if (typeof crypto.randomUUID === "function") return crypto.randomUUID();
 | 
			
		||||
  return ([
 | 
			
		||||
    crypto.pseudoRandomBytes(8).toString("hex"),
 | 
			
		||||
    crypto.pseudoRandomBytes(4).toString("hex"),
 | 
			
		||||
    crypto.pseudoRandomBytes(4).toString("hex"),
 | 
			
		||||
    crypto.pseudoRandomBytes(4).toString("hex"),
 | 
			
		||||
    crypto.pseudoRandomBytes(12).toString("hex"),
 | 
			
		||||
    crypto.randomBytes(8).toString("hex"),
 | 
			
		||||
    crypto.randomBytes(4).toString("hex"),
 | 
			
		||||
    crypto.randomBytes(4).toString("hex"),
 | 
			
		||||
    crypto.randomBytes(4).toString("hex"),
 | 
			
		||||
    crypto.randomBytes(12).toString("hex"),
 | 
			
		||||
  ]).join("-");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -174,7 +175,7 @@ export async function generateUserID() {
 | 
			
		||||
 | 
			
		||||
export async function generateToken() {
 | 
			
		||||
  const genToken = () => {
 | 
			
		||||
    let data = Array(crypto.randomInt(3, 8)+1).fill(null).map(() => crypto.pseudoRandomBytes(crypto.randomInt(1, 6)).toString("hex"));
 | 
			
		||||
    let data = Array(crypto.randomInt(3, 8)+1).fill(null).map(() => crypto.randomBytes(crypto.randomInt(1, 6)).toString("hex"));
 | 
			
		||||
    let scg =  "tk_";
 | 
			
		||||
 | 
			
		||||
    scg += data.shift() + data.pop();
 | 
			
		||||
@@ -187,3 +188,33 @@ export async function generateToken() {
 | 
			
		||||
  while (true) if (!(await usersCollection.findOne({tokens: [(token = genToken())]}))) break;
 | 
			
		||||
  return token;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
declare module "express-serve-static-core" {
 | 
			
		||||
  interface Request {
 | 
			
		||||
    userInfo?: userStorage;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const authRoute: express.RequestHandler = async (req, res, next) => {
 | 
			
		||||
  if (typeof req.headers.authorization === "string" && (req.headers.authorization = req.headers.authorization.trim()).length > 0) {
 | 
			
		||||
    let userInfo: userStorage;
 | 
			
		||||
    const { authorization } = req.headers;
 | 
			
		||||
    if (authorization.startsWith("Basic ")) {
 | 
			
		||||
      const decode64 = Buffer.from(authorization.slice(5).trim(), "base64").toString("utf8");
 | 
			
		||||
      let index: number, email = decode64.slice(0, (index = decode64.indexOf(":"))), password = decode64.slice(index+1);
 | 
			
		||||
      userInfo = await usersCollection.findOne({email});
 | 
			
		||||
      if (await passwordDecrypt(userInfo.password.hash, userInfo.password.salt) !== password) userInfo = undefined;
 | 
			
		||||
    } else if (authorization.startsWith("Token ")||authorization.startsWith("Bearer ")) {
 | 
			
		||||
      const token = authorization.slice(6).trim();
 | 
			
		||||
      userInfo = await usersCollection.findOne({tokens: [token]});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!userInfo) return res.status(401).json({error: "invalid authentication"});
 | 
			
		||||
    req.userInfo = userInfo;
 | 
			
		||||
    req.session.userID = userInfo.userID;
 | 
			
		||||
    return req.session.save(next);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (typeof req.session.userID === "string" && !req.userInfo) req.userInfo = await usersCollection.findOne({userID: req.session.userID});
 | 
			
		||||
  return next();
 | 
			
		||||
}
 | 
			
		||||
@@ -2,11 +2,12 @@ import { randomBytes } from "node:crypto";
 | 
			
		||||
import fs from "node:fs/promises";
 | 
			
		||||
import path from "node:path";
 | 
			
		||||
import { createSSHKey } from "./auth.js";
 | 
			
		||||
import { homedir } from "node:os";
 | 
			
		||||
 | 
			
		||||
export type configFile = {
 | 
			
		||||
  serversPath: string;
 | 
			
		||||
  /** HTTP port listen */
 | 
			
		||||
  portListen: number;
 | 
			
		||||
  domain?: string;
 | 
			
		||||
  /** Super cookie secret */
 | 
			
		||||
  cookieSecret: string;
 | 
			
		||||
  /** MongoDB URI connection */
 | 
			
		||||
@@ -22,6 +23,7 @@ export type configFile = {
 | 
			
		||||
const sshKeys = Object.keys(process.env).filter(name => name.startsWith("SSH_HOST")).map(name => path.resolve(process.cwd(), process.env[name]));
 | 
			
		||||
 | 
			
		||||
export const localConfig: configFile = {
 | 
			
		||||
  serversPath: process.env.SERVER_PATH ? path.resolve(process.cwd(), process.env.SERVER_PATH) : path.join(homedir(), ".bdsManeger"),
 | 
			
		||||
  cookieSecret: process.env.COOKIE_SECRET || randomBytes(8).toString("hex"),
 | 
			
		||||
  mongoConnection: process.env.MONGO_URI || "mongodb://127.0.0.1",
 | 
			
		||||
  mongoDatabase: (typeof process.env.MONGO_DB === "string" && process.env.MONGO_DB.length >= 2) ? process.env.MONGO_DB : undefined,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
#!/usr/bin/env node
 | 
			
		||||
import express from "express";
 | 
			
		||||
import http from "node:http";
 | 
			
		||||
import { cookie } from "./auth.js";
 | 
			
		||||
import { authRoute, cookie } from "./auth.js";
 | 
			
		||||
import { localConfig } from "./config.js";
 | 
			
		||||
import mcserver from "./mcserver.js";
 | 
			
		||||
import { nextHandler, nextUpgarde } from "./reactServer.js";
 | 
			
		||||
@@ -12,7 +12,7 @@ server.on("upgrade", nextUpgarde);
 | 
			
		||||
server.on("request", app);
 | 
			
		||||
 | 
			
		||||
app.disable("etag").disable("x-powered-by");
 | 
			
		||||
app.use(cookie, express.json(), express.urlencoded({ extended: true }));
 | 
			
		||||
app.use(cookie, authRoute, express.json(), express.urlencoded({ extended: true }));
 | 
			
		||||
 | 
			
		||||
// API 404
 | 
			
		||||
app.use("/api/mcserver", mcserver);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,85 @@
 | 
			
		||||
import express from "express";
 | 
			
		||||
import { random } from "./auth.js";
 | 
			
		||||
import { mongoDatabase } from "./databaseConnect.js";
 | 
			
		||||
import bdsCore from "@the-bds-maneger/core";
 | 
			
		||||
import path from "node:path";
 | 
			
		||||
import { localConfig } from "./config.js";
 | 
			
		||||
 | 
			
		||||
type serverStor = {
 | 
			
		||||
  /** Unique ID to identify server */
 | 
			
		||||
  readonly ID: string;
 | 
			
		||||
 | 
			
		||||
  readonly platform: `bedrock-${bdsCore.Bedrock.platforms}` | `java-${bdsCore.Java.platform}`;
 | 
			
		||||
 | 
			
		||||
  public: boolean;
 | 
			
		||||
 | 
			
		||||
  /** user allowed to modify server */
 | 
			
		||||
  usersID: string[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const serverCollection = mongoDatabase.collection<serverStor>("servers");
 | 
			
		||||
export async function generateID() {
 | 
			
		||||
  let ID: string;
 | 
			
		||||
  while (true) if (!(await serverCollection.findOne({ID: (ID = random())}))) break;
 | 
			
		||||
  while (true) if (!(await serverCollection.findOne({ ID: (ID = random()) }))) break;
 | 
			
		||||
  return ID;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const app = express.Router();
 | 
			
		||||
export default app;
 | 
			
		||||
 | 
			
		||||
export const serverSessions = new Map<string, bdsCore.Bedrock.Bedrock<any> | bdsCore.Java.Java<any>>();
 | 
			
		||||
app.get("/public", (_req, res, next) => serverCollection.find({ public: true }).toArray().then(data => res.json(data.map(v => ({ ID: v.ID, serverPlatform: v.platform }))), next));
 | 
			
		||||
 | 
			
		||||
app.use((req, res, next) => {
 | 
			
		||||
  if (!req.userInfo) return res.status(401).json({ error: "need authorization" });
 | 
			
		||||
  return next();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
app.get("/", (req, res, next) => serverCollection.find({ usersID: [req.session.userID] }).toArray().then(res.json, next));
 | 
			
		||||
app.post("/", async (req, res) => {
 | 
			
		||||
  if (typeof req.body !== "object") return res.status(400).json({ error: "Require body to install platform" });
 | 
			
		||||
  const { version, platform } = req.body as { version?: string | number, platform: serverStor["platform"] };
 | 
			
		||||
 | 
			
		||||
  if (!platform) return res.status(400).json({ error: "require platform" });
 | 
			
		||||
  if (!(([
 | 
			
		||||
    "bedrock-mojang",
 | 
			
		||||
    "java-mojang",
 | 
			
		||||
    "bedrock-pocketmine",
 | 
			
		||||
    "bedrock-cloudburst",
 | 
			
		||||
    "bedrock-nukkit",
 | 
			
		||||
    "bedrock-powernukkit",
 | 
			
		||||
    "java-spigot",
 | 
			
		||||
    "java-paper",
 | 
			
		||||
    "java-cuberite",
 | 
			
		||||
    "java-purpur",
 | 
			
		||||
    "java-folia",
 | 
			
		||||
    "java-glowstone"
 | 
			
		||||
  ]).includes(platform))) res.status(400).json({ error: "invalid platform" });
 | 
			
		||||
  const ID = await generateID();
 | 
			
		||||
  await serverCollection.insertOne({
 | 
			
		||||
    ID,
 | 
			
		||||
    platform,
 | 
			
		||||
    public: false,
 | 
			
		||||
    usersID: [
 | 
			
		||||
      req.userInfo.userID,
 | 
			
		||||
    ]
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const pathInstall = path.join(localConfig.serversPath, ID.split("-").join("_"));
 | 
			
		||||
  let serverManeger: bdsCore.Bedrock.Bedrock<any> | bdsCore.Java.Java<any>;
 | 
			
		||||
  if (platform === "bedrock-mojang") serverManeger = new bdsCore.Bedrock.Bedrock(pathInstall, "mojang");
 | 
			
		||||
  else if (platform === "java-mojang") serverManeger = new bdsCore.Java.Java(pathInstall, "mojang");
 | 
			
		||||
  else if (platform === "bedrock-pocketmine") serverManeger = new bdsCore.Bedrock.Bedrock(pathInstall, "pocketmine");
 | 
			
		||||
  else if (platform === "bedrock-cloudburst") serverManeger = new bdsCore.Bedrock.Bedrock(pathInstall, "cloudburst");
 | 
			
		||||
  else if (platform === "bedrock-nukkit") serverManeger = new bdsCore.Bedrock.Bedrock(pathInstall, "nukkit");
 | 
			
		||||
  else if (platform === "bedrock-powernukkit") serverManeger = new bdsCore.Bedrock.Bedrock(pathInstall, "powernukkit");
 | 
			
		||||
  else if (platform === "java-spigot") serverManeger = new bdsCore.Java.Java(pathInstall, "spigot");
 | 
			
		||||
  else if (platform === "java-paper") serverManeger = new bdsCore.Java.Java(pathInstall, "paper");
 | 
			
		||||
  else if (platform === "java-cuberite") serverManeger = new bdsCore.Java.Java(pathInstall, "cuberite");
 | 
			
		||||
  else if (platform === "java-purpur") serverManeger = new bdsCore.Java.Java(pathInstall, "purpur");
 | 
			
		||||
  else if (platform === "java-folia") serverManeger = new bdsCore.Java.Java(pathInstall, "folia");
 | 
			
		||||
  else if (platform === "java-glowstone") serverManeger = new bdsCore.Java.Java(pathInstall, "glowstone");
 | 
			
		||||
 | 
			
		||||
  await serverManeger.installServer(version);
 | 
			
		||||
  return res.json(serverManeger.getVersion(version));
 | 
			
		||||
});
 | 
			
		||||
@@ -1,20 +0,0 @@
 | 
			
		||||
import { GetServerSidePropsContext, InferGetStaticPropsType } from "next";
 | 
			
		||||
import { useState } from "react";
 | 
			
		||||
 | 
			
		||||
export default function Maneger(props: InferGetStaticPropsType<typeof getServerSideProps>) {
 | 
			
		||||
  const [ stats, updateStats ] = useState(props.server);
 | 
			
		||||
  return <div>
 | 
			
		||||
    <pre>{JSON.stringify(stats, null, 2)}</pre>
 | 
			
		||||
  </div>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function getServerSideProps({req, params: { server_id }}: GetServerSidePropsContext) {
 | 
			
		||||
  const serversData = await fetch(`http://localhost:${process.env.SERVER_PORT}/api/mcserver/server/${String(server_id)}`, {headers: req.headers as any});
 | 
			
		||||
  return {
 | 
			
		||||
    props: {
 | 
			
		||||
      server_id: String(server_id),
 | 
			
		||||
      server: await serversData.json(),
 | 
			
		||||
      navbarprops: [{name: "Settings", path: `${server_id}/settings`}]
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
@@ -1,17 +0,0 @@
 | 
			
		||||
import { GetServerSidePropsContext, InferGetStaticPropsType } from "next";
 | 
			
		||||
 | 
			
		||||
export default function ServerConfig(props: InferGetStaticPropsType<typeof getServerSideProps>) {
 | 
			
		||||
  return <div>
 | 
			
		||||
    <pre>{JSON.stringify(props, null, 2)}</pre>
 | 
			
		||||
  </div>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function getServerSideProps({req, params: { server_id }}: GetServerSidePropsContext) {
 | 
			
		||||
  // const serversData = await fetch(`http://localhost:${process.env.SERVER_PORT}/api/mcserver/server/${String(server_id)}`, {headers: req.headers as any});
 | 
			
		||||
  return {
 | 
			
		||||
    props: {
 | 
			
		||||
      server_id: String(server_id),
 | 
			
		||||
      navbarprops: [{name: "Back", path: `./`}]
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
@@ -1,16 +0,0 @@
 | 
			
		||||
.ServersGrid {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-evenly;
 | 
			
		||||
  align-items: flex-start;
 | 
			
		||||
  justify-items: center;
 | 
			
		||||
  flex-wrap: wrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.serverModule {
 | 
			
		||||
  color: grey;
 | 
			
		||||
  background-color: #00000069;
 | 
			
		||||
  padding: 1.5%;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  border-radius: 36px;
 | 
			
		||||
  border-style: dotted;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,54 +0,0 @@
 | 
			
		||||
import { InferGetStaticPropsType } from "next";
 | 
			
		||||
import { useState } from "react";
 | 
			
		||||
import homeStyle from "./index.module.css";
 | 
			
		||||
 | 
			
		||||
export default function Dashboard(props: InferGetStaticPropsType<typeof getServerSideProps>) {
 | 
			
		||||
  const [ server, updateServer ] = useState(props.servers);
 | 
			
		||||
  const refresh = () => fetch("/api/mcserver").then(res => res.json().then(data => ({data, res}))).then(data => data.res.status < 300 ? updateServer(data.data) : data.res);
 | 
			
		||||
 | 
			
		||||
  return <div>
 | 
			
		||||
    <button style={{display: "none"}} id="refreshServers" onClick={refresh}>Refresh Servers</button>
 | 
			
		||||
    <div className={homeStyle["ServersGrid"]}>
 | 
			
		||||
      {server.map((value) => {
 | 
			
		||||
        return <div key={JSON.stringify(value)} className={homeStyle["serverModule"]} onClick={() => {
 | 
			
		||||
          const a = document.createElement("a");
 | 
			
		||||
          a.href = `/dashboard/${value.ID}`;
 | 
			
		||||
          a.click();
 | 
			
		||||
        }}>
 | 
			
		||||
          <div style={{textAlign: "center"}}>
 | 
			
		||||
            <a href={`/dashboard/${value.ID}`}>{value.name}</a>
 | 
			
		||||
          </div>
 | 
			
		||||
          <br />
 | 
			
		||||
          <div>Platform: {value.platform.slice(0, 1).toUpperCase()}{value.platform.slice(1)}</div>
 | 
			
		||||
          <div>Status: <span style={{color: value.running ? "green" : "red"}}>{value.running ? "Avaible" : "Stoped"}</span></div>
 | 
			
		||||
        </div>;
 | 
			
		||||
      })}
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Dashboard.navBar = [
 | 
			
		||||
  {
 | 
			
		||||
    name: "New server",
 | 
			
		||||
    path: "/dashboard/new"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    name: "Refresh",
 | 
			
		||||
    action: () => document.querySelector("#refreshServers")["click"](),
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
export async function getServerSideProps({req}) {
 | 
			
		||||
  const serversData = await fetch(`http://localhost:${process.env.SERVER_PORT}/api/mcserver`, {headers: req.headers as any});
 | 
			
		||||
  return {
 | 
			
		||||
    props: {
 | 
			
		||||
      servers: (await serversData.json()) as {
 | 
			
		||||
        ID: string,
 | 
			
		||||
        platform: "bedrock"|"java",
 | 
			
		||||
        name: string,
 | 
			
		||||
        running: boolean
 | 
			
		||||
      }[],
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
.install {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: row;
 | 
			
		||||
  justify-content: space-evenly;
 | 
			
		||||
  align-items: flex-start;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,120 +0,0 @@
 | 
			
		||||
import { FormEvent, useState } from "react";
 | 
			
		||||
import indexStyle from "./new.module.css";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export default function NewServer() {
 | 
			
		||||
  const [ currentPlatform, setPlatform ] = useState<"bedrock" | "java">("bedrock");
 | 
			
		||||
  const [ __lock__, setLock ] = useState<boolean>(false);
 | 
			
		||||
  const [ status, setStatus ] = useState<undefined|{ID: string}>();
 | 
			
		||||
  async function submit(form: FormEvent<HTMLFormElement>) {
 | 
			
		||||
    setLock(true);
 | 
			
		||||
    form.preventDefault();
 | 
			
		||||
    const platform: "bedrock" | "java" = form.currentTarget.querySelector("input[name=\"platform\"]:checked")["value"];
 | 
			
		||||
    const altserver: string = form.currentTarget.querySelector("select[name=\"altServer\"]")["value"];
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      const installStatus = await fetch("/api/mcserver", {
 | 
			
		||||
        method: "POST",
 | 
			
		||||
        headers: {
 | 
			
		||||
          "Content-Type": "application/json",
 | 
			
		||||
        },
 | 
			
		||||
        body: JSON.stringify({
 | 
			
		||||
          platform,
 | 
			
		||||
          altServer: altserver
 | 
			
		||||
        }),
 | 
			
		||||
      });
 | 
			
		||||
      if (installStatus.status < 300) setStatus(await installStatus.json());
 | 
			
		||||
      else {
 | 
			
		||||
        setLock(false);
 | 
			
		||||
        console.error(await installStatus.json());
 | 
			
		||||
      }
 | 
			
		||||
    } catch {}
 | 
			
		||||
  }
 | 
			
		||||
  return <div>
 | 
			
		||||
    <form onSubmit={submit} className={indexStyle.install}>
 | 
			
		||||
      <div>
 | 
			
		||||
        <span>Select platform:</span>
 | 
			
		||||
        <div>
 | 
			
		||||
          <div>
 | 
			
		||||
            <input type="radio" id="bedrockPlatform" name="platform" value="bedrock" defaultChecked onClick={() => setPlatform("bedrock")} />
 | 
			
		||||
            <label htmlFor="bedrockPlatform"> Bedrock</label>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div>
 | 
			
		||||
            <input type="radio" id="javaPlatform" name="platform" value="java" onClick={() => setPlatform("java")} />
 | 
			
		||||
            <label htmlFor="javaPlatform"> Java</label>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div>
 | 
			
		||||
        <span>Select server software</span>
 | 
			
		||||
        <br />
 | 
			
		||||
        <select disabled={__lock__} name="altServer">
 | 
			
		||||
          <option id="mojang" defaultChecked value="mojang">
 | 
			
		||||
            Mojang
 | 
			
		||||
          </option>
 | 
			
		||||
          { currentPlatform === "bedrock" ?
 | 
			
		||||
            <option id="pocketmine" value="pocketmine">
 | 
			
		||||
              Pocketmine PMMP
 | 
			
		||||
            </option> : null
 | 
			
		||||
          }
 | 
			
		||||
          { currentPlatform === "bedrock" ?
 | 
			
		||||
            <option id="cloudbust" value="cloudbust">
 | 
			
		||||
              Cloudbust
 | 
			
		||||
            </option> : null
 | 
			
		||||
          }
 | 
			
		||||
          { currentPlatform === "bedrock" ?
 | 
			
		||||
            <option id="nukkit" value="nukkit">
 | 
			
		||||
              Nukkit
 | 
			
		||||
            </option> : null
 | 
			
		||||
          }
 | 
			
		||||
          { currentPlatform === "bedrock" ?
 | 
			
		||||
            <option id="powernukkit" value="powernukkit">
 | 
			
		||||
              Powernukkit
 | 
			
		||||
            </option> : null
 | 
			
		||||
          }
 | 
			
		||||
          { currentPlatform === "java" ?
 | 
			
		||||
            <option id="spigot" value="spigot">
 | 
			
		||||
              Spigot MC
 | 
			
		||||
            </option> : null
 | 
			
		||||
          }
 | 
			
		||||
          { currentPlatform === "java" ?
 | 
			
		||||
            <option id="paper" value="paper">
 | 
			
		||||
              Paper MC
 | 
			
		||||
            </option> : null
 | 
			
		||||
          }
 | 
			
		||||
          { currentPlatform === "java" ?
 | 
			
		||||
            <option id="purpur" value="purpur">
 | 
			
		||||
              Purpur MC
 | 
			
		||||
            </option> : null
 | 
			
		||||
          }
 | 
			
		||||
          { currentPlatform === "java" ?
 | 
			
		||||
            <option id="glowstone" value="glowstone">
 | 
			
		||||
              Glowstone
 | 
			
		||||
            </option> : null
 | 
			
		||||
          }
 | 
			
		||||
          { currentPlatform === "java" ?
 | 
			
		||||
            <option id="folia" value="folia">
 | 
			
		||||
              folia
 | 
			
		||||
            </option> : null
 | 
			
		||||
          }
 | 
			
		||||
          { currentPlatform === "java" ?
 | 
			
		||||
            <option id="cuberite" value="cuberite">
 | 
			
		||||
              Cuberite
 | 
			
		||||
            </option> : null
 | 
			
		||||
          }
 | 
			
		||||
        </select>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div>
 | 
			
		||||
        <input disabled={__lock__} type="submit" value="Install" />
 | 
			
		||||
      </div>
 | 
			
		||||
    </form>
 | 
			
		||||
    <div style={{textAlign: "center"}}>
 | 
			
		||||
      { !status ? <div></div> : <div>
 | 
			
		||||
        <span>{status.ID}</span>
 | 
			
		||||
        <br />
 | 
			
		||||
        <a href={`/dashboard/${status.ID}`}>Open painel</a>
 | 
			
		||||
      </div> }
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,37 +0,0 @@
 | 
			
		||||
import { FormEvent } from "react";
 | 
			
		||||
 | 
			
		||||
async function onLogin(elemnt: FormEvent<HTMLFormElement>) {
 | 
			
		||||
  elemnt.preventDefault();
 | 
			
		||||
  const inputs = Array.from(elemnt.currentTarget.querySelectorAll("input"));
 | 
			
		||||
  const username = inputs.find(e => e.name === "username").value;
 | 
			
		||||
  const password = inputs.find(e => e.type === "password").value;
 | 
			
		||||
 | 
			
		||||
  const onCreate = await fetch("/api/login", {
 | 
			
		||||
    method: "POST",
 | 
			
		||||
    headers: {
 | 
			
		||||
      "Content-Type": "application/json"
 | 
			
		||||
    },
 | 
			
		||||
    body: JSON.stringify({
 | 
			
		||||
      username,
 | 
			
		||||
      password
 | 
			
		||||
    })
 | 
			
		||||
  });
 | 
			
		||||
  if (onCreate.status === 200) return location.href = "/";
 | 
			
		||||
  return elemnt.currentTarget.querySelector("errorsMessage").textContent = (await onCreate.json()).error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function LoginPage() {
 | 
			
		||||
  return <>
 | 
			
		||||
    <form onSubmit={onLogin}>
 | 
			
		||||
      <div>
 | 
			
		||||
        <label>Username/Email: </label>
 | 
			
		||||
        <input type="text" name="username" />
 | 
			
		||||
      </div>
 | 
			
		||||
      <div>
 | 
			
		||||
        <label>Password: </label>
 | 
			
		||||
        <input type="password" name="password" />
 | 
			
		||||
      </div>
 | 
			
		||||
      <input type="submit" value="Login" />
 | 
			
		||||
    </form>
 | 
			
		||||
  </>;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,44 +0,0 @@
 | 
			
		||||
import { FormEvent } from "react";
 | 
			
		||||
 | 
			
		||||
async function create(elemnt: FormEvent<HTMLFormElement>) {
 | 
			
		||||
  elemnt.preventDefault();
 | 
			
		||||
  const inputs = Array.from(elemnt.currentTarget.querySelectorAll("input"));
 | 
			
		||||
  const username = inputs.find(e => e.name === "username").value;
 | 
			
		||||
  const email = inputs.find(e => e.name === "email").value;
 | 
			
		||||
  const password = inputs.find(e => e.type === "password").value;
 | 
			
		||||
 | 
			
		||||
  const onCreate = await fetch("/api/register", {
 | 
			
		||||
    method: "POST",
 | 
			
		||||
    headers: {
 | 
			
		||||
      "Content-Type": "application/json"
 | 
			
		||||
    },
 | 
			
		||||
    body: JSON.stringify({
 | 
			
		||||
      username,
 | 
			
		||||
      email,
 | 
			
		||||
      password
 | 
			
		||||
    })
 | 
			
		||||
  });
 | 
			
		||||
  if (onCreate.status === 201) return; location.href = "/login";
 | 
			
		||||
  elemnt.currentTarget.querySelector("errorsMessage").textContent = (await onCreate.json()).error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function RegisterPage() {
 | 
			
		||||
  return <>
 | 
			
		||||
    <div id="errorsMessage"></div>
 | 
			
		||||
    <form onSubmit={create}>
 | 
			
		||||
      <div>
 | 
			
		||||
        <label>Username:</label>
 | 
			
		||||
        <input type="text" name="username" />
 | 
			
		||||
      </div>
 | 
			
		||||
      <div>
 | 
			
		||||
        <label>Email:</label>
 | 
			
		||||
        <input type="email" name="email" />
 | 
			
		||||
      </div>
 | 
			
		||||
      <div>
 | 
			
		||||
        <label>Password:</label>
 | 
			
		||||
        <input type="password" name="password" />
 | 
			
		||||
      </div>
 | 
			
		||||
      <input type="submit" value="Create" />
 | 
			
		||||
    </form>
 | 
			
		||||
  </>;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user