Files
Media-Aggregation-and-Sorti…/ServerFiles/password_manager.js
T

102 lines
2.6 KiB
JavaScript

const crypto = require('crypto');
const fs = require('fs');
const config = require('./config');
const ALGORITHM = 'aes-256-gcm';
const KEY_LENGTH = 32;
const IV_LENGTH = 16;
const SALT_LENGTH = 32;
function deriveKey(passphrase, salt) {
return crypto.pbkdf2Sync(passphrase, salt, 100000, KEY_LENGTH, 'sha512');
}
function getMachineId() {
const os = require('os');
const raw = `${os.hostname()}-${os.platform()}-${os.arch()}-${os.userInfo().username}`;
return crypto.createHash('sha256').update(raw).digest('hex');
}
function encrypt(plaintext) {
const machineKey = getMachineId();
const salt = crypto.randomBytes(SALT_LENGTH);
const key = deriveKey(machineKey, salt);
const iv = crypto.randomBytes(IV_LENGTH);
const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
let encrypted = cipher.update(plaintext, 'utf-8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag();
return {
salt: salt.toString('hex'),
iv: iv.toString('hex'),
authTag: authTag.toString('hex'),
data: encrypted,
};
}
function decrypt(encObj) {
const machineKey = getMachineId();
const salt = Buffer.from(encObj.salt, 'hex');
const key = deriveKey(machineKey, salt);
const iv = Buffer.from(encObj.iv, 'hex');
const authTag = Buffer.from(encObj.authTag, 'hex');
const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
decipher.setAuthTag(authTag);
let decrypted = decipher.update(encObj.data, 'hex', 'utf-8');
decrypted += decipher.final('utf-8');
return decrypted;
}
function storePassword(password) {
config.ensureConfigDir();
const encrypted = encrypt(password);
const content = JSON.stringify(encrypted);
fs.writeFileSync(config.PASSWORD_FILE, content, { encoding: 'utf-8', mode: 0o600 });
// On Windows, hide the file with attrib
if (process.platform === 'win32') {
try {
const { execSync } = require('child_process');
execSync(`attrib +h "${config.PASSWORD_FILE}"`, { stdio: 'ignore' });
} catch (_) {}
}
return true;
}
function retrievePassword() {
if (!fs.existsSync(config.PASSWORD_FILE)) return null;
try {
const content = fs.readFileSync(config.PASSWORD_FILE, 'utf-8');
const encObj = JSON.parse(content);
return decrypt(encObj);
} catch (err) {
return null;
}
}
function hasStoredPassword() {
return fs.existsSync(config.PASSWORD_FILE);
}
function deletePassword() {
if (fs.existsSync(config.PASSWORD_FILE)) {
fs.unlinkSync(config.PASSWORD_FILE);
return true;
}
return false;
}
module.exports = {
storePassword,
retrievePassword,
hasStoredPassword,
deletePassword,
};