Code

/**
 * mcp/skills/resetLocalPassword.ts — reset_local_password skill
 *
 * Resets the local macOS/Windows account password. IMPORTANT: requires admin
 * privileges. Always confirm with the user before executing. Use only for
 * local accounts — not for Active Directory accounts.
 *
 * Platform strategy
 * -----------------
 * darwin  `dscl . -passwd /Users/{username} {newPassword}` (only if not dryRun)
 * win32   PowerShell Set-LocalUser -Name {username} -Password (ConvertTo-SecureString ...)
 *
 * Smoke test
 *   npx tsx -r dotenv/config mcp/skills/resetLocalPassword.ts
 */
 
import * as os       from "os";
import { exec }      from "child_process";
import { promisify } from "util";
import { z }         from "zod";
 
const execAsync = promisify(exec);
 
// -- Meta ---------------------------------------------------------------------
 
export const meta = {
  name: "reset_local_password",
  description:
    "Resets the local macOS/Windows account password. " +
    "IMPORTANT: requires admin privileges. Always confirm with the user before executing. " +
    "Use only for local accounts — not for Active Directory accounts.",
  riskLevel:       "critical",
  destructive:     true,
  requiresConsent: true,
  supportsDryRun:  true,
  affectedScope:   ["system"],
  auditRequired:   true,
  escalationHint:  {
    darwin: "sudo dscl . -passwd /Users/<username> '<newPassword>'  # substitute the user's real username and a strong temporary password; user should change at next login",
    win32:  "Set-LocalUser -Name '<username>' -Password (ConvertTo-SecureString '<newPassword>' -AsPlainText -Force)  # run from elevated PowerShell",
  },
  schema: {
    username: z
      .string()
      .describe("Username whose password to reset"),
    newPassword: z
      .string()
      .describe("New password to set"),
    dryRun: z
      .boolean()
      .optional()
      .describe("If true, validate inputs without changing password. Default: true"),
  },
} as const;
 
// -- Types --------------------------------------------------------------------
 
interface ResetResult {
  username: string;
  success:  boolean;
  dryRun:   boolean;
  message:  string;
}
 
// -- PowerShell helper --------------------------------------------------------
 
async function runPS(script: string): Promise<string> {
  const encoded = Buffer.from(script, "utf16le").toString("base64");
  const { stdout } = await execAsync(
    `powershell.exe -NoProfile -NonInteractive -EncodedCommand ${encoded}`,
    { maxBuffer: 10 * 1024 * 1024 },
  );
  return stdout.trim();
}
 
// -- darwin implementation ----------------------------------------------------
 
async function resetLocalPasswordDarwin(
  username:    string,
  newPassword: string,
  dryRun:      boolean,
): Promise<ResetResult> {
  // Validate that the user exists
  const safeName = username.replace(/'/g, `'\\''`);
  try {
    await execAsync(
      `dscl . -read /Users/'${safeName}' UniqueID 2>/dev/null`,
      { maxBuffer: 1 * 1024 * 1024, shell: "/bin/bash" },
    );
  } catch {
    return {
      username,
      success: false,
      dryRun,
      message: `User '${username}' not found in local directory.`,
    };
  }
 
  // Validate password is non-empty
  if (!newPassword || newPassword.length === 0) {
    return {
      username,
      success: false,
      dryRun,
      message: "New password must not be empty.",
    };
  }
 
  if (dryRun) {
    return {
      username,
      success: true,
      dryRun:  true,
      message: `Dry run: user '${username}' exists. Password would be reset. Run with dryRun=false to apply.`,
    };
  }
 
  // Perform actual password reset — password masked in all log output
  try {
    // Use dscl . -passwd with newline to avoid password appearing in process list
    const safePassword = newPassword.replace(/'/g, `'\\''`);
    await execAsync(
      `dscl . -passwd /Users/'${safeName}' '${safePassword}'`,
      { maxBuffer: 1 * 1024 * 1024, shell: "/bin/bash" },
    );
    return {
      username,
      success: true,
      dryRun:  false,
      message: `Password for '${username}' has been reset successfully.`,
    };
  } catch (err) {
    const msg = (err as Error).message ?? "Unknown error";
    // Do not include the password in the error message
    return {
      username,
      success: false,
      dryRun:  false,
      message: `Failed to reset password for '${username}': ${msg.replace(/password/gi, "[password]")}`,
    };
  }
}
 
// -- win32 implementation -----------------------------------------------------
 
async function resetLocalPasswordWin32(
  username:    string,
  newPassword: string,
  dryRun:      boolean,
): Promise<ResetResult> {
  // Validate user exists
  const ps_check = `
$ErrorActionPreference = 'Stop'
try {
  $u = Get-LocalUser -Name '${username.replace(/'/g, "''")}' -ErrorAction Stop
  Write-Output "EXISTS:$($u.Name)"
} catch {
  Write-Output "NOTFOUND"
}`.trim();
 
  let checkResult = "";
  try {
    checkResult = await runPS(ps_check);
  } catch {
    return { username, success: false, dryRun, message: `Could not verify user '${username}'.` };
  }
 
  if (checkResult.includes("NOTFOUND")) {
    return { username, success: false, dryRun, message: `User '${username}' not found.` };
  }
 
  if (!newPassword || newPassword.length === 0) {
    return { username, success: false, dryRun, message: "New password must not be empty." };
  }
 
  if (dryRun) {
    return {
      username,
      success: true,
      dryRun:  true,
      message: `Dry run: user '${username}' exists. Password would be reset. Run with dryRun=false to apply.`,
    };
  }
 
  // Perform reset — password masked in output
  const safeUser = username.replace(/'/g, "''");
  const safePw   = newPassword.replace(/'/g, "''");
  const ps_reset = `
$ErrorActionPreference = 'Stop'
$secPw = ConvertTo-SecureString -String '${safePw}' -AsPlainText -Force
Set-LocalUser -Name '${safeUser}' -Password $secPw
Write-Output "OK"`.trim();
 
  try {
    const result = await runPS(ps_reset);
    if (result.includes("OK")) {
      return { username, success: true, dryRun: false, message: `Password for '${username}' has been reset successfully.` };
    }
    return { username, success: false, dryRun: false, message: "Password reset command did not confirm success." };
  } catch (err) {
    const msg = (err as Error).message ?? "Unknown error";
    return {
      username,
      success: false,
      dryRun:  false,
      message: `Failed to reset password for '${username}': ${msg.replace(/password/gi, "[password]")}`,
    };
  }
}
 
// -- Exported run function ----------------------------------------------------
 
export async function run({
  username,
  newPassword,
  dryRun = true,
}: {
  username:    string;
  newPassword: string;
  dryRun?:     boolean;
}) {
  if (!username) throw new Error("[reset_local_password] username is required");
  if (!newPassword) throw new Error("[reset_local_password] newPassword is required");
 
  const platform = os.platform();
 
  const result = platform === "win32"
    ? await resetLocalPasswordWin32(username, newPassword, dryRun)
    : await resetLocalPasswordDarwin(username, newPassword, dryRun);
 
  return { platform, ...result };
}
 
// -- CLI smoke test -----------------------------------------------------------
 
if (false) {
  run({ username: "testuser", newPassword: "TestPass123!", dryRun: true })
    .then(r => console.log(JSON.stringify(r, null, 2)))
    .catch((err: Error) => { console.error(err.message); process.exit(1); });
}