penguins-eggs 25.11.29 → 25.12.7

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.
Files changed (92) hide show
  1. package/.oclif.manifest.json +1 -1
  2. package/README.md +72 -110
  3. package/README.pdf +11041 -10623
  4. package/conf/derivatives.yaml +2 -1
  5. package/conf/exclude.list.d/var.list +11 -6
  6. package/dist/appimage/dependency-manager.js +1 -1
  7. package/dist/classes/cli-autologin.js +77 -52
  8. package/dist/classes/compressors.d.ts +7 -10
  9. package/dist/classes/compressors.js +44 -31
  10. package/dist/classes/distro.js +2 -2
  11. package/dist/classes/diversions.js +2 -3
  12. package/dist/classes/incubation/fisherman-helper/initcpio.d.ts +2 -5
  13. package/dist/classes/incubation/fisherman-helper/initcpio.js +7 -4
  14. package/dist/classes/incubation/fisherman-helper/settings.js +1 -1
  15. package/dist/classes/incubation/fisherman.js +1 -1
  16. package/dist/classes/incubation/incubator.js +1 -1
  17. package/dist/classes/ovary.d/create-xdg-autostart.js +1 -1
  18. package/dist/classes/ovary.d/edit-live-fs.d.ts +1 -12
  19. package/dist/classes/ovary.d/edit-live-fs.js +129 -135
  20. package/dist/classes/ovary.d/make-dot-disk.js +1 -1
  21. package/dist/classes/ovary.d/produce.js +1 -1
  22. package/dist/classes/ovary.d/user-create-live.d.ts +4 -10
  23. package/dist/classes/ovary.d/user-create-live.js +82 -84
  24. package/dist/classes/ovary.d/users-remove.d.ts +5 -6
  25. package/dist/classes/ovary.d/users-remove.js +61 -31
  26. package/dist/classes/ovary.d.ts +2 -2
  27. package/dist/classes/ovary.js +2 -2
  28. package/dist/classes/pacman.d/alpine.js +2 -2
  29. package/dist/classes/pacman.d/archlinux.js +2 -2
  30. package/dist/classes/pacman.d/debian.js +2 -3
  31. package/dist/classes/pacman.d/fedora.js +2 -3
  32. package/dist/classes/pacman.d/openmamba.js +2 -3
  33. package/dist/classes/pacman.d/opensuse.js +2 -3
  34. package/dist/classes/pacman.d.ts +0 -5
  35. package/dist/classes/pacman.js +3 -16
  36. package/dist/classes/pve-live.js +1 -1
  37. package/dist/classes/settings.js +1 -1
  38. package/dist/classes/sys-users.d.ts +76 -0
  39. package/dist/classes/sys-users.js +206 -0
  40. package/dist/classes/utils.d/kernel.js +3 -3
  41. package/dist/classes/utils.d.ts +15 -6
  42. package/dist/classes/utils.js +79 -46
  43. package/dist/classes/xdg.js +1 -1
  44. package/dist/classes/yolk.js +2 -4
  45. package/dist/commands/export/appimage.js +3 -3
  46. package/dist/commands/export/pkg.js +3 -3
  47. package/dist/commands/export/tarballs.js +3 -3
  48. package/dist/commands/krill.js +1 -1
  49. package/dist/commands/produce.js +9 -4
  50. package/dist/commands/setup/install.js +1 -1
  51. package/dist/commands/setup/purge.js +1 -1
  52. package/dist/commands/tools/yolk.js +1 -1
  53. package/dist/commands/update.js +1 -2
  54. package/dist/interfaces/i-exec.d.ts +1 -0
  55. package/dist/krill/classes/prepare.d/location.js +1 -1
  56. package/dist/krill/classes/prepare.d/partitions.js +1 -1
  57. package/dist/krill/classes/prepare.d/users.js +2 -2
  58. package/dist/krill/classes/prepare.js +5 -5
  59. package/dist/krill/classes/sequence.d/add_user.d.ts +3 -15
  60. package/dist/krill/classes/sequence.d/add_user.js +87 -57
  61. package/dist/krill/classes/sequence.d/change_password.d.ts +5 -7
  62. package/dist/krill/classes/sequence.d/change_password.js +25 -10
  63. package/dist/krill/classes/sequence.d/del_live_user.d.ts +5 -7
  64. package/dist/krill/classes/sequence.d/del_live_user.js +39 -25
  65. package/dist/krill/classes/sequence.d/fstab.js +1 -1
  66. package/dist/krill/classes/sequence.d/grubcfg.d.ts +3 -7
  67. package/dist/krill/classes/sequence.d/grubcfg.js +33 -13
  68. package/dist/krill/classes/sequence.d/mkfs.js +1 -2
  69. package/dist/krill/classes/sequence.d/unpackfs.d.ts +2 -4
  70. package/dist/krill/classes/sequence.d/unpackfs.js +8 -5
  71. package/dist/krill/classes/sequence.js +2 -3
  72. package/dist/krill/components/title.js +2 -2
  73. package/dist/krill/lib/select_installation_device.js +1 -1
  74. package/dist/krill/lib/select_replaced_partition.js +1 -1
  75. package/dist/lib/utils.d.ts +51 -19
  76. package/dist/lib/utils.js +225 -20
  77. package/manpages/doc/man/eggs.1.gz +0 -0
  78. package/manpages/doc/man/eggs.html +8 -8
  79. package/package.json +9 -9
  80. package/perrisbrewery/template/dependencies.yaml +1 -0
  81. package/scripts/boot-encrypted-root.sh +220 -0
  82. package/scripts/mount-encrypted-home.sh +324 -0
  83. package/dracut/create-symlink +0 -71
  84. package/dracut/dracut-log.txt +0 -3
  85. package/dracut/export +0 -4
  86. package/dracut/export-dracut-analysis +0 -51
  87. package/dracut/export-dracut-log +0 -2
  88. package/dracut/mkisofs +0 -10
  89. package/dracut/renew-initramfs +0 -17
  90. package/dracut/sbin2bin +0 -10
  91. package/dracut/update-dracut-conf-d +0 -2
  92. package/dracut/update-dracut-modules +0 -62
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * ./src/classes/ovary.d/edit-live-fs.ts
3
- * penguins-eggs v.25.11.x / ecmascript 2020
3
+ * penguins-eggs v.25.12.5 / ecmascript 2020
4
4
  * author: Piero Proietti
5
5
  * email: piero.proietti@gmail.com
6
6
  * license: MIT
@@ -9,76 +9,45 @@
9
9
  import fs from 'fs';
10
10
  import os from 'os';
11
11
  import path from 'node:path';
12
- import shx from 'shelljs';
12
+ import { shx } from '../../lib/utils.js';
13
13
  import Utils from '../utils.js';
14
14
  import Pacman from '../pacman.js';
15
15
  import Systemctl from '../systemctl.js';
16
16
  import { exec } from '../../lib/utils.js';
17
17
  // _dirname
18
18
  const __dirname = path.dirname(new URL(import.meta.url).pathname);
19
- /**
20
- * editLiveFs
21
- * - Mark if is_clone or is_clone_crypted
22
- * - Truncate logs, remove archived log
23
- * - Allow all fixed drives to be mounted with pmount
24
- * - Enable or disable password login trhough ssh for users (not root)
25
- * - Create an empty /etc/fstab
26
- * - Blanck /etc/machine-id
27
- * - Add some basic files to /dev
28
- * - Clear configs from /etc/network/interfaces, wicd and NetworkManager and netman
29
- */
30
19
  export async function editLiveFs(clone = false) {
31
- if (this.verbose) {
20
+ if (this.verbose)
32
21
  console.log('Ovary: editLiveFs');
33
- }
34
22
  const workDir = this.settings.work_dir.merged;
35
- /**
36
- * /etc/penguins-eggs.d/is_clone file created on live
37
- */
38
23
  if (clone) {
39
24
  await exec(`touch ${workDir}/etc/penguins-eggs.d/is_clone`, this.echo);
40
25
  }
41
- /**
42
- * /etc/default/epoptes-client created on live
43
- */
44
26
  if (Pacman.packageIsInstalled('epoptes')) {
45
27
  const file = `${workDir}/etc/default/epoptes-client`;
46
28
  const text = `SERVER=${os.hostname}.local\n`;
47
29
  fs.writeFileSync(file, text);
48
30
  }
49
31
  if (this.familyId === 'debian') {
50
- // Aggiungo UMASK=0077 in /etc/initramfs-tools/conf.d/calamares-safe-initramfs.conf
51
32
  const text = 'UMASK=0077\n';
52
33
  const file = '/etc/initramfs-tools/conf.d/eggs-safe-initramfs.conf';
53
34
  Utils.write(file, text);
54
35
  }
55
- // Truncate logs, remove archived logs.
36
+ // Truncate logs
56
37
  let cmd = `find ${workDir}/var/log -name "*gz" -print0 | xargs -0r rm -f`;
57
38
  await exec(cmd, this.echo);
58
39
  cmd = `find ${workDir}/var/log/ -type f -exec truncate -s 0 {} \\;`;
59
40
  await exec(cmd, this.echo);
60
41
  // =========================================================================
61
- // FIX STRUTTURALE PER DEVUAN/DEBIAN (/var folders)
42
+ // FIX DEFINITIVO PER DEVUAN/SYSVINIT (Init Script Hardening)
62
43
  // =========================================================================
63
- // Ricrea le directory essenziali che potrebbero essere state rimosse
64
- // o che devono esistere vuote per il corretto avvio dei servizi.
65
- const dirsToCreate = [
66
- `${workDir}/var/lib/dbus`, // Fondamentale per dbus
67
- `${workDir}/var/spool/rsyslog`, // Fondamentale per rsyslog
68
- `${workDir}/var/spool/cron/crontabs` // Fondamentale per cron
69
- ];
70
- for (const dir of dirsToCreate) {
71
- if (!fs.existsSync(dir)) {
72
- await exec(`mkdir -p ${dir}`, this.echo);
73
- // Assicuriamo permessi corretti (dbus vuole 755 root:root di base)
74
- await exec(`chmod 755 ${dir}`, this.echo);
75
- }
44
+ if (Utils.isSysvinit()) {
45
+ if (this.verbose)
46
+ console.log('SysVinit detected: Hardening init scripts...');
47
+ await patchInitScripts(workDir, this.verbose);
76
48
  }
77
49
  // =========================================================================
78
- // FIX CRITICO PER /var/run e /var/lock
79
- // =========================================================================
80
- // Su Debian/Devuan moderni, /var/run DEVE essere un symlink a /run.
81
- // Se rsync lo ha copiato come directory, D-Bus e altri servizi falliscono.
50
+ // Fix Symlinks /var/run e /var/lock
82
51
  const varRun = `${workDir}/var/run`;
83
52
  if (fs.existsSync(varRun) && !fs.lstatSync(varRun).isSymbolicLink()) {
84
53
  if (this.verbose)
@@ -93,20 +62,14 @@ export async function editLiveFs(clone = false) {
93
62
  await exec(`rm -rf ${varLock}`, this.echo);
94
63
  await exec(`ln -s /run/lock ${varLock}`, this.echo);
95
64
  }
96
- // =========================================================================
97
- // Allow all fixed drives to be mounted with pmount
65
+ // Altri fix standard
98
66
  if (this.settings.config.pmount_fixed && fs.existsSync(`${workDir}/etc/pmount.allow`)) {
99
- // MX aggiunto /etc
100
67
  await exec(`sed -i 's:#/dev/sd\[a-z\]:/dev/sd\[a-z\]:' ${workDir}/etc/pmount.allow`, this.echo);
101
68
  }
102
- // Remove obsolete live-config file
103
69
  if (fs.existsSync(`${workDir}lib/live/config/1161-openssh-server`)) {
104
70
  await exec(`rm -f ${workDir}/lib/live/config/1161-openssh-server`, this.echo);
105
71
  }
106
72
  if (fs.existsSync(`${workDir}/etc/ssh/sshd_config`)) {
107
- /**
108
- * enable/disable SSH root/users password login
109
- */
110
73
  await exec(`sed -i '/PermitRootLogin/d' ${workDir}/etc/ssh/sshd_config`);
111
74
  await exec(`sed -i '/PasswordAuthentication/d' ${workDir}/etc/ssh/sshd_config`);
112
75
  if (this.settings.config.ssh_pass) {
@@ -117,111 +80,53 @@ export async function editLiveFs(clone = false) {
117
80
  await exec(`echo 'PasswordAuthentication no' | tee -a ${workDir}/etc/ssh/sshd_config`, this.echo);
118
81
  }
119
82
  }
120
- /**
121
- * /etc/fstab should exist, even if it's empty,
122
- * to prevent error messages at boot
123
- */
124
83
  await exec(`rm ${workDir}/etc/fstab`, this.echo);
125
84
  await exec(`touch ${workDir}/etc/fstab`, this.echo);
126
- /**
127
- * Remove crypttab if exists
128
- * this is crucial for tpm systems.
129
- */
130
85
  if (fs.existsSync(`${workDir}/etc/crypttab`)) {
131
86
  await exec(`rm ${workDir}/etc/crypttab`, this.echo);
132
87
  }
133
- // =========================================================================
134
- // FIX MACHINE-ID (Il colpevole del blocco SysVinit)
135
- // =========================================================================
136
- /**
137
- * Blank out systemd machine id.
138
- * SU SYSTEMD: File vuoto = rigenerazione.
139
- * SU SYSVINIT (Devuan): File NON deve esistere o deve essere 0 bytes.
140
- */
141
- // 1. Pulisci /etc/machine-id
88
+ // 🔧 [MODIFICA 1] Machine ID cleanup
89
+ // Cancelliamo SEMPRE il machine-id, anche su SysVinit.
90
+ // Questo garantisce che lo script patchato (dbus) trovi il file mancante e lo rigeneri.
142
91
  if (fs.existsSync(`${workDir}/etc/machine-id`)) {
143
92
  await exec(`rm ${workDir}/etc/machine-id`, this.echo);
144
- // Per Systemd serve il file vuoto per fare il bind mount
145
- // Per Devuan va bene vuoto (lo riempie dbus-uuidgen)
146
- await exec(`touch ${workDir}/etc/machine-id`, this.echo);
93
+ await exec(`touch ${workDir}/etc/machine-id`, this.echo); // Lo ricreiamo vuoto
147
94
  }
148
- // 2. Rimuovi /var/lib/dbus/machine-id
149
- // Questo è il file "vero" per dbus su sistemi non-systemd.
150
- // Deve sparire per essere rigenerato al boot.
95
+ // Rimuoviamo anche quello in /var/lib/dbus per forzare la rigenerazione
151
96
  if (fs.existsSync(`${workDir}/var/lib/dbus/machine-id`)) {
152
97
  await exec(`rm ${workDir}/var/lib/dbus/machine-id`, this.echo);
153
98
  }
154
- // =========================================================================
155
- /**
156
- * LMDE4: utilizza UbuntuMono16.pf2
157
- * aggiungo un link a /boot/grub/fonts/UbuntuMono16.pf2
158
- */
159
99
  if (fs.existsSync(`${workDir}/boot/grub/fonts/unicode.pf2`)) {
160
100
  shx.cp(`${workDir}/boot/grub/fonts/unicode.pf2`, `${workDir}/boot/grub/fonts/UbuntuMono16.pf2`);
161
101
  }
162
- /**
163
- * cleaning /etc/resolv.conf
164
- */
165
- const resolvFile = `${workDir}/etc/resolv.conf`;
166
- shx.rm(resolvFile);
167
- /**
168
- * Per tutte le distro systemd
169
- */
102
+ shx.rm(`${workDir}/etc/resolv.conf`);
103
+ // Systemd cleanup
170
104
  if (Utils.isSystemd()) {
171
105
  const systemdctl = new Systemctl(this.verbose);
172
- /*
173
- * Arch: /ci/minimal/arch-minimal.sh:
174
- * systemctl set-default multi-user.target
175
- * systemctl enable getty@tty1.service
176
- * systemctl enable systemd-networkd.service
177
- * systemctl enable 'systemd-resolved.service
178
- */
179
- if (await systemdctl.isEnabled('remote-cryptsetup.target')) {
106
+ if (await systemdctl.isEnabled('remote-cryptsetup.target'))
180
107
  await systemdctl.disable('remote-cryptsetup.target', workDir, true);
181
- }
182
- if (await systemdctl.isEnabled('speech-dispatcherd.service')) {
108
+ if (await systemdctl.isEnabled('speech-dispatcherd.service'))
183
109
  await systemdctl.disable('speech-dispatcherd.service', workDir, true);
184
- }
185
- if (await systemdctl.isEnabled('wpa_supplicant-nl80211@.service')) {
110
+ if (await systemdctl.isEnabled('wpa_supplicant-nl80211@.service'))
186
111
  await systemdctl.disable('wpa_supplicant-nl80211@.service', workDir, true);
187
- }
188
- if (await systemdctl.isEnabled('wpa_supplicant@.service')) {
112
+ if (await systemdctl.isEnabled('wpa_supplicant@.service'))
189
113
  await systemdctl.disable('wpa_supplicant@.service', workDir, true);
190
- }
191
- if (await systemdctl.isEnabled('wpa_supplicant-wired@.service')) {
114
+ if (await systemdctl.isEnabled('wpa_supplicant-wired@.service'))
192
115
  await systemdctl.disable('wpa_supplicant-wired@.service', workDir, true);
193
- }
194
- /**
195
- * All systemd distros
196
- */
197
116
  await exec(`rm -f ${workDir}/var/lib/wicd/configurations/*`, this.echo);
198
117
  await exec(`rm -f ${workDir}/etc/wicd/wireless-settings.conf`, this.echo);
199
118
  await exec(`rm -f ${workDir}/etc/NetworkManager/system-connections/*`, this.echo);
200
119
  await exec(`rm -f ${workDir}/etc/network/wifi/*`, this.echo);
201
- /**
202
- * removing from /etc/network/:
203
- * if-down.d if-post-down.d if-pre-up.d if-up.d interfaces interfaces.d
204
- */
205
120
  const cleanDirs = ['if-down.d', 'if-post-down.d', 'if-pre-up.d', 'if-up.d', 'interfaces.d'];
206
- let cleanDir = '';
207
- for (cleanDir of cleanDirs) {
121
+ for (const cleanDir of cleanDirs) {
208
122
  await exec(`rm -f ${workDir}/etc/network/${cleanDir}/wpasupplicant`, this.echo);
209
123
  }
210
124
  }
211
- /**
212
- * Clear configs from /etc/network/interfaces, wicd and NetworkManager
213
- * and netman, so they aren't stealthily included in the snapshot.
214
- */
215
125
  if (this.familyId === 'debian') {
216
126
  if (fs.existsSync(`${workDir}/etc/network/interfaces`)) {
217
127
  await exec(`rm -f ${workDir}/etc/network/interfaces`, this.echo);
218
128
  Utils.write(`${workDir}/etc/network/interfaces`, 'auto lo\niface lo inet loopback');
219
129
  }
220
- /**
221
- * add some basic files to /dev
222
- */
223
- // Ho condensato i controlli ripetitivi su mknod per leggibilità
224
- // Nota: Questo è safe da eseguire, anche se devtmpfs solitamente gestisce tutto.
225
130
  const devNodes = [
226
131
  { path: 'console', m: '622', type: 'c', major: 5, minor: 1 },
227
132
  { path: 'null', m: '666', type: 'c', major: 1, minor: 3 },
@@ -236,10 +141,9 @@ export async function editLiveFs(clone = false) {
236
141
  await exec(`mknod -m ${node.m} ${workDir}/dev/${node.path} ${node.type} ${node.major} ${node.minor}`, this.echo);
237
142
  }
238
143
  }
239
- if (!fs.existsSync(`${workDir}/dev/{console,ptmx,tty}`)) {
144
+ if (!fs.existsSync(`${workDir}/dev/console`)) {
240
145
  await exec(`chown -v root:tty ${workDir}/dev/{console,ptmx,tty}`, this.echo);
241
146
  }
242
- // Link simbolici standard
243
147
  const links = [
244
148
  { src: '/proc/self/fd', dest: 'fd' },
245
149
  { src: '/proc/self/fd/0', dest: 'stdin' },
@@ -252,24 +156,114 @@ export async function editLiveFs(clone = false) {
252
156
  await exec(`ln -sv ${link.src} ${workDir}/dev/${link.dest}`, this.echo);
253
157
  }
254
158
  }
255
- if (!fs.existsSync(`${workDir}/dev/shm`)) {
159
+ if (!fs.existsSync(`${workDir}/dev/shm`))
256
160
  await exec(`mkdir -v ${workDir}/dev/shm`, this.echo);
257
- }
258
- if (!fs.existsSync(`${workDir}/dev/pts`)) {
161
+ if (!fs.existsSync(`${workDir}/dev/pts`))
259
162
  await exec(`mkdir -v ${workDir}/dev/pts`, this.echo);
163
+ await exec(`chmod 1777 ${workDir}/dev/shm`, this.echo);
164
+ if (!fs.existsSync(`${workDir}/tmp`))
165
+ await exec(`mkdir ${workDir}/tmp`, this.echo);
166
+ await exec(`chmod 1777 ${workDir}/tmp`, this.echo);
167
+ }
168
+ }
169
+ /**
170
+ * Patcha direttamente gli script di init in /etc/init.d/
171
+ */
172
+ async function patchInitScripts(workDir, verbose) {
173
+ // 1. PATCH DBUS (Il più importante)
174
+ const dbusScript = `${workDir}/etc/init.d/dbus`;
175
+ if (fs.existsSync(dbusScript)) {
176
+ if (verbose)
177
+ console.log(`Patching ${dbusScript} to fix missing directories and RO fs...`);
178
+ let content = fs.readFileSync(dbusScript, 'utf8');
179
+ let modified = false;
180
+ // PATCH A: Header con gestione Ramdisk Fallback e Mount Proc
181
+ // Questa intestazione viene inserita all'inizio e prova a montare tmpfs se non può scrivere
182
+ const dbusFix = `
183
+ ### EGGS-FIX-START
184
+ # 1. Assicuriamoci che /proc sia montato (necessario per leggere uuid kernel)
185
+ if ! mountpoint -q /proc/; then
186
+ mount -t proc proc /proc
187
+ fi
188
+
189
+ # 2. Gestione Filesystem Read-Only (RO)
190
+ # Se non possiamo scrivere in /var/lib/dbus, montiamo un tmpfs (RAM) sopra.
191
+ # Questo bypassa il blocco dell'overlayfs non ancora pronto tipico delle build AppImage.
192
+ if ! mkdir -p /var/lib/dbus 2>/dev/null || ! touch /var/lib/dbus/.rw_check 2>/dev/null; then
193
+ echo "EGGS-DEBUG: Filesystem Read-Only detected! Mounting tmpfs on /var/lib/dbus" > /dev/console
194
+ mount -t tmpfs -o size=1m tmpfs /var/lib/dbus
195
+ fi
196
+ rm -f /var/lib/dbus/.rw_check
197
+
198
+ # 3. Creazione Directory Runtime
199
+ mkdir -p /var/run/dbus /var/lib/dbus
200
+ chmod 755 /var/run/dbus /var/lib/dbus
201
+
202
+ # 4. Generazione Machine ID (Non-Blocking Strategy)
203
+ # Se il file non esiste (o è vuoto), lo creiamo.
204
+ if [ ! -s /var/lib/dbus/machine-id ]; then
205
+ # Prova A: Usa UUID del kernel (Istantaneo, non blocca)
206
+ if [ -f /proc/sys/kernel/random/uuid ]; then
207
+ cat /proc/sys/kernel/random/uuid | tr -d '-' > /var/lib/dbus/machine-id
208
+ # Prova B: Fallback statico
209
+ else
210
+ echo "00000000000000000000000000000001" > /var/lib/dbus/machine-id
211
+ fi
212
+ chmod 644 /var/lib/dbus/machine-id
213
+ fi
214
+
215
+ # 5. Sync /etc/machine-id (Best effort, ignora errori se /etc è RO)
216
+ if [ ! -s /etc/machine-id ] && [ -s /var/lib/dbus/machine-id ]; then
217
+ cp /var/lib/dbus/machine-id /etc/machine-id 2>/dev/null || true
218
+ fi
219
+ ### EGGS-FIX-END
220
+ `;
221
+ if (!content.includes('EGGS-FIX-START')) {
222
+ content = content.replace('#!/bin/sh', `#!/bin/sh\n${dbusFix}`);
223
+ modified = true;
260
224
  }
261
- if (!fs.existsSync(`${workDir}/dev/shm`)) {
262
- await exec(`chmod 1777 ${workDir}/dev/shm`, this.echo);
225
+ // PATCH B: SABOTAGE PREVENTION (Questa è quella che mancava!)
226
+ // Impediamo che create_machineid cancelli il file che abbiamo appena creato
227
+ // perché l'uptime è basso.
228
+ if (content.includes('rm -f "${MACHINEID}"')) {
229
+ if (verbose)
230
+ console.log('Patching dbus: disabling auto-delete of machine-id on boot');
231
+ content = content.replace('rm -f "${MACHINEID}"', ': # EGGS-PATCH: Prevent deletion of valid machine-id');
232
+ modified = true;
263
233
  }
264
- /**
265
- * creo /tmp
266
- */
267
- if (!fs.existsSync(`${workDir}/tmp`)) {
268
- await exec(`mkdir ${workDir}/tmp`, this.echo);
234
+ if (modified) {
235
+ fs.writeFileSync(dbusScript, content, 'utf8');
236
+ }
237
+ }
238
+ // 2. PATCH RSYSLOG
239
+ const rsyslogScript = `${workDir}/etc/init.d/rsyslog`;
240
+ if (fs.existsSync(rsyslogScript)) {
241
+ let content = fs.readFileSync(rsyslogScript, 'utf8');
242
+ const fix = `
243
+ ### EGGS-FIX-START
244
+ mkdir -p /var/spool/rsyslog
245
+ chmod 755 /var/spool/rsyslog
246
+ ### EGGS-FIX-END
247
+ `;
248
+ if (!content.includes('EGGS-FIX-START')) {
249
+ content = content.replace('#!/bin/sh', `#!/bin/sh\n${fix}`);
250
+ fs.writeFileSync(rsyslogScript, content, 'utf8');
251
+ }
252
+ }
253
+ // 3. PATCH CRON
254
+ const cronScript = `${workDir}/etc/init.d/cron`;
255
+ if (fs.existsSync(cronScript)) {
256
+ let content = fs.readFileSync(cronScript, 'utf8');
257
+ const fix = `
258
+ ### EGGS-FIX-START
259
+ mkdir -p /var/spool/cron/crontabs
260
+ chmod 1730 /var/spool/cron/crontabs
261
+ chown root:crontab /var/spool/cron/crontabs 2>/dev/null || true
262
+ ### EGGS-FIX-END
263
+ `;
264
+ if (!content.includes('EGGS-FIX-START')) {
265
+ content = content.replace('#!/bin/sh', `#!/bin/sh\n${fix}`);
266
+ fs.writeFileSync(cronScript, content, 'utf8');
269
267
  }
270
- /**
271
- * Assegno 1777 a /tmp creava problemi con MXLINUX
272
- */
273
- await exec(`chmod 1777 ${workDir}/tmp`, this.echo);
274
268
  }
275
269
  }
@@ -7,7 +7,7 @@
7
7
  */
8
8
  // packages
9
9
  import fs from 'node:fs';
10
- import shx from 'shelljs';
10
+ import { shx } from '../../lib/utils.js';
11
11
  import path from 'path';
12
12
  // interfaces
13
13
  // libraries
@@ -9,7 +9,7 @@ import chalk from 'chalk';
9
9
  import mustache from 'mustache';
10
10
  // packages
11
11
  import fs from 'node:fs';
12
- import shx from 'shelljs';
12
+ import { shx } from '../../lib/utils.js';
13
13
  import path from 'path';
14
14
  // libraries
15
15
  import { exec } from '../../lib/utils.js';
@@ -1,14 +1,8 @@
1
1
  /**
2
- * ./src/classes/ovary.d/create-user-live.ts
2
+ * src/classes/ovary.d/user-create-live.ts
3
3
  * penguins-eggs v.25.7.x / ecmascript 2020
4
- * author: Piero Proietti
5
- * email: piero.proietti@gmail.com
6
- * license: MIT
4
+ * * REFACTORED: Uses "The SysUser Master" class.
5
+ * Creates the live user directly in the merged filesystem safely.
7
6
  */
8
7
  import Ovary from '../ovary.js';
9
- /**
10
- * list degli utenti: grep -E 1[0-9]{3} /etc/passwd | sed s/:/\ / | awk '{print $1}'
11
- * create la home per user_opt
12
- * @param verbose
13
- */
14
- export declare function userCreateLive(this: Ovary): Promise<void>;
8
+ export default function userCreateLive(this: Ovary): Promise<void>;
@@ -1,97 +1,95 @@
1
1
  /**
2
- * ./src/classes/ovary.d/create-user-live.ts
2
+ * src/classes/ovary.d/user-create-live.ts
3
3
  * penguins-eggs v.25.7.x / ecmascript 2020
4
- * author: Piero Proietti
5
- * email: piero.proietti@gmail.com
6
- * license: MIT
4
+ * * REFACTORED: Uses "The SysUser Master" class.
5
+ * Creates the live user directly in the merged filesystem safely.
7
6
  */
8
- // packages
9
7
  import fs from 'fs';
10
- import path from 'node:path';
11
- import yaml from 'js-yaml';
12
- // functions
8
+ import path from 'path';
13
9
  import { exec } from '../../lib/utils.js';
14
- import rexec from './rexec.js';
15
- import Utils from '../utils.js';
16
- // _dirname
17
- const __dirname = path.dirname(new URL(import.meta.url).pathname);
18
- /**
19
- * list degli utenti: grep -E 1[0-9]{3} /etc/passwd | sed s/:/\ / | awk '{print $1}'
20
- * create la home per user_opt
21
- * @param verbose
22
- */
23
- export async function userCreateLive() {
24
- if (this.verbose) {
25
- console.log('Ovary: userCreateLive');
10
+ import SysUsers from '../sys-users.js';
11
+ export default async function userCreateLive() {
12
+ // Target: la directory "merged" dell'overlayfs
13
+ let target = this.settings.work_dir.merged;
14
+ if (!target || !fs.existsSync(target)) {
15
+ console.error(`SysUsers Error: Target directory not found at: ${target}`);
16
+ return;
26
17
  }
27
- const cmds = [];
28
- cmds.push(await rexec('chroot ' + this.settings.work_dir.merged + ' rm /home/' + this.settings.config.user_opt + ' -rf', this.verbose));
29
- cmds.push(await rexec('chroot ' + this.settings.work_dir.merged + ' mkdir /home/' + this.settings.config.user_opt, this.verbose));
30
- // Create user using useradd
31
- cmds.push(await rexec('chroot ' + this.settings.work_dir.merged + ' useradd ' + this.settings.config.user_opt + ' --home-dir /home/' + this.settings.config.user_opt + ' --shell /bin/bash ', this.verbose));
32
- // live password
33
- cmds.push(await rexec('echo ' + this.settings.config.user_opt + ':' + this.settings.config.user_opt_passwd + ' | chroot ' + this.settings.work_dir.merged + ' /usr/sbin/chpasswd', this.verbose));
34
- // root password
35
- cmds.push(await rexec(' echo root:' + this.settings.config.root_passwd + ' | chroot ' + this.settings.work_dir.merged + ' /usr/sbin/chpasswd', this.verbose));
36
- // Alpine naked don't have /etc/skel
37
- if (fs.existsSync('/etc/skel')) {
38
- cmds.push(await rexec('chroot ' + this.settings.work_dir.merged + ' cp /etc/skel/. /home/' + this.settings.config.user_opt + ' -R', this.verbose));
18
+ const familyId = this.distro?.familyId || this.familyId;
19
+ console.log(`Creating LIVE user in snapshot at ${target} (Family: ${familyId})...`);
20
+ // 1. CARICAMENTO CONFIGURAZIONE ESISTENTE
21
+ const sysUsers = new SysUsers(target, familyId);
22
+ sysUsers.load();
23
+ // 2. DEFINIZIONE UTENTE LIVE
24
+ const username = this.settings.config.user_opt || 'live';
25
+ const password = 'evolution'; // Password default live
26
+ // Shell detection
27
+ let shell = '/bin/bash';
28
+ if (!fs.existsSync(path.join(target, 'bin/bash')) && fs.existsSync(path.join(target, 'bin/ash'))) {
29
+ shell = '/bin/ash';
39
30
  }
40
- // da problemi con il mount sshfs
41
- cmds.push(await rexec('chroot ' + this.settings.work_dir.merged + ' chown ' + this.settings.config.user_opt + ':users' + ' /home/' + this.settings.config.user_opt + ' -R', this.verbose));
42
- /**
43
- *
44
- */
45
- switch (this.familyId) {
46
- case 'alpine': {
47
- cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG wheel ${this.settings.config.user_opt}`, this.verbose));
48
- break;
49
- }
50
- case 'archlinux': {
51
- cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} gpasswd -a ${this.settings.config.user_opt} wheel`, this.verbose));
52
- // check or create group: autologin
53
- cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} getent group autologin || chroot ${this.settings.work_dir.merged} groupadd autologin`, this.verbose));
54
- cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} gpasswd -a ${this.settings.config.user_opt} autologin`, this.verbose));
55
- break;
56
- }
57
- case 'debian': {
58
- cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG sudo ${this.settings.config.user_opt}`, this.verbose));
59
- break;
60
- }
61
- case 'fedora': {
62
- cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG wheel ${this.settings.config.user_opt}`, this.verbose));
63
- break;
64
- }
65
- case 'openmamba': {
66
- cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG sysadmin ${this.settings.config.user_opt}`, this.verbose));
67
- cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG autologin ${this.settings.config.user_opt}`, this.verbose));
68
- break;
69
- }
70
- case 'opensuse': {
71
- cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG wheel ${this.settings.config.user_opt}`, this.verbose));
72
- break;
73
- }
74
- // No default
31
+ const liveUser = {
32
+ username: username,
33
+ password: 'x',
34
+ uid: '1000', // Live user è sempre 1000
35
+ gid: '1000',
36
+ gecos: 'Live User,,,',
37
+ home: `/home/${username}`,
38
+ shell: shell
39
+ };
40
+ // 3. CREAZIONE LOGICA (IN MEMORIA)
41
+ // Rimuove eventuali residui precedenti e aggiunge il nuovo
42
+ sysUsers.addUser(liveUser, password);
43
+ // Aggiungi ai gruppi amministrativi
44
+ let adminGroup = 'wheel';
45
+ if (['debian', 'ubuntu', 'linuxmint', 'pop', 'neon'].includes(familyId)) {
46
+ adminGroup = 'sudo';
75
47
  }
76
- /**
77
- * look to calamares/modules/users.conf for groups
78
- */
79
- let usersConf = '/etc/calamares/modules/users.conf';
80
- if (!fs.existsSync(usersConf)) {
81
- usersConf = '/etc/penguins-eggs.d/krill/modules/users.conf';
48
+ else if (familyId === 'openmamba') {
49
+ adminGroup = 'sysadmin';
82
50
  }
83
- if (fs.existsSync(usersConf)) {
84
- const o = yaml.load(fs.readFileSync(usersConf, 'utf8'));
85
- for (const group of o.defaultGroups) {
86
- const groupExists = await exec(`chroot ${this.settings.work_dir.merged} getent group ${group}`, { ignore: true });
87
- if (groupExists.code == 0) {
88
- cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG ${group} ${this.settings.config.user_opt} ${this.toNull}`, this.verbose));
89
- Utils.warning(`added ${this.settings.config.user_opt} to group ${group}`);
90
- }
91
- }
51
+ sysUsers.addUserToGroup(username, adminGroup);
52
+ // GRUPPO AUTOLOGIN (Fondamentale per la live!)
53
+ // Creiamo il gruppo se non esiste (logica semplificata: lo aggiungiamo a sysUsers se manca?)
54
+ // SysUsers.addUserToGroup fallisce silenziosamente se il gruppo non c'è.
55
+ // Per sicurezza su Fedora/Arch, autologin di solito esiste o va creato.
56
+ // Proviamo ad aggiungerlo:
57
+ sysUsers.addUserToGroup(username, 'autologin'); // <--- PUNTO E VIRGOLA FONDAMENTALE QUI!
58
+ // Aggiungiamo anche ai gruppi standard audio/video/network se esistono
59
+ ['video', 'audio', 'network', 'input', 'lp', 'storage', 'optical'].forEach(grp => {
60
+ sysUsers.addUserToGroup(username, grp);
61
+ });
62
+ // 4. SALVATAGGIO ATOMICO SU DISCO
63
+ await sysUsers.save();
64
+ // 5. CREAZIONE FISICA HOME DIRECTORY
65
+ const homeDir = path.join(target, 'home', username);
66
+ // Cleanup
67
+ if (fs.existsSync(homeDir))
68
+ await exec(`rm -rf ${homeDir}`, this.echo);
69
+ // Scheletro (/etc/skel)
70
+ const skelPath = path.join(target, 'etc', 'skel');
71
+ if (fs.existsSync(skelPath)) {
72
+ await exec(`mkdir -p ${homeDir}`, this.echo);
73
+ await exec(`cp -rT ${skelPath} ${homeDir}`, this.echo);
92
74
  }
93
75
  else {
94
- console.log(`il file ${usersConf} non esiste!`);
95
- await Utils.pressKeyToExit();
76
+ await exec(`mkdir -p ${homeDir}`, this.echo);
77
+ }
78
+ // Permessi
79
+ await exec(`chown -R 1000:1000 ${homeDir}`, this.echo);
80
+ // Per la live va bene anche 755, ma 700 è più sicuro. Lasciamo standard.
81
+ await exec(`chmod 755 ${homeDir}`, this.echo);
82
+ // 6. FIX SELINUX SPECIFICO PER HOME LIVE
83
+ if (['fedora', 'rhel', 'centos', 'almalinux', 'rocky'].includes(familyId)) {
84
+ try {
85
+ await exec(`chcon -R -t user_home_t ${homeDir}`, { echo: false }).catch(() => { });
86
+ // Nota: .autorelabel nella root della live potrebbe rallentare il boot,
87
+ // ma è meglio averlo se i contesti sono dubbi.
88
+ // await exec(`touch ${target}/.autorelabel`, { echo: false })
89
+ }
90
+ catch (e) {
91
+ console.error('SELinux home fix warning:', e);
92
+ }
96
93
  }
94
+ console.log(`Live user '${username}' created successfully via SysUser Master.`);
97
95
  }
@@ -1,9 +1,8 @@
1
1
  /**
2
- * ./src/classes/ovary.d/users-remove.ts
2
+ * src/classes/ovary.d/users-remove.ts
3
3
  * penguins-eggs v.25.7.x / ecmascript 2020
4
- * author: Piero Proietti
5
- * email: piero.proietti@gmail.com
6
- * license: MIT
4
+ * * REFACTORED: Uses "The SysUser Master" class.
5
+ * Cleans up host users from the ISO filesystem safely.
7
6
  */
8
- import Ovary from './../ovary.js';
9
- export declare function usersRemove(this: Ovary): Promise<void>;
7
+ import Ovary from '../ovary.js';
8
+ export default function usersRemove(this: Ovary): Promise<void>;