/**
* Centralized validation utilities
* Consolidates duplicated validation logic from across the codebase
*/
import { SSHArgSecurityError, SYSTEMD_SERVICE_NAME_PATTERN } from "./path-security.js";
import { validateSSHArg } from "./path-security.js";
/**
* Validates alphanumeric string (letters, numbers, dots, dashes, underscores)
*
* @param value - Value to validate
* @param name - Parameter name for error messages
* @param options - Optional flags for allowing slashes and tildes
* @throws Error if value contains invalid characters
*/
export function validateAlphanumeric(
value: string,
name: string,
options: { allowSlash?: boolean; allowTilde?: boolean } = {}
): void {
if (!value || value.length === 0) {
throw new Error(`${name} cannot be empty`);
}
const { allowSlash = false, allowTilde = false } = options;
let pattern: RegExp;
if (allowSlash && allowTilde) {
pattern = /^[a-zA-Z0-9._\-/~]+$/;
} else if (allowSlash) {
pattern = /^[a-zA-Z0-9._\-/]+$/;
} else if (allowTilde) {
pattern = /^[a-zA-Z0-9._\-~]+$/;
} else {
pattern = /^[a-zA-Z0-9._-]+$/;
}
if (!pattern.test(value)) {
const allowed = ["letters", "numbers", "dots", "dashes", "underscores"];
if (allowSlash) allowed.push("forward slashes");
if (allowTilde) allowed.push("tilde");
throw new Error(`${name}: Invalid characters (allowed: ${allowed.join(", ")})`);
}
}
/**
* Validates systemd service name format
* Consolidates validation from 4 locations
*
* @param service - Service name to validate
* @throws SSHArgSecurityError if service name is invalid
*/
export function validateServiceName(service: string): void {
// First check for shell metacharacters (from validateSSHArg)
validateSSHArg(service, "service");
// Then check systemd naming rules
if (!SYSTEMD_SERVICE_NAME_PATTERN.test(service)) {
throw new SSHArgSecurityError(
"Invalid service name: only letters, numbers, @, ., _, and - are allowed",
service.substring(0, 50),
"service"
);
}
}