@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.
package/dist/node.js CHANGED
@@ -1774,6 +1774,29 @@ function userEnv(account, system) {
1774
1774
  PATH: `${pnpm}/bin:/usr/local/bin:/usr/bin:/bin`
1775
1775
  };
1776
1776
  }
1777
+ function groupsOf(groups, names) {
1778
+ return names.map((g) => {
1779
+ const row = groups.find((r) => r.name === g);
1780
+ if (!row) throw fsError("ENOENT", `no group ${g}`);
1781
+ return row;
1782
+ });
1783
+ }
1784
+ function homeModeOf(mode) {
1785
+ if (mode === void 0) return void 0;
1786
+ if (!Number.isInteger(mode) || mode < 0 || mode > 4095) {
1787
+ throw fsError("EINVAL", `not a mode: ${String(mode)}`);
1788
+ }
1789
+ return mode;
1790
+ }
1791
+ function joined(name2, rows) {
1792
+ let changed = false;
1793
+ for (const g of rows) {
1794
+ if (g.members.includes(name2)) continue;
1795
+ g.members.push(name2);
1796
+ changed = true;
1797
+ }
1798
+ return changed;
1799
+ }
1777
1800
  function homeGroupOf(groups, name2) {
1778
1801
  if (name2 === void 0) return void 0;
1779
1802
  const found = groups.find((g) => g.name === name2);
@@ -1789,14 +1812,14 @@ var UserDb = class {
1789
1812
  this.fs = fs;
1790
1813
  this.owners = owners;
1791
1814
  }
1792
- async stampHome(row, shared) {
1815
+ async stampHome(row, shared, homeMode) {
1793
1816
  const home = this.fs.resolvePath("/", row.home);
1794
1817
  if (!this.owners || !this.fs.chown || !HOME_DIR.test(home)) return;
1795
1818
  if (!await this.realDir(home)) return;
1796
1819
  const gid = shared?.gid ?? row.gid;
1797
1820
  await this.fs.chown(home, { uid: row.uid, gid, follow: false, kind: "adopt" });
1798
1821
  const scoop = row.name.startsWith("scoop-");
1799
- await this.fs.chmod(home, shared ? 1512 : scoop ? 488 : 448);
1822
+ await this.fs.chmod(home, homeMode ?? (shared ? 1512 : scoop ? 488 : 448));
1800
1823
  const pnpm = `${home}/.local/share/pnpm`;
1801
1824
  if (await this.realDir(pnpm)) await this.fs.chmod(pnpm, scoop ? 488 : 448);
1802
1825
  }
@@ -1910,31 +1933,33 @@ var UserDb = class {
1910
1933
  const groups = parsed(group);
1911
1934
  const found = users.find((r) => r.name === name2);
1912
1935
  const shared = homeGroupOf(groups, options.homeGroup);
1936
+ const homeMode = homeModeOf(options.homeMode);
1913
1937
  if (found) {
1938
+ const more = groupsOf(groups, options.groups ?? []);
1939
+ if (more.some((g) => g.gid === found.gid)) {
1940
+ throw fsError("EINVAL", `a user is no member of its own group ${name2}`);
1941
+ }
1914
1942
  if (found.uid >= FIRST_UID && found.uid <= LAST_UID) {
1915
1943
  await this.provision(found);
1916
- await this.stampHome(found, shared);
1944
+ await this.stampHome(found, shared, homeMode);
1917
1945
  }
1946
+ if (joined(name2, more)) await this.fs.writeFile(GROUP, formatGroup(group));
1918
1947
  remember();
1919
1948
  return this.account(found, groups);
1920
1949
  }
1921
1950
  const home = homeOf(options.home ?? `/home/${name2}`);
1922
- const extra = [USERS_GROUP, ...options.groups ?? []].map((g) => {
1923
- const row2 = groups.find((r) => r.name === g);
1924
- if (!row2) throw fsError("ENOENT", `no group ${g}`);
1925
- return row2;
1926
- });
1951
+ const extra = groupsOf(groups, [USERS_GROUP, ...options.groups ?? []]);
1927
1952
  if (groups.some((r) => r.name === name2)) throw fsError("EEXIST", `group ${name2} exists`);
1928
1953
  const uid = freeId(users, groups);
1929
1954
  const row = { name: name2, uid, gid: uid, gecos: name2, home, shell: "/bin/bash" };
1930
- for (const g of extra) if (!g.members.includes(name2)) g.members.push(name2);
1955
+ joined(name2, extra);
1931
1956
  group.push({ name: name2, gid: uid, members: [] });
1932
1957
  passwd.push(row);
1933
1958
  const fresh = !await this.fs.exists(home);
1934
1959
  await this.fs.mkdir(home, { recursive: true });
1935
1960
  try {
1936
1961
  await this.provision(row);
1937
- await this.stampHome(row, shared);
1962
+ await this.stampHome(row, shared, homeMode);
1938
1963
  await this.fs.mkdir("/etc", { recursive: true });
1939
1964
  await this.commit(formatPasswd(passwd), formatGroup(group));
1940
1965
  } catch (err) {
@@ -1945,6 +1970,31 @@ var UserDb = class {
1945
1970
  return this.account(row, parsed(group));
1946
1971
  });
1947
1972
  }
1973
+ async groups() {
1974
+ const { group } = await this.tables();
1975
+ return parsed(group).map(({ name: name2, gid, members }) => ({ name: name2, gid, members: [...members] }));
1976
+ }
1977
+ addMember(group, user) {
1978
+ return this.member(group, user, true);
1979
+ }
1980
+ removeMember(group, user) {
1981
+ return this.member(group, user, false);
1982
+ }
1983
+ member(name2, user, on) {
1984
+ return this.serial(async () => {
1985
+ const { passwd, group } = await this.tables();
1986
+ const row = parsed(group).find((g) => g.name === name2);
1987
+ if (!row) throw fsError("ENOENT", `no group ${String(name2)}`);
1988
+ const who = parsed(passwd).find((u) => u.name === user);
1989
+ if (!who) throw fsError("ENOENT", `no user ${String(user)}`);
1990
+ if (who.gid === row.gid) throw fsError("EINVAL", `${name2} is the own group of ${user}`);
1991
+ if (row.members.includes(user) !== on) {
1992
+ row.members = on ? [...row.members, user] : row.members.filter((m) => m !== user);
1993
+ await this.fs.writeFile(GROUP, formatGroup(group));
1994
+ }
1995
+ return { name: row.name, gid: row.gid, members: [...row.members] };
1996
+ });
1997
+ }
1948
1998
  remove(name2, options = {}) {
1949
1999
  return this.serial(async () => {
1950
2000
  const { passwd, group } = await this.tables();
@@ -14831,10 +14881,10 @@ var ByteSource = class {
14831
14881
  async more() {
14832
14882
  const { done: done4, value } = await this.reader.read();
14833
14883
  if (done4) return false;
14834
- const joined = new Uint8Array(this.buffered.length + value.length);
14835
- joined.set(this.buffered);
14836
- joined.set(value, this.buffered.length);
14837
- this.buffered = joined;
14884
+ const joined2 = new Uint8Array(this.buffered.length + value.length);
14885
+ joined2.set(this.buffered);
14886
+ joined2.set(value, this.buffered.length);
14887
+ this.buffered = joined2;
14838
14888
  return true;
14839
14889
  }
14840
14890
  async until(marker) {
@@ -15522,6 +15572,11 @@ async function createNodeKernel(options = {}) {
15522
15572
  remove: (name2, options2) => guard(() => launcher.users.remove(name2, options2)),
15523
15573
  list: () => guard(() => launcher.users.list())
15524
15574
  },
15575
+ groups: {
15576
+ list: () => guard(() => launcher.users.groups()),
15577
+ addMember: (group, user) => guard(() => launcher.users.addMember(group, user)),
15578
+ removeMember: (group, user) => guard(() => launcher.users.removeMember(group, user))
15579
+ },
15525
15580
  async connect({ user } = {}) {
15526
15581
  if (terminated) throw new Error(TERMINATED);
15527
15582
  if (user !== void 0 && !await launcher.users.lookup(user)) {