File size: 2,705 Bytes
cd8bd0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import { existsSync } from "node:fs";
import { resolveDataDir } from "../data-dir.mjs";
import { join } from "node:path";

const ENCRYPTED_PATTERN = "enc:v1:%";
const ENCRYPTED_COLUMNS = ["api_key", "access_token", "refresh_token", "id_token"];

/**
 * Direct SQLite implementation for reset-encrypted-columns.
 * Uses better-sqlite3 directly to avoid TypeScript source dependencies in production builds.
 */
export async function runResetEncryptedColumns(argv) {
  const dataDir = resolveDataDir();
  const dbPath = join(dataDir, "storage.sqlite");

  if (!existsSync(dbPath)) {
    console.log(`\x1b[33m⚠ No database found at ${dbPath}\x1b[0m`);
    return 0;
  }

  const force = Array.isArray(argv) ? argv.includes("--force") : argv?.force === true;

  if (!force) {
    console.log(`
  \x1b[1m\x1b[33m⚠ WARNING: This will erase all encrypted credentials\x1b[0m

  This command will NULL out the following columns in provider_connections:
    • api_key
    • access_token
    • refresh_token
    • id_token

  Provider metadata (name, provider_id, settings) will be preserved.
  You will need to re-authenticate all providers after this operation.

  Database: ${dbPath}

  \x1b[1mTo confirm, run:\x1b[0m
    omniroute reset-encrypted-columns --force
    `);
    return 0;
  }

  let db;
  try {
    // Use createRequire to load better-sqlite3 (works in both dev and production)
    const { createRequire } = await import("node:module");
    const require = createRequire(import.meta.url);
    const Database = require("better-sqlite3");

    db = new Database(dbPath);

    // Build WHERE clause for encrypted values
    const whereClause = ENCRYPTED_COLUMNS.map((col) => `${col} LIKE '${ENCRYPTED_PATTERN}'`).join(
      " OR "
    );

    // Count affected rows
    const countResult = db
      .prepare(`SELECT COUNT(*) AS cnt FROM provider_connections WHERE ${whereClause}`)
      .get();
    const count = countResult?.cnt ?? 0;

    if (count === 0) {
      console.log("\x1b[32m✔ No encrypted credentials found — nothing to reset.\x1b[0m");
      return 0;
    }

    // Reset columns
    const nullCols = ENCRYPTED_COLUMNS.map((col) => `${col} = NULL`).join(", ");
    db.prepare(`UPDATE provider_connections SET ${nullCols} WHERE ${whereClause}`).run();

    console.log(
      `\x1b[32m✔ Reset ${count} provider connection(s).\x1b[0m\n` +
        `  Re-authenticate your providers in the dashboard or re-add API keys.\n`
    );
    return 0;
  } catch (err) {
    console.error(
      `\x1b[31m✖ Failed to reset encrypted columns:\x1b[0m ${err instanceof Error ? err.message : String(err)}`
    );
    return 1;
  } finally {
    if (db) {
      db.close();
    }
  }
}