Updates
This commit is contained in:
@@ -1,20 +1,14 @@
|
||||
import { AppContext } from "@/src/pages/_app";
|
||||
import { TurboCISignupFormObject } from "@/src/types";
|
||||
import useStatus from "@/twui/components/hooks/useStatus";
|
||||
import { useContext, useState } from "react";
|
||||
|
||||
export type SettingsFormData = {
|
||||
first_name?: string;
|
||||
last_name?: string;
|
||||
email?: string;
|
||||
image?: string;
|
||||
};
|
||||
|
||||
export default function useSettingsForm() {
|
||||
const { pageProps } = useContext(AppContext);
|
||||
const { user } = pageProps;
|
||||
const { loading, setLoading } = useStatus();
|
||||
|
||||
const [formData, setFormData] = useState<SettingsFormData>({
|
||||
const [formData, setFormData] = useState<TurboCISignupFormObject>({
|
||||
first_name: user?.first_name || "",
|
||||
last_name: user?.last_name || "",
|
||||
email: user?.email || "",
|
||||
|
||||
@@ -10,6 +10,7 @@ import Stack from "@/twui/components/layout/Stack";
|
||||
import { APIResponseObject } from "@moduletrace/datasquirel/dist/package-shared/types";
|
||||
import { useContext } from "react";
|
||||
import useSettingsForm from "../(hooks)/use-settings-form";
|
||||
import { APIReqObject } from "@/src/types";
|
||||
|
||||
export default function SettingsForm() {
|
||||
const { setToast } = useContext(AppContext);
|
||||
@@ -22,9 +23,14 @@ export default function SettingsForm() {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const res = await fetchApi<typeof formData, APIResponseObject>(
|
||||
const res = await fetchApi<APIReqObject, APIResponseObject>(
|
||||
`/api/admin/settings`,
|
||||
{ method: "POST", body: formData },
|
||||
{
|
||||
method: "POST",
|
||||
body: {
|
||||
new_user: formData,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (res.success) {
|
||||
@@ -55,7 +61,9 @@ export default function SettingsForm() {
|
||||
Username
|
||||
</Span>
|
||||
<Span>
|
||||
<strong>{user?.username || "—"}</strong>
|
||||
<strong>
|
||||
{user.super_admin ? "root" : user?.username || "—"}
|
||||
</strong>
|
||||
</Span>
|
||||
</Stack>
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ export default function SignupForm({ new_deployment_user }: Props) {
|
||||
}}
|
||||
loading={loading}
|
||||
>
|
||||
Signup
|
||||
{pageProps.user.super_admin ? "Add User" : "Signup"}
|
||||
</Button>
|
||||
</Stack>
|
||||
</form>
|
||||
|
||||
+13
-1
@@ -1,5 +1,17 @@
|
||||
import { AppData } from "@/src/data/app-data";
|
||||
import cronCheckServices from "./functions/check-services";
|
||||
import { watchFile } from "fs";
|
||||
import path from "path";
|
||||
import { execSync } from "child_process";
|
||||
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
watchFile(path.resolve(__dirname, "../db/db-schema.js"), (curr, prev) => {
|
||||
execSync(`bunx nsqlite schema -t`, {
|
||||
cwd: path.resolve(__dirname, "../.."),
|
||||
stdio: "inherit",
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
while (true) {
|
||||
console.log(`Running Cron Services ...`);
|
||||
@@ -11,4 +23,4 @@ while (true) {
|
||||
await Bun.sleep(AppData["CronInterval"]);
|
||||
}
|
||||
|
||||
export {};
|
||||
// export {};
|
||||
|
||||
@@ -58,6 +58,19 @@ const schema = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
tableName: "users_allowed_services",
|
||||
fields: [
|
||||
{
|
||||
fieldName: "user_id",
|
||||
dataType: "INTEGER",
|
||||
},
|
||||
{
|
||||
fieldName: "service_name",
|
||||
dataType: "TEXT",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
+19
-1
@@ -1,6 +1,7 @@
|
||||
export const NSQLiteTables = [
|
||||
"users",
|
||||
"users_ports",
|
||||
"users_allowed_services",
|
||||
] as const
|
||||
|
||||
export type NSQLITE_TURBOCI_ADMIN_USERS = {
|
||||
@@ -43,4 +44,21 @@ export type NSQLITE_TURBOCI_ADMIN_USERS_PORTS = {
|
||||
port?: number;
|
||||
}
|
||||
|
||||
export type NSQLITE_TURBOCI_ADMIN_ALL_TYPEDEFS = NSQLITE_TURBOCI_ADMIN_USERS & NSQLITE_TURBOCI_ADMIN_USERS_PORTS
|
||||
export type NSQLITE_TURBOCI_ADMIN_USERS_ALLOWED_SERVICES = {
|
||||
/**
|
||||
* The unique identifier of the record.
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* The time when the record was created. (Unix Timestamp)
|
||||
*/
|
||||
created_at?: number;
|
||||
/**
|
||||
* The time when the record was updated. (Unix Timestamp)
|
||||
*/
|
||||
updated_at?: number;
|
||||
user_id?: number;
|
||||
service_name?: string;
|
||||
}
|
||||
|
||||
export type NSQLITE_TURBOCI_ADMIN_ALL_TYPEDEFS = NSQLITE_TURBOCI_ADMIN_USERS & NSQLITE_TURBOCI_ADMIN_USERS_PORTS & NSQLITE_TURBOCI_ADMIN_USERS_ALLOWED_SERVICES
|
||||
@@ -103,7 +103,7 @@ export default async function loginUser({
|
||||
logged_in_status: true,
|
||||
image: fetched_user.image,
|
||||
image_thumbnail: fetched_user.image,
|
||||
super_admin: fetched_user.is_super_admin ? 1 : 0,
|
||||
super_admin: fetched_user.is_super_admin ? true : false,
|
||||
};
|
||||
|
||||
const payload_string = EJSON.stringify(logged_in_user_payload);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { NSQLITE_TURBOCI_ADMIN_USERS, NSQLiteTables } from "@/src/db/types";
|
||||
import { _n } from "@/src/exports/client-exports";
|
||||
import grabDeploymentUserDirNames from "@/src/utils/grab-deployment-user-dir-names";
|
||||
import NSQLite from "@moduletrace/nsqlite";
|
||||
import { execSync } from "child_process";
|
||||
import { existsSync } from "fs";
|
||||
|
||||
type Params = {
|
||||
@@ -24,15 +26,17 @@ export default async function setupDeploymentUser({ user_id }: Params) {
|
||||
|
||||
const { username } = target_user;
|
||||
|
||||
const user_dir = `/home/${username}`;
|
||||
const ssh_dir = `${user_dir}/.ssh`;
|
||||
const ssh_key_file = `${ssh_dir}/${username}`;
|
||||
const sshd_config_file = `/etc/ssh/sshd_config.d/${username}`;
|
||||
const force_command_file = `/usr/local/bin/turboci-deployment-user-${username}`;
|
||||
const {
|
||||
force_command_file,
|
||||
ssh_dir,
|
||||
ssh_key_file,
|
||||
sshd_config_file,
|
||||
user_dir,
|
||||
} = grabDeploymentUserDirNames({ user: target_user });
|
||||
|
||||
let cmd = `/bin/bash << 'TURBOCIHEREDOC'\n`;
|
||||
|
||||
if (!existsSync(user_dir)) {
|
||||
let cmd = ``;
|
||||
|
||||
cmd += `useradd --create-home --shell /bin/bash --comment "TurboCI Deployment user ${username}" ${username}\n`;
|
||||
cmd += `passwd --lock "${username}"\n`;
|
||||
cmd += `mkdir -p "${ssh_dir}"\n`;
|
||||
@@ -44,26 +48,35 @@ export default async function setupDeploymentUser({ user_id }: Params) {
|
||||
cmd += `chmod 600 "${ssh_key_file}"\n`;
|
||||
cmd += `chmod 644 "${ssh_key_file}.pub"\n`;
|
||||
cmd += `chmod 600 "${ssh_dir}/authorized_keys"\n`;
|
||||
|
||||
cmd += `cat << 'EOF' > ${force_command_file}\n`;
|
||||
cmd += `#!/bin/bash\n`;
|
||||
cmd += `EOF\n`;
|
||||
|
||||
cmd += `cat << 'EOF' > ${sshd_config_file}\n`;
|
||||
cmd += `Match User ${username}\n`;
|
||||
cmd += ` # Authentication\n`;
|
||||
cmd += ` PasswordAuthentication no\n`;
|
||||
cmd += ` PubkeyAuthentication yes\n`;
|
||||
cmd += ` AuthenticationMethods publickey\n\n`;
|
||||
|
||||
cmd += ` # Restrict shell / tunneling\n`;
|
||||
cmd += ` AllowTcpForwarding yes\n`;
|
||||
cmd += ` X11Forwarding no\n\n`;
|
||||
|
||||
cmd += ` # Restrict Commands\n`;
|
||||
cmd += ` ForceCommand ${force_command_file}\n`;
|
||||
cmd += `EOF\n`;
|
||||
}
|
||||
|
||||
cmd += `cat << 'EOF' > ${force_command_file}\n`;
|
||||
cmd += `#!/bin/bash\n`;
|
||||
cmd += `case "$SSH_ORIGINAL_COMMAND" in\n`;
|
||||
cmd += ` "shell")\n`;
|
||||
cmd += ` exec /bin/bash\n`;
|
||||
cmd += ` ;;\n`;
|
||||
cmd += ` *)\n`;
|
||||
cmd += ` echo "Access denied."\n`;
|
||||
cmd += ` exit 1\n`;
|
||||
cmd += ` ;;\n`;
|
||||
cmd += `esac\n`;
|
||||
cmd += `EOF\n\n`;
|
||||
|
||||
cmd += `chmod +x ${force_command_file}\n\n`;
|
||||
|
||||
cmd += `cat << 'EOF' > ${sshd_config_file}\n`;
|
||||
cmd += `Match User ${username}\n`;
|
||||
cmd += ` PasswordAuthentication no\n`;
|
||||
cmd += ` PubkeyAuthentication yes\n`;
|
||||
cmd += ` AuthenticationMethods publickey\n\n`;
|
||||
cmd += ` AllowTcpForwarding yes\n`;
|
||||
cmd += ` X11Forwarding no\n\n`;
|
||||
cmd += ` ForceCommand ${force_command_file}\n`;
|
||||
cmd += `EOF\n`;
|
||||
cmd += `TURBOCIHEREDOC\n`;
|
||||
|
||||
execSync(cmd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4,13 +4,7 @@ import userAuth from "@/src/utils/user-auth";
|
||||
import NSQLite from "@moduletrace/nsqlite";
|
||||
import { APIResponseObject } from "@moduletrace/datasquirel/dist/package-shared/types";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
type ReqBody = {
|
||||
first_name?: string;
|
||||
last_name?: string;
|
||||
email?: string;
|
||||
image?: string;
|
||||
};
|
||||
import { APIReqObject } from "@/src/types";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
@@ -33,7 +27,13 @@ export default async function handler(
|
||||
});
|
||||
}
|
||||
|
||||
const { first_name, last_name, email, image } = req.body as ReqBody;
|
||||
const { new_user } = req.body as APIReqObject;
|
||||
|
||||
if (!new_user) {
|
||||
throw new Error(`No User Form Sent.`);
|
||||
}
|
||||
|
||||
const { first_name, last_name, email, image } = new_user;
|
||||
|
||||
if (!first_name?.match(/./)) {
|
||||
return res.json({ success: false, msg: "First name is required" });
|
||||
|
||||
@@ -7,6 +7,7 @@ import NSQLite from "@moduletrace/nsqlite";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import userAuth from "@/src/utils/user-auth";
|
||||
import { slugify } from "@/src/exports/client-exports";
|
||||
import setupDeploymentUser from "@/src/functions/deployment-users/setup-deployment-user";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
@@ -103,6 +104,8 @@ export default async function handler(
|
||||
}
|
||||
|
||||
if (user?.id) {
|
||||
await setupDeploymentUser({ user_id: newly_inserted_user.id });
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
singleRes: newly_inserted_user,
|
||||
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
export NODE_ENV=production
|
||||
|
||||
bun next build
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
export NODE_ENV=production
|
||||
|
||||
pm2 kill
|
||||
|
||||
pm2 start --name turboci-web 'bunx next start -p 3772'
|
||||
|
||||
+2
-1
@@ -6,7 +6,7 @@ import { ChildProcess } from "child_process";
|
||||
import { NSQLITE_TURBOCI_ADMIN_USERS } from "../db/types";
|
||||
|
||||
export type User = DATASQUIREL_LoggedInUser & {
|
||||
super_admin?: 0 | 1;
|
||||
super_admin?: boolean;
|
||||
};
|
||||
|
||||
export const CloudProviders = [
|
||||
@@ -231,6 +231,7 @@ export type TurboCISignupFormObject = {
|
||||
password?: string;
|
||||
confirmed_password?: string;
|
||||
username?: string;
|
||||
image?: string;
|
||||
};
|
||||
|
||||
export type TurboCIAdminAppContextType = ReturnType<typeof useAppInit>;
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { NSQLITE_TURBOCI_ADMIN_USERS } from "../db/types";
|
||||
import { User } from "../types";
|
||||
|
||||
type Params = {
|
||||
user: NSQLITE_TURBOCI_ADMIN_USERS;
|
||||
};
|
||||
|
||||
export default function grabDeploymentUserDirNames({ user }: Params) {
|
||||
const { username } = user;
|
||||
|
||||
const user_dir = `/home/${username}`;
|
||||
const ssh_dir = `${user_dir}/.ssh`;
|
||||
const ssh_key_file = `${ssh_dir}/${username}`;
|
||||
const sshd_config_file = `/etc/ssh/sshd_config.d/${username}`;
|
||||
const force_command_file = `/usr/local/bin/turboci-deployment-user-${username}`;
|
||||
|
||||
return {
|
||||
user_dir,
|
||||
ssh_dir,
|
||||
ssh_key_file,
|
||||
sshd_config_file,
|
||||
force_command_file,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user