mirror of
https://github.com/Routstr/routstrd.git
synced 2026-10-05 20:38:22 +00:00
fix(wallet): protect mnemonic file permissions
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import { afterEach, describe, expect, test } from "bun:test";
|
||||
import { mkdtempSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from "fs";
|
||||
import { tmpdir } from "os";
|
||||
import { join } from "path";
|
||||
import { initializeWallet } from "./cli";
|
||||
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
function makeTempDir(): string {
|
||||
const dir = mkdtempSync(join(tmpdir(), "routstrd-wallet-test-"));
|
||||
tempDirs.push(dir);
|
||||
return dir;
|
||||
}
|
||||
|
||||
function permissions(path: string): number {
|
||||
return statSync(path).mode & 0o777;
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
for (const dir of tempDirs.splice(0)) {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
describe("initializeWallet", () => {
|
||||
test("creates the wallet directory and config with restrictive permissions", () => {
|
||||
const walletDir = join(makeTempDir(), ".cocod");
|
||||
|
||||
initializeWallet(walletDir);
|
||||
|
||||
const walletConfig = join(walletDir, "config.json");
|
||||
expect(permissions(walletDir)).toBe(0o700);
|
||||
expect(permissions(walletConfig)).toBe(0o600);
|
||||
|
||||
const config = JSON.parse(readFileSync(walletConfig, "utf8"));
|
||||
expect(config.encrypted).toBe(false);
|
||||
expect(typeof config.mnemonic).toBe("string");
|
||||
expect(config.mnemonic.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test("repairs permissions without replacing an existing wallet", () => {
|
||||
const walletDir = join(makeTempDir(), ".cocod");
|
||||
const walletConfig = join(walletDir, "config.json");
|
||||
const existingConfig = JSON.stringify({ mnemonic: "existing seed" });
|
||||
|
||||
mkdirSync(walletDir, { mode: 0o755 });
|
||||
writeFileSync(walletConfig, existingConfig, { mode: 0o644 });
|
||||
|
||||
initializeWallet(walletDir);
|
||||
|
||||
expect(readFileSync(walletConfig, "utf8")).toBe(existingConfig);
|
||||
expect(permissions(walletDir)).toBe(0o700);
|
||||
expect(permissions(walletConfig)).toBe(0o600);
|
||||
});
|
||||
});
|
||||
+17
-6
@@ -15,7 +15,7 @@ import {
|
||||
deleteClientAction,
|
||||
addClientAction,
|
||||
} from "./utils/clients";
|
||||
import { existsSync, mkdirSync, writeFileSync } from "fs";
|
||||
import { chmodSync, existsSync, mkdirSync, writeFileSync } from "fs";
|
||||
import { execSync } from "child_process";
|
||||
import {
|
||||
CONFIG_DIR,
|
||||
@@ -79,16 +79,24 @@ async function printLightningInvoice(invoice: string): Promise<void> {
|
||||
console.log(`${qr}\nInvoice:\n${invoice}`);
|
||||
}
|
||||
|
||||
function initializeWallet(): void {
|
||||
const walletDir =
|
||||
export function initializeWallet(
|
||||
walletDir =
|
||||
process.env.COCOD_DIR ||
|
||||
`${process.env.HOME || process.env.USERPROFILE || ""}/.cocod`;
|
||||
`${process.env.HOME || process.env.USERPROFILE || ""}/.cocod`,
|
||||
): void {
|
||||
const walletConfig = `${walletDir}/config.json`;
|
||||
|
||||
// The wallet directory and config contain the plaintext seed phrase. Correct
|
||||
// permissions on existing installations as well as newly created ones.
|
||||
mkdirSync(walletDir, { recursive: true, mode: 0o700 });
|
||||
chmodSync(walletDir, 0o700);
|
||||
|
||||
if (existsSync(walletConfig)) {
|
||||
chmodSync(walletConfig, 0o600);
|
||||
console.log("Wallet already initialized.");
|
||||
return;
|
||||
}
|
||||
mkdirSync(walletDir, { recursive: true });
|
||||
|
||||
const mnemonic = generateMnemonic(wordlist);
|
||||
const config = {
|
||||
version: 1,
|
||||
@@ -96,7 +104,10 @@ function initializeWallet(): void {
|
||||
encrypted: false,
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
writeFileSync(walletConfig, JSON.stringify(config, null, 2));
|
||||
writeFileSync(walletConfig, JSON.stringify(config, null, 2), {
|
||||
mode: 0o600,
|
||||
flag: "wx",
|
||||
});
|
||||
console.log("Initialized. Mnemonic:", mnemonic);
|
||||
console.log("IMPORTANT: Write down this mnemonic and keep it safe!");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user