@ai-ecoverse/slicc-kernel 1.59.1 → 1.60.0

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.
@@ -2626,6 +2626,29 @@ function userEnv(account, system) {
2626
2626
  PATH: `${pnpm}/bin:/usr/local/bin:/usr/bin:/bin`
2627
2627
  };
2628
2628
  }
2629
+ function groupsOf(groups, names) {
2630
+ return names.map((g) => {
2631
+ const row = groups.find((r) => r.name === g);
2632
+ if (!row) throw fsError("ENOENT", `no group ${g}`);
2633
+ return row;
2634
+ });
2635
+ }
2636
+ function homeModeOf(mode) {
2637
+ if (mode === void 0) return void 0;
2638
+ if (!Number.isInteger(mode) || mode < 0 || mode > 4095) {
2639
+ throw fsError("EINVAL", `not a mode: ${String(mode)}`);
2640
+ }
2641
+ return mode;
2642
+ }
2643
+ function joined(name2, rows) {
2644
+ let changed = false;
2645
+ for (const g of rows) {
2646
+ if (g.members.includes(name2)) continue;
2647
+ g.members.push(name2);
2648
+ changed = true;
2649
+ }
2650
+ return changed;
2651
+ }
2629
2652
  function homeGroupOf(groups, name2) {
2630
2653
  if (name2 === void 0) return void 0;
2631
2654
  const found = groups.find((g) => g.name === name2);
@@ -2641,14 +2664,14 @@ var UserDb = class {
2641
2664
  this.fs = fs;
2642
2665
  this.owners = owners;
2643
2666
  }
2644
- async stampHome(row, shared) {
2667
+ async stampHome(row, shared, homeMode) {
2645
2668
  const home = this.fs.resolvePath("/", row.home);
2646
2669
  if (!this.owners || !this.fs.chown || !HOME_DIR.test(home)) return;
2647
2670
  if (!await this.realDir(home)) return;
2648
2671
  const gid = shared?.gid ?? row.gid;
2649
2672
  await this.fs.chown(home, { uid: row.uid, gid, follow: false, kind: "adopt" });
2650
2673
  const scoop = row.name.startsWith("scoop-");
2651
- await this.fs.chmod(home, shared ? 1512 : scoop ? 488 : 448);
2674
+ await this.fs.chmod(home, homeMode ?? (shared ? 1512 : scoop ? 488 : 448));
2652
2675
  const pnpm = `${home}/.local/share/pnpm`;
2653
2676
  if (await this.realDir(pnpm)) await this.fs.chmod(pnpm, scoop ? 488 : 448);
2654
2677
  }
@@ -2762,31 +2785,33 @@ var UserDb = class {
2762
2785
  const groups = parsed(group);
2763
2786
  const found = users.find((r) => r.name === name2);
2764
2787
  const shared = homeGroupOf(groups, options.homeGroup);
2788
+ const homeMode = homeModeOf(options.homeMode);
2765
2789
  if (found) {
2790
+ const more = groupsOf(groups, options.groups ?? []);
2791
+ if (more.some((g) => g.gid === found.gid)) {
2792
+ throw fsError("EINVAL", `a user is no member of its own group ${name2}`);
2793
+ }
2766
2794
  if (found.uid >= FIRST_UID && found.uid <= LAST_UID) {
2767
2795
  await this.provision(found);
2768
- await this.stampHome(found, shared);
2796
+ await this.stampHome(found, shared, homeMode);
2769
2797
  }
2798
+ if (joined(name2, more)) await this.fs.writeFile(GROUP, formatGroup(group));
2770
2799
  remember();
2771
2800
  return this.account(found, groups);
2772
2801
  }
2773
2802
  const home = homeOf(options.home ?? `/home/${name2}`);
2774
- const extra = [USERS_GROUP, ...options.groups ?? []].map((g) => {
2775
- const row2 = groups.find((r) => r.name === g);
2776
- if (!row2) throw fsError("ENOENT", `no group ${g}`);
2777
- return row2;
2778
- });
2803
+ const extra = groupsOf(groups, [USERS_GROUP, ...options.groups ?? []]);
2779
2804
  if (groups.some((r) => r.name === name2)) throw fsError("EEXIST", `group ${name2} exists`);
2780
2805
  const uid = freeId(users, groups);
2781
2806
  const row = { name: name2, uid, gid: uid, gecos: name2, home, shell: "/bin/bash" };
2782
- for (const g of extra) if (!g.members.includes(name2)) g.members.push(name2);
2807
+ joined(name2, extra);
2783
2808
  group.push({ name: name2, gid: uid, members: [] });
2784
2809
  passwd.push(row);
2785
2810
  const fresh = !await this.fs.exists(home);
2786
2811
  await this.fs.mkdir(home, { recursive: true });
2787
2812
  try {
2788
2813
  await this.provision(row);
2789
- await this.stampHome(row, shared);
2814
+ await this.stampHome(row, shared, homeMode);
2790
2815
  await this.fs.mkdir("/etc", { recursive: true });
2791
2816
  await this.commit(formatPasswd(passwd), formatGroup(group));
2792
2817
  } catch (err) {
@@ -2797,6 +2822,31 @@ var UserDb = class {
2797
2822
  return this.account(row, parsed(group));
2798
2823
  });
2799
2824
  }
2825
+ async groups() {
2826
+ const { group } = await this.tables();
2827
+ return parsed(group).map(({ name: name2, gid, members }) => ({ name: name2, gid, members: [...members] }));
2828
+ }
2829
+ addMember(group, user) {
2830
+ return this.member(group, user, true);
2831
+ }
2832
+ removeMember(group, user) {
2833
+ return this.member(group, user, false);
2834
+ }
2835
+ member(name2, user, on) {
2836
+ return this.serial(async () => {
2837
+ const { passwd, group } = await this.tables();
2838
+ const row = parsed(group).find((g) => g.name === name2);
2839
+ if (!row) throw fsError("ENOENT", `no group ${String(name2)}`);
2840
+ const who = parsed(passwd).find((u) => u.name === user);
2841
+ if (!who) throw fsError("ENOENT", `no user ${String(user)}`);
2842
+ if (who.gid === row.gid) throw fsError("EINVAL", `${name2} is the own group of ${user}`);
2843
+ if (row.members.includes(user) !== on) {
2844
+ row.members = on ? [...row.members, user] : row.members.filter((m) => m !== user);
2845
+ await this.fs.writeFile(GROUP, formatGroup(group));
2846
+ }
2847
+ return { name: row.name, gid: row.gid, members: [...row.members] };
2848
+ });
2849
+ }
2800
2850
  remove(name2, options = {}) {
2801
2851
  return this.serial(async () => {
2802
2852
  const { passwd, group } = await this.tables();
@@ -14491,7 +14541,14 @@ function answered(data, remote, uplink) {
14491
14541
  else return false;
14492
14542
  return true;
14493
14543
  }
14494
- var USERS_OPS = /* @__PURE__ */ new Set(["users-add", "users-remove", "users-list"]);
14544
+ var USERS_OPS = /* @__PURE__ */ new Set([
14545
+ "users-add",
14546
+ "users-remove",
14547
+ "users-list",
14548
+ "groups-list",
14549
+ "groups-add-member",
14550
+ "groups-remove-member"
14551
+ ]);
14495
14552
  function isUsersRequest(req) {
14496
14553
  return USERS_OPS.has(req.op);
14497
14554
  }
@@ -14505,6 +14562,9 @@ function failure(err) {
14505
14562
  function usersOp(l, req) {
14506
14563
  if (req.op === "users-add") return l.users.add(req.user);
14507
14564
  if (req.op === "users-remove") return l.users.remove(req.name, req.options);
14565
+ if (req.op === "groups-list") return l.users.groups();
14566
+ if (req.op === "groups-add-member") return l.users.addMember(req.group, req.user);
14567
+ if (req.op === "groups-remove-member") return l.users.removeMember(req.group, req.user);
14508
14568
  return l.users.list();
14509
14569
  }
14510
14570
  function hostOptions(req) {