varlock 0.9.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auto-load.js +3 -3
- package/dist/{chunk-LRT2CHDN.js → chunk-2ABRAKHE.js} +4 -4
- package/dist/{chunk-LRT2CHDN.js.map → chunk-2ABRAKHE.js.map} +1 -1
- package/dist/chunk-2EEXFFKL.js +149 -0
- package/dist/chunk-2EEXFFKL.js.map +1 -0
- package/dist/{chunk-6CCHLM3U.js → chunk-2PFIYNFA.js} +3 -2
- package/dist/chunk-2PFIYNFA.js.map +1 -0
- package/dist/chunk-6DXWXIQV.js +1092 -0
- package/dist/chunk-6DXWXIQV.js.map +1 -0
- package/dist/{chunk-DGXO2UN7.js → chunk-6JKWTWLB.js} +80 -10
- package/dist/chunk-6JKWTWLB.js.map +1 -0
- package/dist/chunk-7WB7HK5Z.js +21 -0
- package/dist/chunk-7WB7HK5Z.js.map +1 -0
- package/dist/chunk-AMNNQL7K.js +26 -0
- package/dist/chunk-AMNNQL7K.js.map +1 -0
- package/dist/{chunk-P5H6JZZR.js → chunk-CKWXLVMV.js} +10 -9
- package/dist/chunk-CKWXLVMV.js.map +1 -0
- package/dist/{chunk-WLPAS4VQ.js → chunk-FTVXXJMG.js} +3 -3
- package/dist/{chunk-WLPAS4VQ.js.map → chunk-FTVXXJMG.js.map} +1 -1
- package/dist/{chunk-YBV5OJW6.js → chunk-GBCB7Y3B.js} +5 -4
- package/dist/chunk-GBCB7Y3B.js.map +1 -0
- package/dist/chunk-HDKXXS2X.js +1959 -0
- package/dist/chunk-HDKXXS2X.js.map +1 -0
- package/dist/chunk-JEZQ2DFL.js +198 -0
- package/dist/chunk-JEZQ2DFL.js.map +1 -0
- package/dist/{chunk-LAI7XVJU.js → chunk-LOIJO4MO.js} +4 -4
- package/dist/{chunk-LAI7XVJU.js.map → chunk-LOIJO4MO.js.map} +1 -1
- package/dist/{chunk-QYICMUCP.js → chunk-NJONB6CB.js} +5 -5
- package/dist/{chunk-QYICMUCP.js.map → chunk-NJONB6CB.js.map} +1 -1
- package/dist/{chunk-K5536FEN.js → chunk-QJ6NMN5H.js} +5 -5
- package/dist/{chunk-K5536FEN.js.map → chunk-QJ6NMN5H.js.map} +1 -1
- package/dist/{chunk-27CA3M4N.js → chunk-QNTIIXD5.js} +5 -5
- package/dist/{chunk-27CA3M4N.js.map → chunk-QNTIIXD5.js.map} +1 -1
- package/dist/{chunk-C4ITUXON.js → chunk-U7RQPX5K.js} +350 -1056
- package/dist/chunk-U7RQPX5K.js.map +1 -0
- package/dist/{chunk-Q2XA45LC.js → chunk-UKFHSMKY.js} +5 -5
- package/dist/{chunk-Q2XA45LC.js.map → chunk-UKFHSMKY.js.map} +1 -1
- package/dist/{chunk-N2E6DRSH.js → chunk-UUDTMOJS.js} +4 -4
- package/dist/{chunk-N2E6DRSH.js.map → chunk-UUDTMOJS.js.map} +1 -1
- package/dist/chunk-V2MTE4J6.js +426 -0
- package/dist/chunk-V2MTE4J6.js.map +1 -0
- package/dist/{chunk-ZZCDYV63.js → chunk-VODQDF4Q.js} +5 -5
- package/dist/{chunk-ZZCDYV63.js.map → chunk-VODQDF4Q.js.map} +1 -1
- package/dist/{chunk-2R7CWGVL.js → chunk-XADO6HQG.js} +7 -7
- package/dist/{chunk-2R7CWGVL.js.map → chunk-XADO6HQG.js.map} +1 -1
- package/dist/{chunk-GWQJHKYT.js → chunk-XTOUG72X.js} +5 -5
- package/dist/{chunk-GWQJHKYT.js.map → chunk-XTOUG72X.js.map} +1 -1
- package/dist/cli/cli-executable.js +48 -32
- package/dist/cli/cli-executable.js.map +1 -1
- package/dist/config-item-2FQ6I6PO.js +7 -0
- package/dist/{config-item-5WIOGFHA.js.map → config-item-2FQ6I6PO.js.map} +1 -1
- package/dist/dist-WGIHRGBZ.js +4 -0
- package/dist/dist-WGIHRGBZ.js.map +1 -0
- package/dist/dotenv-compat.js +3 -3
- package/dist/encrypt.command-K2SBJVQ5.js +14 -0
- package/dist/encrypt.command-K2SBJVQ5.js.map +1 -0
- package/dist/{env-graph-DaF8Aebq.d.ts → env-graph-CXTsI2Eg.d.ts} +3 -0
- package/dist/explain.command-E6MR72IY.js +15 -0
- package/dist/{explain.command-NST64XIO.js.map → explain.command-E6MR72IY.js.map} +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +11 -8
- package/dist/index.js.map +1 -1
- package/dist/init.command-TGDNXHJ7.js +13 -0
- package/dist/{init.command-4Z3VRGOV.js.map → init.command-TGDNXHJ7.js.map} +1 -1
- package/dist/install-plugin.command-Z2S5DIFS.js +13 -0
- package/dist/{install-plugin.command-F244Y3RI.js.map → install-plugin.command-Z2S5DIFS.js.map} +1 -1
- package/dist/load.command-K2IH3646.js +15 -0
- package/dist/{load.command-JTUAYW2W.js.map → load.command-K2IH3646.js.map} +1 -1
- package/dist/lock.command-GL4CLXED.js +7 -0
- package/dist/lock.command-GL4CLXED.js.map +1 -0
- package/dist/plugin-lib.d.ts +2 -2
- package/dist/plugin-lib.js +2 -2
- package/dist/printenv.command-34LGQT6W.js +15 -0
- package/dist/{printenv.command-NAHG4T76.js.map → printenv.command-34LGQT6W.js.map} +1 -1
- package/dist/reveal.command-WOHYRSYO.js +15 -0
- package/dist/reveal.command-WOHYRSYO.js.map +1 -0
- package/dist/run.command-PPC2X2N7.js +16 -0
- package/dist/{run.command-2IUKOZHD.js.map → run.command-PPC2X2N7.js.map} +1 -1
- package/dist/runtime/env.d.ts +1 -1
- package/dist/scan.command-4DJBQEML.js +16 -0
- package/dist/{scan.command-BEPDT3YQ.js.map → scan.command-4DJBQEML.js.map} +1 -1
- package/dist/telemetry.command-LIOCXWQK.js +13 -0
- package/dist/{telemetry.command-E6GIZKTJ.js.map → telemetry.command-LIOCXWQK.js.map} +1 -1
- package/dist/typegen.command-COL35ALE.js +15 -0
- package/dist/{typegen.command-JGJUSFGG.js.map → typegen.command-COL35ALE.js.map} +1 -1
- package/native-bins/darwin/VarlockEnclave.app/Contents/CodeResources +0 -0
- package/native-bins/darwin/VarlockEnclave.app/Contents/Info.plist +28 -0
- package/native-bins/darwin/VarlockEnclave.app/Contents/MacOS/varlock-local-encrypt +0 -0
- package/native-bins/darwin/VarlockEnclave.app/Contents/Resources/AppIcon.icns +0 -0
- package/native-bins/darwin/VarlockEnclave.app/Contents/Resources/varlock-menu-locked.pdf +0 -0
- package/native-bins/darwin/VarlockEnclave.app/Contents/Resources/varlock-menu-unlocked.pdf +0 -0
- package/native-bins/darwin/VarlockEnclave.app/Contents/_CodeSignature/CodeResources +150 -0
- package/native-bins/linux-arm64/varlock-local-encrypt +0 -0
- package/native-bins/linux-x64/varlock-local-encrypt +0 -0
- package/native-bins/win32-x64/varlock-local-encrypt.exe +0 -0
- package/package.json +9 -2
- package/dist/chunk-6CCHLM3U.js.map +0 -1
- package/dist/chunk-C4ITUXON.js.map +0 -1
- package/dist/chunk-DGXO2UN7.js.map +0 -1
- package/dist/chunk-P5H6JZZR.js.map +0 -1
- package/dist/chunk-S5EU3LTR.js +0 -83
- package/dist/chunk-S5EU3LTR.js.map +0 -1
- package/dist/chunk-YBV5OJW6.js.map +0 -1
- package/dist/config-item-5WIOGFHA.js +0 -5
- package/dist/explain.command-NST64XIO.js +0 -12
- package/dist/init.command-4Z3VRGOV.js +0 -11
- package/dist/install-plugin.command-F244Y3RI.js +0 -11
- package/dist/load.command-JTUAYW2W.js +0 -12
- package/dist/printenv.command-NAHG4T76.js +0 -12
- package/dist/run.command-2IUKOZHD.js +0 -13
- package/dist/scan.command-BEPDT3YQ.js +0 -13
- package/dist/telemetry.command-E6GIZKTJ.js +0 -11
- package/dist/typegen.command-JGJUSFGG.js +0 -12
|
@@ -0,0 +1,1092 @@
|
|
|
1
|
+
import { getUserVarlockDir } from './chunk-7WB7HK5Z.js';
|
|
2
|
+
import { __name } from './chunk-6PEHRAEP.js';
|
|
3
|
+
import { spawn, execFileSync, spawnSync } from 'child_process';
|
|
4
|
+
import fs3 from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import net from 'net';
|
|
8
|
+
import crypto, { webcrypto } from 'crypto';
|
|
9
|
+
|
|
10
|
+
var _isWSL;
|
|
11
|
+
function isWSL() {
|
|
12
|
+
if (_isWSL !== void 0) return _isWSL;
|
|
13
|
+
if (process.env.WSL_DISTRO_NAME) {
|
|
14
|
+
_isWSL = true;
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
const version = fs3.readFileSync("/proc/version", "utf-8");
|
|
19
|
+
_isWSL = /microsoft|wsl/i.test(version);
|
|
20
|
+
} catch {
|
|
21
|
+
_isWSL = false;
|
|
22
|
+
}
|
|
23
|
+
return _isWSL;
|
|
24
|
+
}
|
|
25
|
+
__name(isWSL, "isWSL");
|
|
26
|
+
|
|
27
|
+
// src/lib/local-encrypt/binary-resolver.ts
|
|
28
|
+
var __dirname$1 = path.dirname(fileURLToPath(import.meta.url));
|
|
29
|
+
function debug(msg) {
|
|
30
|
+
if (process.env.VARLOCK_DEBUG) {
|
|
31
|
+
process.stderr.write(`[varlock:binary-resolver] ${msg}
|
|
32
|
+
`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
__name(debug, "debug");
|
|
36
|
+
var BINARY_NAME = "varlock-local-encrypt";
|
|
37
|
+
var MACOS_APP_BUNDLE = "VarlockEnclave.app";
|
|
38
|
+
function resolvePackageRoot() {
|
|
39
|
+
let dir = __dirname$1;
|
|
40
|
+
for (let i = 0; i < 10; i++) {
|
|
41
|
+
const pkgJsonPath = path.join(dir, "package.json");
|
|
42
|
+
if (fs3.existsSync(pkgJsonPath)) {
|
|
43
|
+
try {
|
|
44
|
+
const pkgJson = JSON.parse(fs3.readFileSync(pkgJsonPath, "utf-8"));
|
|
45
|
+
if (pkgJson.name === "varlock") return dir;
|
|
46
|
+
} catch {
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const parent = path.dirname(dir);
|
|
50
|
+
if (parent === dir) break;
|
|
51
|
+
dir = parent;
|
|
52
|
+
}
|
|
53
|
+
return path.resolve(__dirname$1, "..", "..", "..");
|
|
54
|
+
}
|
|
55
|
+
__name(resolvePackageRoot, "resolvePackageRoot");
|
|
56
|
+
function getPlatformBinaryName() {
|
|
57
|
+
if (process.platform === "win32" || isWSL()) return `${BINARY_NAME}.exe`;
|
|
58
|
+
return BINARY_NAME;
|
|
59
|
+
}
|
|
60
|
+
__name(getPlatformBinaryName, "getPlatformBinaryName");
|
|
61
|
+
function getNativeBinSubdir() {
|
|
62
|
+
if (process.platform === "darwin") return "darwin";
|
|
63
|
+
if (process.platform === "win32") return `win32-${process.arch}`;
|
|
64
|
+
if (isWSL()) return "win32-x64";
|
|
65
|
+
return `${process.platform}-${process.arch}`;
|
|
66
|
+
}
|
|
67
|
+
__name(getNativeBinSubdir, "getNativeBinSubdir");
|
|
68
|
+
function resolveMacOSBinary(dir) {
|
|
69
|
+
const appBundlePath = path.join(dir, MACOS_APP_BUNDLE, "Contents", "MacOS", BINARY_NAME);
|
|
70
|
+
if (fs3.existsSync(appBundlePath)) return appBundlePath;
|
|
71
|
+
const barePath = path.join(dir, BINARY_NAME);
|
|
72
|
+
if (fs3.existsSync(barePath)) return barePath;
|
|
73
|
+
return void 0;
|
|
74
|
+
}
|
|
75
|
+
__name(resolveMacOSBinary, "resolveMacOSBinary");
|
|
76
|
+
function resolveStandardBinary(dir) {
|
|
77
|
+
const binaryPath = path.join(dir, getPlatformBinaryName());
|
|
78
|
+
if (fs3.existsSync(binaryPath)) return binaryPath;
|
|
79
|
+
return void 0;
|
|
80
|
+
}
|
|
81
|
+
__name(resolveStandardBinary, "resolveStandardBinary");
|
|
82
|
+
function resolveBinaryFromDir(dir) {
|
|
83
|
+
if (process.platform === "darwin") return resolveMacOSBinary(dir);
|
|
84
|
+
return resolveStandardBinary(dir);
|
|
85
|
+
}
|
|
86
|
+
__name(resolveBinaryFromDir, "resolveBinaryFromDir");
|
|
87
|
+
function resolveSeaSibling() {
|
|
88
|
+
const execDir = path.dirname(fs3.realpathSync(process.execPath));
|
|
89
|
+
const sibling = resolveBinaryFromDir(execDir);
|
|
90
|
+
if (sibling) return sibling;
|
|
91
|
+
const libexecDir = path.join(execDir, "..", "libexec");
|
|
92
|
+
return resolveBinaryFromDir(libexecDir);
|
|
93
|
+
}
|
|
94
|
+
__name(resolveSeaSibling, "resolveSeaSibling");
|
|
95
|
+
function resolveNpmBundled() {
|
|
96
|
+
const packageRoot = resolvePackageRoot();
|
|
97
|
+
const nativeBinsDir = path.join(packageRoot, "native-bins", getNativeBinSubdir());
|
|
98
|
+
if (fs3.existsSync(nativeBinsDir)) return resolveBinaryFromDir(nativeBinsDir);
|
|
99
|
+
const adjacentNativeBinsDir = path.join(path.dirname(packageRoot), "native-bins", getNativeBinSubdir());
|
|
100
|
+
if (fs3.existsSync(adjacentNativeBinsDir)) return resolveBinaryFromDir(adjacentNativeBinsDir);
|
|
101
|
+
return void 0;
|
|
102
|
+
}
|
|
103
|
+
__name(resolveNpmBundled, "resolveNpmBundled");
|
|
104
|
+
function resolveDevFallback() {
|
|
105
|
+
let dir = __dirname$1;
|
|
106
|
+
for (let i = 0; i < 10; i++) {
|
|
107
|
+
const parent = path.dirname(dir);
|
|
108
|
+
if (parent === dir) break;
|
|
109
|
+
dir = parent;
|
|
110
|
+
if (process.platform === "darwin") {
|
|
111
|
+
const swiftBuild = path.join(dir, "packages", "encryption-binary-swift", "swift", ".build", "release", "VarlockEnclave");
|
|
112
|
+
if (fs3.existsSync(swiftBuild)) return swiftBuild;
|
|
113
|
+
}
|
|
114
|
+
const rustBuild = path.join(dir, "packages", "encryption-binary-rust", "target", "release", getPlatformBinaryName());
|
|
115
|
+
if (fs3.existsSync(rustBuild)) return rustBuild;
|
|
116
|
+
}
|
|
117
|
+
return void 0;
|
|
118
|
+
}
|
|
119
|
+
__name(resolveDevFallback, "resolveDevFallback");
|
|
120
|
+
function ensureExecutable(binaryPath) {
|
|
121
|
+
try {
|
|
122
|
+
fs3.accessSync(binaryPath, fs3.constants.X_OK);
|
|
123
|
+
} catch {
|
|
124
|
+
if (process.platform !== "win32") {
|
|
125
|
+
fs3.chmodSync(binaryPath, 493);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return binaryPath;
|
|
129
|
+
}
|
|
130
|
+
__name(ensureExecutable, "ensureExecutable");
|
|
131
|
+
var _cachedBinaryPath = null;
|
|
132
|
+
function resolveNativeBinary() {
|
|
133
|
+
if (_cachedBinaryPath !== null) return _cachedBinaryPath;
|
|
134
|
+
if (process.env._VARLOCK_FORCE_FILE_ENCRYPTION_FALLBACK) {
|
|
135
|
+
debug("_VARLOCK_FORCE_FILE_ENCRYPTION_FALLBACK is set \u2014 skipping native binary resolution");
|
|
136
|
+
_cachedBinaryPath = void 0;
|
|
137
|
+
return void 0;
|
|
138
|
+
}
|
|
139
|
+
debug(`resolving: platform=${process.platform}, isWSL=${isWSL()}, binaryName=${getPlatformBinaryName()}, subdir=${getNativeBinSubdir()}`);
|
|
140
|
+
const seaSibling = resolveSeaSibling();
|
|
141
|
+
if (seaSibling) {
|
|
142
|
+
debug(`resolved via SEA sibling: ${seaSibling}`);
|
|
143
|
+
_cachedBinaryPath = ensureExecutable(seaSibling);
|
|
144
|
+
return _cachedBinaryPath;
|
|
145
|
+
}
|
|
146
|
+
const npmBundled = resolveNpmBundled();
|
|
147
|
+
if (npmBundled) {
|
|
148
|
+
debug(`resolved via npm bundled: ${npmBundled}`);
|
|
149
|
+
_cachedBinaryPath = ensureExecutable(npmBundled);
|
|
150
|
+
return _cachedBinaryPath;
|
|
151
|
+
}
|
|
152
|
+
const devFallback = resolveDevFallback();
|
|
153
|
+
if (devFallback) {
|
|
154
|
+
debug(`resolved via dev fallback: ${devFallback}`);
|
|
155
|
+
_cachedBinaryPath = ensureExecutable(devFallback);
|
|
156
|
+
return _cachedBinaryPath;
|
|
157
|
+
}
|
|
158
|
+
debug("NOT FOUND: no binary resolved from any strategy");
|
|
159
|
+
debug(` SEA sibling dir: ${path.dirname(process.execPath)}`);
|
|
160
|
+
const packageRoot = resolvePackageRoot();
|
|
161
|
+
debug(` npm bundled dir: ${path.join(packageRoot, "native-bins", getNativeBinSubdir())}`);
|
|
162
|
+
_cachedBinaryPath = void 0;
|
|
163
|
+
return void 0;
|
|
164
|
+
}
|
|
165
|
+
__name(resolveNativeBinary, "resolveNativeBinary");
|
|
166
|
+
function debug2(msg) {
|
|
167
|
+
if (process.env.VARLOCK_DEBUG) {
|
|
168
|
+
process.stderr.write(`[varlock:daemon-client] ${msg}
|
|
169
|
+
`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
__name(debug2, "debug");
|
|
173
|
+
function getSocketDir() {
|
|
174
|
+
return path.join(getUserVarlockDir(), "local-encrypt");
|
|
175
|
+
}
|
|
176
|
+
__name(getSocketDir, "getSocketDir");
|
|
177
|
+
function getSocketPath() {
|
|
178
|
+
if (process.platform === "win32") {
|
|
179
|
+
return "\\\\.\\pipe\\varlock-local-encrypt";
|
|
180
|
+
}
|
|
181
|
+
return path.join(getSocketDir(), "daemon.sock");
|
|
182
|
+
}
|
|
183
|
+
__name(getSocketPath, "getSocketPath");
|
|
184
|
+
function getPidPath() {
|
|
185
|
+
return path.join(getSocketDir(), "daemon.pid");
|
|
186
|
+
}
|
|
187
|
+
__name(getPidPath, "getPidPath");
|
|
188
|
+
function getDaemonInfoPath() {
|
|
189
|
+
return path.join(getSocketDir(), "daemon.info");
|
|
190
|
+
}
|
|
191
|
+
__name(getDaemonInfoPath, "getDaemonInfoPath");
|
|
192
|
+
function checkDaemonBinaryStale() {
|
|
193
|
+
const infoPath = getDaemonInfoPath();
|
|
194
|
+
const pidPath = getPidPath();
|
|
195
|
+
let info;
|
|
196
|
+
try {
|
|
197
|
+
info = JSON.parse(fs3.readFileSync(infoPath, "utf-8"));
|
|
198
|
+
} catch {
|
|
199
|
+
}
|
|
200
|
+
const currentBinaryPath = resolveNativeBinary();
|
|
201
|
+
if (!currentBinaryPath) return void 0;
|
|
202
|
+
if (info) {
|
|
203
|
+
if (currentBinaryPath !== info.binaryPath) {
|
|
204
|
+
debug2(`daemon binary path changed: ${info.binaryPath} \u2192 ${currentBinaryPath}`);
|
|
205
|
+
} else {
|
|
206
|
+
try {
|
|
207
|
+
const stat = fs3.statSync(currentBinaryPath);
|
|
208
|
+
if (stat.mtimeMs === info.binaryMtimeMs) {
|
|
209
|
+
debug2("daemon binary is current \u2014 no restart needed");
|
|
210
|
+
return void 0;
|
|
211
|
+
}
|
|
212
|
+
debug2(`daemon binary mtime changed: ${info.binaryMtimeMs} \u2192 ${stat.mtimeMs}`);
|
|
213
|
+
} catch {
|
|
214
|
+
return void 0;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
debug2("no daemon.info file \u2014 treating running daemon as stale");
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
const pid = parseInt(fs3.readFileSync(pidPath, "utf-8").trim(), 10);
|
|
222
|
+
process.kill(pid, 0);
|
|
223
|
+
return pid;
|
|
224
|
+
} catch {
|
|
225
|
+
return void 0;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
__name(checkDaemonBinaryStale, "checkDaemonBinaryStale");
|
|
229
|
+
function writeDaemonInfo(binaryPath) {
|
|
230
|
+
try {
|
|
231
|
+
const stat = fs3.statSync(binaryPath);
|
|
232
|
+
fs3.writeFileSync(getDaemonInfoPath(), JSON.stringify({
|
|
233
|
+
binaryPath,
|
|
234
|
+
binaryMtimeMs: stat.mtimeMs
|
|
235
|
+
}));
|
|
236
|
+
} catch {
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
__name(writeDaemonInfo, "writeDaemonInfo");
|
|
240
|
+
var DaemonClient = class {
|
|
241
|
+
static {
|
|
242
|
+
__name(this, "DaemonClient");
|
|
243
|
+
}
|
|
244
|
+
socket = null;
|
|
245
|
+
messageQueue = /* @__PURE__ */ new Map();
|
|
246
|
+
isConnected = false;
|
|
247
|
+
buffer = Buffer.alloc(0);
|
|
248
|
+
connectingPromise = null;
|
|
249
|
+
/** Set after we spawn a daemon in this process — skip stale check to avoid restart loops */
|
|
250
|
+
spawnedInThisProcess = false;
|
|
251
|
+
async ensureConnected() {
|
|
252
|
+
if (this.isConnected && this.socket) return;
|
|
253
|
+
if (this.connectingPromise) return this.connectingPromise;
|
|
254
|
+
this.connectingPromise = this.doConnect();
|
|
255
|
+
try {
|
|
256
|
+
await this.connectingPromise;
|
|
257
|
+
} finally {
|
|
258
|
+
this.connectingPromise = null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Try to connect to an existing daemon without spawning a new one.
|
|
263
|
+
* Returns true if connected, false if no daemon is running.
|
|
264
|
+
*/
|
|
265
|
+
async tryConnect() {
|
|
266
|
+
if (this.isConnected && this.socket) return true;
|
|
267
|
+
const socketPath = getSocketPath();
|
|
268
|
+
try {
|
|
269
|
+
await this.connectToSocket(socketPath);
|
|
270
|
+
return true;
|
|
271
|
+
} catch {
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
async doConnect() {
|
|
276
|
+
const socketPath = getSocketPath();
|
|
277
|
+
const stalePid = this.spawnedInThisProcess ? void 0 : checkDaemonBinaryStale();
|
|
278
|
+
if (stalePid) {
|
|
279
|
+
debug2(`killing stale daemon (pid ${stalePid}) \u2014 binary has been updated`);
|
|
280
|
+
try {
|
|
281
|
+
process.kill(stalePid, "SIGTERM");
|
|
282
|
+
} catch {
|
|
283
|
+
}
|
|
284
|
+
for (const file of [getPidPath(), getDaemonInfoPath()]) {
|
|
285
|
+
try {
|
|
286
|
+
fs3.unlinkSync(file);
|
|
287
|
+
} catch {
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (process.platform !== "win32") {
|
|
291
|
+
try {
|
|
292
|
+
fs3.unlinkSync(socketPath);
|
|
293
|
+
} catch {
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
} else {
|
|
297
|
+
try {
|
|
298
|
+
await this.connectToSocket(socketPath);
|
|
299
|
+
return;
|
|
300
|
+
} catch {
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
try {
|
|
304
|
+
await this.spawnDaemon();
|
|
305
|
+
} catch {
|
|
306
|
+
await new Promise((r) => {
|
|
307
|
+
setTimeout(r, 1e3);
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
await this.connectToSocket(socketPath);
|
|
311
|
+
}
|
|
312
|
+
async decrypt(ciphertext, keyId = "varlock-default") {
|
|
313
|
+
await this.ensureConnected();
|
|
314
|
+
const result = await this.sendMessage({
|
|
315
|
+
action: "decrypt",
|
|
316
|
+
payload: { ciphertext, keyId }
|
|
317
|
+
});
|
|
318
|
+
if (typeof result === "string") return result;
|
|
319
|
+
if (result && typeof result === "object" && "error" in result) {
|
|
320
|
+
throw new Error(String(result.error));
|
|
321
|
+
}
|
|
322
|
+
return String(result);
|
|
323
|
+
}
|
|
324
|
+
async promptSecret(opts) {
|
|
325
|
+
await this.ensureConnected();
|
|
326
|
+
try {
|
|
327
|
+
const result = await this.sendMessage({
|
|
328
|
+
action: "prompt-secret",
|
|
329
|
+
payload: {
|
|
330
|
+
itemKey: opts?.itemKey,
|
|
331
|
+
message: opts?.message,
|
|
332
|
+
keyId: opts?.keyId
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
if (result && typeof result === "object" && "ciphertext" in result) {
|
|
336
|
+
return result.ciphertext;
|
|
337
|
+
}
|
|
338
|
+
return void 0;
|
|
339
|
+
} catch (err) {
|
|
340
|
+
if (err instanceof Error && err.message === "cancelled") return void 0;
|
|
341
|
+
throw err;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
async invalidateSession() {
|
|
345
|
+
await this.ensureConnected();
|
|
346
|
+
await this.sendMessage({ action: "invalidate-session" });
|
|
347
|
+
}
|
|
348
|
+
async keychainGet(opts) {
|
|
349
|
+
await this.ensureConnected();
|
|
350
|
+
const result = await this.sendMessage({
|
|
351
|
+
action: "keychain-get",
|
|
352
|
+
payload: opts
|
|
353
|
+
});
|
|
354
|
+
if (typeof result === "string") return result;
|
|
355
|
+
if (result && typeof result === "object" && "error" in result) {
|
|
356
|
+
throw new Error(String(result.error));
|
|
357
|
+
}
|
|
358
|
+
return String(result);
|
|
359
|
+
}
|
|
360
|
+
async keychainSearch(opts) {
|
|
361
|
+
await this.ensureConnected();
|
|
362
|
+
const result = await this.sendMessage({
|
|
363
|
+
action: "keychain-search",
|
|
364
|
+
payload: opts ?? {}
|
|
365
|
+
});
|
|
366
|
+
return result ?? [];
|
|
367
|
+
}
|
|
368
|
+
async keychainPick(opts) {
|
|
369
|
+
await this.ensureConnected();
|
|
370
|
+
try {
|
|
371
|
+
const result = await this.sendMessage({
|
|
372
|
+
action: "keychain-pick",
|
|
373
|
+
payload: { itemKey: opts?.itemKey }
|
|
374
|
+
});
|
|
375
|
+
if (result && typeof result === "object" && "service" in result) {
|
|
376
|
+
return result;
|
|
377
|
+
}
|
|
378
|
+
return void 0;
|
|
379
|
+
} catch (err) {
|
|
380
|
+
if (err instanceof Error && err.message === "cancelled") return void 0;
|
|
381
|
+
throw err;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
cleanup() {
|
|
385
|
+
for (const { reject } of this.messageQueue.values()) {
|
|
386
|
+
reject(new Error("Connection closed"));
|
|
387
|
+
}
|
|
388
|
+
this.messageQueue.clear();
|
|
389
|
+
this.socket?.end();
|
|
390
|
+
this.socket = null;
|
|
391
|
+
this.isConnected = false;
|
|
392
|
+
this.buffer = Buffer.alloc(0);
|
|
393
|
+
}
|
|
394
|
+
// -- Private --
|
|
395
|
+
connectToSocket(socketPath) {
|
|
396
|
+
return new Promise((resolve, reject) => {
|
|
397
|
+
const socket = new net.Socket();
|
|
398
|
+
const timeout = setTimeout(() => {
|
|
399
|
+
socket.destroy();
|
|
400
|
+
reject(new Error("Connection timeout"));
|
|
401
|
+
}, 5e3);
|
|
402
|
+
socket.on("connect", () => {
|
|
403
|
+
clearTimeout(timeout);
|
|
404
|
+
this.socket = socket;
|
|
405
|
+
this.isConnected = true;
|
|
406
|
+
this.buffer = Buffer.alloc(0);
|
|
407
|
+
resolve();
|
|
408
|
+
});
|
|
409
|
+
socket.on("data", (data) => {
|
|
410
|
+
this.handleData(data);
|
|
411
|
+
});
|
|
412
|
+
socket.on("error", (err) => {
|
|
413
|
+
clearTimeout(timeout);
|
|
414
|
+
this.isConnected = false;
|
|
415
|
+
reject(err);
|
|
416
|
+
});
|
|
417
|
+
socket.on("close", () => {
|
|
418
|
+
this.isConnected = false;
|
|
419
|
+
this.socket = null;
|
|
420
|
+
});
|
|
421
|
+
socket.connect(socketPath);
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
handleData(data) {
|
|
425
|
+
this.buffer = Buffer.concat([this.buffer, data]);
|
|
426
|
+
while (this.buffer.length >= 4) {
|
|
427
|
+
const messageLength = this.buffer.readUInt32LE(0);
|
|
428
|
+
if (this.buffer.length < 4 + messageLength) break;
|
|
429
|
+
const messageData = this.buffer.subarray(4, 4 + messageLength);
|
|
430
|
+
this.buffer = this.buffer.subarray(4 + messageLength);
|
|
431
|
+
try {
|
|
432
|
+
const message = JSON.parse(messageData.toString());
|
|
433
|
+
if (message.id && this.messageQueue.has(message.id)) {
|
|
434
|
+
const { resolve: res, reject: rej } = this.messageQueue.get(message.id);
|
|
435
|
+
this.messageQueue.delete(message.id);
|
|
436
|
+
if (message.error) {
|
|
437
|
+
rej(new Error(message.error));
|
|
438
|
+
} else {
|
|
439
|
+
res(message.result);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
} catch {
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
sendMessage(message) {
|
|
447
|
+
return new Promise((resolve, reject) => {
|
|
448
|
+
if (!this.isConnected || !this.socket) {
|
|
449
|
+
reject(new Error("Not connected to daemon"));
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
const messageId = `${Date.now().toString(36)}-${crypto.randomBytes(4).toString("hex")}`;
|
|
453
|
+
const messageWithId = { ...message, id: messageId };
|
|
454
|
+
const jsonData = JSON.stringify(messageWithId);
|
|
455
|
+
const messageBytes = Buffer.from(jsonData, "utf-8");
|
|
456
|
+
const lengthBuf = Buffer.alloc(4);
|
|
457
|
+
lengthBuf.writeUInt32LE(messageBytes.length, 0);
|
|
458
|
+
this.messageQueue.set(messageId, { resolve, reject });
|
|
459
|
+
this.socket.write(Buffer.concat([lengthBuf, messageBytes]));
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
async spawnDaemon() {
|
|
463
|
+
const binaryPath = resolveNativeBinary();
|
|
464
|
+
if (!binaryPath) {
|
|
465
|
+
throw new Error("Native encryption binary not found \u2014 cannot start daemon");
|
|
466
|
+
}
|
|
467
|
+
const socketPath = getSocketPath();
|
|
468
|
+
const pidPath = getPidPath();
|
|
469
|
+
const isWindows = process.platform === "win32";
|
|
470
|
+
if (!isWindows) {
|
|
471
|
+
fs3.mkdirSync(path.dirname(socketPath), { recursive: true });
|
|
472
|
+
}
|
|
473
|
+
fs3.mkdirSync(path.dirname(pidPath), { recursive: true });
|
|
474
|
+
if (fs3.existsSync(pidPath)) {
|
|
475
|
+
try {
|
|
476
|
+
const pid = parseInt(fs3.readFileSync(pidPath, "utf-8").trim(), 10);
|
|
477
|
+
process.kill(pid, 0);
|
|
478
|
+
await new Promise((r) => {
|
|
479
|
+
setTimeout(r, 500);
|
|
480
|
+
});
|
|
481
|
+
return;
|
|
482
|
+
} catch {
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
if (!isWindows) {
|
|
486
|
+
for (const file of [socketPath, pidPath, getDaemonInfoPath()]) {
|
|
487
|
+
if (fs3.existsSync(file)) {
|
|
488
|
+
fs3.unlinkSync(file);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
if (fs3.existsSync(socketPath)) {
|
|
492
|
+
throw new Error(`Failed to clean up stale socket file: ${socketPath}`);
|
|
493
|
+
}
|
|
494
|
+
} else {
|
|
495
|
+
for (const file of [pidPath, getDaemonInfoPath()]) {
|
|
496
|
+
if (fs3.existsSync(file)) {
|
|
497
|
+
fs3.unlinkSync(file);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return new Promise((resolve, reject) => {
|
|
502
|
+
const child = spawn(binaryPath, [
|
|
503
|
+
"daemon",
|
|
504
|
+
"--socket-path",
|
|
505
|
+
socketPath,
|
|
506
|
+
"--pid-path",
|
|
507
|
+
pidPath
|
|
508
|
+
], {
|
|
509
|
+
detached: true,
|
|
510
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
511
|
+
});
|
|
512
|
+
const timeout = setTimeout(() => {
|
|
513
|
+
reject(new Error("Daemon failed to start within timeout"));
|
|
514
|
+
}, 1e4);
|
|
515
|
+
let stdoutData = "";
|
|
516
|
+
let stderrData = "";
|
|
517
|
+
child.stdout.on("data", (data) => {
|
|
518
|
+
stdoutData += data.toString();
|
|
519
|
+
try {
|
|
520
|
+
const parsed = JSON.parse(stdoutData);
|
|
521
|
+
if (parsed.ready) {
|
|
522
|
+
clearTimeout(timeout);
|
|
523
|
+
writeDaemonInfo(binaryPath);
|
|
524
|
+
this.spawnedInThisProcess = true;
|
|
525
|
+
child.unref();
|
|
526
|
+
child.stdout.destroy();
|
|
527
|
+
child.stderr.destroy();
|
|
528
|
+
resolve();
|
|
529
|
+
}
|
|
530
|
+
} catch {
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
child.stderr.on("data", (data) => {
|
|
534
|
+
stderrData += data.toString();
|
|
535
|
+
});
|
|
536
|
+
child.on("error", (err) => {
|
|
537
|
+
clearTimeout(timeout);
|
|
538
|
+
reject(new Error(`Failed to spawn daemon: ${err.message}`));
|
|
539
|
+
});
|
|
540
|
+
child.on("exit", (code) => {
|
|
541
|
+
clearTimeout(timeout);
|
|
542
|
+
if (code !== 0) {
|
|
543
|
+
const details = [
|
|
544
|
+
stderrData.trim() && `stderr: ${stderrData.trim()}`,
|
|
545
|
+
stdoutData.trim() && `stdout: ${stdoutData.trim()}`,
|
|
546
|
+
`binary: ${binaryPath}`,
|
|
547
|
+
`socket: ${socketPath}`
|
|
548
|
+
].filter(Boolean).join("\n");
|
|
549
|
+
reject(new Error(`Daemon exited with code ${code}
|
|
550
|
+
${details}`));
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
var subtle = webcrypto.subtle;
|
|
557
|
+
var PAYLOAD_VERSION = 1;
|
|
558
|
+
var HKDF_SALT = new TextEncoder().encode("varlock-ecies-v1");
|
|
559
|
+
var EC_ALGORITHM = { name: "ECDH", namedCurve: "P-256" };
|
|
560
|
+
var PUBLIC_KEY_LENGTH = 65;
|
|
561
|
+
var NONCE_LENGTH = 12;
|
|
562
|
+
var TAG_LENGTH = 16;
|
|
563
|
+
var HEADER_LENGTH = 1 + PUBLIC_KEY_LENGTH + NONCE_LENGTH;
|
|
564
|
+
var bs = /* @__PURE__ */ __name((data) => data, "bs");
|
|
565
|
+
function concatBuffers(...buffers) {
|
|
566
|
+
const totalLength = buffers.reduce((sum, b) => sum + b.length, 0);
|
|
567
|
+
const result = new Uint8Array(totalLength);
|
|
568
|
+
let offset = 0;
|
|
569
|
+
for (const buf of buffers) {
|
|
570
|
+
result.set(buf, offset);
|
|
571
|
+
offset += buf.length;
|
|
572
|
+
}
|
|
573
|
+
return result;
|
|
574
|
+
}
|
|
575
|
+
__name(concatBuffers, "concatBuffers");
|
|
576
|
+
function bufferToBase64(buffer) {
|
|
577
|
+
if (buffer instanceof Uint8Array) {
|
|
578
|
+
return Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength).toString("base64");
|
|
579
|
+
}
|
|
580
|
+
return Buffer.from(buffer).toString("base64");
|
|
581
|
+
}
|
|
582
|
+
__name(bufferToBase64, "bufferToBase64");
|
|
583
|
+
function base64ToUint8(base64) {
|
|
584
|
+
const buf = Buffer.from(base64, "base64");
|
|
585
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
586
|
+
}
|
|
587
|
+
__name(base64ToUint8, "base64ToUint8");
|
|
588
|
+
async function hkdfSha256(ikm, salt, info, outputByteCount) {
|
|
589
|
+
const saltKey = await subtle.importKey("raw", bs(salt), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
590
|
+
const prk = new Uint8Array(await subtle.sign("HMAC", saltKey, bs(ikm)));
|
|
591
|
+
const prkKey = await subtle.importKey("raw", bs(prk), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
592
|
+
const okm = new Uint8Array(outputByteCount);
|
|
593
|
+
let t = new Uint8Array(0);
|
|
594
|
+
let offset = 0;
|
|
595
|
+
let counter = 1;
|
|
596
|
+
while (offset < outputByteCount) {
|
|
597
|
+
const input = concatBuffers(t, info, new Uint8Array([counter]));
|
|
598
|
+
t = new Uint8Array(await subtle.sign("HMAC", prkKey, bs(input)));
|
|
599
|
+
okm.set(t.slice(0, Math.min(t.length, outputByteCount - offset)), offset);
|
|
600
|
+
offset += t.length;
|
|
601
|
+
counter++;
|
|
602
|
+
}
|
|
603
|
+
return okm;
|
|
604
|
+
}
|
|
605
|
+
__name(hkdfSha256, "hkdfSha256");
|
|
606
|
+
async function importPublicKey(base64) {
|
|
607
|
+
return subtle.importKey("raw", bs(base64ToUint8(base64)), EC_ALGORITHM, true, []);
|
|
608
|
+
}
|
|
609
|
+
__name(importPublicKey, "importPublicKey");
|
|
610
|
+
async function importPrivateKey(base64) {
|
|
611
|
+
return subtle.importKey("pkcs8", bs(base64ToUint8(base64)), EC_ALGORITHM, true, ["deriveBits"]);
|
|
612
|
+
}
|
|
613
|
+
__name(importPrivateKey, "importPrivateKey");
|
|
614
|
+
async function createKeyPair() {
|
|
615
|
+
const keyPair = await subtle.generateKey(EC_ALGORITHM, true, ["deriveBits"]);
|
|
616
|
+
const publicKeyRaw = await subtle.exportKey("raw", keyPair.publicKey);
|
|
617
|
+
const privateKeyPkcs8 = await subtle.exportKey("pkcs8", keyPair.privateKey);
|
|
618
|
+
return {
|
|
619
|
+
publicKey: bufferToBase64(publicKeyRaw),
|
|
620
|
+
privateKey: bufferToBase64(privateKeyPkcs8)
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
__name(createKeyPair, "createKeyPair");
|
|
624
|
+
async function encrypt(publicKeyBase64, plaintext) {
|
|
625
|
+
const recipientPublicKey = await importPublicKey(publicKeyBase64);
|
|
626
|
+
const recipientPubKeyRaw = base64ToUint8(publicKeyBase64);
|
|
627
|
+
const ephemeralKeyPair = await subtle.generateKey(EC_ALGORITHM, true, ["deriveBits"]);
|
|
628
|
+
const ephemeralPubKeyRaw = new Uint8Array(await subtle.exportKey("raw", ephemeralKeyPair.publicKey));
|
|
629
|
+
const sharedSecretBits = await subtle.deriveBits(
|
|
630
|
+
{ name: "ECDH", public: recipientPublicKey },
|
|
631
|
+
ephemeralKeyPair.privateKey,
|
|
632
|
+
256
|
|
633
|
+
);
|
|
634
|
+
const sharedSecret = new Uint8Array(sharedSecretBits);
|
|
635
|
+
const info = concatBuffers(ephemeralPubKeyRaw, recipientPubKeyRaw);
|
|
636
|
+
const aesKey = await hkdfSha256(sharedSecret, HKDF_SALT, info, 32);
|
|
637
|
+
const nonce = webcrypto.getRandomValues(new Uint8Array(NONCE_LENGTH));
|
|
638
|
+
const plaintextBytes = new TextEncoder().encode(plaintext);
|
|
639
|
+
const cryptoKey = await subtle.importKey("raw", bs(aesKey), "AES-GCM", false, ["encrypt"]);
|
|
640
|
+
const encrypted = new Uint8Array(
|
|
641
|
+
await subtle.encrypt({ name: "AES-GCM", iv: bs(nonce), tagLength: TAG_LENGTH * 8 }, cryptoKey, bs(plaintextBytes))
|
|
642
|
+
);
|
|
643
|
+
const ciphertext = encrypted.slice(0, encrypted.length - TAG_LENGTH);
|
|
644
|
+
const tag = encrypted.slice(encrypted.length - TAG_LENGTH);
|
|
645
|
+
const payload = concatBuffers(
|
|
646
|
+
new Uint8Array([PAYLOAD_VERSION]),
|
|
647
|
+
ephemeralPubKeyRaw,
|
|
648
|
+
nonce,
|
|
649
|
+
ciphertext,
|
|
650
|
+
tag
|
|
651
|
+
);
|
|
652
|
+
return bufferToBase64(payload);
|
|
653
|
+
}
|
|
654
|
+
__name(encrypt, "encrypt");
|
|
655
|
+
async function decrypt(privateKeyBase64, publicKeyBase64, ciphertextBase64) {
|
|
656
|
+
const payloadBytes = base64ToUint8(ciphertextBase64);
|
|
657
|
+
if (payloadBytes.byteLength < HEADER_LENGTH + TAG_LENGTH) {
|
|
658
|
+
throw new Error("Payload too short");
|
|
659
|
+
}
|
|
660
|
+
const version = payloadBytes[0];
|
|
661
|
+
if (version !== PAYLOAD_VERSION) {
|
|
662
|
+
throw new Error(`Unsupported payload version: ${version}`);
|
|
663
|
+
}
|
|
664
|
+
const ephemeralPubKeyRaw = payloadBytes.slice(1, 1 + PUBLIC_KEY_LENGTH);
|
|
665
|
+
const nonce = payloadBytes.slice(1 + PUBLIC_KEY_LENGTH, HEADER_LENGTH);
|
|
666
|
+
const ciphertextAndTag = payloadBytes.slice(HEADER_LENGTH);
|
|
667
|
+
if (ciphertextAndTag.length < TAG_LENGTH) {
|
|
668
|
+
throw new Error("Payload too short for tag");
|
|
669
|
+
}
|
|
670
|
+
const privateKey = await importPrivateKey(privateKeyBase64);
|
|
671
|
+
const ephemeralPublicKey = await subtle.importKey("raw", bs(ephemeralPubKeyRaw), EC_ALGORITHM, true, []);
|
|
672
|
+
const recipientPubKeyRaw = base64ToUint8(publicKeyBase64);
|
|
673
|
+
const sharedSecretBits = await subtle.deriveBits(
|
|
674
|
+
{ name: "ECDH", public: ephemeralPublicKey },
|
|
675
|
+
privateKey,
|
|
676
|
+
256
|
|
677
|
+
);
|
|
678
|
+
const sharedSecret = new Uint8Array(sharedSecretBits);
|
|
679
|
+
const info = concatBuffers(ephemeralPubKeyRaw, recipientPubKeyRaw);
|
|
680
|
+
const aesKey = await hkdfSha256(sharedSecret, HKDF_SALT, info, 32);
|
|
681
|
+
const cryptoKey = await subtle.importKey("raw", bs(aesKey), "AES-GCM", false, ["decrypt"]);
|
|
682
|
+
try {
|
|
683
|
+
const decrypted = await subtle.decrypt(
|
|
684
|
+
{ name: "AES-GCM", iv: bs(nonce), tagLength: TAG_LENGTH * 8 },
|
|
685
|
+
cryptoKey,
|
|
686
|
+
bs(ciphertextAndTag)
|
|
687
|
+
// already ciphertext || tag
|
|
688
|
+
);
|
|
689
|
+
return new TextDecoder().decode(decrypted);
|
|
690
|
+
} catch (err) {
|
|
691
|
+
throw new Error(
|
|
692
|
+
"Unable to decrypt value",
|
|
693
|
+
{ cause: err }
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
__name(decrypt, "decrypt");
|
|
698
|
+
|
|
699
|
+
// src/lib/local-encrypt/file-backend.ts
|
|
700
|
+
var KEY_STORE_SUBDIR = "local-encrypt/keys";
|
|
701
|
+
var DEFAULT_KEY_ID = "varlock-default";
|
|
702
|
+
function getKeyStorePath() {
|
|
703
|
+
return path.join(getUserVarlockDir(), KEY_STORE_SUBDIR);
|
|
704
|
+
}
|
|
705
|
+
__name(getKeyStorePath, "getKeyStorePath");
|
|
706
|
+
function getKeyFilePath(keyId) {
|
|
707
|
+
return path.join(getKeyStorePath(), `${keyId}.json`);
|
|
708
|
+
}
|
|
709
|
+
__name(getKeyFilePath, "getKeyFilePath");
|
|
710
|
+
function keyExists(keyId = DEFAULT_KEY_ID) {
|
|
711
|
+
return fs3.existsSync(getKeyFilePath(keyId));
|
|
712
|
+
}
|
|
713
|
+
__name(keyExists, "keyExists");
|
|
714
|
+
async function generateKey(keyId = DEFAULT_KEY_ID) {
|
|
715
|
+
const keyPair = await createKeyPair();
|
|
716
|
+
const stored = {
|
|
717
|
+
keyId,
|
|
718
|
+
publicKey: keyPair.publicKey,
|
|
719
|
+
privateKey: keyPair.privateKey,
|
|
720
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
721
|
+
};
|
|
722
|
+
const keyStorePath = getKeyStorePath();
|
|
723
|
+
fs3.mkdirSync(keyStorePath, { recursive: true });
|
|
724
|
+
const filePath = getKeyFilePath(keyId);
|
|
725
|
+
fs3.writeFileSync(filePath, JSON.stringify(stored, null, 2), { mode: 384 });
|
|
726
|
+
return { keyId, publicKey: keyPair.publicKey };
|
|
727
|
+
}
|
|
728
|
+
__name(generateKey, "generateKey");
|
|
729
|
+
function loadKeyPair(keyId) {
|
|
730
|
+
const filePath = getKeyFilePath(keyId);
|
|
731
|
+
if (!fs3.existsSync(filePath)) {
|
|
732
|
+
throw new Error(`Key not found: ${keyId}`);
|
|
733
|
+
}
|
|
734
|
+
const data = fs3.readFileSync(filePath, "utf-8");
|
|
735
|
+
const parsed = JSON.parse(data);
|
|
736
|
+
const privateKey = parsed.privateKey ?? (parsed.protection === "none" ? parsed.protectedPrivateKey : void 0) ?? parsed.protectedPrivateKey;
|
|
737
|
+
if (!parsed.publicKey || !privateKey) {
|
|
738
|
+
throw new Error(`Invalid key file format for key: ${keyId}`);
|
|
739
|
+
}
|
|
740
|
+
return {
|
|
741
|
+
keyId: parsed.keyId || keyId,
|
|
742
|
+
publicKey: parsed.publicKey,
|
|
743
|
+
privateKey,
|
|
744
|
+
createdAt: parsed.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
|
|
745
|
+
protection: parsed.protection,
|
|
746
|
+
protectedPrivateKey: parsed.protectedPrivateKey
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
__name(loadKeyPair, "loadKeyPair");
|
|
750
|
+
function getPublicKey(keyId) {
|
|
751
|
+
return loadKeyPair(keyId).publicKey;
|
|
752
|
+
}
|
|
753
|
+
__name(getPublicKey, "getPublicKey");
|
|
754
|
+
async function encryptValue(plaintext, keyId = DEFAULT_KEY_ID) {
|
|
755
|
+
const publicKey = getPublicKey(keyId);
|
|
756
|
+
return encrypt(publicKey, plaintext);
|
|
757
|
+
}
|
|
758
|
+
__name(encryptValue, "encryptValue");
|
|
759
|
+
async function decryptValue(ciphertext, keyId = DEFAULT_KEY_ID) {
|
|
760
|
+
const stored = loadKeyPair(keyId);
|
|
761
|
+
return decrypt(stored.privateKey, stored.publicKey, ciphertext);
|
|
762
|
+
}
|
|
763
|
+
__name(decryptValue, "decryptValue");
|
|
764
|
+
|
|
765
|
+
// src/lib/local-encrypt/index.ts
|
|
766
|
+
var DEFAULT_KEY_ID2 = "varlock-default";
|
|
767
|
+
function debug3(msg) {
|
|
768
|
+
if (process.env.VARLOCK_DEBUG) {
|
|
769
|
+
process.stderr.write(`[varlock:local-encrypt] ${msg}
|
|
770
|
+
`);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
__name(debug3, "debug");
|
|
774
|
+
var _cachedTtyId;
|
|
775
|
+
function getSelfTtyId() {
|
|
776
|
+
if (_cachedTtyId) return _cachedTtyId;
|
|
777
|
+
try {
|
|
778
|
+
const ttyPath = fs3.readlinkSync("/proc/self/fd/0");
|
|
779
|
+
if (ttyPath && ttyPath.startsWith("/dev/")) {
|
|
780
|
+
_cachedTtyId = ttyPath;
|
|
781
|
+
return ttyPath;
|
|
782
|
+
}
|
|
783
|
+
} catch {
|
|
784
|
+
}
|
|
785
|
+
_cachedTtyId = `pid:${process.pid}`;
|
|
786
|
+
return _cachedTtyId;
|
|
787
|
+
}
|
|
788
|
+
__name(getSelfTtyId, "getSelfTtyId");
|
|
789
|
+
var _wslDaemonPrestartAttempted = false;
|
|
790
|
+
function toWindowsPathFromWsl(pathInWsl) {
|
|
791
|
+
if (!isWSL()) return void 0;
|
|
792
|
+
try {
|
|
793
|
+
return execFileSync("wslpath", ["-w", pathInWsl], {
|
|
794
|
+
encoding: "utf-8",
|
|
795
|
+
timeout: 1e4
|
|
796
|
+
}).trim();
|
|
797
|
+
} catch (err) {
|
|
798
|
+
debug3(`toWindowsPathFromWsl failed: ${err instanceof Error ? err.message : err}`);
|
|
799
|
+
return void 0;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
__name(toWindowsPathFromWsl, "toWindowsPathFromWsl");
|
|
803
|
+
function tryPrestartWindowsDaemonFromWsl(binaryPath) {
|
|
804
|
+
if (_wslDaemonPrestartAttempted) {
|
|
805
|
+
return true;
|
|
806
|
+
}
|
|
807
|
+
const windowsPath = toWindowsPathFromWsl(binaryPath);
|
|
808
|
+
if (!windowsPath) {
|
|
809
|
+
return false;
|
|
810
|
+
}
|
|
811
|
+
const escapedPath = windowsPath.replaceAll("'", "''");
|
|
812
|
+
const psScript = `Start-Process -WindowStyle Hidden -FilePath '${escapedPath}' -ArgumentList 'start-daemon'`;
|
|
813
|
+
const proc = spawnSync("powershell.exe", [
|
|
814
|
+
"-NoProfile",
|
|
815
|
+
"-NonInteractive",
|
|
816
|
+
"-ExecutionPolicy",
|
|
817
|
+
"Bypass",
|
|
818
|
+
"-Command",
|
|
819
|
+
psScript
|
|
820
|
+
], {
|
|
821
|
+
encoding: "utf-8",
|
|
822
|
+
timeout: 2e4
|
|
823
|
+
});
|
|
824
|
+
if (proc.error) {
|
|
825
|
+
debug3(`tryPrestartWindowsDaemonFromWsl: powershell error: ${proc.error.message}`);
|
|
826
|
+
return false;
|
|
827
|
+
}
|
|
828
|
+
if (proc.status !== 0) {
|
|
829
|
+
debug3(`tryPrestartWindowsDaemonFromWsl: powershell exit ${proc.status}: ${(proc.stderr || proc.stdout || "").trim()}`);
|
|
830
|
+
return false;
|
|
831
|
+
}
|
|
832
|
+
debug3("tryPrestartWindowsDaemonFromWsl: start-daemon invoked via PowerShell");
|
|
833
|
+
_wslDaemonPrestartAttempted = true;
|
|
834
|
+
return true;
|
|
835
|
+
}
|
|
836
|
+
__name(tryPrestartWindowsDaemonFromWsl, "tryPrestartWindowsDaemonFromWsl");
|
|
837
|
+
function pingWindowsDaemonFromWsl(binaryPath, timeoutMs = 2e3) {
|
|
838
|
+
const proc = spawnSync(binaryPath, ["ping-daemon"], {
|
|
839
|
+
encoding: "utf-8",
|
|
840
|
+
timeout: timeoutMs
|
|
841
|
+
});
|
|
842
|
+
if (proc.error || proc.status !== 0) {
|
|
843
|
+
return false;
|
|
844
|
+
}
|
|
845
|
+
try {
|
|
846
|
+
const parsed = JSON.parse((proc.stdout || "").trim());
|
|
847
|
+
return parsed.ready === true;
|
|
848
|
+
} catch {
|
|
849
|
+
return false;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
__name(pingWindowsDaemonFromWsl, "pingWindowsDaemonFromWsl");
|
|
853
|
+
function waitForWindowsDaemonFromWsl(binaryPath, timeoutMs = 12e3) {
|
|
854
|
+
const deadline = Date.now() + timeoutMs;
|
|
855
|
+
while (Date.now() < deadline) {
|
|
856
|
+
if (pingWindowsDaemonFromWsl(binaryPath)) {
|
|
857
|
+
debug3("waitForWindowsDaemonFromWsl: daemon is ready");
|
|
858
|
+
return true;
|
|
859
|
+
}
|
|
860
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 150);
|
|
861
|
+
}
|
|
862
|
+
debug3("waitForWindowsDaemonFromWsl: timed out waiting for daemon readiness");
|
|
863
|
+
return false;
|
|
864
|
+
}
|
|
865
|
+
__name(waitForWindowsDaemonFromWsl, "waitForWindowsDaemonFromWsl");
|
|
866
|
+
function runNativeBinary(args, opts) {
|
|
867
|
+
const binaryPath = resolveNativeBinary();
|
|
868
|
+
if (!binaryPath) {
|
|
869
|
+
debug3("runNativeBinary: no binary found");
|
|
870
|
+
throw new Error("Native binary not found");
|
|
871
|
+
}
|
|
872
|
+
debug3(`runNativeBinary: ${binaryPath} ${args.join(" ")}`);
|
|
873
|
+
const output = execFileSync(binaryPath, args, {
|
|
874
|
+
encoding: "utf-8",
|
|
875
|
+
timeout: opts?.timeout ?? 3e4
|
|
876
|
+
}).trim();
|
|
877
|
+
debug3(`runNativeBinary result: ${output.slice(0, 200)}`);
|
|
878
|
+
return output;
|
|
879
|
+
}
|
|
880
|
+
__name(runNativeBinary, "runNativeBinary");
|
|
881
|
+
function runNativeBinaryJson(args, opts) {
|
|
882
|
+
const output = runNativeBinary(args, opts);
|
|
883
|
+
const parsed = JSON.parse(output);
|
|
884
|
+
if (parsed.error) {
|
|
885
|
+
throw new Error(parsed.error);
|
|
886
|
+
}
|
|
887
|
+
return parsed;
|
|
888
|
+
}
|
|
889
|
+
__name(runNativeBinaryJson, "runNativeBinaryJson");
|
|
890
|
+
var cachedBackendInfo;
|
|
891
|
+
var cachedStatusKeys;
|
|
892
|
+
function detectBackendType() {
|
|
893
|
+
const binaryPath = resolveNativeBinary();
|
|
894
|
+
debug3(`detectBackendType: binaryPath=${binaryPath ?? "NOT FOUND"}, isWSL=${isWSL()}, platform=${process.platform}`);
|
|
895
|
+
if (!binaryPath) {
|
|
896
|
+
const isFileFallback = ["darwin", "win32", "linux"].includes(process.platform);
|
|
897
|
+
return { type: "file", isFileFallback };
|
|
898
|
+
}
|
|
899
|
+
if (isWSL()) return { type: "windows-tpm", isFileFallback: false };
|
|
900
|
+
switch (process.platform) {
|
|
901
|
+
case "darwin":
|
|
902
|
+
return { type: "secure-enclave", isFileFallback: false };
|
|
903
|
+
case "win32":
|
|
904
|
+
return { type: "windows-tpm", isFileFallback: false };
|
|
905
|
+
case "linux":
|
|
906
|
+
return { type: "linux-tpm", isFileFallback: false };
|
|
907
|
+
default:
|
|
908
|
+
return { type: "file", isFileFallback: false };
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
__name(detectBackendType, "detectBackendType");
|
|
912
|
+
function getBackendInfo() {
|
|
913
|
+
if (cachedBackendInfo) return cachedBackendInfo;
|
|
914
|
+
const { type, isFileFallback } = detectBackendType();
|
|
915
|
+
const binaryPath = type !== "file" ? resolveNativeBinary() : void 0;
|
|
916
|
+
if (type !== "file" && binaryPath) {
|
|
917
|
+
try {
|
|
918
|
+
const status = runNativeBinaryJson(["status"]);
|
|
919
|
+
debug3(`getBackendInfo: status result: hardwareBacked=${status.hardwareBacked}, biometricAvailable=${status.biometricAvailable}, backend=${status.backend}, keys=${status.keys?.join(",")}`);
|
|
920
|
+
cachedStatusKeys = status.keys;
|
|
921
|
+
cachedBackendInfo = {
|
|
922
|
+
type,
|
|
923
|
+
platform: process.platform,
|
|
924
|
+
hardwareBacked: status.hardwareBacked,
|
|
925
|
+
biometricAvailable: status.biometricAvailable,
|
|
926
|
+
binaryPath
|
|
927
|
+
};
|
|
928
|
+
} catch (err) {
|
|
929
|
+
debug3(`getBackendInfo: status command failed: ${err instanceof Error ? err.message : err}`);
|
|
930
|
+
cachedBackendInfo = {
|
|
931
|
+
type,
|
|
932
|
+
platform: process.platform,
|
|
933
|
+
hardwareBacked: type === "secure-enclave",
|
|
934
|
+
biometricAvailable: type === "secure-enclave",
|
|
935
|
+
binaryPath
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
} else {
|
|
939
|
+
debug3(`getBackendInfo: using file backend (type=${type}, binaryPath=${binaryPath ?? "none"}, isFileFallback=${isFileFallback})`);
|
|
940
|
+
if (isFileFallback && !process.env._VARLOCK_FORCE_FILE_ENCRYPTION_FALLBACK) {
|
|
941
|
+
process.stderr.write(
|
|
942
|
+
"[varlock] Warning: native encryption binary not found, falling back to file-based encryption (not hardware-backed)\n"
|
|
943
|
+
);
|
|
944
|
+
}
|
|
945
|
+
cachedBackendInfo = {
|
|
946
|
+
type,
|
|
947
|
+
platform: process.platform,
|
|
948
|
+
hardwareBacked: false,
|
|
949
|
+
biometricAvailable: false,
|
|
950
|
+
binaryPath: void 0,
|
|
951
|
+
isFileFallback
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
debug3(`getBackendInfo: final result: type=${cachedBackendInfo.type}, biometric=${cachedBackendInfo.biometricAvailable}, hwBacked=${cachedBackendInfo.hardwareBacked}`);
|
|
955
|
+
return cachedBackendInfo;
|
|
956
|
+
}
|
|
957
|
+
__name(getBackendInfo, "getBackendInfo");
|
|
958
|
+
var daemonClient;
|
|
959
|
+
function getDaemonClient() {
|
|
960
|
+
daemonClient ||= new DaemonClient();
|
|
961
|
+
return daemonClient;
|
|
962
|
+
}
|
|
963
|
+
__name(getDaemonClient, "getDaemonClient");
|
|
964
|
+
function keyExists2(keyId = DEFAULT_KEY_ID2) {
|
|
965
|
+
const backend = getBackendInfo();
|
|
966
|
+
if (backend.type === "file") {
|
|
967
|
+
return keyExists(keyId);
|
|
968
|
+
}
|
|
969
|
+
if (cachedStatusKeys) {
|
|
970
|
+
debug3(`keyExists: using cached status keys for ${keyId}`);
|
|
971
|
+
return cachedStatusKeys.includes(keyId);
|
|
972
|
+
}
|
|
973
|
+
const result = runNativeBinaryJson(["key-exists", "--key-id", keyId]);
|
|
974
|
+
return result.exists;
|
|
975
|
+
}
|
|
976
|
+
__name(keyExists2, "keyExists");
|
|
977
|
+
async function generateKey2(keyId = DEFAULT_KEY_ID2) {
|
|
978
|
+
const backend = getBackendInfo();
|
|
979
|
+
if (backend.type === "file") {
|
|
980
|
+
return generateKey(keyId);
|
|
981
|
+
}
|
|
982
|
+
return runNativeBinaryJson(["generate-key", "--key-id", keyId]);
|
|
983
|
+
}
|
|
984
|
+
__name(generateKey2, "generateKey");
|
|
985
|
+
async function ensureKey(keyId = DEFAULT_KEY_ID2) {
|
|
986
|
+
if (!keyExists2(keyId)) {
|
|
987
|
+
await generateKey2(keyId);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
__name(ensureKey, "ensureKey");
|
|
991
|
+
async function encryptValue2(plaintext, keyId = DEFAULT_KEY_ID2) {
|
|
992
|
+
const backend = getBackendInfo();
|
|
993
|
+
if (backend.type === "file") {
|
|
994
|
+
return encryptValue(plaintext, keyId);
|
|
995
|
+
}
|
|
996
|
+
const b64Input = Buffer.from(plaintext, "utf-8").toString("base64");
|
|
997
|
+
if (isWSL()) {
|
|
998
|
+
const binaryPath = resolveNativeBinary();
|
|
999
|
+
if (!binaryPath) throw new Error("Native binary not found");
|
|
1000
|
+
const proc = spawnSync(binaryPath, ["encrypt", "--key-id", keyId, "--data-stdin"], {
|
|
1001
|
+
input: b64Input,
|
|
1002
|
+
encoding: "utf-8",
|
|
1003
|
+
timeout: 3e4
|
|
1004
|
+
});
|
|
1005
|
+
if (proc.error) throw proc.error;
|
|
1006
|
+
const result2 = JSON.parse(proc.stdout.trim());
|
|
1007
|
+
if (result2.error) throw new Error(result2.error);
|
|
1008
|
+
return result2.ciphertext;
|
|
1009
|
+
}
|
|
1010
|
+
const result = runNativeBinaryJson(["encrypt", "--key-id", keyId, "--data", b64Input]);
|
|
1011
|
+
return result.ciphertext;
|
|
1012
|
+
}
|
|
1013
|
+
__name(encryptValue2, "encryptValue");
|
|
1014
|
+
async function decryptValue2(ciphertext, keyId = DEFAULT_KEY_ID2) {
|
|
1015
|
+
const backend = getBackendInfo();
|
|
1016
|
+
if (backend.type === "file") {
|
|
1017
|
+
debug3("decryptValue: using file backend");
|
|
1018
|
+
return decryptValue(ciphertext, keyId);
|
|
1019
|
+
}
|
|
1020
|
+
if (backend.biometricAvailable) {
|
|
1021
|
+
if (isWSL()) {
|
|
1022
|
+
debug3("decryptValue: WSL2 biometric decrypt via --via-daemon");
|
|
1023
|
+
const binaryPath = resolveNativeBinary();
|
|
1024
|
+
if (!binaryPath) throw new Error("Native binary not found");
|
|
1025
|
+
const daemonAlreadyReady = pingWindowsDaemonFromWsl(binaryPath, 1500);
|
|
1026
|
+
const daemonPrestarted = daemonAlreadyReady || tryPrestartWindowsDaemonFromWsl(binaryPath);
|
|
1027
|
+
if (!daemonAlreadyReady && daemonPrestarted) {
|
|
1028
|
+
waitForWindowsDaemonFromWsl(binaryPath);
|
|
1029
|
+
}
|
|
1030
|
+
const stdinPayload = JSON.stringify({
|
|
1031
|
+
data: ciphertext,
|
|
1032
|
+
ttyId: getSelfTtyId()
|
|
1033
|
+
});
|
|
1034
|
+
const runViaDaemon = /* @__PURE__ */ __name((timeout) => spawnSync(binaryPath, ["decrypt", "--key-id", keyId, "--data-stdin", "--via-daemon"], {
|
|
1035
|
+
input: stdinPayload,
|
|
1036
|
+
encoding: "utf-8",
|
|
1037
|
+
timeout
|
|
1038
|
+
}), "runViaDaemon");
|
|
1039
|
+
let proc = runViaDaemon(daemonPrestarted ? 12e4 : 6e4);
|
|
1040
|
+
const output = (proc.stdout || proc.stderr || "").trim();
|
|
1041
|
+
const timedOut = proc.error && proc.error.code === "ETIMEDOUT";
|
|
1042
|
+
const needsRetry = Boolean(proc.error) || proc.status !== 0;
|
|
1043
|
+
const likelyDaemonStartupIssue = timedOut || /daemon is not running|daemon did not become ready within timeout|schtasks|windows hello daemon/i.test(output);
|
|
1044
|
+
if (needsRetry && likelyDaemonStartupIssue) {
|
|
1045
|
+
debug3(`decryptValue: via-daemon startup issue detected; attempting native start-daemon bridge. output=${output.slice(0, 180)}`);
|
|
1046
|
+
if (tryPrestartWindowsDaemonFromWsl(binaryPath)) {
|
|
1047
|
+
proc = runViaDaemon(12e4);
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
if (proc.error) throw proc.error;
|
|
1051
|
+
if (proc.status !== 0) {
|
|
1052
|
+
const finalOutput = (proc.stdout || proc.stderr || "").trim();
|
|
1053
|
+
try {
|
|
1054
|
+
const parsed = JSON.parse(finalOutput);
|
|
1055
|
+
if (parsed.error) throw new Error(parsed.error);
|
|
1056
|
+
} catch {
|
|
1057
|
+
}
|
|
1058
|
+
const windowsPath = toWindowsPathFromWsl(binaryPath);
|
|
1059
|
+
const setupHint = windowsPath ? `
|
|
1060
|
+
Hint: In native Windows PowerShell run:
|
|
1061
|
+
Start-Process -WindowStyle Hidden "${windowsPath}" start-daemon` : "";
|
|
1062
|
+
throw new Error(`Decrypt failed (exit ${proc.status}): ${finalOutput}${setupHint}`);
|
|
1063
|
+
}
|
|
1064
|
+
const result2 = JSON.parse(proc.stdout.trim());
|
|
1065
|
+
if (result2.error) throw new Error(result2.error);
|
|
1066
|
+
debug3(`decryptValue: WSL2 result: ${proc.stdout.trim().slice(0, 100)}`);
|
|
1067
|
+
return result2.plaintext;
|
|
1068
|
+
}
|
|
1069
|
+
debug3("decryptValue: biometric decrypt via daemon client");
|
|
1070
|
+
const client = getDaemonClient();
|
|
1071
|
+
return client.decrypt(ciphertext, keyId);
|
|
1072
|
+
}
|
|
1073
|
+
debug3("decryptValue: non-biometric one-shot decrypt");
|
|
1074
|
+
const result = runNativeBinaryJson(["decrypt", "--key-id", keyId, "--data", ciphertext]);
|
|
1075
|
+
return result.plaintext;
|
|
1076
|
+
}
|
|
1077
|
+
__name(decryptValue2, "decryptValue");
|
|
1078
|
+
async function lockSession() {
|
|
1079
|
+
const backend = getBackendInfo();
|
|
1080
|
+
if (!backend.biometricAvailable) return;
|
|
1081
|
+
const client = getDaemonClient();
|
|
1082
|
+
const connected = await client.tryConnect();
|
|
1083
|
+
if (!connected) {
|
|
1084
|
+
throw new Error("No encryption daemon is running");
|
|
1085
|
+
}
|
|
1086
|
+
await client.invalidateSession();
|
|
1087
|
+
}
|
|
1088
|
+
__name(lockSession, "lockSession");
|
|
1089
|
+
|
|
1090
|
+
export { decryptValue2 as decryptValue, encryptValue2 as encryptValue, ensureKey, getBackendInfo, getDaemonClient, lockSession };
|
|
1091
|
+
//# sourceMappingURL=chunk-6DXWXIQV.js.map
|
|
1092
|
+
//# sourceMappingURL=chunk-6DXWXIQV.js.map
|