@hotfusion/cipher 0.0.1
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/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/cipher.d.ts +122 -0
- package/dist/lib/cipher.d.ts.map +1 -0
- package/dist/lib/cipher.js +362 -0
- package/dist/lib/cipher.js.map +1 -0
- package/dist/lib/luks.d.ts +49 -0
- package/dist/lib/luks.d.ts.map +1 -0
- package/dist/lib/luks.js +302 -0
- package/dist/lib/luks.js.map +1 -0
- package/package.json +66 -0
- package/readme.md +369 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { Cipher } from "./lib/cipher";
|
|
2
|
+
export { CipherError } from "./lib/cipher";
|
|
3
|
+
export { Luks } from "./lib/luks";
|
|
4
|
+
export type { ICipherConfig, ICipherLevel, ISecret, ISecretKey, ISecretResult, ICollection } from "./lib/cipher";
|
|
5
|
+
export type { ILuks } from "./lib/luks";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAC,MAAM,cAAc,CAAA;AACnC,OAAO,EAAC,WAAW,EAAC,MAAM,cAAc,CAAA;AACxC,OAAO,EAAC,IAAI,EAAC,MAAM,YAAY,CAAA;AAI/B,YAAY,EACR,aAAa,EACb,YAAY,EACZ,OAAO,EACP,UAAU,EACV,aAAa,EACb,WAAW,EACd,MAAM,cAAc,CAAA;AAErB,YAAY,EACR,KAAK,EACR,MAAM,YAAY,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Luks = exports.CipherError = exports.Cipher = void 0;
|
|
4
|
+
var cipher_1 = require("./lib/cipher");
|
|
5
|
+
Object.defineProperty(exports, "Cipher", { enumerable: true, get: function () { return cipher_1.Cipher; } });
|
|
6
|
+
var cipher_2 = require("./lib/cipher");
|
|
7
|
+
Object.defineProperty(exports, "CipherError", { enumerable: true, get: function () { return cipher_2.CipherError; } });
|
|
8
|
+
var luks_1 = require("./lib/luks");
|
|
9
|
+
Object.defineProperty(exports, "Luks", { enumerable: true, get: function () { return luks_1.Luks; } });
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,uCAAmC;AAA3B,gGAAA,MAAM,OAAA;AACd,uCAAwC;AAAhC,qGAAA,WAAW,OAAA;AACnB,mCAA+B;AAAvB,4FAAA,IAAI,OAAA"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { Luks, LuksError } from './luks';
|
|
2
|
+
export type ICipherLevel = 0 | 1 | 2;
|
|
3
|
+
export interface ICipherConfig {
|
|
4
|
+
readonly?: boolean;
|
|
5
|
+
path: string;
|
|
6
|
+
password: string;
|
|
7
|
+
level?: ICipherLevel;
|
|
8
|
+
size?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface ISecret {
|
|
11
|
+
id: string;
|
|
12
|
+
secret: any;
|
|
13
|
+
version: number;
|
|
14
|
+
keyName?: string;
|
|
15
|
+
meta?: {
|
|
16
|
+
readonly?: boolean;
|
|
17
|
+
version?: number;
|
|
18
|
+
__created?: number;
|
|
19
|
+
__updated?: number;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export interface ISecretKey {
|
|
23
|
+
id: string;
|
|
24
|
+
keyName?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface ISecretResult {
|
|
27
|
+
key: {
|
|
28
|
+
[key: string]: string;
|
|
29
|
+
};
|
|
30
|
+
meta: {
|
|
31
|
+
version: number;
|
|
32
|
+
readonly?: boolean;
|
|
33
|
+
};
|
|
34
|
+
_id: number;
|
|
35
|
+
}
|
|
36
|
+
export interface ICollection {
|
|
37
|
+
name: string;
|
|
38
|
+
schema?: any;
|
|
39
|
+
}
|
|
40
|
+
export declare class CipherError extends Error {
|
|
41
|
+
code: string;
|
|
42
|
+
details?: string;
|
|
43
|
+
constructor(code: string, message: string, details?: string);
|
|
44
|
+
}
|
|
45
|
+
interface LokiCollection {
|
|
46
|
+
name: string;
|
|
47
|
+
insert(doc: any): any;
|
|
48
|
+
find(query?: any): any[];
|
|
49
|
+
findAndRemove(query?: any): void;
|
|
50
|
+
get(id: number): any;
|
|
51
|
+
chain(): {
|
|
52
|
+
find(query?: any): {
|
|
53
|
+
simplesort(prop: string, isDesc?: boolean): {
|
|
54
|
+
data(): any[];
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
findOne(query: any): any | null;
|
|
59
|
+
update(doc: any): void;
|
|
60
|
+
data: any[];
|
|
61
|
+
idIndex: number[] | null;
|
|
62
|
+
binaryIndices: {
|
|
63
|
+
[key: string]: {
|
|
64
|
+
name: string;
|
|
65
|
+
dirty: boolean;
|
|
66
|
+
values: number[];
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
uniqueNames: string[];
|
|
70
|
+
}
|
|
71
|
+
declare class SecretCollection {
|
|
72
|
+
private ajv;
|
|
73
|
+
private cipher;
|
|
74
|
+
private collection;
|
|
75
|
+
private schema;
|
|
76
|
+
constructor(cipher: Cipher, collection: LokiCollection, schema: {
|
|
77
|
+
keySchema?: any;
|
|
78
|
+
});
|
|
79
|
+
private validateKey;
|
|
80
|
+
insert(key: ISecretKey, secret: any, meta?: {
|
|
81
|
+
readonly?: boolean;
|
|
82
|
+
version?: number;
|
|
83
|
+
}): Promise<void>;
|
|
84
|
+
update(key: ISecretKey, secret: any, meta?: {
|
|
85
|
+
readonly?: boolean;
|
|
86
|
+
version?: number;
|
|
87
|
+
}): Promise<void>;
|
|
88
|
+
delete(key: ISecretKey, meta?: {
|
|
89
|
+
readonly?: boolean;
|
|
90
|
+
}): Promise<void>;
|
|
91
|
+
find(key: ISecretKey): ISecretResult | null;
|
|
92
|
+
unseal(id: string): any;
|
|
93
|
+
list(): Array<{
|
|
94
|
+
key: {
|
|
95
|
+
[key: string]: string;
|
|
96
|
+
};
|
|
97
|
+
meta: {
|
|
98
|
+
version: number;
|
|
99
|
+
readonly?: boolean;
|
|
100
|
+
};
|
|
101
|
+
}>;
|
|
102
|
+
}
|
|
103
|
+
export declare class Cipher {
|
|
104
|
+
private settings;
|
|
105
|
+
private collections;
|
|
106
|
+
private loki;
|
|
107
|
+
private readyPromise;
|
|
108
|
+
private luks?;
|
|
109
|
+
private mounted;
|
|
110
|
+
constructor(settings: ICipherConfig, collections?: ICollection[]);
|
|
111
|
+
private databaseInitialize;
|
|
112
|
+
canWrite(meta: any): boolean;
|
|
113
|
+
save(): Promise<void>;
|
|
114
|
+
collection(name: string): SecretCollection;
|
|
115
|
+
ready(): Promise<void>;
|
|
116
|
+
changePassword(oldPassword: string, newPassword: string): Promise<void>;
|
|
117
|
+
unmount(): Promise<void>;
|
|
118
|
+
getInfo(): any;
|
|
119
|
+
isMounted(): boolean;
|
|
120
|
+
}
|
|
121
|
+
export { Luks, LuksError };
|
|
122
|
+
//# sourceMappingURL=cipher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cipher.d.ts","sourceRoot":"","sources":["../../src/lib/cipher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.LuksError = exports.Luks = exports.Cipher = exports.CipherError = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const crypto = __importStar(require("crypto"));
|
|
39
|
+
//@ts-ignore
|
|
40
|
+
const Loki = __importStar(require("lokijs"));
|
|
41
|
+
const Ajv = __importStar(require("ajv"));
|
|
42
|
+
const luks_1 = require("./luks");
|
|
43
|
+
Object.defineProperty(exports, "Luks", { enumerable: true, get: function () { return luks_1.Luks; } });
|
|
44
|
+
Object.defineProperty(exports, "LuksError", { enumerable: true, get: function () { return luks_1.LuksError; } });
|
|
45
|
+
// ?? Encryption constants ??????????????????????????????????????????????????????
|
|
46
|
+
const algorithm = 'aes-256-gcm';
|
|
47
|
+
const keyLen = 32;
|
|
48
|
+
const ivLen = 12;
|
|
49
|
+
const saltLen = 16;
|
|
50
|
+
const tagLen = 16;
|
|
51
|
+
// ?? Errors ??????????????????????????????????????????????????????????????????
|
|
52
|
+
class CipherError extends Error {
|
|
53
|
+
constructor(code, message, details) {
|
|
54
|
+
super(message);
|
|
55
|
+
this.code = code;
|
|
56
|
+
this.details = details;
|
|
57
|
+
this.name = 'CipherError';
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.CipherError = CipherError;
|
|
61
|
+
// ?? Encrypted LokiJS adapter ??????????????????????????????????????????????????
|
|
62
|
+
class EncryptedFsAdapter {
|
|
63
|
+
constructor(password) {
|
|
64
|
+
this.password = password;
|
|
65
|
+
}
|
|
66
|
+
deriveKey(salt) {
|
|
67
|
+
return crypto.pbkdf2Sync(this.password, salt, 100000, keyLen, 'sha256');
|
|
68
|
+
}
|
|
69
|
+
loadDatabase(dbname, callback) {
|
|
70
|
+
if (!fs.existsSync(dbname)) {
|
|
71
|
+
return callback(null, '{}');
|
|
72
|
+
}
|
|
73
|
+
fs.readFile(dbname, (err, data) => {
|
|
74
|
+
if (err)
|
|
75
|
+
return callback(err);
|
|
76
|
+
try {
|
|
77
|
+
const salt = data.slice(0, saltLen);
|
|
78
|
+
const iv = data.slice(saltLen, saltLen + ivLen);
|
|
79
|
+
const tag = data.slice(saltLen + ivLen, saltLen + ivLen + tagLen);
|
|
80
|
+
const encrypted = data.slice(saltLen + ivLen + tagLen);
|
|
81
|
+
const key = this.deriveKey(salt);
|
|
82
|
+
const decipher = crypto.createDecipheriv(algorithm, key, iv);
|
|
83
|
+
decipher.setAuthTag(tag);
|
|
84
|
+
let decrypted = decipher.update(encrypted, undefined, 'utf8');
|
|
85
|
+
decrypted += decipher.final('utf8');
|
|
86
|
+
callback(null, decrypted);
|
|
87
|
+
}
|
|
88
|
+
catch (e) {
|
|
89
|
+
callback(e);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
saveDatabase(dbname, dbstring, callback) {
|
|
94
|
+
try {
|
|
95
|
+
const salt = crypto.randomBytes(saltLen);
|
|
96
|
+
const iv = crypto.randomBytes(ivLen);
|
|
97
|
+
const key = this.deriveKey(salt);
|
|
98
|
+
const cipher = crypto.createCipheriv(algorithm, key, iv);
|
|
99
|
+
let encrypted = cipher.update(dbstring, 'utf8');
|
|
100
|
+
encrypted = Buffer.concat([encrypted, cipher.final()]);
|
|
101
|
+
const tag = cipher.getAuthTag();
|
|
102
|
+
const data = Buffer.concat([salt, iv, tag, encrypted]);
|
|
103
|
+
fs.writeFile(dbname, data, (err) => {
|
|
104
|
+
if (err)
|
|
105
|
+
return callback(err);
|
|
106
|
+
callback(null);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
catch (e) {
|
|
110
|
+
callback(e);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// ?? SecretCollection ????????????????????????????????????????????????????????
|
|
115
|
+
class SecretCollection {
|
|
116
|
+
constructor(cipher, collection, schema) {
|
|
117
|
+
this.cipher = cipher;
|
|
118
|
+
this.collection = collection;
|
|
119
|
+
this.schema = schema;
|
|
120
|
+
this.ajv = new Ajv.default({ allErrors: true });
|
|
121
|
+
}
|
|
122
|
+
validateKey(key) {
|
|
123
|
+
if (this.schema?.keySchema) {
|
|
124
|
+
const validate = this.ajv.compile(this.schema.keySchema);
|
|
125
|
+
if (!validate(key))
|
|
126
|
+
throw new CipherError('KEY_VALIDATION_FAILED', 'Key validation failed', JSON.stringify(validate.errors, null, 2));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async insert(key, secret, meta = {}) {
|
|
130
|
+
if (!this.cipher.canWrite(meta))
|
|
131
|
+
throw new CipherError('READONLY_MODE', 'Cannot insert: cipher is in readonly mode');
|
|
132
|
+
this.validateKey(key);
|
|
133
|
+
const id = key.id;
|
|
134
|
+
const keyName = key.keyName || 'id';
|
|
135
|
+
const existing = this.collection.findOne({ id });
|
|
136
|
+
if (existing)
|
|
137
|
+
throw new CipherError('KEY_EXISTS', `Secret with id "${id}" already exists; use update instead`);
|
|
138
|
+
const version = meta.version ?? 1;
|
|
139
|
+
if (version < 1)
|
|
140
|
+
throw new CipherError('INVALID_VERSION', 'Version must be at least 1');
|
|
141
|
+
this.collection.insert({
|
|
142
|
+
id,
|
|
143
|
+
secret,
|
|
144
|
+
version,
|
|
145
|
+
keyName,
|
|
146
|
+
meta: { ...meta, version, __created: Date.now(), __updated: Date.now() },
|
|
147
|
+
});
|
|
148
|
+
await this.cipher.save();
|
|
149
|
+
}
|
|
150
|
+
async update(key, secret, meta = {}) {
|
|
151
|
+
if (!this.cipher.canWrite(meta))
|
|
152
|
+
throw new CipherError('READONLY_MODE', 'Cannot update: cipher is in readonly mode');
|
|
153
|
+
this.validateKey(key);
|
|
154
|
+
const id = key.id;
|
|
155
|
+
const existing = this.collection.findOne({ id });
|
|
156
|
+
if (!existing)
|
|
157
|
+
throw new CipherError('KEY_NOT_FOUND', `Secret with id "${id}" not found; use insert instead`);
|
|
158
|
+
const newVersion = meta.version ?? existing.version + 1;
|
|
159
|
+
if (newVersion <= existing.version)
|
|
160
|
+
throw new CipherError('INVALID_VERSION', `Version must be higher than current (${existing.version})`);
|
|
161
|
+
existing.secret = secret;
|
|
162
|
+
existing.version = newVersion;
|
|
163
|
+
existing.meta = { ...existing.meta, ...meta, version: newVersion, __updated: Date.now() };
|
|
164
|
+
this.collection.update(existing);
|
|
165
|
+
await this.cipher.save();
|
|
166
|
+
}
|
|
167
|
+
async delete(key, meta = {}) {
|
|
168
|
+
if (!this.cipher.canWrite(meta))
|
|
169
|
+
throw new CipherError('READONLY_MODE', 'Cannot delete: cipher is in readonly mode');
|
|
170
|
+
this.validateKey(key);
|
|
171
|
+
this.collection.findAndRemove({ id: key.id });
|
|
172
|
+
await this.cipher.save();
|
|
173
|
+
}
|
|
174
|
+
find(key) {
|
|
175
|
+
this.validateKey(key);
|
|
176
|
+
const existing = this.collection.findOne({ id: key.id });
|
|
177
|
+
if (!existing)
|
|
178
|
+
return null;
|
|
179
|
+
const keyName = existing.keyName || 'id';
|
|
180
|
+
return {
|
|
181
|
+
key: { [keyName]: existing.id },
|
|
182
|
+
meta: { version: existing.version, readonly: existing.meta.readonly },
|
|
183
|
+
_id: existing.$loki,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
unseal(id) {
|
|
187
|
+
const doc = this.collection.findOne({ id });
|
|
188
|
+
if (!doc)
|
|
189
|
+
throw new CipherError('KEY_NOT_FOUND', `Secret with id "${id}" not found`);
|
|
190
|
+
return doc.secret;
|
|
191
|
+
}
|
|
192
|
+
list() {
|
|
193
|
+
return this.collection.find().map(doc => ({
|
|
194
|
+
key: { [doc.keyName || 'id']: doc.id },
|
|
195
|
+
meta: { version: doc.version, readonly: doc.meta.readonly },
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// ?? Cipher ??????????????????????????????????????????????????????????????????
|
|
200
|
+
class Cipher {
|
|
201
|
+
constructor(settings, collections = [{ name: 'secrets', schema: {} }]) {
|
|
202
|
+
this.mounted = false;
|
|
203
|
+
this.collections = new Map();
|
|
204
|
+
// Password can come from:
|
|
205
|
+
// 1. settings.password
|
|
206
|
+
// 2. --password=xxx CLI argument
|
|
207
|
+
// 3. CIPHER_PASSWORD env variable
|
|
208
|
+
const cliPassword = process.argv.find(arg => arg.startsWith('--password='))?.split('=')[1];
|
|
209
|
+
settings.password = settings.password || cliPassword || process.env.CIPHER_PASSWORD || '';
|
|
210
|
+
if (!settings.password) {
|
|
211
|
+
throw new CipherError('NO_PASSWORD', 'Cipher requires a password. Pass it via settings.password, --password=xxx CLI arg, or CIPHER_PASSWORD env variable.');
|
|
212
|
+
}
|
|
213
|
+
// Validate password strength
|
|
214
|
+
if (settings.password.length < 12) {
|
|
215
|
+
throw new CipherError('WEAK_PASSWORD', 'Password must be at least 12 characters');
|
|
216
|
+
}
|
|
217
|
+
this.settings = settings;
|
|
218
|
+
const level = settings.level ?? 0;
|
|
219
|
+
try {
|
|
220
|
+
// ?? Level 0: plain encrypted file ?????????????????????????????????????
|
|
221
|
+
if (level === 0) {
|
|
222
|
+
if (!fs.existsSync(settings.path))
|
|
223
|
+
fs.mkdirSync(settings.path, { recursive: true, mode: 0o700 });
|
|
224
|
+
}
|
|
225
|
+
// ?? Level 1: LUKS container + encrypted file ??????????????????????????
|
|
226
|
+
else if (level === 1) {
|
|
227
|
+
if (!settings.size) {
|
|
228
|
+
throw new CipherError('MISSING_SIZE', 'Cipher level 1 requires a size (MB) for the LUKS container');
|
|
229
|
+
}
|
|
230
|
+
this.luks = new luks_1.Luks(settings.path, {
|
|
231
|
+
size: settings.size,
|
|
232
|
+
password: settings.password,
|
|
233
|
+
locked: settings.readonly ?? false,
|
|
234
|
+
});
|
|
235
|
+
this.luks.mount();
|
|
236
|
+
this.mounted = true;
|
|
237
|
+
}
|
|
238
|
+
// ?? Level 2: VM-level isolation (future) ??????????????????????????????
|
|
239
|
+
else if (level === 2) {
|
|
240
|
+
throw new CipherError('NOT_IMPLEMENTED', 'Cipher level 2 (VM-level isolation) is not yet implemented');
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
throw new CipherError('INVALID_LEVEL', `Unknown cipher level: ${level}`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
catch (err) {
|
|
247
|
+
if (err instanceof CipherError)
|
|
248
|
+
throw err;
|
|
249
|
+
if (err instanceof luks_1.LuksError) {
|
|
250
|
+
throw new CipherError('LUKS_ERROR', `LUKS initialization failed: ${err.message}`, err.details);
|
|
251
|
+
}
|
|
252
|
+
throw err;
|
|
253
|
+
}
|
|
254
|
+
const adapter = new EncryptedFsAdapter(settings.password);
|
|
255
|
+
let resolveReady;
|
|
256
|
+
let rejectReady;
|
|
257
|
+
this.readyPromise = new Promise((res, rej) => {
|
|
258
|
+
resolveReady = res;
|
|
259
|
+
rejectReady = rej;
|
|
260
|
+
});
|
|
261
|
+
const dbPath = `${settings.path}/database.db`;
|
|
262
|
+
this.loki = new (Loki.default || Loki)(dbPath, {
|
|
263
|
+
adapter,
|
|
264
|
+
autoload: true,
|
|
265
|
+
autosave: false,
|
|
266
|
+
autoloadCallback: (err) => {
|
|
267
|
+
if (err) {
|
|
268
|
+
rejectReady(err);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
this.databaseInitialize(collections);
|
|
272
|
+
resolveReady();
|
|
273
|
+
},
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
databaseInitialize(collections) {
|
|
277
|
+
for (const col of collections) {
|
|
278
|
+
let collection = this.loki.getCollection(col.name);
|
|
279
|
+
if (!collection) {
|
|
280
|
+
collection = this.loki.addCollection(col.name, {
|
|
281
|
+
indices: ['id', 'version'],
|
|
282
|
+
unique: ['id'],
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
this.collections.set(col.name, { collection, schema: col.schema });
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
canWrite(meta) {
|
|
289
|
+
const readonlyOverride = meta.hasOwnProperty('readonly') ? meta.readonly : this.settings.readonly;
|
|
290
|
+
return !readonlyOverride;
|
|
291
|
+
}
|
|
292
|
+
async save() {
|
|
293
|
+
return new Promise((resolve, reject) => {
|
|
294
|
+
this.loki.saveDatabase((err) => {
|
|
295
|
+
if (err)
|
|
296
|
+
reject(err);
|
|
297
|
+
else
|
|
298
|
+
resolve();
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
collection(name) {
|
|
303
|
+
const col = this.collections.get(name);
|
|
304
|
+
if (!col)
|
|
305
|
+
throw new CipherError('COLLECTION_NOT_FOUND', `Collection "${name}" not found`);
|
|
306
|
+
return new SecretCollection(this, col.collection, col.schema);
|
|
307
|
+
}
|
|
308
|
+
async ready() {
|
|
309
|
+
return this.readyPromise;
|
|
310
|
+
}
|
|
311
|
+
async changePassword(oldPassword, newPassword) {
|
|
312
|
+
if (newPassword.length < 12) {
|
|
313
|
+
throw new CipherError('WEAK_PASSWORD', 'New password must be at least 12 characters');
|
|
314
|
+
}
|
|
315
|
+
if (this.settings.level === 1 && this.luks) {
|
|
316
|
+
try {
|
|
317
|
+
await this.luks.changePassword(oldPassword, newPassword);
|
|
318
|
+
this.settings.password = newPassword;
|
|
319
|
+
}
|
|
320
|
+
catch (err) {
|
|
321
|
+
if (err instanceof luks_1.LuksError) {
|
|
322
|
+
throw new CipherError('PASSWORD_CHANGE_FAILED', `Failed to change password: ${err.message}`, err.details);
|
|
323
|
+
}
|
|
324
|
+
throw err;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
// For level 0, we would need to re-encrypt the database file
|
|
329
|
+
// This is a placeholder - implement if needed
|
|
330
|
+
throw new CipherError('NOT_IMPLEMENTED', 'Password change for level 0 encryption not yet implemented');
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
async unmount() {
|
|
334
|
+
if (this.luks && this.mounted) {
|
|
335
|
+
try {
|
|
336
|
+
this.luks.unmount();
|
|
337
|
+
this.mounted = false;
|
|
338
|
+
}
|
|
339
|
+
catch (err) {
|
|
340
|
+
if (err instanceof luks_1.LuksError) {
|
|
341
|
+
throw new CipherError('UNMOUNT_FAILED', `Failed to unmount: ${err.message}`, err.details);
|
|
342
|
+
}
|
|
343
|
+
throw err;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
getInfo() {
|
|
348
|
+
return {
|
|
349
|
+
level: this.settings.level ?? 0,
|
|
350
|
+
path: this.settings.path,
|
|
351
|
+
readonly: this.settings.readonly ?? false,
|
|
352
|
+
mounted: this.mounted,
|
|
353
|
+
collections: Array.from(this.collections.keys()),
|
|
354
|
+
luks: this.luks?.getInfo() ?? null,
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
isMounted() {
|
|
358
|
+
return this.mounted;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
exports.Cipher = Cipher;
|
|
362
|
+
//# sourceMappingURL=cipher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cipher.js","sourceRoot":"","sources":["../../src/lib/cipher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,+CAAiC;AACjC,YAAY;AACZ,6CAA+B;AAC/B,yCAA2B;AAC3B,iCAAyC;AA0chC,qFA1cA,WAAI,OA0cA;AAAE,0FA1cA,gBAAS,OA0cA;AAxcxB,iFAAiF;AAEjF,MAAM,SAAS,GAAG,aAAa,CAAC;AAChC,MAAM,MAAM,GAAG,EAAE,CAAC;AAClB,MAAM,KAAK,GAAG,EAAE,CAAC;AACjB,MAAM,OAAO,GAAG,EAAE,CAAC;AACnB,MAAM,MAAM,GAAG,EAAE,CAAC;AA2ClB,+EAA+E;AAE/E,MAAa,WAAY,SAAQ,KAAK;IAIlC,YAAY,IAAY,EAAE,OAAe,EAAE,OAAgB;QACvD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC9B,CAAC;CACJ;AAVD,kCAUC;AA0BD,iFAAiF;AAEjF,MAAM,kBAAkB;IAGpB,YAAY,QAAgB;QACxB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;IAEO,SAAS,CAAC,IAAY;QAC1B,OAAO,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC5E,CAAC;IAED,YAAY,CAAC,MAAc,EAAE,QAA2C;QACpE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACzB,OAAO,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAChC,CAAC;QACD,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;YAC9B,IAAI,GAAG;gBAAE,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;YAC9B,IAAI,CAAC;gBACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;gBACpC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,KAAK,CAAC,CAAC;gBAChD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,KAAK,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC,CAAC;gBAClE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC,CAAC;gBACvD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;gBACjC,MAAM,QAAQ,GAAG,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;gBAC7D,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;gBACzB,IAAI,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;gBAC9D,SAAS,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBACpC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAC9B,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACT,QAAQ,CAAC,CAAC,CAAC,CAAC;YAChB,CAAC;QACL,CAAC,CAAC,CAAC;IACP,CAAC;IAED,YAAY,CAAC,MAAc,EAAE,QAAgB,EAAE,QAA6B;QACxE,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YACzC,MAAM,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YACrC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;YACzD,IAAI,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YAChD,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YACvD,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;YAChC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC;YACvD,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE;gBAC/B,IAAI,GAAG;oBAAE,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;gBAC9B,QAAQ,CAAC,IAAI,CAAC,CAAC;YACnB,CAAC,CAAC,CAAC;QACP,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACT,QAAQ,CAAC,CAAC,CAAC,CAAC;QAChB,CAAC;IACL,CAAC;CACJ;AAED,+EAA+E;AAE/E,MAAM,gBAAgB;IAMlB,YAAY,MAAc,EAAE,UAA0B,EAAE,MAA2B;QAC/E,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC;IAEO,WAAW,CAAC,GAAQ;QACxB,IAAI,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACzD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;gBACd,MAAM,IAAI,WAAW,CACjB,uBAAuB,EACvB,uBAAuB,EACvB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAC3C,CAAC;QACV,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAe,EAAE,MAAW,EAAE,OAAiD,EAAE;QAC1F,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;YAC3B,MAAM,IAAI,WAAW,CAAC,eAAe,EAAE,2CAA2C,CAAC,CAAC;QAExF,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAEtB,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC;QAClB,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC;QACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAEjD,IAAI,QAAQ;YACR,MAAM,IAAI,WAAW,CAAC,YAAY,EAAE,mBAAmB,EAAE,sCAAsC,CAAC,CAAC;QAErG,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;QAClC,IAAI,OAAO,GAAG,CAAC;YACX,MAAM,IAAI,WAAW,CAAC,iBAAiB,EAAE,4BAA4B,CAAC,CAAC;QAE3E,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;YACnB,EAAE;YACF,MAAM;YACN,OAAO;YACP,OAAO;YACP,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE;SAC3E,CAAC,CAAC;QAEH,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAe,EAAE,MAAW,EAAE,OAAiD,EAAE;QAC1F,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;YAC3B,MAAM,IAAI,WAAW,CAAC,eAAe,EAAE,2CAA2C,CAAC,CAAC;QAExF,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAEtB,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC;QAClB,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAEjD,IAAI,CAAC,QAAQ;YACT,MAAM,IAAI,WAAW,CAAC,eAAe,EAAE,mBAAmB,EAAE,iCAAiC,CAAC,CAAC;QAEnG,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,GAAG,CAAC,CAAC;QACxD,IAAI,UAAU,IAAI,QAAQ,CAAC,OAAO;YAC9B,MAAM,IAAI,WAAW,CACjB,iBAAiB,EACjB,wCAAwC,QAAQ,CAAC,OAAO,GAAG,CAC9D,CAAC;QAEN,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC;QACzB,QAAQ,CAAC,OAAO,GAAG,UAAU,CAAC;QAC9B,QAAQ,CAAC,IAAI,GAAG,EAAE,GAAG,QAAQ,CAAC,IAAI,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAE1F,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACjC,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAe,EAAE,OAA+B,EAAE;QAC3D,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;YAC3B,MAAM,IAAI,WAAW,CAAC,eAAe,EAAE,2CAA2C,CAAC,CAAC;QAExF,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QAC9C,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAC7B,CAAC;IAED,IAAI,CAAC,GAAe;QAChB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAEtB,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QACzD,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAE3B,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,IAAI,IAAI,CAAC;QACzC,OAAO;YACH,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,EAAE,EAAE;YAC/B,IAAI,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE;YACrE,GAAG,EAAE,QAAQ,CAAC,KAAK;SACtB,CAAC;IACN,CAAC;IAED,MAAM,CAAC,EAAU;QACb,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,WAAW,CAAC,eAAe,EAAE,mBAAmB,EAAE,aAAa,CAAC,CAAC;QACrF,OAAO,GAAG,CAAC,MAAM,CAAC;IACtB,CAAC;IAED,IAAI;QACA,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACtC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE;YACtC,IAAI,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE;SAC9D,CAAC,CAAC,CAAC;IACR,CAAC;CACJ;AAED,+EAA+E;AAE/E,MAAa,MAAM;IAQf,YAAY,QAAuB,EAAE,cAA6B,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QAF3F,YAAO,GAAY,KAAK,CAAC;QAG7B,IAAI,CAAC,WAAW,GAAG,IAAI,GAAG,EAAE,CAAC;QAE7B,0BAA0B;QAC1B,yBAAyB;QACzB,mCAAmC;QACnC,oCAAoC;QACpC,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAE3F,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC,QAAQ,IAAI,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC;QAE1F,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACrB,MAAM,IAAI,WAAW,CACjB,aAAa,EACb,qHAAqH,CACxH,CAAC;QACN,CAAC;QAED,6BAA6B;QAC7B,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YAChC,MAAM,IAAI,WAAW,CAAC,eAAe,EAAE,yCAAyC,CAAC,CAAC;QACtF,CAAC;QAED,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAEzB,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC;QAElC,IAAI,CAAC;YACD,yEAAyE;YACzE,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBACd,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC;oBAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YACrG,CAAC;YAED,yEAAyE;iBACpE,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBACnB,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;oBACjB,MAAM,IAAI,WAAW,CAAC,cAAc,EAAE,4DAA4D,CAAC,CAAC;gBACxG,CAAC;gBAED,IAAI,CAAC,IAAI,GAAG,IAAI,WAAI,CAAC,QAAQ,CAAC,IAAI,EAAE;oBAChC,IAAI,EAAE,QAAQ,CAAC,IAAI;oBACnB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;oBAC3B,MAAM,EAAE,QAAQ,CAAC,QAAQ,IAAI,KAAK;iBACrC,CAAC,CAAC;gBAEH,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gBAClB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACxB,CAAC;YAED,yEAAyE;iBACpE,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBACnB,MAAM,IAAI,WAAW,CACjB,iBAAiB,EACjB,4DAA4D,CAC/D,CAAC;YACN,CAAC;iBAAM,CAAC;gBACJ,MAAM,IAAI,WAAW,CAAC,eAAe,EAAE,yBAAyB,KAAK,EAAE,CAAC,CAAC;YAC7E,CAAC;QACL,CAAC;QAAC,OAAO,GAAO,EAAE,CAAC;YACf,IAAI,GAAG,YAAY,WAAW;gBAAE,MAAM,GAAG,CAAC;YAC1C,IAAI,GAAG,YAAY,gBAAS,EAAE,CAAC;gBAC3B,MAAM,IAAI,WAAW,CAAC,YAAY,EAAE,+BAA+B,GAAG,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;YACnG,CAAC;YACD,MAAM,GAAG,CAAC;QACd,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,kBAAkB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAE1D,IAAI,YAAyB,CAAC;QAC9B,IAAI,WAAgC,CAAC;QACrC,IAAI,CAAC,YAAY,GAAG,IAAI,OAAO,CAAO,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YAC/C,YAAY,GAAG,GAAG,CAAC;YACnB,WAAW,GAAG,GAAG,CAAC;QACtB,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,cAAc,CAAC;QAE9C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,MAAM,EAAE;YAC3C,OAAO;YACP,QAAQ,EAAE,IAAI;YACd,QAAQ,EAAE,KAAK;YACf,gBAAgB,EAAE,CAAC,GAAS,EAAE,EAAE;gBAC5B,IAAI,GAAG,EAAE,CAAC;oBACN,WAAW,CAAC,GAAG,CAAC,CAAC;oBACjB,OAAO;gBACX,CAAC;gBACD,IAAI,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC;gBACrC,YAAY,EAAE,CAAC;YACnB,CAAC;SACJ,CAAC,CAAC;IACP,CAAC;IAEO,kBAAkB,CAAC,WAA0B;QACjD,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;YAC5B,IAAI,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACnD,IAAI,CAAC,UAAU,EAAE,CAAC;gBACd,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE;oBAC3C,OAAO,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC;oBAC1B,MAAM,EAAE,CAAC,IAAI,CAAC;iBACjB,CAAC,CAAC;YACP,CAAC;YACD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QACvE,CAAC;IACL,CAAC;IAED,QAAQ,CAAC,IAAS;QACd,MAAM,gBAAgB,GAAG,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAClG,OAAO,CAAC,gBAAgB,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,IAAI;QACN,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,EAAE;gBAC3B,IAAI,GAAG;oBAAE,MAAM,CAAC,GAAG,CAAC,CAAC;;oBAChB,OAAO,EAAE,CAAC;YACnB,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;IACP,CAAC;IAED,UAAU,CAAC,IAAY;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,WAAW,CAAC,sBAAsB,EAAE,eAAe,IAAI,aAAa,CAAC,CAAC;QAC1F,OAAO,IAAI,gBAAgB,CAAC,IAAI,EAAE,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,KAAK;QACP,OAAO,IAAI,CAAC,YAAY,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,WAAmB,EAAE,WAAmB;QACzD,IAAI,WAAW,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YAC1B,MAAM,IAAI,WAAW,CAAC,eAAe,EAAE,6CAA6C,CAAC,CAAC;QAC1F,CAAC;QAED,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACzC,IAAI,CAAC;gBACD,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;gBACzD,IAAI,CAAC,QAAQ,CAAC,QAAQ,GAAG,WAAW,CAAC;YACzC,CAAC;YAAC,OAAO,GAAO,EAAE,CAAC;gBACf,IAAI,GAAG,YAAY,gBAAS,EAAE,CAAC;oBAC3B,MAAM,IAAI,WAAW,CAAC,wBAAwB,EAAE,8BAA8B,GAAG,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC9G,CAAC;gBACD,MAAM,GAAG,CAAC;YACd,CAAC;QACL,CAAC;aAAM,CAAC;YACJ,6DAA6D;YAC7D,8CAA8C;YAC9C,MAAM,IAAI,WAAW,CACjB,iBAAiB,EACjB,4DAA4D,CAC/D,CAAC;QACN,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO;QACT,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC5B,IAAI,CAAC;gBACD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACpB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACzB,CAAC;YAAC,OAAO,GAAO,EAAE,CAAC;gBACf,IAAI,GAAG,YAAY,gBAAS,EAAE,CAAC;oBAC3B,MAAM,IAAI,WAAW,CAAC,gBAAgB,EAAE,sBAAsB,GAAG,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC9F,CAAC;gBACD,MAAM,GAAG,CAAC;YACd,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO;QACH,OAAO;YACH,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;YAC/B,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;YACxB,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,IAAI,KAAK;YACzC,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;YAChD,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,IAAI;SACrC,CAAC;IACN,CAAC;IAED,SAAS;QACL,OAAO,IAAI,CAAC,OAAO,CAAC;IACxB,CAAC;CACJ;AA9LD,wBA8LC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
interface IContainer {
|
|
2
|
+
size: number;
|
|
3
|
+
directory: string;
|
|
4
|
+
password: string;
|
|
5
|
+
locked: boolean;
|
|
6
|
+
}
|
|
7
|
+
export type ILuks = Omit<IContainer, 'directory'>;
|
|
8
|
+
export type IContainerSettings = Pick<IContainer, 'locked'>;
|
|
9
|
+
export interface ILuksError {
|
|
10
|
+
code: string;
|
|
11
|
+
message: string;
|
|
12
|
+
details?: string;
|
|
13
|
+
}
|
|
14
|
+
declare class LuksError extends Error implements ILuksError {
|
|
15
|
+
code: string;
|
|
16
|
+
details?: string;
|
|
17
|
+
constructor(code: string, message: string, details?: string);
|
|
18
|
+
}
|
|
19
|
+
declare class Container {
|
|
20
|
+
private config;
|
|
21
|
+
imagepath: string;
|
|
22
|
+
id: string;
|
|
23
|
+
constructor(config: IContainer);
|
|
24
|
+
getSettings(): IContainerSettings;
|
|
25
|
+
isMounted(): boolean;
|
|
26
|
+
private executeCommand;
|
|
27
|
+
mount(): void;
|
|
28
|
+
unmount(): Container;
|
|
29
|
+
delete(force?: boolean): Container;
|
|
30
|
+
resize(targetMB: number): Container;
|
|
31
|
+
changePassword(oldPassword: string, newPassword: string): Promise<Container>;
|
|
32
|
+
getInfo(): any;
|
|
33
|
+
}
|
|
34
|
+
export declare class Luks {
|
|
35
|
+
private directory;
|
|
36
|
+
private config;
|
|
37
|
+
container: Container;
|
|
38
|
+
constructor(directory: string, config: ILuks);
|
|
39
|
+
static list(): any[];
|
|
40
|
+
mount(): Luks;
|
|
41
|
+
unmount(): Luks;
|
|
42
|
+
delete(force?: boolean): Luks;
|
|
43
|
+
resize(size: number): Luks;
|
|
44
|
+
changePassword(oldPassword: string, newPassword: string): Promise<Luks>;
|
|
45
|
+
getInfo(): any;
|
|
46
|
+
isMounted(): boolean;
|
|
47
|
+
}
|
|
48
|
+
export { LuksError };
|
|
49
|
+
//# sourceMappingURL=luks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"luks.d.ts","sourceRoot":"","sources":["../../src/lib/luks.ts"],"names":[],"mappings":"AAMA,UAAU,UAAU;IAChB,IAAI,EAAQ,MAAM,CAAA;IAClB,SAAS,EAAG,MAAM,CAAA;IAClB,QAAQ,EAAI,MAAM,CAAA;IAClB,MAAM,EAAM,OAAO,CAAA;CACtB;AAED,MAAM,MAAM,KAAK,GAAgB,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AAC/D,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;AAE5D,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAID,cAAM,SAAU,SAAQ,KAAM,YAAW,UAAU;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;gBAEL,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;CAM9D;AAID,cAAM,SAAS;IACX,OAAO,CAAC,MAAM,CAAe;IAC7B,SAAS,EAAS,MAAM,CAAC;IACzB,EAAE,EAAgB,MAAM,CAAkB;gBAE9B,MAAM,EAAE,UAAU;IAW9B,WAAW,IAAI,kBAAkB;IAQjC,SAAS,IAAI,OAAO;IASpB,OAAO,CAAC,cAAc;IAiBtB,KAAK;IA+EL,OAAO,IAAI,SAAS;IAmBpB,MAAM,CAAC,KAAK,GAAE,OAAe,GAAG,SAAS;IA6BzC,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS;IA0D7B,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAqBlF,OAAO,IAAI,GAAG;CAejB;AAID,qBAAa,IAAI;IACb,OAAO,CAAC,SAAS,CAAU;IAC3B,OAAO,CAAC,MAAM,CAAY;IAC1B,SAAS,EAAW,SAAS,CAAC;gBAElB,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK;IAM5C,MAAM,CAAC,IAAI,IAAI,GAAG,EAAE;IAYpB,KAAK,IAAI,IAAI;IAKb,OAAO,IAAI,IAAI;IAKf,MAAM,CAAC,KAAK,GAAE,OAAe,GAAG,IAAI;IAKpC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKpB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7E,OAAO,IAAI,GAAG;IAId,SAAS,IAAI,OAAO;CAGvB;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
package/dist/lib/luks.js
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.LuksError = exports.Luks = void 0;
|
|
37
|
+
const child_process_1 = require("child_process");
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path_1 = require("path");
|
|
40
|
+
// ?? Errors ??????????????????????????????????????????????????????????????????
|
|
41
|
+
class LuksError extends Error {
|
|
42
|
+
constructor(code, message, details) {
|
|
43
|
+
super(message);
|
|
44
|
+
this.code = code;
|
|
45
|
+
this.details = details;
|
|
46
|
+
this.name = 'LuksError';
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.LuksError = LuksError;
|
|
50
|
+
// ?? Container ??????????????????????????????????????????????????????????????
|
|
51
|
+
class Container {
|
|
52
|
+
constructor(config) {
|
|
53
|
+
this.id = '_.cipher.img';
|
|
54
|
+
this.config = config;
|
|
55
|
+
this.id = `_.${(0, path_1.basename)(this.config.directory).replace(/[^a-z0-9-]/gi, '_')}`;
|
|
56
|
+
this.imagepath = `${(0, path_1.dirname)(this.config.directory)}/${this.id}.img`;
|
|
57
|
+
// Validate password strength
|
|
58
|
+
if (this.config.password.length < 12) {
|
|
59
|
+
throw new LuksError('WEAK_PASSWORD', 'Password must be at least 12 characters');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
getSettings() {
|
|
63
|
+
try {
|
|
64
|
+
return JSON.parse(fs.readFileSync((0, path_1.join)(this.config.directory, "_.settings.json")).toString());
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
return { locked: false };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
isMounted() {
|
|
71
|
+
try {
|
|
72
|
+
(0, child_process_1.execSync)(`mountpoint -q ${this.config.directory}`);
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
executeCommand(cmd, description) {
|
|
80
|
+
try {
|
|
81
|
+
const output = (0, child_process_1.execSync)(cmd, {
|
|
82
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
83
|
+
timeout: 30000 // 30 second timeout
|
|
84
|
+
});
|
|
85
|
+
return output.toString();
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
const errorMsg = err.stderr?.toString() || err.message || String(err);
|
|
89
|
+
throw new LuksError('EXEC_FAILED', `${description} failed`, errorMsg);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
mount() {
|
|
93
|
+
try {
|
|
94
|
+
// Check if already mounted
|
|
95
|
+
if (this.isMounted()) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
// Create directories
|
|
99
|
+
if (!fs.existsSync(this.config.directory))
|
|
100
|
+
fs.mkdirSync(this.config.directory, { recursive: true, mode: 0o700 });
|
|
101
|
+
if (!fs.existsSync((0, path_1.dirname)(this.imagepath)))
|
|
102
|
+
fs.mkdirSync((0, path_1.dirname)(this.imagepath), { recursive: true, mode: 0o700 });
|
|
103
|
+
// New container - create and format
|
|
104
|
+
if (!fs.existsSync(this.imagepath)) {
|
|
105
|
+
console.log(`Creating LUKS container at ${this.imagepath} (${this.config.size}MB)...`);
|
|
106
|
+
// Create disk image
|
|
107
|
+
this.executeCommand(`dd if=/dev/zero of=${this.imagepath} bs=1M count=${this.config.size} 2>/dev/null`, 'Create disk image');
|
|
108
|
+
// Format as LUKS
|
|
109
|
+
this.executeCommand(`echo -n "${this.config.password.replace(/"/g, '\\"')}" | cryptsetup luksFormat --batch-mode ${this.imagepath}`, 'Format LUKS container');
|
|
110
|
+
// Open LUKS
|
|
111
|
+
this.executeCommand(`echo -n "${this.config.password.replace(/"/g, '\\"')}" | cryptsetup luksOpen ${this.imagepath} ${this.id}`, 'Open LUKS container');
|
|
112
|
+
// Create filesystem
|
|
113
|
+
this.executeCommand(`mkfs.ext4 -F /dev/mapper/${this.id} -q`, 'Create ext4 filesystem');
|
|
114
|
+
// Mount
|
|
115
|
+
this.executeCommand(`mount -o defaults /dev/mapper/${this.id} ${this.config.directory}`, 'Mount filesystem');
|
|
116
|
+
// Write settings
|
|
117
|
+
fs.writeFileSync((0, path_1.join)(this.config.directory, "_.settings.json"), JSON.stringify({ locked: this.config.locked }, null, 2), { mode: 0o600 });
|
|
118
|
+
console.log(`✓ LUKS container mounted at ${this.config.directory}`);
|
|
119
|
+
}
|
|
120
|
+
// Existing container - open and mount
|
|
121
|
+
else {
|
|
122
|
+
console.log(`Opening existing LUKS container at ${this.imagepath}...`);
|
|
123
|
+
this.executeCommand(`echo -n "${this.config.password.replace(/"/g, '\\"')}" | cryptsetup luksOpen ${this.imagepath} ${this.id}`, 'Open LUKS container');
|
|
124
|
+
this.executeCommand(`mount -o defaults /dev/mapper/${this.id} ${this.config.directory}`, 'Mount filesystem');
|
|
125
|
+
console.log(`✓ LUKS container mounted at ${this.config.directory}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
if (err instanceof LuksError)
|
|
130
|
+
throw err;
|
|
131
|
+
throw new LuksError('MOUNT_FAILED', 'Failed to mount container', String(err));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
unmount() {
|
|
135
|
+
try {
|
|
136
|
+
if (!this.isMounted()) {
|
|
137
|
+
return this;
|
|
138
|
+
}
|
|
139
|
+
this.executeCommand(`umount ${this.config.directory}`, 'Unmount filesystem');
|
|
140
|
+
this.executeCommand(`cryptsetup luksClose ${this.id}`, 'Close LUKS container');
|
|
141
|
+
console.log(`✓ LUKS container unmounted`);
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
// Don't throw on unmount - try to force unmount
|
|
145
|
+
try {
|
|
146
|
+
(0, child_process_1.execSync)(`umount -f ${this.config.directory} 2>/dev/null`);
|
|
147
|
+
(0, child_process_1.execSync)(`cryptsetup luksClose ${this.id} 2>/dev/null`);
|
|
148
|
+
}
|
|
149
|
+
catch { }
|
|
150
|
+
}
|
|
151
|
+
return this;
|
|
152
|
+
}
|
|
153
|
+
delete(force = false) {
|
|
154
|
+
try {
|
|
155
|
+
this.mount();
|
|
156
|
+
if (this.getSettings()?.locked && !force) {
|
|
157
|
+
throw new LuksError('CONTAINER_LOCKED', 'Container is protected from deletion. Use force: true to override');
|
|
158
|
+
}
|
|
159
|
+
this.unmount();
|
|
160
|
+
if (fs.existsSync(this.config.directory)) {
|
|
161
|
+
fs.rmSync(this.config.directory, { recursive: true, force: true });
|
|
162
|
+
}
|
|
163
|
+
if (fs.existsSync(this.imagepath)) {
|
|
164
|
+
fs.unlinkSync(this.imagepath);
|
|
165
|
+
}
|
|
166
|
+
console.log(`✓ LUKS container deleted`);
|
|
167
|
+
}
|
|
168
|
+
catch (err) {
|
|
169
|
+
if (err instanceof LuksError)
|
|
170
|
+
throw err;
|
|
171
|
+
throw new LuksError('DELETE_FAILED', 'Failed to delete container', String(err));
|
|
172
|
+
}
|
|
173
|
+
return this;
|
|
174
|
+
}
|
|
175
|
+
resize(targetMB) {
|
|
176
|
+
try {
|
|
177
|
+
if (!this.isMounted()) {
|
|
178
|
+
this.mount();
|
|
179
|
+
}
|
|
180
|
+
// Calculate space requirements
|
|
181
|
+
const usedOutput = (0, child_process_1.execSync)(`du -sb ${this.config.directory}`, { encoding: 'utf-8' });
|
|
182
|
+
const usedBytes = parseInt(usedOutput.split(/\s+/)[0], 10);
|
|
183
|
+
const usedMB = Math.ceil(usedBytes / (1024 * 1024));
|
|
184
|
+
const bufferMB = Math.max(5, Math.ceil(usedMB * 0.1)); // 10% buffer
|
|
185
|
+
const minMB = usedMB + bufferMB;
|
|
186
|
+
if (targetMB < minMB) {
|
|
187
|
+
console.warn(`Target ${targetMB}MB too small, resizing to ${minMB}MB (used: ${usedMB}MB + buffer: ${bufferMB}MB)`);
|
|
188
|
+
targetMB = minMB;
|
|
189
|
+
}
|
|
190
|
+
// Check available disk space
|
|
191
|
+
const dfOutput = (0, child_process_1.execSync)(`df -B1 ${(0, path_1.dirname)(this.imagepath)}`, { encoding: 'utf-8' }).split('\n')[1];
|
|
192
|
+
const freeBytes = parseInt(dfOutput.split(/\s+/)[3], 10);
|
|
193
|
+
const freeMB = Math.floor(freeBytes / (1024 * 1024));
|
|
194
|
+
if (targetMB > freeMB) {
|
|
195
|
+
throw new LuksError('INSUFFICIENT_SPACE', `Target ${targetMB}MB exceeds available space ${freeMB}MB`);
|
|
196
|
+
}
|
|
197
|
+
const currentSizeBytes = fs.statSync(this.imagepath).size;
|
|
198
|
+
const currentSizeMB = Math.ceil(currentSizeBytes / (1024 * 1024));
|
|
199
|
+
const isShrinking = targetMB < currentSizeMB;
|
|
200
|
+
console.log(`Resizing container from ${currentSizeMB}MB to ${targetMB}MB...`);
|
|
201
|
+
if (isShrinking) {
|
|
202
|
+
// Shrink: check → resize fs → resize crypto → truncate
|
|
203
|
+
this.executeCommand(`e2fsck -f -y /dev/mapper/${this.id}`, 'Check filesystem');
|
|
204
|
+
this.executeCommand(`resize2fs /dev/mapper/${this.id} ${targetMB}M`, 'Resize filesystem');
|
|
205
|
+
this.executeCommand(`cryptsetup resize ${this.id}`, 'Resize crypto layer');
|
|
206
|
+
this.executeCommand(`truncate -s ${targetMB}M ${this.imagepath}`, 'Truncate image');
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
// Grow: truncate → resize crypto → resize fs → check
|
|
210
|
+
this.executeCommand(`truncate -s ${targetMB}M ${this.imagepath}`, 'Truncate image');
|
|
211
|
+
this.executeCommand(`cryptsetup resize ${this.id}`, 'Resize crypto layer');
|
|
212
|
+
this.executeCommand(`resize2fs /dev/mapper/${this.id} ${targetMB}M`, 'Resize filesystem');
|
|
213
|
+
this.executeCommand(`e2fsck -f -y /dev/mapper/${this.id}`, 'Check filesystem');
|
|
214
|
+
}
|
|
215
|
+
console.log(`✓ Container resized to ${targetMB}MB`);
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
if (err instanceof LuksError)
|
|
219
|
+
throw err;
|
|
220
|
+
throw new LuksError('RESIZE_FAILED', 'Failed to resize container', String(err));
|
|
221
|
+
}
|
|
222
|
+
return this;
|
|
223
|
+
}
|
|
224
|
+
async changePassword(oldPassword, newPassword) {
|
|
225
|
+
try {
|
|
226
|
+
if (newPassword.length < 12) {
|
|
227
|
+
throw new LuksError('WEAK_PASSWORD', 'New password must be at least 12 characters');
|
|
228
|
+
}
|
|
229
|
+
console.log('Changing LUKS password...');
|
|
230
|
+
this.executeCommand(`echo -e "${oldPassword.replace(/"/g, '\\"')}\n${newPassword.replace(/"/g, '\\"')}" | cryptsetup luksChangeKey ${this.imagepath}`, 'Change LUKS password');
|
|
231
|
+
this.config.password = newPassword;
|
|
232
|
+
console.log(`✓ Password changed successfully`);
|
|
233
|
+
}
|
|
234
|
+
catch (err) {
|
|
235
|
+
if (err instanceof LuksError)
|
|
236
|
+
throw err;
|
|
237
|
+
throw new LuksError('PASSWORD_CHANGE_FAILED', 'Failed to change password', String(err));
|
|
238
|
+
}
|
|
239
|
+
return this;
|
|
240
|
+
}
|
|
241
|
+
getInfo() {
|
|
242
|
+
try {
|
|
243
|
+
const output = (0, child_process_1.execSync)(`cryptsetup luksDump ${this.imagepath}`, { encoding: 'utf-8' });
|
|
244
|
+
return {
|
|
245
|
+
locked: this.getSettings().locked,
|
|
246
|
+
mounted: this.isMounted(),
|
|
247
|
+
imagePath: this.imagepath,
|
|
248
|
+
containerPath: this.config.directory,
|
|
249
|
+
size: this.config.size,
|
|
250
|
+
raw: output
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
catch (err) {
|
|
254
|
+
throw new LuksError('INFO_FAILED', 'Failed to get container info', String(err));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// ?? Luks (Public API) ?????????????????????????????????????????????????????
|
|
259
|
+
class Luks {
|
|
260
|
+
constructor(directory, config) {
|
|
261
|
+
this.directory = directory;
|
|
262
|
+
this.config = config;
|
|
263
|
+
this.container = new Container({ ...this.config, directory: this.directory });
|
|
264
|
+
}
|
|
265
|
+
static list() {
|
|
266
|
+
try {
|
|
267
|
+
const output = (0, child_process_1.execSync)("lsblk -J | jq '[.blockdevices[] | select(.fstype == null and .children != null) | {name: .name, uuid: .uuid, children: .children}]'", { encoding: 'utf-8' });
|
|
268
|
+
return JSON.parse(output);
|
|
269
|
+
}
|
|
270
|
+
catch (err) {
|
|
271
|
+
throw new LuksError('LIST_FAILED', 'Failed to list LUKS containers', String(err));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
mount() {
|
|
275
|
+
this.container.mount();
|
|
276
|
+
return this;
|
|
277
|
+
}
|
|
278
|
+
unmount() {
|
|
279
|
+
this.container.unmount();
|
|
280
|
+
return this;
|
|
281
|
+
}
|
|
282
|
+
delete(force = false) {
|
|
283
|
+
this.container.delete(force);
|
|
284
|
+
return this;
|
|
285
|
+
}
|
|
286
|
+
resize(size) {
|
|
287
|
+
this.container.resize(size);
|
|
288
|
+
return this;
|
|
289
|
+
}
|
|
290
|
+
async changePassword(oldPassword, newPassword) {
|
|
291
|
+
await this.container.changePassword(oldPassword, newPassword);
|
|
292
|
+
return this;
|
|
293
|
+
}
|
|
294
|
+
getInfo() {
|
|
295
|
+
return this.container.getInfo();
|
|
296
|
+
}
|
|
297
|
+
isMounted() {
|
|
298
|
+
return this.container.isMounted();
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
exports.Luks = Luks;
|
|
302
|
+
//# sourceMappingURL=luks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"luks.js","sourceRoot":"","sources":["../../src/lib/luks.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAAyC;AACzC,uCAAyB;AACzB,+BAA8C;AAoB9C,+EAA+E;AAE/E,MAAM,SAAU,SAAQ,KAAK;IAIzB,YAAY,IAAY,EAAE,OAAe,EAAE,OAAgB;QACvD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC5B,CAAC;CACJ;AAgVQ,8BAAS;AA9UlB,8EAA8E;AAE9E,MAAM,SAAS;IAKX,YAAY,MAAkB;QAF9B,OAAE,GAAyB,cAAc,CAAC;QAGtC,IAAI,CAAC,MAAM,GAAM,MAAM,CAAC;QACxB,IAAI,CAAC,EAAE,GAAU,KAAK,IAAA,eAAQ,EAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,EAAE,CAAC;QACrF,IAAI,CAAC,SAAS,GAAG,GAAG,IAAA,cAAO,EAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,EAAE,MAAM,CAAC;QAEpE,6BAA6B;QAC7B,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YACnC,MAAM,IAAI,SAAS,CAAC,eAAe,EAAE,yCAAyC,CAAC,CAAC;QACpF,CAAC;IACL,CAAC;IAED,WAAW;QACP,IAAI,CAAC;YACD,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAA,WAAI,EAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAA;QACjG,CAAC;QAAC,OAAM,CAAC,EAAE,CAAC;YACR,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QAC7B,CAAC;IACL,CAAC;IAED,SAAS;QACL,IAAI,CAAC;YACD,IAAA,wBAAQ,EAAC,iBAAiB,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;YACnD,OAAO,IAAI,CAAC;QAChB,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IAEO,cAAc,CAAC,GAAW,EAAE,WAAmB;QACnD,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,IAAA,wBAAQ,EAAC,GAAG,EAAE;gBACzB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;gBAC/B,OAAO,EAAE,KAAK,CAAC,oBAAoB;aACtC,CAAC,CAAC;YACH,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;QAC7B,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAChB,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;YACtE,MAAM,IAAI,SAAS,CACf,aAAa,EACb,GAAG,WAAW,SAAS,EACvB,QAAQ,CACX,CAAC;QACN,CAAC;IACL,CAAC;IAED,KAAK;QACD,IAAI,CAAC;YACD,2BAA2B;YAC3B,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;gBACnB,OAAO;YACX,CAAC;YAED,qBAAqB;YACrB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;gBACrC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YAE1E,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAA,cAAO,EAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBACvC,EAAE,CAAC,SAAS,CAAC,IAAA,cAAO,EAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YAE5E,oCAAoC;YACpC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;gBACjC,OAAO,CAAC,GAAG,CAAC,8BAA8B,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,CAAC;gBAEvF,oBAAoB;gBACpB,IAAI,CAAC,cAAc,CACf,sBAAsB,IAAI,CAAC,SAAS,gBAAgB,IAAI,CAAC,MAAM,CAAC,IAAI,cAAc,EAClF,mBAAmB,CACtB,CAAC;gBAEF,iBAAiB;gBACjB,IAAI,CAAC,cAAc,CACf,YAAY,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,0CAA0C,IAAI,CAAC,SAAS,EAAE,EAC/G,uBAAuB,CAC1B,CAAC;gBAEF,YAAY;gBACZ,IAAI,CAAC,cAAc,CACf,YAAY,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,2BAA2B,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,EAAE,EAAE,EAC3G,qBAAqB,CACxB,CAAC;gBAEF,oBAAoB;gBACpB,IAAI,CAAC,cAAc,CACf,4BAA4B,IAAI,CAAC,EAAE,KAAK,EACxC,wBAAwB,CAC3B,CAAC;gBAEF,QAAQ;gBACR,IAAI,CAAC,cAAc,CACf,iCAAiC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,EACnE,kBAAkB,CACrB,CAAC;gBAEF,iBAAiB;gBACjB,EAAE,CAAC,aAAa,CACZ,IAAA,WAAI,EAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAC9C,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EACvD,EAAE,IAAI,EAAE,KAAK,EAAE,CAClB,CAAC;gBAEF,OAAO,CAAC,GAAG,CAAC,+BAA+B,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;YACxE,CAAC;YACD,sCAAsC;iBACjC,CAAC;gBACF,OAAO,CAAC,GAAG,CAAC,sCAAsC,IAAI,CAAC,SAAS,KAAK,CAAC,CAAC;gBAEvE,IAAI,CAAC,cAAc,CACf,YAAY,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,2BAA2B,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,EAAE,EAAE,EAC3G,qBAAqB,CACxB,CAAC;gBAEF,IAAI,CAAC,cAAc,CACf,iCAAiC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,EACnE,kBAAkB,CACrB,CAAC;gBAEF,OAAO,CAAC,GAAG,CAAC,+BAA+B,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;YACxE,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,IAAI,GAAG,YAAY,SAAS;gBAAE,MAAM,GAAG,CAAC;YACxC,MAAM,IAAI,SAAS,CAAC,cAAc,EAAE,2BAA2B,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAClF,CAAC;IACL,CAAC;IAED,OAAO;QACH,IAAI,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;gBACpB,OAAO,IAAI,CAAC;YAChB,CAAC;YAED,IAAI,CAAC,cAAc,CAAC,UAAU,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,oBAAoB,CAAC,CAAC;YAC7E,IAAI,CAAC,cAAc,CAAC,wBAAwB,IAAI,CAAC,EAAE,EAAE,EAAE,sBAAsB,CAAC,CAAC;YAC/E,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;QAC9C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,gDAAgD;YAChD,IAAI,CAAC;gBACD,IAAA,wBAAQ,EAAC,aAAa,IAAI,CAAC,MAAM,CAAC,SAAS,cAAc,CAAC,CAAC;gBAC3D,IAAA,wBAAQ,EAAC,wBAAwB,IAAI,CAAC,EAAE,cAAc,CAAC,CAAC;YAC5D,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,MAAM,CAAC,QAAiB,KAAK;QACzB,IAAI,CAAC;YACD,IAAI,CAAC,KAAK,EAAE,CAAC;YAEb,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;gBACvC,MAAM,IAAI,SAAS,CACf,kBAAkB,EAClB,mEAAmE,CACtE,CAAC;YACN,CAAC;YAED,IAAI,CAAC,OAAO,EAAE,CAAC;YAEf,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;gBACvC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACvE,CAAC;YAED,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;gBAChC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAClC,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;QAC5C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,IAAI,GAAG,YAAY,SAAS;gBAAE,MAAM,GAAG,CAAC;YACxC,MAAM,IAAI,SAAS,CAAC,eAAe,EAAE,4BAA4B,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACpF,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,MAAM,CAAC,QAAgB;QACnB,IAAI,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;gBACpB,IAAI,CAAC,KAAK,EAAE,CAAC;YACjB,CAAC;YAED,+BAA+B;YAC/B,MAAM,UAAU,GAAG,IAAA,wBAAQ,EAAC,UAAU,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;YACtF,MAAM,SAAS,GAAG,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC3D,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC;YACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa;YACpE,MAAM,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;YAEhC,IAAI,QAAQ,GAAG,KAAK,EAAE,CAAC;gBACnB,OAAO,CAAC,IAAI,CAAC,UAAU,QAAQ,6BAA6B,KAAK,aAAa,MAAM,gBAAgB,QAAQ,KAAK,CAAC,CAAC;gBACnH,QAAQ,GAAG,KAAK,CAAC;YACrB,CAAC;YAED,6BAA6B;YAC7B,MAAM,QAAQ,GAAG,IAAA,wBAAQ,EAAC,UAAU,IAAA,cAAO,EAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACrG,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACzD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC;YAErD,IAAI,QAAQ,GAAG,MAAM,EAAE,CAAC;gBACpB,MAAM,IAAI,SAAS,CACf,oBAAoB,EACpB,UAAU,QAAQ,8BAA8B,MAAM,IAAI,CAC7D,CAAC;YACN,CAAC;YAED,MAAM,gBAAgB,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC;YAC1D,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC;YAClE,MAAM,WAAW,GAAG,QAAQ,GAAG,aAAa,CAAC;YAE7C,OAAO,CAAC,GAAG,CAAC,2BAA2B,aAAa,SAAS,QAAQ,OAAO,CAAC,CAAC;YAE9E,IAAI,WAAW,EAAE,CAAC;gBACd,uDAAuD;gBACvD,IAAI,CAAC,cAAc,CAAC,4BAA4B,IAAI,CAAC,EAAE,EAAE,EAAE,kBAAkB,CAAC,CAAC;gBAC/E,IAAI,CAAC,cAAc,CAAC,yBAAyB,IAAI,CAAC,EAAE,IAAI,QAAQ,GAAG,EAAE,mBAAmB,CAAC,CAAC;gBAC1F,IAAI,CAAC,cAAc,CAAC,qBAAqB,IAAI,CAAC,EAAE,EAAE,EAAE,qBAAqB,CAAC,CAAC;gBAC3E,IAAI,CAAC,cAAc,CAAC,eAAe,QAAQ,KAAK,IAAI,CAAC,SAAS,EAAE,EAAE,gBAAgB,CAAC,CAAC;YACxF,CAAC;iBAAM,CAAC;gBACJ,qDAAqD;gBACrD,IAAI,CAAC,cAAc,CAAC,eAAe,QAAQ,KAAK,IAAI,CAAC,SAAS,EAAE,EAAE,gBAAgB,CAAC,CAAC;gBACpF,IAAI,CAAC,cAAc,CAAC,qBAAqB,IAAI,CAAC,EAAE,EAAE,EAAE,qBAAqB,CAAC,CAAC;gBAC3E,IAAI,CAAC,cAAc,CAAC,yBAAyB,IAAI,CAAC,EAAE,IAAI,QAAQ,GAAG,EAAE,mBAAmB,CAAC,CAAC;gBAC1F,IAAI,CAAC,cAAc,CAAC,4BAA4B,IAAI,CAAC,EAAE,EAAE,EAAE,kBAAkB,CAAC,CAAC;YACnF,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,0BAA0B,QAAQ,IAAI,CAAC,CAAC;QACxD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,IAAI,GAAG,YAAY,SAAS;gBAAE,MAAM,GAAG,CAAC;YACxC,MAAM,IAAI,SAAS,CAAC,eAAe,EAAE,4BAA4B,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACpF,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,WAAmB,EAAE,WAAmB;QACzD,IAAI,CAAC;YACD,IAAI,WAAW,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;gBAC1B,MAAM,IAAI,SAAS,CAAC,eAAe,EAAE,6CAA6C,CAAC,CAAC;YACxF,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;YACzC,IAAI,CAAC,cAAc,CACf,YAAY,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,gCAAgC,IAAI,CAAC,SAAS,EAAE,EACjI,sBAAsB,CACzB,CAAC;YAEF,IAAI,CAAC,MAAM,CAAC,QAAQ,GAAG,WAAW,CAAC;YACnC,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;QACnD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,IAAI,GAAG,YAAY,SAAS;gBAAE,MAAM,GAAG,CAAC;YACxC,MAAM,IAAI,SAAS,CAAC,wBAAwB,EAAE,2BAA2B,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5F,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,OAAO;QACH,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,IAAA,wBAAQ,EAAC,uBAAuB,IAAI,CAAC,SAAS,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;YACxF,OAAO;gBACH,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM;gBACjC,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE;gBACzB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS;gBACpC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;gBACtB,GAAG,EAAE,MAAM;aACd,CAAC;QACN,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,MAAM,IAAI,SAAS,CAAC,aAAa,EAAE,8BAA8B,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACpF,CAAC;IACL,CAAC;CACJ;AAED,6EAA6E;AAE7E,MAAa,IAAI;IAKb,YAAY,SAAiB,EAAE,MAAa;QACxC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,SAAS,GAAG,IAAI,SAAS,CAAC,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IAClF,CAAC;IAED,MAAM,CAAC,IAAI;QACP,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,IAAA,wBAAQ,EACnB,qIAAqI,EACrI,EAAE,QAAQ,EAAE,OAAO,EAAE,CACxB,CAAC;YACF,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,MAAM,IAAI,SAAS,CAAC,aAAa,EAAE,gCAAgC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACtF,CAAC;IACL,CAAC;IAED,KAAK;QACD,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,OAAO;QACH,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,MAAM,CAAC,QAAiB,KAAK;QACzB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7B,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,MAAM,CAAC,IAAY;QACf,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5B,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,WAAmB,EAAE,WAAmB;QACzD,MAAM,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,OAAO;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;IACpC,CAAC;IAED,SAAS;QACL,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC;IACtC,CAAC;CACJ;AAvDD,oBAuDC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hotfusion/cipher",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Vault-like secrets management with AES-256-GCM encryption and optional LUKS container support",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"secrets",
|
|
7
|
+
"vault",
|
|
8
|
+
"encryption",
|
|
9
|
+
"aes-256-gcm",
|
|
10
|
+
"luks",
|
|
11
|
+
"security",
|
|
12
|
+
"key-management"
|
|
13
|
+
],
|
|
14
|
+
"author": "Alex Loginov <you@example.com>",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/yourusername/cipher.git"
|
|
19
|
+
},
|
|
20
|
+
"main": "dist/index.js",
|
|
21
|
+
"types": "dist/index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"import": "./dist/index.js",
|
|
25
|
+
"require": "./dist/index.cjs",
|
|
26
|
+
"types": "./dist/index.d.ts"
|
|
27
|
+
},
|
|
28
|
+
"./luks": {
|
|
29
|
+
"import": "./dist/luks.js",
|
|
30
|
+
"require": "./dist/luks.cjs",
|
|
31
|
+
"types": "./dist/luks.d.ts"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE"
|
|
38
|
+
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsc && npm run build:cjs",
|
|
41
|
+
"build:cjs": "tsc --module commonjs --outDir dist",
|
|
42
|
+
"test": "vitest",
|
|
43
|
+
"test:coverage": "vitest --coverage",
|
|
44
|
+
"lint": "eslint src --ext .ts",
|
|
45
|
+
"prepack": "npm run build"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"ajv": "^8.12.0",
|
|
49
|
+
"lokijs": "^1.5.12"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/node": "^20.0.0",
|
|
53
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
54
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
55
|
+
"eslint": "^8.0.0",
|
|
56
|
+
"typescript": "^5.0.0",
|
|
57
|
+
"vitest": "^0.34.0"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=16.0.0"
|
|
61
|
+
},
|
|
62
|
+
"publishConfig": {
|
|
63
|
+
"registry": "https://registry.npmjs.org/",
|
|
64
|
+
"access": "public"
|
|
65
|
+
}
|
|
66
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
# @hotfusion/cipher
|
|
2
|
+
|
|
3
|
+
A production-ready, Vault-like secrets management library for Node.js with **AES-256-GCM encryption** and optional **LUKS container support**.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
✅ **AES-256-GCM encryption** - Industry-standard authenticated encryption
|
|
8
|
+
✅ **PBKDF2 key derivation** - 100,000 iterations for security
|
|
9
|
+
✅ **Three security levels:**
|
|
10
|
+
- **Level 0**: Plain encrypted file (fast, no root required)
|
|
11
|
+
- **Level 1**: LUKS container + AES-256-GCM (maximum security, requires root)
|
|
12
|
+
- **Level 2**: VM-level isolation (coming soon)
|
|
13
|
+
|
|
14
|
+
✅ **Version control** - Track secret versions, prevent downgrade attacks
|
|
15
|
+
✅ **Readonly mode** - Immutable deployments
|
|
16
|
+
✅ **Password lifecycle** - Change passwords, rotate credentials
|
|
17
|
+
✅ **LokiJS database** - In-memory with persistent encryption
|
|
18
|
+
✅ **AJV schema validation** - Optional key schemas
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install @hotfusion/cipher
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or with yarn:
|
|
27
|
+
```bash
|
|
28
|
+
yarn add @hotfusion/cipher
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
### Level 0: Simple Encrypted Storage
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { Cipher } from '@hotfusion/cipher';
|
|
37
|
+
|
|
38
|
+
// Create cipher
|
|
39
|
+
const cipher = new Cipher({
|
|
40
|
+
path: './secrets',
|
|
41
|
+
password: 'super-secure-password-min-12-chars',
|
|
42
|
+
level: 0 // plain encrypted file
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
await cipher.ready();
|
|
46
|
+
|
|
47
|
+
// Store a secret
|
|
48
|
+
const secrets = cipher.collection('secrets');
|
|
49
|
+
await secrets.insert(
|
|
50
|
+
{ id: 'api_key' },
|
|
51
|
+
{ token: 'super-secret-token' }
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
// Retrieve a secret
|
|
55
|
+
const found = secrets.find({ id: 'api_key' });
|
|
56
|
+
const unsealed = secrets.unseal('api_key');
|
|
57
|
+
console.log(unsealed); // { token: 'super-secret-token' }
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Level 1: LUKS Container (Requires root/sudo)
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
const cipher = new Cipher({
|
|
64
|
+
path: '/mnt/secrets',
|
|
65
|
+
password: 'super-secure-password-min-12-chars',
|
|
66
|
+
level: 1, // LUKS encrypted container
|
|
67
|
+
size: 1024 // 1GB container
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
await cipher.ready();
|
|
71
|
+
|
|
72
|
+
// Same API as level 0
|
|
73
|
+
const secrets = cipher.collection('secrets');
|
|
74
|
+
await secrets.insert({ id: 'db_password' }, { pwd: '...' });
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Note**: Level 1 requires:
|
|
78
|
+
- Linux with cryptsetup/LUKS support
|
|
79
|
+
- Root/sudo access (for mount/unmount)
|
|
80
|
+
- The LUKS container is automatically mounted on initialization
|
|
81
|
+
|
|
82
|
+
## API Reference
|
|
83
|
+
|
|
84
|
+
### Cipher
|
|
85
|
+
|
|
86
|
+
#### Constructor
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
new Cipher(config: ICipherConfig, collections?: ICollection[])
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**Config options:**
|
|
93
|
+
```typescript
|
|
94
|
+
{
|
|
95
|
+
path: string; // Directory to store secrets
|
|
96
|
+
password: string; // Min 12 characters
|
|
97
|
+
level?: 0 | 1 | 2; // Default: 0
|
|
98
|
+
size?: number; // MB (required for level 1)
|
|
99
|
+
readonly?: boolean; // Default: false
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Password sources** (in order of precedence):
|
|
104
|
+
1. `config.password`
|
|
105
|
+
2. `--password=xxx` CLI argument
|
|
106
|
+
3. `CIPHER_PASSWORD` environment variable
|
|
107
|
+
|
|
108
|
+
#### Methods
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
// Wait for database to load
|
|
112
|
+
await cipher.ready(): Promise<void>
|
|
113
|
+
|
|
114
|
+
// Get collection by name
|
|
115
|
+
cipher.collection(name: string): SecretCollection
|
|
116
|
+
|
|
117
|
+
// Save all changes to disk
|
|
118
|
+
await cipher.save(): Promise<void>
|
|
119
|
+
|
|
120
|
+
// Change password (level 1 only)
|
|
121
|
+
await cipher.changePassword(oldPassword: string, newPassword: string): Promise<void>
|
|
122
|
+
|
|
123
|
+
// Unmount LUKS container (level 1 only)
|
|
124
|
+
await cipher.unmount(): Promise<void>
|
|
125
|
+
|
|
126
|
+
// Get cipher info
|
|
127
|
+
cipher.getInfo(): {
|
|
128
|
+
level: number;
|
|
129
|
+
path: string;
|
|
130
|
+
readonly: boolean;
|
|
131
|
+
mounted: boolean;
|
|
132
|
+
collections: string[];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Check if container is mounted
|
|
136
|
+
cipher.isMounted(): boolean
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### SecretCollection
|
|
140
|
+
|
|
141
|
+
#### Methods
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// Insert a new secret (fails if exists)
|
|
145
|
+
await collection.insert(
|
|
146
|
+
key: { id: string },
|
|
147
|
+
secret: any,
|
|
148
|
+
options?: { readonly?: boolean; version?: number }
|
|
149
|
+
): Promise<void>
|
|
150
|
+
|
|
151
|
+
// Update existing secret (fails if not exists)
|
|
152
|
+
await collection.update(
|
|
153
|
+
key: { id: string },
|
|
154
|
+
secret: any,
|
|
155
|
+
options?: { readonly?: boolean; version?: number }
|
|
156
|
+
): Promise<void>
|
|
157
|
+
|
|
158
|
+
// Delete a secret
|
|
159
|
+
await collection.delete(
|
|
160
|
+
key: { id: string },
|
|
161
|
+
options?: { readonly?: boolean }
|
|
162
|
+
): Promise<void>
|
|
163
|
+
|
|
164
|
+
// Find secret metadata
|
|
165
|
+
collection.find(key: { id: string }): {
|
|
166
|
+
key: { [key: string]: string };
|
|
167
|
+
meta: { version: number; readonly?: boolean };
|
|
168
|
+
_id: number;
|
|
169
|
+
} | null
|
|
170
|
+
|
|
171
|
+
// Retrieve secret value
|
|
172
|
+
collection.unseal(id: string): any
|
|
173
|
+
|
|
174
|
+
// List all secrets (metadata only)
|
|
175
|
+
collection.list(): Array<{ key: any; meta: any }>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Examples
|
|
179
|
+
|
|
180
|
+
### Full Example: API Credentials
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
import { Cipher } from '@hotfusion/cipher';
|
|
184
|
+
|
|
185
|
+
const cipher = new Cipher({
|
|
186
|
+
path: './vault',
|
|
187
|
+
password: process.env.VAULT_PASSWORD!,
|
|
188
|
+
level: 0
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
await cipher.ready();
|
|
192
|
+
|
|
193
|
+
const creds = cipher.collection('credentials');
|
|
194
|
+
|
|
195
|
+
// Store API key
|
|
196
|
+
await creds.insert(
|
|
197
|
+
{ id: 'github_token' },
|
|
198
|
+
{
|
|
199
|
+
token: 'ghp_xxxxxxxxxxxxxxxxxxxx',
|
|
200
|
+
scope: 'repo,gist,user'
|
|
201
|
+
}
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
// Store database password
|
|
205
|
+
await creds.insert(
|
|
206
|
+
{ id: 'db_password' },
|
|
207
|
+
{
|
|
208
|
+
password: 'postgres-password',
|
|
209
|
+
database: 'myapp_prod',
|
|
210
|
+
host: 'db.example.com'
|
|
211
|
+
}
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
// Update with new version
|
|
215
|
+
await creds.update(
|
|
216
|
+
{ id: 'github_token' },
|
|
217
|
+
{
|
|
218
|
+
token: 'ghp_new_token',
|
|
219
|
+
scope: 'repo,gist,user'
|
|
220
|
+
},
|
|
221
|
+
{ version: 2 }
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
// List all secrets
|
|
225
|
+
const all = creds.list();
|
|
226
|
+
console.log(all);
|
|
227
|
+
// [
|
|
228
|
+
// { key: { id: 'github_token' }, meta: { version: 2, readonly: false } },
|
|
229
|
+
// { key: { id: 'db_password' }, meta: { version: 1, readonly: false } }
|
|
230
|
+
// ]
|
|
231
|
+
|
|
232
|
+
// Retrieve secret
|
|
233
|
+
const dbCreds = creds.unseal('db_password');
|
|
234
|
+
console.log(dbCreds);
|
|
235
|
+
// { password: 'postgres-password', database: 'myapp_prod', host: '...' }
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### With Schema Validation
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
const cipher = new Cipher({
|
|
242
|
+
path: './vault',
|
|
243
|
+
password: 'xxx',
|
|
244
|
+
}, [
|
|
245
|
+
{
|
|
246
|
+
name: 'api_keys',
|
|
247
|
+
schema: {
|
|
248
|
+
keySchema: {
|
|
249
|
+
type: 'object',
|
|
250
|
+
properties: {
|
|
251
|
+
id: { type: 'string', minLength: 3 }
|
|
252
|
+
},
|
|
253
|
+
required: ['id']
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
]);
|
|
258
|
+
|
|
259
|
+
await cipher.ready();
|
|
260
|
+
|
|
261
|
+
const keys = cipher.collection('api_keys');
|
|
262
|
+
|
|
263
|
+
// This will fail validation
|
|
264
|
+
try {
|
|
265
|
+
await keys.insert({ id: 'ab' }, { token: '...' });
|
|
266
|
+
} catch (err) {
|
|
267
|
+
console.error(err.message); // Key validation failed
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Environment-based Configuration
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
const cipher = new Cipher({
|
|
275
|
+
path: process.env.CIPHER_PATH || './vault',
|
|
276
|
+
password: process.env.CIPHER_PASSWORD!,
|
|
277
|
+
level: (process.env.CIPHER_LEVEL ?? 0) as any,
|
|
278
|
+
size: process.env.CIPHER_LEVEL === '1' ? 1024 : undefined,
|
|
279
|
+
readonly: process.env.NODE_ENV === 'production'
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
await cipher.ready();
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Security Considerations
|
|
286
|
+
|
|
287
|
+
### Password Strength
|
|
288
|
+
|
|
289
|
+
- Minimum **12 characters** (enforced)
|
|
290
|
+
- Use strong, random passwords
|
|
291
|
+
- Store in environment variables or secure vaults (not in code)
|
|
292
|
+
|
|
293
|
+
### LUKS Containers (Level 1)
|
|
294
|
+
|
|
295
|
+
- Requires **root/sudo** access
|
|
296
|
+
- Automatically mounted during `Cipher` initialization
|
|
297
|
+
- Automatically unmounted on error
|
|
298
|
+
- Use for maximum security (encryption at filesystem level)
|
|
299
|
+
|
|
300
|
+
### File Permissions
|
|
301
|
+
|
|
302
|
+
- Database files created with mode `0o600` (read/write owner only)
|
|
303
|
+
- Container directories created with mode `0o700` (rwx owner only)
|
|
304
|
+
|
|
305
|
+
### Key Rotation
|
|
306
|
+
|
|
307
|
+
- Secrets support versioning to prevent downgrade
|
|
308
|
+
- Use `update()` with new version to rotate credentials
|
|
309
|
+
- Change password with `changePassword()` (re-encrypts entire vault)
|
|
310
|
+
|
|
311
|
+
### Readonly Mode
|
|
312
|
+
|
|
313
|
+
- Set `readonly: true` for immutable deployments
|
|
314
|
+
- Prevents any insert/update/delete operations
|
|
315
|
+
- Useful for CI/CD pipelines
|
|
316
|
+
|
|
317
|
+
## Error Handling
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
import { Cipher, CipherError } from '@hotfusion/cipher';
|
|
321
|
+
|
|
322
|
+
try {
|
|
323
|
+
const cipher = new Cipher({ path: './vault', password: 'xxx' });
|
|
324
|
+
await cipher.ready();
|
|
325
|
+
} catch (err) {
|
|
326
|
+
if (err instanceof CipherError) {
|
|
327
|
+
console.error(`[${err.code}] ${err.message}`);
|
|
328
|
+
console.error(err.details);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Common error codes:**
|
|
334
|
+
|
|
335
|
+
| Code | Meaning |
|
|
336
|
+
|------|---------|
|
|
337
|
+
| `NO_PASSWORD` | Password not provided |
|
|
338
|
+
| `WEAK_PASSWORD` | Password < 12 characters |
|
|
339
|
+
| `KEY_EXISTS` | Secret already exists |
|
|
340
|
+
| `KEY_NOT_FOUND` | Secret doesn't exist |
|
|
341
|
+
| `READONLY_MODE` | Cannot modify in readonly mode |
|
|
342
|
+
| `COLLECTION_NOT_FOUND` | Collection doesn't exist |
|
|
343
|
+
| `INVALID_VERSION` | Version constraint violated |
|
|
344
|
+
| `LUKS_ERROR` | LUKS container error |
|
|
345
|
+
|
|
346
|
+
## Performance
|
|
347
|
+
|
|
348
|
+
- **Level 0**: ~1-5ms per operation (local SSD)
|
|
349
|
+
- **Level 1**: ~5-50ms per operation (LUKS mount overhead)
|
|
350
|
+
- Encryption: AES-256-GCM with 100k PBKDF2 iterations
|
|
351
|
+
|
|
352
|
+
## Limitations
|
|
353
|
+
|
|
354
|
+
- **Level 2** (VM-level isolation) not yet implemented
|
|
355
|
+
- LUKS requires Linux + cryptsetup
|
|
356
|
+
- Single-process (no distributed locking)
|
|
357
|
+
- LokiJS is in-memory (loaded at startup)
|
|
358
|
+
|
|
359
|
+
## License
|
|
360
|
+
|
|
361
|
+
MIT
|
|
362
|
+
|
|
363
|
+
## Contributing
|
|
364
|
+
|
|
365
|
+
Contributions welcome! Please submit PRs to the [GitHub repository](https://github.com/yourusername/cipher).
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
**Made with ❤️ for secure secrets management**
|