penguins-eggs
Version:
A remaster system tool, compatible with Almalinux, Alpine, Arch, Debian, Devuan, Fedora, Manjaro, Opensuse, Ubuntu and derivatives
147 lines (146 loc) • 7.12 kB
JavaScript
/**
* ./src/classes/ovary.d/luks-home.ts
* penguins-eggs v.25.10.x / ecmascript 2020
* author: Piero Proietti
* email: piero.proietti@gmail.com
* license: MIT
*/
// packages
import fs from 'fs';
import { exec } from '../../lib/utils.js';
import Utils from '../utils.js';
const noop = () => { };
/**
* luksHome()
*
* create a container LUKS with the entire
* filesystem.squashfs
*/
export async function luksHome(clone = false, homecrypt = false) {
const loggers = {
info: this.hidden ? noop : Utils.info,
log: this.hidden ? noop : console.log,
success: this.hidden ? noop : Utils.success,
warning: this.hidden ? noop : Utils.warning
};
const { info, log, success, warning } = loggers;
try {
/**
* this.luksMappedName = 'home.img';
* this.luksFile = `/var/tmp/${luksMappedName}`
* this.luksDevice = `/dev/mapper/${luksMappedName}`
* this.luksMountpoint = `/tmp/mnt/${luksMappedName}`
* this.luksPassword = '0'
*/
if (this.hidden) {
Utils.warning('intentionally blank. System is working, please wait');
}
log();
log('====================================');
log(` Creating ${this.luksMappedName}`);
log('====================================');
// Utils.warning('1. Calculation of space requirements...')
const sizeString = (await exec('du -sb --exclude=/home/eggs /home', { capture: true })).data.trim().split(/\s+/)[0];
const size = Number.parseInt(sizeString, 10);
const fsOverhead = Math.ceil(size * 0.05);
const luksHeader = 32 * 1024 * 1024;
const safetyBuffer = 100 * 1024 * 1024;
let calculatedSize = size + fsOverhead + luksHeader + safetyBuffer;
const minSize = 64 * 1024 * 1024;
if (calculatedSize < minSize)
calculatedSize = minSize;
const alignment = 4 * 1024 * 1024;
const luksSize = Math.ceil(calculatedSize / alignment) * alignment;
warning(`------------------------------------------`);
warning(`HOME CRYPT CALCULATION (Read-Only):`);
warning(` Data Payload: ${bytesToGB(size)}`);
warning(` Overhead+Buf: ${bytesToGB(luksSize - size)}`);
warning(` TOTAL SIZE: ${bytesToGB(luksSize)}`);
warning(`------------------------------------------`);
warning(`creating partition LUKS: ${this.luksFile}`);
await this.luksExecuteCommand('truncate', ['--size', `${luksSize}`, this.luksFile]);
warning(`formatting ${this.luksFile} as a LUKS volume...`);
// await this.luksExecuteCommand('cryptsetup', ['--batch-mode', 'luksFormat', this.luksFile], `${this.luksPassword}\n`);
const luksFormatArgs = this.buildLuksFormatArgs(this.luksConfig, this.luksFile);
await this.luksExecuteCommand('cryptsetup', luksFormatArgs, `${this.luksPassword}\n`);
warning(`opening the LUKS volume. It will be mapped to ${this.luksDevice}`);
await this.luksExecuteCommand('cryptsetup', ['luksOpen', this.luksFile, this.luksMappedName], `${this.luksPassword}\n`);
warning(`formatting ext4 `);
await exec(`mkfs.ext4 -L live-home ${this.luksDevice}`, this.echo);
warning(`mounting ${this.luksDevice} on ${this.luksMountpoint}`);
if (fs.existsSync(this.luksMountpoint)) {
if (Utils.isMountpoint(this.luksMountpoint)) {
throw new Error(`${this.luksMountpoint} is already mounted, process will abort!`);
}
else {
await exec(`rm -rf ${this.luksMountpoint}`, this.echo);
}
}
await exec(`mkdir -p ${this.luksMountpoint}`, this.echo);
await exec(`mount /dev/mapper/${this.luksMappedName} ${this.luksMountpoint}`, this.echo);
warning(`copying /home on ${this.luksMountpoint}`);
await exec(`rsync -ah --exclude='eggs' /home/ ${this.luksMountpoint}`, this.echo);
/**
* utenti e gruppi in .system-backup
*/
warning(`saving user accounts info...`);
await exec(`mkdir -p ${this.luksMountpoint}/.system-backup`, this.echo);
// passwd/shadow: solo utenti con UID >= 1000
await exec(`awk -F: '$3 >= 1000 {print}' /etc/passwd > ${this.luksMountpoint}/.system-backup/passwd`, this.echo);
await exec(`awk -F: '$3 >= 1000 {print}' /etc/shadow > ${this.luksMountpoint}/.system-backup/shadow`, this.echo);
// group/gshadow TUTTI
// Gli utenti possono appartenere a gruppi di sistema (sudo, audio, video, etc.)
await exec(`cp /etc/group ${this.luksMountpoint}/.system-backup/group`, this.echo);
await exec(`cp /etc/gshadow ${this.luksMountpoint}/.system-backup/gshadow`, this.echo);
/**
* saving display manager (autologin) configs...
*/
warning(`saving display manager configuration...`);
// GDM (gdm3 è comune su Debian/Ubuntu)
await exec(`[ -e /etc/gdm3 ] && cp -a /etc/gdm3 ${this.luksMountpoint}/.system-backup/`, this.echo);
// GDM (altre distro)
await exec(`[ -e /etc/gdm ] && cp -a /etc/gdm ${this.luksMountpoint}/.system-backup/`, this.echo);
// LightDM
await exec(`[ -e /etc/lightdm ] && cp -a /etc/lightdm ${this.luksMountpoint}/.system-backup/`, this.echo);
// SDDM (sia file .conf che directory .conf.d)
await exec(`[ -e /etc/sddm.conf ] && cp -a /etc/sddm.conf ${this.luksMountpoint}/.system-backup/`, this.echo);
await exec(`[ -e /etc/sddm.conf.d ] && cp -a /etc/sddm.conf.d ${this.luksMountpoint}/.system-backup/`, this.echo);
warning(`Syncing filesystem on ${this.luksMountpoint}...`);
await exec('sync', this.echo); // Forza scrittura dati su disco
// Shrink()
await this.luksShrink();
warning(`moving ${this.luksMappedName} to (ISO)/live/.`);
await exec(`mv ${this.luksFile} ${this.settings.iso_work}/live`, this.echo);
warning('encryption process successfully completed!');
}
catch (error) {
if (error instanceof Error) {
Utils.error(`ERROR: ${error.message}`);
}
else {
Utils.error(`An unknown error has occurred.`);
}
Utils.warning('Cleaning performed following the error...');
if (fs.existsSync(this.luksMountpoint)) {
await exec(`umount -lf ${this.luksMountpoint}`).catch(() => { });
}
if (fs.existsSync(this.luksDevice)) {
await this.luksExecuteCommand('cryptsetup', ['close', this.luksMappedName]).catch(() => { });
}
if (fs.existsSync(this.luksFile)) {
Utils.warning(`Removing temporary container: ${this.luksFile}`);
fs.unlinkSync(this.luksFile);
}
await Utils.pressKeyToExit();
process.exit(1);
}
}
/**
* Converte bytes in gigabytes per la visualizzazione.
*/
function bytesToGB(bytes) {
if (bytes === 0)
return '0.00 GB';
const gigabytes = bytes / (1024 * 1024 * 1024);
return gigabytes.toFixed(2) + ' GB';
}