pairpod-bot 0.1.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/LICENSE +21 -0
- package/README.md +6 -0
- package/dist/access.d.ts +2 -0
- package/dist/access.js +14 -0
- package/dist/access.js.map +1 -0
- package/dist/agents.d.ts +7 -0
- package/dist/agents.js +10 -0
- package/dist/agents.js.map +1 -0
- package/dist/attach.d.ts +2 -0
- package/dist/attach.js +65 -0
- package/dist/attach.js.map +1 -0
- package/dist/bot.d.ts +1 -0
- package/dist/bot.js +357 -0
- package/dist/bot.js.map +1 -0
- package/dist/config.d.ts +18 -0
- package/dist/config.js +39 -0
- package/dist/config.js.map +1 -0
- package/dist/db.d.ts +2 -0
- package/dist/db.js +87 -0
- package/dist/db.js.map +1 -0
- package/dist/docker.d.ts +15 -0
- package/dist/docker.js +113 -0
- package/dist/docker.js.map +1 -0
- package/dist/env.d.ts +2 -0
- package/dist/env.js +36 -0
- package/dist/env.js.map +1 -0
- package/dist/errors.d.ts +7 -0
- package/dist/errors.js +25 -0
- package/dist/errors.js.map +1 -0
- package/dist/local/sessions.d.ts +5 -0
- package/dist/local/sessions.js +83 -0
- package/dist/local/sessions.js.map +1 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +8 -0
- package/dist/main.js.map +1 -0
- package/dist/naming.d.ts +3 -0
- package/dist/naming.js +19 -0
- package/dist/naming.js.map +1 -0
- package/dist/network.d.ts +1 -0
- package/dist/network.js +11 -0
- package/dist/network.js.map +1 -0
- package/dist/notifier.d.ts +4 -0
- package/dist/notifier.js +47 -0
- package/dist/notifier.js.map +1 -0
- package/dist/notify.d.ts +2 -0
- package/dist/notify.js +19 -0
- package/dist/notify.js.map +1 -0
- package/dist/paths.d.ts +9 -0
- package/dist/paths.js +18 -0
- package/dist/paths.js.map +1 -0
- package/dist/routes/attach.d.ts +13 -0
- package/dist/routes/attach.js +49 -0
- package/dist/routes/attach.js.map +1 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +51 -0
- package/dist/server.js.map +1 -0
- package/dist/ssh.d.ts +2 -0
- package/dist/ssh.js +84 -0
- package/dist/ssh.js.map +1 -0
- package/dist/store.d.ts +65 -0
- package/dist/store.js +337 -0
- package/dist/store.js.map +1 -0
- package/dist/targets/docker.d.ts +7 -0
- package/dist/targets/docker.js +14 -0
- package/dist/targets/docker.js.map +1 -0
- package/dist/targets/index.d.ts +4 -0
- package/dist/targets/index.js +33 -0
- package/dist/targets/index.js.map +1 -0
- package/dist/targets/ssh.d.ts +25 -0
- package/dist/targets/ssh.js +121 -0
- package/dist/targets/ssh.js.map +1 -0
- package/dist/targets/types.d.ts +15 -0
- package/dist/targets/types.js +2 -0
- package/dist/targets/types.js.map +1 -0
- package/dist/telegram-auth.d.ts +7 -0
- package/dist/telegram-auth.js +41 -0
- package/dist/telegram-auth.js.map +1 -0
- package/dist/vault.d.ts +4 -0
- package/dist/vault.js +57 -0
- package/dist/vault.js.map +1 -0
- package/miniapp/index.html +597 -0
- package/miniapp/ssh.html +251 -0
- package/package.json +44 -0
- package/scripts/fix-pty.cjs +15 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { execInContainer, attachExec } from "../docker.js";
|
|
2
|
+
export class DockerTarget {
|
|
3
|
+
ref;
|
|
4
|
+
constructor(ref) {
|
|
5
|
+
this.ref = ref;
|
|
6
|
+
}
|
|
7
|
+
exec(cmd) {
|
|
8
|
+
return execInContainer(this.ref, cmd);
|
|
9
|
+
}
|
|
10
|
+
openPty(cmd, cols, rows) {
|
|
11
|
+
return attachExec(this.ref, cmd, cols, rows);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=docker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker.js","sourceRoot":"","sources":["../../src/targets/docker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG3D,MAAM,OAAO,YAAY;IACM;IAA7B,YAA6B,GAAW;QAAX,QAAG,GAAH,GAAG,CAAQ;IAAG,CAAC;IAE5C,IAAI,CAAC,GAAa;QAChB,OAAO,eAAe,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,CAAC,GAAa,EAAE,IAAY,EAAE,IAAY;QAC/C,OAAO,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC/C,CAAC;CACF"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { getDb } from "../db.js";
|
|
2
|
+
import { DockerTarget } from "./docker.js";
|
|
3
|
+
import { SshTarget } from "./ssh.js";
|
|
4
|
+
const sshPool = new Map();
|
|
5
|
+
export function targetForPod(p) {
|
|
6
|
+
if (p.kind !== "ssh")
|
|
7
|
+
return new DockerTarget(`pairpod-${p.id}`);
|
|
8
|
+
let target = sshPool.get(p.id);
|
|
9
|
+
if (!target) {
|
|
10
|
+
target = new SshTarget({
|
|
11
|
+
host: p.ssh_host,
|
|
12
|
+
port: p.ssh_port ?? 22,
|
|
13
|
+
username: p.ssh_user,
|
|
14
|
+
auth: p.ssh_auth,
|
|
15
|
+
keyPath: p.ssh_key_path ?? undefined,
|
|
16
|
+
vaultRef: p.ssh_vault_ref ?? undefined,
|
|
17
|
+
hostFingerprint: p.host_fingerprint ?? undefined,
|
|
18
|
+
onFingerprint: (fp) => {
|
|
19
|
+
getDb().prepare("UPDATE pods SET host_fingerprint = ? WHERE id = ?").run(fp, p.id);
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
sshPool.set(p.id, target);
|
|
23
|
+
}
|
|
24
|
+
return target;
|
|
25
|
+
}
|
|
26
|
+
export async function disposeTarget(podId) {
|
|
27
|
+
const target = sshPool.get(podId);
|
|
28
|
+
if (target) {
|
|
29
|
+
await target.dispose();
|
|
30
|
+
sshPool.delete(podId);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/targets/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAgB,MAAM,UAAU,CAAC;AAGnD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAqB,CAAC;AAE7C,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,IAAI,CAAC,CAAC,IAAI,KAAK,KAAK;QAAE,OAAO,IAAI,YAAY,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACjE,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,IAAI,SAAS,CAAC;YACrB,IAAI,EAAE,CAAC,CAAC,QAAkB;YAC1B,IAAI,EAAE,CAAC,CAAC,QAAQ,IAAI,EAAE;YACtB,QAAQ,EAAE,CAAC,CAAC,QAAkB;YAC9B,IAAI,EAAE,CAAC,CAAC,QAAmB;YAC3B,OAAO,EAAE,CAAC,CAAC,YAAY,IAAI,SAAS;YACpC,QAAQ,EAAE,CAAC,CAAC,aAAa,IAAI,SAAS;YACtC,eAAe,EAAE,CAAC,CAAC,gBAAgB,IAAI,SAAS;YAChD,aAAa,EAAE,CAAC,EAAE,EAAE,EAAE;gBACpB,KAAK,EAAE,CAAC,OAAO,CAAC,mDAAmD,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YACrF,CAAC;SACF,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAa;IAC/C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;QACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { PodTarget, ExecResult, PtySession } from "./types.js";
|
|
2
|
+
export type SshAuth = "agent" | "key_path" | "vault";
|
|
3
|
+
export interface SshConnInfo {
|
|
4
|
+
host: string;
|
|
5
|
+
port: number;
|
|
6
|
+
username: string;
|
|
7
|
+
auth: SshAuth;
|
|
8
|
+
keyPath?: string;
|
|
9
|
+
vaultRef?: string;
|
|
10
|
+
hostFingerprint?: string;
|
|
11
|
+
onFingerprint?: (fingerprint: string) => void;
|
|
12
|
+
}
|
|
13
|
+
export declare function shellQuote(arg: string): string;
|
|
14
|
+
export declare function shellJoin(cmd: string[]): string;
|
|
15
|
+
export declare class SshTarget implements PodTarget {
|
|
16
|
+
private readonly info;
|
|
17
|
+
private client;
|
|
18
|
+
private connecting;
|
|
19
|
+
constructor(info: SshConnInfo);
|
|
20
|
+
private buildConfig;
|
|
21
|
+
private connect;
|
|
22
|
+
exec(cmd: string[]): Promise<ExecResult>;
|
|
23
|
+
openPty(cmd: string[], cols: number, rows: number): Promise<PtySession>;
|
|
24
|
+
dispose(): Promise<void>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import { Client } from "ssh2";
|
|
4
|
+
import { vaultGet } from "../vault.js";
|
|
5
|
+
export function shellQuote(arg) {
|
|
6
|
+
return `'${arg.replace(/'/g, `'\\''`)}'`;
|
|
7
|
+
}
|
|
8
|
+
export function shellJoin(cmd) {
|
|
9
|
+
return cmd.map(shellQuote).join(" ");
|
|
10
|
+
}
|
|
11
|
+
function fingerprintOf(hostKey) {
|
|
12
|
+
return "SHA256:" + crypto.createHash("sha256").update(hostKey).digest("base64").replace(/=+$/, "");
|
|
13
|
+
}
|
|
14
|
+
export class SshTarget {
|
|
15
|
+
info;
|
|
16
|
+
client = null;
|
|
17
|
+
connecting = null;
|
|
18
|
+
constructor(info) {
|
|
19
|
+
this.info = info;
|
|
20
|
+
}
|
|
21
|
+
buildConfig() {
|
|
22
|
+
const cfg = {
|
|
23
|
+
host: this.info.host,
|
|
24
|
+
port: this.info.port,
|
|
25
|
+
username: this.info.username,
|
|
26
|
+
keepaliveInterval: 15000,
|
|
27
|
+
hostVerifier: (hostKey) => {
|
|
28
|
+
const fp = fingerprintOf(hostKey);
|
|
29
|
+
if (this.info.hostFingerprint)
|
|
30
|
+
return fp === this.info.hostFingerprint;
|
|
31
|
+
this.info.onFingerprint?.(fp);
|
|
32
|
+
return true;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
if (this.info.auth === "agent") {
|
|
36
|
+
cfg.agent = process.env.SSH_AUTH_SOCK;
|
|
37
|
+
}
|
|
38
|
+
else if (this.info.auth === "key_path") {
|
|
39
|
+
cfg.privateKey = fs.readFileSync(this.info.keyPath);
|
|
40
|
+
if (this.info.vaultRef) {
|
|
41
|
+
const secret = JSON.parse(vaultGet(this.info.vaultRef));
|
|
42
|
+
if (secret.passphrase)
|
|
43
|
+
cfg.passphrase = secret.passphrase;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const secret = JSON.parse(vaultGet(this.info.vaultRef));
|
|
48
|
+
cfg.privateKey = secret.privateKey;
|
|
49
|
+
if (secret.passphrase)
|
|
50
|
+
cfg.passphrase = secret.passphrase;
|
|
51
|
+
}
|
|
52
|
+
return cfg;
|
|
53
|
+
}
|
|
54
|
+
connect() {
|
|
55
|
+
if (this.client)
|
|
56
|
+
return Promise.resolve(this.client);
|
|
57
|
+
if (this.connecting)
|
|
58
|
+
return this.connecting;
|
|
59
|
+
this.connecting = new Promise((resolve, reject) => {
|
|
60
|
+
const conn = new Client();
|
|
61
|
+
conn.on("ready", () => {
|
|
62
|
+
this.client = conn;
|
|
63
|
+
resolve(conn);
|
|
64
|
+
});
|
|
65
|
+
conn.on("error", (e) => {
|
|
66
|
+
this.connecting = null;
|
|
67
|
+
reject(e);
|
|
68
|
+
});
|
|
69
|
+
conn.on("close", () => {
|
|
70
|
+
this.client = null;
|
|
71
|
+
this.connecting = null;
|
|
72
|
+
});
|
|
73
|
+
conn.connect(this.buildConfig());
|
|
74
|
+
});
|
|
75
|
+
return this.connecting;
|
|
76
|
+
}
|
|
77
|
+
async exec(cmd) {
|
|
78
|
+
const conn = await this.connect();
|
|
79
|
+
return new Promise((resolve, reject) => {
|
|
80
|
+
conn.exec(shellJoin(cmd), (err, stream) => {
|
|
81
|
+
if (err)
|
|
82
|
+
return reject(err);
|
|
83
|
+
let stdout = "";
|
|
84
|
+
let stderr = "";
|
|
85
|
+
stream.on("data", (d) => {
|
|
86
|
+
stdout += d.toString();
|
|
87
|
+
});
|
|
88
|
+
stream.stderr.on("data", (d) => {
|
|
89
|
+
stderr += d.toString();
|
|
90
|
+
});
|
|
91
|
+
stream.on("close", (code) => {
|
|
92
|
+
resolve({ stdout, stderr, exitCode: code ?? 0 });
|
|
93
|
+
});
|
|
94
|
+
stream.on("error", reject);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
async openPty(cmd, cols, rows) {
|
|
99
|
+
const conn = await this.connect();
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
conn.exec(shellJoin(cmd), { pty: { cols, rows, term: "xterm-256color" } }, (err, stream) => {
|
|
102
|
+
if (err)
|
|
103
|
+
return reject(err);
|
|
104
|
+
resolve({
|
|
105
|
+
stream: stream,
|
|
106
|
+
resize: (c, r) => {
|
|
107
|
+
stream.setWindow(r, c, 0, 0);
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
async dispose() {
|
|
114
|
+
if (this.client) {
|
|
115
|
+
this.client.end();
|
|
116
|
+
this.client = null;
|
|
117
|
+
}
|
|
118
|
+
this.connecting = null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=ssh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh.js","sourceRoot":"","sources":["../../src/targets/ssh.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Duplex } from "node:stream";
|
|
2
|
+
export interface ExecResult {
|
|
3
|
+
stdout: string;
|
|
4
|
+
stderr: string;
|
|
5
|
+
exitCode: number;
|
|
6
|
+
}
|
|
7
|
+
export interface PtySession {
|
|
8
|
+
stream: Duplex;
|
|
9
|
+
resize(cols: number, rows: number): Promise<void> | void;
|
|
10
|
+
}
|
|
11
|
+
export interface PodTarget {
|
|
12
|
+
exec(cmd: string[]): Promise<ExecResult>;
|
|
13
|
+
openPty(cmd: string[], cols: number, rows: number): Promise<PtySession>;
|
|
14
|
+
dispose?(): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/targets/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
export function validateInitData(initData, botToken, maxAgeSec) {
|
|
3
|
+
if (!initData)
|
|
4
|
+
return { ok: false, reason: "empty" };
|
|
5
|
+
if (!botToken)
|
|
6
|
+
return { ok: false, reason: "no_token" };
|
|
7
|
+
const params = new URLSearchParams(initData);
|
|
8
|
+
const hash = params.get("hash");
|
|
9
|
+
if (!hash)
|
|
10
|
+
return { ok: false, reason: "no_hash" };
|
|
11
|
+
params.delete("hash");
|
|
12
|
+
const dataCheckString = [...params.entries()]
|
|
13
|
+
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
|
|
14
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
15
|
+
.join("\n");
|
|
16
|
+
const secretKey = crypto.createHmac("sha256", "WebAppData").update(botToken).digest();
|
|
17
|
+
const computed = crypto.createHmac("sha256", secretKey).update(dataCheckString).digest("hex");
|
|
18
|
+
const a = Buffer.from(computed, "hex");
|
|
19
|
+
const b = Buffer.from(hash, "hex");
|
|
20
|
+
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
|
|
21
|
+
return { ok: false, reason: "bad_hash" };
|
|
22
|
+
}
|
|
23
|
+
const authDate = Number(params.get("auth_date"));
|
|
24
|
+
if (maxAgeSec > 0 && authDate > 0) {
|
|
25
|
+
const ageSec = Date.now() / 1000 - authDate;
|
|
26
|
+
if (ageSec > maxAgeSec)
|
|
27
|
+
return { ok: false, reason: "expired" };
|
|
28
|
+
}
|
|
29
|
+
let userId;
|
|
30
|
+
let username;
|
|
31
|
+
try {
|
|
32
|
+
const user = JSON.parse(params.get("user") ?? "{}");
|
|
33
|
+
if (typeof user.id === "number")
|
|
34
|
+
userId = user.id;
|
|
35
|
+
if (typeof user.username === "string")
|
|
36
|
+
username = user.username;
|
|
37
|
+
}
|
|
38
|
+
catch { }
|
|
39
|
+
return { ok: true, userId, username };
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=telegram-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram-auth.js","sourceRoot":"","sources":["../src/telegram-auth.ts"],"names":[],"mappings":"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"}
|
package/dist/vault.d.ts
ADDED
package/dist/vault.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { paths } from "./paths.js";
|
|
5
|
+
const VAULT_DIR = paths.vault;
|
|
6
|
+
function masterKey() {
|
|
7
|
+
const b64 = process.env.PAIRPOD_VAULT_KEY;
|
|
8
|
+
if (!b64)
|
|
9
|
+
return null;
|
|
10
|
+
const key = Buffer.from(b64, "base64");
|
|
11
|
+
if (key.length !== 32) {
|
|
12
|
+
throw new Error("PAIRPOD_VAULT_KEY must decode to 32 bytes (base64)");
|
|
13
|
+
}
|
|
14
|
+
return key;
|
|
15
|
+
}
|
|
16
|
+
export function vaultEnabled() {
|
|
17
|
+
return masterKey() !== null;
|
|
18
|
+
}
|
|
19
|
+
function refPath(ref) {
|
|
20
|
+
return path.join(VAULT_DIR, `${ref}.json`);
|
|
21
|
+
}
|
|
22
|
+
export function vaultPut(plaintext) {
|
|
23
|
+
const key = masterKey();
|
|
24
|
+
if (!key)
|
|
25
|
+
throw new Error("vault disabled (PAIRPOD_VAULT_KEY unset)");
|
|
26
|
+
const ref = crypto.randomUUID();
|
|
27
|
+
const iv = crypto.randomBytes(12);
|
|
28
|
+
const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
|
|
29
|
+
const data = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
|
|
30
|
+
const entry = {
|
|
31
|
+
iv: iv.toString("base64"),
|
|
32
|
+
tag: cipher.getAuthTag().toString("base64"),
|
|
33
|
+
data: data.toString("base64"),
|
|
34
|
+
};
|
|
35
|
+
fs.mkdirSync(VAULT_DIR, { recursive: true, mode: 0o700 });
|
|
36
|
+
fs.writeFileSync(refPath(ref), JSON.stringify(entry), { mode: 0o600 });
|
|
37
|
+
return ref;
|
|
38
|
+
}
|
|
39
|
+
export function vaultGet(ref) {
|
|
40
|
+
const key = masterKey();
|
|
41
|
+
if (!key)
|
|
42
|
+
throw new Error("vault disabled (PAIRPOD_VAULT_KEY unset)");
|
|
43
|
+
const entry = JSON.parse(fs.readFileSync(refPath(ref), "utf8"));
|
|
44
|
+
const decipher = crypto.createDecipheriv("aes-256-gcm", key, Buffer.from(entry.iv, "base64"));
|
|
45
|
+
decipher.setAuthTag(Buffer.from(entry.tag, "base64"));
|
|
46
|
+
return Buffer.concat([
|
|
47
|
+
decipher.update(Buffer.from(entry.data, "base64")),
|
|
48
|
+
decipher.final(),
|
|
49
|
+
]).toString("utf8");
|
|
50
|
+
}
|
|
51
|
+
export function vaultRemove(ref) {
|
|
52
|
+
try {
|
|
53
|
+
fs.rmSync(refPath(ref));
|
|
54
|
+
}
|
|
55
|
+
catch { }
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=vault.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vault.js","sourceRoot":"","sources":["../src/vault.ts"],"names":[],"mappings":"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"}
|