mirror of
https://github.com/fccview/cronmaster.git
synced 2025-12-26 15:37:54 -05:00
177 lines
4.5 KiB
TypeScript
177 lines
4.5 KiB
TypeScript
import {
|
|
GET_DOCKER_SOCKET_OWNER,
|
|
GET_TARGET_USER,
|
|
ID_G,
|
|
ID_U,
|
|
READ_CRONTAB,
|
|
READ_CRONTABS_DIRECTORY,
|
|
WRITE_HOST_CRONTAB,
|
|
} from "@/app/_consts/commands";
|
|
import { NSENTER_HOST_CRONTAB } from "@/app/_consts/nsenter";
|
|
import { exec } from "child_process";
|
|
import { promisify } from "util";
|
|
|
|
const execAsync = promisify(exec);
|
|
|
|
export interface UserInfo {
|
|
username: string;
|
|
uid: number;
|
|
gid: number;
|
|
}
|
|
|
|
const execHostCrontab = async (command: string): Promise<string> => {
|
|
try {
|
|
const { stdout } = await execAsync(NSENTER_HOST_CRONTAB(command?.trim()));
|
|
return stdout;
|
|
} catch (error: any) {
|
|
console.error("Error executing host crontab command:", error);
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
const getTargetUser = async (): Promise<string> => {
|
|
try {
|
|
if (process.env.HOST_CRONTAB_USER) {
|
|
return process.env.HOST_CRONTAB_USER;
|
|
}
|
|
|
|
const { stdout } = await execAsync(GET_DOCKER_SOCKET_OWNER);
|
|
const dockerSocketOwner = stdout.trim();
|
|
|
|
if (dockerSocketOwner === "root") {
|
|
try {
|
|
const targetUser = await execHostCrontab(GET_TARGET_USER);
|
|
if (targetUser) {
|
|
return targetUser.trim();
|
|
}
|
|
} catch (error) {
|
|
console.warn("Could not detect user from passwd:", error);
|
|
}
|
|
|
|
return "root";
|
|
}
|
|
|
|
return dockerSocketOwner;
|
|
} catch (error) {
|
|
console.error("Error detecting target user:", error);
|
|
return "root";
|
|
}
|
|
};
|
|
|
|
export const getAllTargetUsers = async (): Promise<string[]> => {
|
|
try {
|
|
if (process.env.HOST_CRONTAB_USER) {
|
|
return process.env.HOST_CRONTAB_USER.split(",").map((u) => u.trim());
|
|
}
|
|
|
|
try {
|
|
const stdout = await execHostCrontab(READ_CRONTABS_DIRECTORY);
|
|
|
|
const users = stdout
|
|
.trim()
|
|
.split("\n")
|
|
.filter((user) => user.trim());
|
|
|
|
return users.length > 0 ? users : ["root"];
|
|
} catch (error) {
|
|
console.error("Error detecting users from crontabs directory:", error);
|
|
return ["root"];
|
|
}
|
|
} catch (error) {
|
|
console.error("Error getting all target users:", error);
|
|
return ["root"];
|
|
}
|
|
};
|
|
|
|
export const readHostCrontab = async (): Promise<string> => {
|
|
try {
|
|
const user = await getTargetUser();
|
|
return await execHostCrontab(READ_CRONTAB(user));
|
|
} catch (error) {
|
|
console.error("Error reading host crontab:", error);
|
|
return "";
|
|
}
|
|
};
|
|
|
|
export const readAllHostCrontabs = async (): Promise<
|
|
{ user: string; content: string }[]
|
|
> => {
|
|
try {
|
|
const users = await getAllTargetUsers();
|
|
const results: { user: string; content: string }[] = [];
|
|
|
|
for (const user of users) {
|
|
try {
|
|
const content = await execHostCrontab(READ_CRONTAB(user));
|
|
results.push({ user, content });
|
|
} catch (error) {
|
|
console.warn(`Error reading crontab for user ${user}:`, error);
|
|
results.push({ user, content: "" });
|
|
}
|
|
}
|
|
|
|
return results;
|
|
} catch (error) {
|
|
console.error("Error reading all host crontabs:", error);
|
|
return [];
|
|
}
|
|
};
|
|
|
|
export const writeHostCrontab = async (content: string): Promise<boolean> => {
|
|
try {
|
|
const user = await getTargetUser();
|
|
let finalContent = content;
|
|
if (!finalContent.endsWith("\n")) {
|
|
finalContent += "\n";
|
|
}
|
|
|
|
const base64Content = Buffer.from(finalContent).toString("base64");
|
|
await execHostCrontab(WRITE_HOST_CRONTAB(base64Content, user));
|
|
return true;
|
|
} catch (error) {
|
|
console.error("Error writing host crontab:", error);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
export const writeHostCrontabForUser = async (
|
|
user: string,
|
|
content: string
|
|
): Promise<boolean> => {
|
|
try {
|
|
let finalContent = content;
|
|
if (!finalContent.endsWith("\n")) {
|
|
finalContent += "\n";
|
|
}
|
|
|
|
const base64Content = Buffer.from(finalContent).toString("base64");
|
|
await execHostCrontab(WRITE_HOST_CRONTAB(base64Content, user));
|
|
return true;
|
|
} catch (error) {
|
|
console.error(`Error writing host crontab for user ${user}:`, error);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
export const getUserInfo = async (
|
|
username: string
|
|
): Promise<UserInfo | null> => {
|
|
try {
|
|
const uidResult = await execHostCrontab(ID_U(username));
|
|
const gidResult = await execHostCrontab(ID_G(username));
|
|
|
|
const uid = parseInt(uidResult.trim());
|
|
const gid = parseInt(gidResult.trim());
|
|
|
|
if (isNaN(uid) || isNaN(gid)) {
|
|
console.error(`Invalid UID/GID for user ${username}`);
|
|
return null;
|
|
}
|
|
|
|
return { username, uid, gid };
|
|
} catch (error) {
|
|
console.error(`Error getting user info for ${username}:`, error);
|
|
return null;
|
|
}
|
|
};
|