convert to ESM
This commit is contained in:
parent
219ca6c083
commit
fd086972a3
157
crypt.js
157
crypt.js
|
@ -1,4 +1,4 @@
|
||||||
const CACHE_PATH = __dirname + '/cache';
|
const CACHE_PATH = dirname(fileURLToPath(import.meta.url)) + '/cache';
|
||||||
const DEFAULT_CIPHER_ALGORITHM = 'aes-256-cbc';
|
const DEFAULT_CIPHER_ALGORITHM = 'aes-256-cbc';
|
||||||
const DEFAULT_HASH_ALGORITHM = 'sha512';
|
const DEFAULT_HASH_ALGORITHM = 'sha512';
|
||||||
const DEFAULT_SPLIT_SIZE = 33554432;
|
const DEFAULT_SPLIT_SIZE = 33554432;
|
||||||
|
@ -6,20 +6,43 @@ const HMAC_KEY_LENGTH = 32;
|
||||||
const RSA_KEY_BITS = 2048;
|
const RSA_KEY_BITS = 2048;
|
||||||
const STREAM_CONCURRENCY = 8;
|
const STREAM_CONCURRENCY = 8;
|
||||||
|
|
||||||
const crypto = require('crypto');
|
import {
|
||||||
const fs = require('fs');
|
createCipheriv,
|
||||||
const path_ = require('path');
|
createDecipheriv,
|
||||||
const v8 = require('v8');
|
createHash,
|
||||||
|
createHmac,
|
||||||
|
createPrivateKey,
|
||||||
|
createPublicKey,
|
||||||
|
generateKeyPairSync,
|
||||||
|
getCipherInfo,
|
||||||
|
privateDecrypt,
|
||||||
|
publicEncrypt,
|
||||||
|
randomBytes,
|
||||||
|
} from 'crypto';
|
||||||
|
import {
|
||||||
|
accessSync,
|
||||||
|
createReadStream,
|
||||||
|
createWriteStream,
|
||||||
|
mkdirSync,
|
||||||
|
readdirSync,
|
||||||
|
readFileSync,
|
||||||
|
statSync,
|
||||||
|
unlinkSync,
|
||||||
|
writeFileSync,
|
||||||
|
} from 'fs';
|
||||||
|
import { dirname } from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import { deserialize, serialize } from 'v8';
|
||||||
|
|
||||||
function init({
|
export function init({
|
||||||
crypt: crypt_dir,
|
crypt: crypt_dir,
|
||||||
cipher: cipher_algorithm = DEFAULT_CIPHER_ALGORITHM,
|
cipher: cipher_algorithm = DEFAULT_CIPHER_ALGORITHM,
|
||||||
hash: hash_algorithm = DEFAULT_HASH_ALGORITHM,
|
hash: hash_algorithm = DEFAULT_HASH_ALGORITHM,
|
||||||
split: split_size = DEFAULT_SPLIT_SIZE,
|
split: split_size = DEFAULT_SPLIT_SIZE,
|
||||||
passphrase,
|
passphrase,
|
||||||
}) {
|
}) {
|
||||||
fs.mkdirSync(crypt_dir, { recursive: true });
|
mkdirSync(crypt_dir, { recursive: true });
|
||||||
fs.writeFileSync(
|
writeFileSync(
|
||||||
crypt_dir + '/info',
|
crypt_dir + '/info',
|
||||||
cipher_algorithm +
|
cipher_algorithm +
|
||||||
'\n' +
|
'\n' +
|
||||||
|
@ -27,30 +50,30 @@ function init({
|
||||||
'\n' +
|
'\n' +
|
||||||
split_size +
|
split_size +
|
||||||
'\n' +
|
'\n' +
|
||||||
crypto.randomBytes(HMAC_KEY_LENGTH).toString('base64url') +
|
randomBytes(HMAC_KEY_LENGTH).toString('base64url') +
|
||||||
'\n',
|
'\n',
|
||||||
);
|
);
|
||||||
const pair = crypto.generateKeyPairSync('rsa', { modulusLength: RSA_KEY_BITS });
|
const pair = generateKeyPairSync('rsa', { modulusLength: RSA_KEY_BITS });
|
||||||
fs.writeFileSync(crypt_dir + '/public', pair.publicKey.export({ type: 'spki', format: 'pem' }));
|
writeFileSync(crypt_dir + '/public', pair.publicKey.export({ type: 'spki', format: 'pem' }));
|
||||||
fs.writeFileSync(
|
writeFileSync(
|
||||||
crypt_dir + '/private',
|
crypt_dir + '/private',
|
||||||
pair.privateKey.export({ type: 'pkcs8', format: 'pem', cipher: cipher_algorithm, passphrase }),
|
pair.privateKey.export({ type: 'pkcs8', format: 'pem', cipher: cipher_algorithm, passphrase }),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_info(crypt_dir, passphrase) {
|
function get_info(crypt_dir, passphrase) {
|
||||||
const s = fs.readFileSync(crypt_dir + '/info', 'ascii').match(/\S+/g);
|
const s = readFileSync(crypt_dir + '/info', 'ascii').match(/\S+/g);
|
||||||
const info = {
|
const info = {
|
||||||
cipher_algorithm: s[0],
|
cipher_algorithm: s[0],
|
||||||
hash_algorithm: s[1],
|
hash_algorithm: s[1],
|
||||||
split_size: +s[2],
|
split_size: +s[2],
|
||||||
hmac_key: Buffer.from(s[3], 'base64url'),
|
hmac_key: Buffer.from(s[3], 'base64url'),
|
||||||
public_key: crypto.createPublicKey(fs.readFileSync(crypt_dir + '/public')),
|
public_key: createPublicKey(readFileSync(crypt_dir + '/public')),
|
||||||
index: new Map(),
|
index: new Map(),
|
||||||
};
|
};
|
||||||
for (const dirent of fs.readdirSync(crypt_dir, { withFileTypes: true })) {
|
for (const dirent of readdirSync(crypt_dir, { withFileTypes: true })) {
|
||||||
if (dirent.isFile() && dirent.name.endsWith('-index')) {
|
if (dirent.isFile() && dirent.name.endsWith('-index')) {
|
||||||
const s = fs.readFileSync(crypt_dir + '/' + dirent.name, 'ascii').match(/\S+/g);
|
const s = readFileSync(crypt_dir + '/' + dirent.name, 'ascii').match(/\S+/g);
|
||||||
info.index.set(dirent.name.slice(0, -6), {
|
info.index.set(dirent.name.slice(0, -6), {
|
||||||
hash_hmac: Buffer.from(s[0], 'base64url'),
|
hash_hmac: Buffer.from(s[0], 'base64url'),
|
||||||
key: Buffer.from(s[1], 'base64url'),
|
key: Buffer.from(s[1], 'base64url'),
|
||||||
|
@ -60,8 +83,8 @@ function get_info(crypt_dir, passphrase) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (passphrase != null) {
|
if (passphrase != null) {
|
||||||
info.private_key = crypto.createPrivateKey({
|
info.private_key = createPrivateKey({
|
||||||
key: fs.readFileSync(crypt_dir + '/private'),
|
key: readFileSync(crypt_dir + '/private'),
|
||||||
passphrase,
|
passphrase,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -71,7 +94,7 @@ function get_info(crypt_dir, passphrase) {
|
||||||
async function get_plain_index(plain_dir, hash_algorithm, filter) {
|
async function get_plain_index(plain_dir, hash_algorithm, filter) {
|
||||||
let cache;
|
let cache;
|
||||||
try {
|
try {
|
||||||
cache = v8.deserialize(fs.readFileSync(CACHE_PATH));
|
cache = deserialize(readFileSync(CACHE_PATH));
|
||||||
} catch {
|
} catch {
|
||||||
cache = new Map();
|
cache = new Map();
|
||||||
}
|
}
|
||||||
|
@ -80,9 +103,9 @@ async function get_plain_index(plain_dir, hash_algorithm, filter) {
|
||||||
const stream_queue = make_stream_queue();
|
const stream_queue = make_stream_queue();
|
||||||
while (pending.length) {
|
while (pending.length) {
|
||||||
const dir = pending.shift();
|
const dir = pending.shift();
|
||||||
for (const name of fs.readdirSync(dir)) {
|
for (const name of readdirSync(dir)) {
|
||||||
const path = dir + '/' + name;
|
const path = dir + '/' + name;
|
||||||
const stats = fs.statSync(path);
|
const stats = statSync(path);
|
||||||
if (stats.isFile()) {
|
if (stats.isFile()) {
|
||||||
if (!filter || filter(path.slice(plain_dir.length + 1))) {
|
if (!filter || filter(path.slice(plain_dir.length + 1))) {
|
||||||
const key = path + ':' + hash_algorithm;
|
const key = path + ':' + hash_algorithm;
|
||||||
|
@ -97,9 +120,8 @@ async function get_plain_index(plain_dir, hash_algorithm, filter) {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
stream_queue.add(() =>
|
stream_queue.add(() =>
|
||||||
fs
|
createReadStream(path)
|
||||||
.createReadStream(path)
|
.pipe(createHash(hash_algorithm))
|
||||||
.pipe(crypto.createHash(hash_algorithm))
|
|
||||||
.once('readable', function () {
|
.once('readable', function () {
|
||||||
const hash = this.read();
|
const hash = this.read();
|
||||||
cache.set(key, { size: stats.size, mtimeMs: stats.mtimeMs, hash });
|
cache.set(key, { size: stats.size, mtimeMs: stats.mtimeMs, hash });
|
||||||
|
@ -114,14 +136,13 @@ async function get_plain_index(plain_dir, hash_algorithm, filter) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await stream_queue.done();
|
await stream_queue.done();
|
||||||
fs.writeFileSync(CACHE_PATH, v8.serialize(cache));
|
writeFileSync(CACHE_PATH, serialize(cache));
|
||||||
return plain_index;
|
return plain_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_crypt_filename(info, path, start) {
|
function get_crypt_filename(info, path, start) {
|
||||||
return (
|
return (
|
||||||
crypto
|
createHmac(info.hash_algorithm, info.hmac_key)
|
||||||
.createHmac(info.hash_algorithm, info.hmac_key)
|
|
||||||
.update(path + '@' + start)
|
.update(path + '@' + start)
|
||||||
.digest('base64url') + '-data'
|
.digest('base64url') + '-data'
|
||||||
);
|
);
|
||||||
|
@ -158,20 +179,20 @@ function make_stream_queue() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function encrypt({ plain: plain_dir, crypt: crypt_dir, filter }) {
|
export async function encrypt({ plain: plain_dir, crypt: crypt_dir, filter }) {
|
||||||
const added = new Set();
|
const added = new Set();
|
||||||
const deleted = new Set();
|
const deleted = new Set();
|
||||||
const updated = new Set();
|
const updated = new Set();
|
||||||
// READ CRYPT INDEX
|
// READ CRYPT INDEX
|
||||||
const info = get_info(crypt_dir);
|
const info = get_info(crypt_dir);
|
||||||
const { keyLength, ivLength } = crypto.getCipherInfo(info.cipher_algorithm);
|
const { keyLength, ivLength } = getCipherInfo(info.cipher_algorithm);
|
||||||
// CONSTRUCT PLAIN INDEX
|
// CONSTRUCT PLAIN INDEX
|
||||||
const plain_index = await get_plain_index(plain_dir, info.hash_algorithm, filter);
|
const plain_index = await get_plain_index(plain_dir, info.hash_algorithm, filter);
|
||||||
// CREATE INDEX OF PLAIN FILES AS THEY WILL APPEAR IN THE CRYPT INDEX
|
// CREATE INDEX OF PLAIN FILES AS THEY WILL APPEAR IN THE CRYPT INDEX
|
||||||
const path_hmac_lookup = new Map();
|
const path_hmac_lookup = new Map();
|
||||||
for (const path of plain_index.keys()) {
|
for (const path of plain_index.keys()) {
|
||||||
path_hmac_lookup.set(
|
path_hmac_lookup.set(
|
||||||
crypto.createHmac(info.hash_algorithm, info.hmac_key).update(path).digest('base64url'),
|
createHmac(info.hash_algorithm, info.hmac_key).update(path).digest('base64url'),
|
||||||
path,
|
path,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -179,14 +200,14 @@ async function encrypt({ plain: plain_dir, crypt: crypt_dir, filter }) {
|
||||||
for (const path_hmac of info.index.keys()) {
|
for (const path_hmac of info.index.keys()) {
|
||||||
if (!path_hmac_lookup.has(path_hmac)) {
|
if (!path_hmac_lookup.has(path_hmac)) {
|
||||||
deleted.add(path_hmac + '-index');
|
deleted.add(path_hmac + '-index');
|
||||||
fs.unlinkSync(crypt_dir + '/' + path_hmac + '-index');
|
unlinkSync(crypt_dir + '/' + path_hmac + '-index');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// UPDATE/ADD FILES
|
// UPDATE/ADD FILES
|
||||||
const stream_queue = make_stream_queue();
|
const stream_queue = make_stream_queue();
|
||||||
for (const [path_hmac, path] of path_hmac_lookup) {
|
for (const [path_hmac, path] of path_hmac_lookup) {
|
||||||
const { size, hash } = plain_index.get(path);
|
const { size, hash } = plain_index.get(path);
|
||||||
const hash_hmac = crypto.createHmac(info.hash_algorithm, info.hmac_key).update(hash).digest();
|
const hash_hmac = createHmac(info.hash_algorithm, info.hmac_key).update(hash).digest();
|
||||||
if (!info.index.has(path_hmac)) {
|
if (!info.index.has(path_hmac)) {
|
||||||
added.add(path);
|
added.add(path);
|
||||||
} else if (Buffer.compare(info.index.get(path_hmac).hash_hmac, hash_hmac)) {
|
} else if (Buffer.compare(info.index.get(path_hmac).hash_hmac, hash_hmac)) {
|
||||||
|
@ -194,16 +215,16 @@ async function encrypt({ plain: plain_dir, crypt: crypt_dir, filter }) {
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const key = crypto.randomBytes(keyLength);
|
const key = randomBytes(keyLength);
|
||||||
const iv = crypto.randomBytes(ivLength);
|
const iv = randomBytes(ivLength);
|
||||||
const cipher = crypto.createCipheriv(info.cipher_algorithm, key, iv);
|
const cipher = createCipheriv(info.cipher_algorithm, key, iv);
|
||||||
fs.writeFileSync(
|
writeFileSync(
|
||||||
crypt_dir + '/' + path_hmac + '-index',
|
crypt_dir + '/' + path_hmac + '-index',
|
||||||
hash_hmac.toString('base64url') +
|
hash_hmac.toString('base64url') +
|
||||||
'\n' +
|
'\n' +
|
||||||
crypto.publicEncrypt(info.public_key, key).toString('base64url') +
|
publicEncrypt(info.public_key, key).toString('base64url') +
|
||||||
'\n' +
|
'\n' +
|
||||||
crypto.publicEncrypt(info.public_key, iv).toString('base64url') +
|
publicEncrypt(info.public_key, iv).toString('base64url') +
|
||||||
'\n' +
|
'\n' +
|
||||||
Buffer.concat([cipher.update(path), cipher.final()]).toString('base64url') +
|
Buffer.concat([cipher.update(path), cipher.final()]).toString('base64url') +
|
||||||
'\n',
|
'\n',
|
||||||
|
@ -211,17 +232,16 @@ async function encrypt({ plain: plain_dir, crypt: crypt_dir, filter }) {
|
||||||
for (let start = 0; ; start += info.split_size) {
|
for (let start = 0; ; start += info.split_size) {
|
||||||
if (start < size) {
|
if (start < size) {
|
||||||
stream_queue.add(() =>
|
stream_queue.add(() =>
|
||||||
fs
|
createReadStream(plain_dir + '/' + path, {
|
||||||
.createReadStream(plain_dir + '/' + path, {
|
start,
|
||||||
start,
|
end: Math.min(start + info.split_size - 1, size - 1),
|
||||||
end: Math.min(start + info.split_size - 1, size - 1),
|
})
|
||||||
})
|
.pipe(createCipheriv(info.cipher_algorithm, key, iv))
|
||||||
.pipe(crypto.createCipheriv(info.cipher_algorithm, key, iv))
|
.pipe(createWriteStream(crypt_dir + '/' + get_crypt_filename(info, path, start))),
|
||||||
.pipe(fs.createWriteStream(crypt_dir + '/' + get_crypt_filename(info, path, start))),
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
fs.unlinkSync(crypt_dir + '/' + get_crypt_filename(info, path, start));
|
unlinkSync(crypt_dir + '/' + get_crypt_filename(info, path, start));
|
||||||
} catch {
|
} catch {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -232,21 +252,21 @@ async function encrypt({ plain: plain_dir, crypt: crypt_dir, filter }) {
|
||||||
return { added, deleted, updated };
|
return { added, deleted, updated };
|
||||||
}
|
}
|
||||||
|
|
||||||
function clean({ crypt: crypt_dir, passphrase }) {
|
export function clean({ crypt: crypt_dir, passphrase }) {
|
||||||
// READ CRYPT INDEX
|
// READ CRYPT INDEX
|
||||||
const info = get_info(crypt_dir, passphrase);
|
const info = get_info(crypt_dir, passphrase);
|
||||||
// GET CRYPT FILES
|
// GET CRYPT FILES
|
||||||
const crypt_filenames = new Set();
|
const crypt_filenames = new Set();
|
||||||
for (const dirent of fs.readdirSync(crypt_dir, { withFileTypes: true })) {
|
for (const dirent of readdirSync(crypt_dir, { withFileTypes: true })) {
|
||||||
if (dirent.isFile() && dirent.name.endsWith('-data')) {
|
if (dirent.isFile() && dirent.name.endsWith('-data')) {
|
||||||
crypt_filenames.add(dirent.name);
|
crypt_filenames.add(dirent.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// SKIP ALL FILES REFERRED TO BY AN INDEX
|
// SKIP ALL FILES REFERRED TO BY AN INDEX
|
||||||
for (const item of info.index.values()) {
|
for (const item of info.index.values()) {
|
||||||
const key = crypto.privateDecrypt(info.private_key, item.key);
|
const key = privateDecrypt(info.private_key, item.key);
|
||||||
const iv = crypto.privateDecrypt(info.private_key, item.iv);
|
const iv = privateDecrypt(info.private_key, item.iv);
|
||||||
const decipher = crypto.createDecipheriv(info.cipher_algorithm, key, iv);
|
const decipher = createDecipheriv(info.cipher_algorithm, key, iv);
|
||||||
const path = Buffer.concat([decipher.update(item.path), decipher.final()]).toString();
|
const path = Buffer.concat([decipher.update(item.path), decipher.final()]).toString();
|
||||||
for (let start = 0; ; start += info.split_size) {
|
for (let start = 0; ; start += info.split_size) {
|
||||||
const crypt_filename = get_crypt_filename(info, path, start);
|
const crypt_filename = get_crypt_filename(info, path, start);
|
||||||
|
@ -259,16 +279,16 @@ function clean({ crypt: crypt_dir, passphrase }) {
|
||||||
}
|
}
|
||||||
// DELETE UNUSED CRYPT FILES
|
// DELETE UNUSED CRYPT FILES
|
||||||
for (const crypt_filename of crypt_filenames) {
|
for (const crypt_filename of crypt_filenames) {
|
||||||
fs.unlinkSync(crypt_dir + '/' + crypt_filename);
|
unlinkSync(crypt_dir + '/' + crypt_filename);
|
||||||
}
|
}
|
||||||
return { deleted: crypt_filenames };
|
return { deleted: crypt_filenames };
|
||||||
}
|
}
|
||||||
|
|
||||||
async function decrypt({ plain: plain_dir, crypt: crypt_dir, filter, passphrase }) {
|
export async function decrypt({ plain: plain_dir, crypt: crypt_dir, filter, passphrase }) {
|
||||||
const added = new Set();
|
const added = new Set();
|
||||||
const deleted = new Set();
|
const deleted = new Set();
|
||||||
const updated = new Set();
|
const updated = new Set();
|
||||||
fs.mkdirSync(plain_dir, { recursive: true });
|
mkdirSync(plain_dir, { recursive: true });
|
||||||
// READ CRYPT INDEX
|
// READ CRYPT INDEX
|
||||||
const info = get_info(crypt_dir, passphrase);
|
const info = get_info(crypt_dir, passphrase);
|
||||||
// CONSTRUCT PLAIN INDEX
|
// CONSTRUCT PLAIN INDEX
|
||||||
|
@ -277,15 +297,14 @@ async function decrypt({ plain: plain_dir, crypt: crypt_dir, filter, passphrase
|
||||||
// DELETE MISSING FILES
|
// DELETE MISSING FILES
|
||||||
const path_hmac_lookup = new Map();
|
const path_hmac_lookup = new Map();
|
||||||
for (const path of plain_index.keys()) {
|
for (const path of plain_index.keys()) {
|
||||||
const path_hmac = crypto
|
const path_hmac = createHmac(info.hash_algorithm, info.hmac_key)
|
||||||
.createHmac(info.hash_algorithm, info.hmac_key)
|
|
||||||
.update(path)
|
.update(path)
|
||||||
.digest('base64url');
|
.digest('base64url');
|
||||||
if (info.index.has(path_hmac)) {
|
if (info.index.has(path_hmac)) {
|
||||||
path_hmac_lookup.set(path_hmac, path);
|
path_hmac_lookup.set(path_hmac, path);
|
||||||
} else {
|
} else {
|
||||||
deleted.add(path);
|
deleted.add(path);
|
||||||
fs.unlinkSync(plain_dir + '/' + path);
|
unlinkSync(plain_dir + '/' + path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// UPDATE/ADD FILES
|
// UPDATE/ADD FILES
|
||||||
|
@ -296,8 +315,7 @@ async function decrypt({ plain: plain_dir, crypt: crypt_dir, filter, passphrase
|
||||||
target = added;
|
target = added;
|
||||||
} else if (
|
} else if (
|
||||||
Buffer.compare(
|
Buffer.compare(
|
||||||
crypto
|
createHmac(info.hash_algorithm, info.hmac_key)
|
||||||
.createHmac(info.hash_algorithm, info.hmac_key)
|
|
||||||
.update(plain_index.get(path_hmac_lookup.get(path_hmac)).hash)
|
.update(plain_index.get(path_hmac_lookup.get(path_hmac)).hash)
|
||||||
.digest(),
|
.digest(),
|
||||||
item.hash_hmac,
|
item.hash_hmac,
|
||||||
|
@ -307,30 +325,27 @@ async function decrypt({ plain: plain_dir, crypt: crypt_dir, filter, passphrase
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const key = crypto.privateDecrypt(info.private_key, item.key);
|
const key = privateDecrypt(info.private_key, item.key);
|
||||||
const iv = crypto.privateDecrypt(info.private_key, item.iv);
|
const iv = privateDecrypt(info.private_key, item.iv);
|
||||||
const decipher = crypto.createDecipheriv(info.cipher_algorithm, key, iv);
|
const decipher = createDecipheriv(info.cipher_algorithm, key, iv);
|
||||||
const path = Buffer.concat([decipher.update(item.path), decipher.final()]).toString();
|
const path = Buffer.concat([decipher.update(item.path), decipher.final()]).toString();
|
||||||
target.add(path);
|
target.add(path);
|
||||||
fs.mkdirSync(plain_dir + '/' + path_.dirname(path), { recursive: true });
|
mkdirSync(plain_dir + '/' + dirname(path), { recursive: true });
|
||||||
fs.writeFileSync(plain_dir + '/' + path, Buffer.alloc(0));
|
writeFileSync(plain_dir + '/' + path, Buffer.alloc(0));
|
||||||
for (let start = 0; ; start += info.split_size) {
|
for (let start = 0; ; start += info.split_size) {
|
||||||
const file = crypt_dir + '/' + get_crypt_filename(info, path, start);
|
const file = crypt_dir + '/' + get_crypt_filename(info, path, start);
|
||||||
try {
|
try {
|
||||||
fs.accessSync(file);
|
accessSync(file);
|
||||||
} catch {
|
} catch {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
stream_queue.add(() =>
|
stream_queue.add(() =>
|
||||||
fs
|
createReadStream(file)
|
||||||
.createReadStream(file)
|
.pipe(createDecipheriv(info.cipher_algorithm, key, iv))
|
||||||
.pipe(crypto.createDecipheriv(info.cipher_algorithm, key, iv))
|
.pipe(createWriteStream(plain_dir + '/' + path, { flags: 'r+', start })),
|
||||||
.pipe(fs.createWriteStream(plain_dir + '/' + path, { flags: 'r+', start })),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await stream_queue.done();
|
await stream_queue.done();
|
||||||
return { added, deleted, updated };
|
return { added, deleted, updated };
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { init, encrypt, clean, decrypt };
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"type": "module"
|
||||||
|
}
|
16
pass.js
16
pass.js
|
@ -1,12 +1,12 @@
|
||||||
const readline = require('readline');
|
import { createInterface } from 'readline';
|
||||||
const stream = require('stream');
|
import { Writable } from 'stream';
|
||||||
const devnull = new stream.Writable({ write: (chunk, encoding, cb) => cb() });
|
|
||||||
|
|
||||||
function get_pass(prompt) {
|
const devnull = new Writable({ write: (chunk, encoding, cb) => cb() });
|
||||||
|
|
||||||
|
export function get_pass(prompt) {
|
||||||
process.stdout.write(prompt);
|
process.stdout.write(prompt);
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
const rl = readline
|
const rl = createInterface({ input: process.stdin, output: devnull, terminal: true })
|
||||||
.createInterface({ input: process.stdin, output: devnull, terminal: true })
|
|
||||||
.once('line', (line) => {
|
.once('line', (line) => {
|
||||||
res(line);
|
res(line);
|
||||||
rl.close();
|
rl.close();
|
||||||
|
@ -18,7 +18,7 @@ function get_pass(prompt) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function confirm_pass(prompt1, prompt2, error) {
|
export async function confirm_pass(prompt1, prompt2, error) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const pass1 = await get_pass(prompt1);
|
const pass1 = await get_pass(prompt1);
|
||||||
const pass2 = await get_pass(prompt2);
|
const pass2 = await get_pass(prompt2);
|
||||||
|
@ -28,5 +28,3 @@ async function confirm_pass(prompt1, prompt2, error) {
|
||||||
process.stdout.write(error + '\n');
|
process.stdout.write(error + '\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { get_pass, confirm_pass };
|
|
||||||
|
|
Loading…
Reference in New Issue