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,38 +1,68 @@
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
- // packages
9
- import path from 'node:path';
10
- // backup
11
- // interfaces
12
- // libraries
7
+ import fs from 'fs';
8
+ import path from 'path';
13
9
  import { exec } from '../../lib/utils.js';
14
- import rexec from './rexec.js';
15
- import Diversions from './../diversions.js';
16
- // _dirname
17
- const __dirname = path.dirname(new URL(import.meta.url).pathname);
18
- //async cleanUsersAccounts() {
19
- export async function usersRemove() {
20
- if (this.verbose) {
21
- console.log('Ovary: cleanUsersAccounts');
10
+ import SysUsers from '../sys-users.js';
11
+ export default async function usersRemove() {
12
+ // Il target corretto in Ovary è la directory "merged" dell'overlayfs
13
+ let target = this.settings.work_dir.merged;
14
+ // Assicuriamoci che il target esista per sicurezza
15
+ if (!target || !fs.existsSync(target)) {
16
+ console.error(`SysUsers Error: Merged target directory not found at: ${target}`);
17
+ return;
22
18
  }
23
- /**
24
- * delete all user in chroot
25
- */
26
- const cmds = [];
27
- const cmd = `chroot ${this.settings.work_dir.merged} getent passwd {1000..60000} |awk -F: '{print $1}'`;
28
- const result = await exec(cmd, {
29
- capture: true,
30
- echo: this.verbose,
31
- ignore: false
32
- });
33
- const users = result.data.split('\n');
34
- let deluser = Diversions.deluser(this.familyId);
35
- for (let i = 0; i < users.length - 1; i++) {
36
- cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} ${deluser} ${users[i]}`, this.verbose));
19
+ // Nota: verifica se in Ovary hai 'this.familyId' diretto o 'this.distro.familyId'.
20
+ // Solitamente è this.distro.familyId, ma se hai un getter va bene così.
21
+ const familyId = this.distro?.familyId || this.familyId;
22
+ console.log(`Cleaning host users from ISO snapshot at ${target} (Family: ${familyId})...`);
23
+ // 2. CARICAMENTO CONFIGURAZIONE
24
+ const sysUsers = new SysUsers(target, familyId);
25
+ sysUsers.load();
26
+ // 3. IDENTIFICAZIONE UTENTI DA RIMUOVERE
27
+ // Dobbiamo leggere il file passwd raw per decidere chi rimuovere
28
+ // (rimuoviamo UID >= 1000 tranne 'nobody' e 'root')
29
+ const usersToDelete = [];
30
+ const passwdPath = path.join(target, 'etc/passwd');
31
+ if (fs.existsSync(passwdPath)) {
32
+ const lines = fs.readFileSync(passwdPath, 'utf8').split('\n');
33
+ for (const line of lines) {
34
+ const parts = line.split(':');
35
+ if (parts.length > 2) {
36
+ const uid = parseInt(parts[2]);
37
+ const username = parts[0];
38
+ // Logica di rimozione standard di eggs
39
+ if (uid >= 1000 && username !== 'nobody') {
40
+ usersToDelete.push(username);
41
+ }
42
+ }
43
+ }
44
+ }
45
+ // 4. ESECUZIONE RIMOZIONE (IN MEMORIA)
46
+ for (const username of usersToDelete) {
47
+ console.log(`- Removing user: ${username}`);
48
+ sysUsers.removeUser(username);
49
+ // Pulizia File Fisici (Home, Mail) - Operazioni FS dirette
50
+ const homeDir = path.join(target, 'home', username);
51
+ if (fs.existsSync(homeDir)) {
52
+ await exec(`rm -rf ${homeDir}`, this.echo);
53
+ }
54
+ const mailFile = path.join(target, 'var/mail', username);
55
+ if (fs.existsSync(mailFile)) {
56
+ fs.unlinkSync(mailFile);
57
+ }
58
+ }
59
+ // 5. SALVATAGGIO ATOMICO SU DISCO
60
+ if (usersToDelete.length > 0) {
61
+ // Scrive passwd, shadow, group, gshadow, subuid... e ripara SELinux
62
+ await sysUsers.save();
63
+ console.log("User cleanup completed via SysUsers Master.");
64
+ }
65
+ else {
66
+ console.log("No users needed to be removed.");
37
67
  }
38
68
  }
@@ -21,9 +21,9 @@ import { createXdgAutostart } from './ovary.d/create-xdg-autostart.js';
21
21
  import { copied, merged, mergedAndOverlay } from './ovary.d/merged.js';
22
22
  import { makeIso } from './ovary.d/make-iso.js';
23
23
  import { initrdAlpine, initrdArch, initrdDebian, initrdDracut } from './ovary.d/initrd.js';
24
- import { userCreateLive } from './ovary.d/user-create-live.js';
24
+ import userCreateLive from './ovary.d/user-create-live.js';
25
25
  import { syslinux } from './ovary.d/syslinux.js';
26
- import { usersRemove } from './ovary.d/users-remove.js';
26
+ import usersRemove from './ovary.d/users-remove.js';
27
27
  import { makeDotDisk } from './ovary.d/make-dot-disk.js';
28
28
  import { kernelCopy } from './ovary.d/kernel-copy.js';
29
29
  import { liveCreateStructure } from './ovary.d/live-create-structure.js';
@@ -22,9 +22,9 @@ import { createXdgAutostart } from './ovary.d/create-xdg-autostart.js';
22
22
  import { copied, merged, mergedAndOverlay } from './ovary.d/merged.js';
23
23
  import { makeIso } from './ovary.d/make-iso.js';
24
24
  import { initrdAlpine, initrdArch, initrdDebian, initrdDracut } from './ovary.d/initrd.js';
25
- import { userCreateLive } from './ovary.d/user-create-live.js';
25
+ import userCreateLive from './ovary.d/user-create-live.js';
26
26
  import { syslinux } from './ovary.d/syslinux.js';
27
- import { usersRemove } from './ovary.d/users-remove.js';
27
+ import usersRemove from './ovary.d/users-remove.js';
28
28
  import { makeDotDisk } from './ovary.d/make-dot-disk.js';
29
29
  import { kernelCopy } from './ovary.d/kernel-copy.js';
30
30
  import { liveCreateStructure } from './ovary.d/live-create-structure.js';
@@ -5,7 +5,7 @@
5
5
  * email: piero.proietti@gmail.com
6
6
  * license: MIT
7
7
  */
8
- import shx from 'shelljs';
8
+ import { shx } from '../../lib/utils.js';
9
9
  import { exec } from '../../lib/utils.js';
10
10
  import Utils from '../utils.js';
11
11
  /**
@@ -131,7 +131,7 @@ export default class Alpine {
131
131
  */
132
132
  static async packageInstall(packageName) {
133
133
  let retVal = false;
134
- if (shx.exec(`/sbin/apk add ${packageName}`, { silent: true }) === '0') {
134
+ if (shx.exec('/sbin/apk add ' + packageName, { silent: true }).code === 0) {
135
135
  retVal = true;
136
136
  }
137
137
  return retVal;
@@ -6,7 +6,7 @@
6
6
  * license: MIT
7
7
  */
8
8
  import fs from 'node:fs';
9
- import shx from 'shelljs';
9
+ import { shx } from '../../lib/utils.js';
10
10
  import { exec } from '../../lib/utils.js';
11
11
  import Utils from '../utils.js';
12
12
  /**
@@ -77,7 +77,7 @@ export default class Archlinux {
77
77
  */
78
78
  static async packageInstall(packageName) {
79
79
  let retVal = false;
80
- if (shx.exec(`/usr/bin/pacman -Si ${packageName}`, { silent: true }) === '0') {
80
+ if (shx.exec('/usr/bin/pacman -Si ' + packageName, { silent: true }).code === 0) {
81
81
  retVal = true;
82
82
  }
83
83
  return retVal;
@@ -6,8 +6,7 @@
6
6
  * license: MIT
7
7
  */
8
8
  import fs from 'node:fs';
9
- import shx from 'shelljs';
10
- import { exec } from '../../lib/utils.js';
9
+ import { exec, shx } from '../../lib/utils.js';
11
10
  import Utils from '../utils.js';
12
11
  /**
13
12
  * Debian
@@ -116,7 +115,7 @@ export default class Debian {
116
115
  */
117
116
  static async packageInstall(packageName) {
118
117
  let retVal = false;
119
- if (shx.exec(`/usr/bin/apt-get install -y ${packageName}`, { silent: true }) === '0') {
118
+ if (shx.exec('/usr/bin/apt-get install -y ' + packageName, { silent: true }).code === 0) {
120
119
  retVal = true;
121
120
  }
122
121
  return retVal;
@@ -6,8 +6,7 @@
6
6
  * license: MIT
7
7
  */
8
8
  import fs from 'node:fs';
9
- import shx from 'shelljs';
10
- import { exec } from '../../lib/utils.js';
9
+ import { exec, shx } from '../../lib/utils.js';
11
10
  import Utils from '../utils.js';
12
11
  /**
13
12
  * Utils: general porpourse utils
@@ -86,7 +85,7 @@ export default class Fedora {
86
85
  */
87
86
  static async packageInstall(packageName) {
88
87
  let retVal = false;
89
- if (shx.exec(`/usr/bin/dnf install ${packageName}`, { silent: true }) === '0') {
88
+ if (shx.exec('/usr/bin/dnf install ' + packageName, { silent: true }).code === 0) {
90
89
  retVal = true;
91
90
  }
92
91
  return retVal;
@@ -6,8 +6,7 @@
6
6
  * license: MIT
7
7
  */
8
8
  import fs from 'node:fs';
9
- import shx from 'shelljs';
10
- import { exec } from '../../lib/utils.js';
9
+ import { exec, shx } from '../../lib/utils.js';
11
10
  import Utils from '../utils.js';
12
11
  /**
13
12
  * Utils: general porpourse utils
@@ -85,7 +84,7 @@ export default class Openmamba {
85
84
  */
86
85
  static async packageInstall(packageName) {
87
86
  let retVal = false;
88
- if (shx.exec(`/usr/bin/dnf install ${packageName}`, { silent: false }) === '0') {
87
+ if (shx.exec('/usr/bin/dnf install ' + packageName, { silent: false }).code === 0) {
89
88
  retVal = true;
90
89
  }
91
90
  return retVal;
@@ -6,8 +6,7 @@
6
6
  * license: MIT
7
7
  */
8
8
  import fs from 'node:fs';
9
- import shx from 'shelljs';
10
- import { exec } from '../../lib/utils.js';
9
+ import { exec, shx } from '../../lib/utils.js';
11
10
  import Utils from '../utils.js';
12
11
  /**
13
12
  * Utils: general porpourse utils
@@ -88,7 +87,7 @@ export default class Opensuse {
88
87
  */
89
88
  static async packageInstall(packageName) {
90
89
  let retVal = false;
91
- if (shx.exec(`/usr/bin/zypper install ${packageName}`, { silent: true }) === '0') {
90
+ if (shx.exec('/usr/bin/zypper install ' + packageName, { silent: true }).code === 0) {
92
91
  retVal = true;
93
92
  }
94
93
  return retVal;
@@ -40,11 +40,6 @@ export default class Pacman {
40
40
  *
41
41
  */
42
42
  static calamaresRemove(verbose?: boolean): Promise<boolean>;
43
- /**
44
- *
45
- * @param cmd
46
- */
47
- static commandIsInstalled(cmd: string): boolean;
48
43
  /**
49
44
  * Restituisce VERO se i file di configurazione SONO presenti
50
45
  */
@@ -5,11 +5,10 @@
5
5
  * email: piero.proietti@gmail.com
6
6
  * license: MIT
7
7
  */
8
- import { execSync } from 'node:child_process';
8
+ import { shx, execSync } from '../lib/utils.js';
9
9
  import fs from 'node:fs';
10
10
  // _dirname
11
11
  import path from 'node:path';
12
- import shx from 'shelljs';
13
12
  import { exec } from '../lib/utils.js';
14
13
  import Distro from './distro.js';
15
14
  import Diversions from './diversions.js';
@@ -61,7 +60,7 @@ export default class Pacman {
61
60
  * return true if calamares is installed
62
61
  */
63
62
  static calamaresExists() {
64
- return this.commandIsInstalled('calamares');
63
+ return Utils.commandExists('calamares');
65
64
  }
66
65
  /**
67
66
  *
@@ -144,17 +143,6 @@ export default class Pacman {
144
143
  }
145
144
  return retVal;
146
145
  }
147
- /**
148
- *
149
- * @param cmd
150
- */
151
- static commandIsInstalled(cmd) {
152
- let installed = false;
153
- if (shx.exec(`command -V ${cmd} >/dev/null 2>&1`).code == 0) {
154
- installed = true;
155
- }
156
- return installed;
157
- }
158
146
  /**
159
147
  * Restituisce VERO se i file di configurazione SONO presenti
160
148
  */
@@ -195,7 +183,7 @@ export default class Pacman {
195
183
  /**
196
184
  * Salvo la configurazione di eggs.yaml
197
185
  */
198
- config.machine_id = Utils.machineId();
186
+ config.machine_id = ''; //Utils.machineId()
199
187
  config.vmlinuz = Utils.vmlinuz();
200
188
  config.initrd_img = Utils.initrdImg();
201
189
  const settings = new Settings();
@@ -231,7 +219,6 @@ export default class Pacman {
231
219
  execSync(`rm -rf ${init}`);
232
220
  }
233
221
  execSync(`mkdir -p ${init}`);
234
- // shx.ln('-s', path.resolve(__dirname, '../../addons'), addons)
235
222
  shx.cp(path.resolve(__dirname, '../../conf/README.md'), confRoot);
236
223
  shx.cp(path.resolve(__dirname, '../../conf/derivatives.yaml'), confRoot);
237
224
  shx.cp(path.resolve(__dirname, '../../conf/derivatives_fedora.yaml'), confRoot);
@@ -14,7 +14,7 @@
14
14
  * This will remove the symbolic link that indicated that the service should be started automatically.
15
15
  */
16
16
  import path from 'node:path';
17
- import shx from 'shelljs';
17
+ import { shx } from '../lib/utils.js';
18
18
  import Systemctl from './systemctl.js';
19
19
  // _dirname
20
20
  const __dirname = path.dirname(new URL(import.meta.url).pathname);
@@ -10,7 +10,7 @@ import yaml from 'js-yaml';
10
10
  // packages
11
11
  import fs from 'node:fs';
12
12
  import os from 'node:os';
13
- import shx from 'shelljs';
13
+ import { shx } from '../lib/utils.js';
14
14
  // pjson
15
15
  import { createRequire } from 'node:module';
16
16
  const require = createRequire(import.meta.url);
@@ -0,0 +1,76 @@
1
+ /**
2
+ * src/classes/sys-users.ts
3
+ * penguins-eggs v.25.7.x / ecmascript 2020
4
+ * * "THE SYSUSER MASTER"
5
+ * Gestione pura Node.js per utenti e gruppi di sistema.
6
+ * Sostituisce i binari (useradd/usermod/deluser) per garantire operazioni atomiche
7
+ * e compatibilità SELinux (Fedora/RHEL) scrivendo file puliti.
8
+ */
9
+ export interface IPasswdEntry {
10
+ username: string;
11
+ password: string;
12
+ uid: string;
13
+ gid: string;
14
+ gecos: string;
15
+ home: string;
16
+ shell: string;
17
+ }
18
+ export interface IShadowEntry {
19
+ username: string;
20
+ hash: string;
21
+ lastChange: string;
22
+ min: string;
23
+ max: string;
24
+ warn: string;
25
+ inactive: string;
26
+ expire: string;
27
+ }
28
+ export interface IGroupEntry {
29
+ groupName: string;
30
+ password: string;
31
+ gid: string;
32
+ members: string[];
33
+ }
34
+ export default class SysUsers {
35
+ private targetRoot;
36
+ private distroFamily;
37
+ private passwd;
38
+ private shadow;
39
+ private group;
40
+ private gshadowLines;
41
+ private subuidLines;
42
+ private subgidLines;
43
+ constructor(targetRoot: string, distroFamily: string);
44
+ /**
45
+ * Carica tutti i file di configurazione in memoria
46
+ */
47
+ load(): void;
48
+ /**
49
+ * Salva lo stato della memoria su disco e applica SELinux fix
50
+ */
51
+ save(): Promise<void>;
52
+ /**
53
+ * Crea un nuovo utente completo
54
+ */
55
+ addUser(user: IPasswdEntry, cleanPassword: string): void;
56
+ /**
57
+ * Rimuove completamente un utente
58
+ */
59
+ removeUser(username: string): void;
60
+ /**
61
+ * Aggiunge utente a un gruppo supplementare
62
+ */
63
+ addUserToGroup(username: string, groupName: string): void;
64
+ /**
65
+ * Cambia password utente
66
+ */
67
+ setPassword(username: string, password: string): void;
68
+ private readFile;
69
+ private writeFile;
70
+ private parsePasswd;
71
+ private serializePasswd;
72
+ private parseShadow;
73
+ private serializeShadow;
74
+ private parseGroup;
75
+ private serializeGroup;
76
+ }
@@ -0,0 +1,206 @@
1
+ /**
2
+ * src/classes/sys-users.ts
3
+ * penguins-eggs v.25.7.x / ecmascript 2020
4
+ * * "THE SYSUSER MASTER"
5
+ * Gestione pura Node.js per utenti e gruppi di sistema.
6
+ * Sostituisce i binari (useradd/usermod/deluser) per garantire operazioni atomiche
7
+ * e compatibilità SELinux (Fedora/RHEL) scrivendo file puliti.
8
+ */
9
+ import fs from 'fs';
10
+ import path from 'path';
11
+ import * as bcrypt from 'bcryptjs';
12
+ import { exec } from '../lib/utils.js';
13
+ export default class SysUsers {
14
+ targetRoot;
15
+ distroFamily;
16
+ // Cache in memoria
17
+ passwd = [];
18
+ shadow = [];
19
+ group = [];
20
+ // File "minori" gestiti a righe raw per semplicità
21
+ gshadowLines = [];
22
+ subuidLines = [];
23
+ subgidLines = [];
24
+ constructor(targetRoot, distroFamily) {
25
+ this.targetRoot = targetRoot;
26
+ this.distroFamily = distroFamily;
27
+ }
28
+ /**
29
+ * Carica tutti i file di configurazione in memoria
30
+ */
31
+ load() {
32
+ this.passwd = this.parsePasswd(this.readFile('etc/passwd'));
33
+ this.shadow = this.parseShadow(this.readFile('etc/shadow'));
34
+ this.group = this.parseGroup(this.readFile('etc/group'));
35
+ this.gshadowLines = this.readFile('etc/gshadow');
36
+ this.subuidLines = this.readFile('etc/subuid');
37
+ this.subgidLines = this.readFile('etc/subgid');
38
+ }
39
+ /**
40
+ * Salva lo stato della memoria su disco e applica SELinux fix
41
+ */
42
+ async save() {
43
+ // Serializzazione
44
+ const passwdContent = this.serializePasswd(this.passwd);
45
+ const shadowContent = this.serializeShadow(this.shadow);
46
+ const groupContent = this.serializeGroup(this.group);
47
+ // Scrittura Atomica + Fix SELinux
48
+ await this.writeFile('etc/passwd', passwdContent, 'passwd_file_t');
49
+ await this.writeFile('etc/shadow', shadowContent, 'shadow_t');
50
+ await this.writeFile('etc/group', groupContent, 'passwd_file_t');
51
+ // File raw
52
+ if (this.gshadowLines.length > 0)
53
+ await this.writeFile('etc/gshadow', this.gshadowLines.join('\n'), 'shadow_t');
54
+ if (this.subuidLines.length > 0)
55
+ await this.writeFile('etc/subuid', this.subuidLines.join('\n'), 'passwd_file_t');
56
+ if (this.subgidLines.length > 0)
57
+ await this.writeFile('etc/subgid', this.subgidLines.join('\n'), 'passwd_file_t');
58
+ }
59
+ // =========================================================================
60
+ // API PUBBLICA
61
+ // =========================================================================
62
+ /**
63
+ * Crea un nuovo utente completo
64
+ */
65
+ addUser(user, cleanPassword) {
66
+ // Rimuovi se esiste (idempotenza)
67
+ this.removeUser(user.username);
68
+ // 1. Passwd
69
+ this.passwd.push(user);
70
+ // 2. Shadow (Hash Password)
71
+ const salt = bcrypt.genSaltSync(10);
72
+ const hash = bcrypt.hashSync(cleanPassword, salt);
73
+ this.shadow.push({
74
+ username: user.username,
75
+ hash: hash,
76
+ lastChange: '19700', // Data approssimativa
77
+ min: '0',
78
+ max: '99999',
79
+ warn: '7',
80
+ inactive: '',
81
+ expire: ''
82
+ });
83
+ // 3. Gruppo Primario
84
+ // Solo se non esiste già un gruppo con quel nome
85
+ if (!this.group.find(g => g.groupName === user.username)) {
86
+ this.group.push({
87
+ groupName: user.username,
88
+ password: 'x',
89
+ gid: user.gid,
90
+ members: []
91
+ });
92
+ }
93
+ // 4. GShadow (placeholder)
94
+ this.gshadowLines.push(`${user.username}:!::`);
95
+ // 5. SubUID/SubGID (Podman rootless)
96
+ // Calcolo offset standard: 100000 + (UID-1000)*65536
97
+ const uidNum = parseInt(user.uid);
98
+ if (!isNaN(uidNum) && uidNum >= 1000) {
99
+ const startUid = 100000 + (uidNum - 1000) * 65536;
100
+ const subEntry = `${user.username}:${startUid}:65536`;
101
+ this.subuidLines.push(subEntry);
102
+ this.subgidLines.push(subEntry);
103
+ }
104
+ }
105
+ /**
106
+ * Rimuove completamente un utente
107
+ */
108
+ removeUser(username) {
109
+ this.passwd = this.passwd.filter(u => u.username !== username);
110
+ this.shadow = this.shadow.filter(s => s.username !== username);
111
+ this.group = this.group.filter(g => g.groupName !== username);
112
+ // Rimuovi dai membri di altri gruppi
113
+ this.group.forEach(g => {
114
+ g.members = g.members.filter(m => m !== username);
115
+ });
116
+ this.gshadowLines = this.gshadowLines.filter(l => !l.startsWith(`${username}:`));
117
+ this.subuidLines = this.subuidLines.filter(l => !l.startsWith(`${username}:`));
118
+ this.subgidLines = this.subgidLines.filter(l => !l.startsWith(`${username}:`));
119
+ }
120
+ /**
121
+ * Aggiunge utente a un gruppo supplementare
122
+ */
123
+ addUserToGroup(username, groupName) {
124
+ const grp = this.group.find(g => g.groupName === groupName);
125
+ if (grp) {
126
+ if (!grp.members.includes(username)) {
127
+ grp.members.push(username);
128
+ }
129
+ }
130
+ // Se il gruppo non esiste, lo ignoriamo silenziosamente o potremmo crearlo
131
+ }
132
+ /**
133
+ * Cambia password utente
134
+ */
135
+ setPassword(username, password) {
136
+ const entry = this.shadow.find(s => s.username === username);
137
+ if (entry) {
138
+ const salt = bcrypt.genSaltSync(10);
139
+ entry.hash = bcrypt.hashSync(password, salt);
140
+ entry.lastChange = '19700';
141
+ }
142
+ }
143
+ // =========================================================================
144
+ // IMPLEMENTAZIONE FILE (Privata)
145
+ // =========================================================================
146
+ readFile(relativePath) {
147
+ const fullPath = path.join(this.targetRoot, relativePath);
148
+ if (fs.existsSync(fullPath)) {
149
+ return fs.readFileSync(fullPath, 'utf8').split('\n').filter(l => l.trim().length > 0);
150
+ }
151
+ return [];
152
+ }
153
+ async writeFile(relativePath, content, contextType) {
154
+ const fullPath = path.join(this.targetRoot, relativePath);
155
+ // Crea dir se manca (es. /etc/sudoers.d/ o simili)
156
+ const dir = path.dirname(fullPath);
157
+ if (!fs.existsSync(dir))
158
+ fs.mkdirSync(dir, { recursive: true });
159
+ try {
160
+ // 1. Scrittura
161
+ fs.writeFileSync(fullPath, content + '\n');
162
+ // 2. Fix SELinux (Solo RHEL Family)
163
+ if (['fedora', 'rhel', 'centos', 'almalinux', 'rocky'].includes(this.distroFamily)) {
164
+ // await exec, echo false per non sporcare i log
165
+ await exec(`chcon -t ${contextType} ${fullPath}`, { echo: false }).catch(() => { });
166
+ }
167
+ }
168
+ catch (e) {
169
+ console.error(`SysUsers Error writing ${relativePath}:`, e);
170
+ }
171
+ }
172
+ // --- PARSERS & SERIALIZERS ---
173
+ parsePasswd(lines) {
174
+ return lines.map(line => {
175
+ const p = line.split(':');
176
+ if (p.length < 7)
177
+ return null;
178
+ return { username: p[0], password: p[1], uid: p[2], gid: p[3], gecos: p[4], home: p[5], shell: p[6] };
179
+ }).filter((u) => u !== null);
180
+ }
181
+ serializePasswd(entries) {
182
+ return entries.map(u => `${u.username}:${u.password}:${u.uid}:${u.gid}:${u.gecos}:${u.home}:${u.shell}`).join('\n');
183
+ }
184
+ parseShadow(lines) {
185
+ return lines.map(line => {
186
+ const p = line.split(':');
187
+ if (p.length < 2)
188
+ return null;
189
+ return { username: p[0], hash: p[1], lastChange: p[2] || '', min: p[3] || '', max: p[4] || '', warn: p[5] || '', inactive: p[6] || '', expire: p[7] || '' };
190
+ }).filter((u) => u !== null);
191
+ }
192
+ serializeShadow(entries) {
193
+ return entries.map(s => `${s.username}:${s.hash}:${s.lastChange}:${s.min}:${s.max}:${s.warn}:${s.inactive}:${s.expire}:`).join('\n');
194
+ }
195
+ parseGroup(lines) {
196
+ return lines.map(line => {
197
+ const p = line.split(':');
198
+ if (p.length < 3)
199
+ return null;
200
+ return { groupName: p[0], password: p[1], gid: p[2], members: p[3] && p[3].trim() ? p[3].split(',') : [] };
201
+ }).filter((g) => g !== null);
202
+ }
203
+ serializeGroup(entries) {
204
+ return entries.map(g => `${g.groupName}:${g.password}:${g.gid}:${g.members.join(',')}`).join('\n');
205
+ }
206
+ }
@@ -8,7 +8,7 @@ import fs from 'node:fs';
8
8
  import path from 'path';
9
9
  import Distro from '../distro.js';
10
10
  import Utils from '../utils.js';
11
- import { execSync } from 'node:child_process';
11
+ import { execSync } from '../../lib/utils.js';
12
12
  /**
13
13
  * Kernel utilities for managing vmlinuz and initramfs paths
14
14
  */
@@ -55,7 +55,7 @@ export default class Kernel {
55
55
  Utils.warning("Non è possibile determinare il kernel in un container.");
56
56
  process.exit(1);
57
57
  }
58
- targetKernel = execSync('uname -r').toString().trim();
58
+ targetKernel = (execSync('uname -r', { stdio: 'ignore' }) || '').trim();
59
59
  }
60
60
  const kernelVersionShort = targetKernel.split('.').slice(0, 2).join('.');
61
61
  const bootDir = '/boot';
@@ -138,7 +138,7 @@ export default class Kernel {
138
138
  * debian, fedora, opensuse, rasberry
139
139
  */
140
140
  static vmlinuzFromUname() {
141
- let kernelVersion = execSync('uname -r').toString().trim();
141
+ let kernelVersion = (execSync('uname -r', { stdio: 'ignore' }) || '').trim();
142
142
  // Try 1: path standard (es. Debian, Ubuntu, Fedora)
143
143
  let standardPath = `/boot/vmlinuz-${kernelVersion}`;
144
144
  if (fs.existsSync(standardPath)) {