@unchainedshop/core-users 4.8.25 → 4.8.27

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.
@@ -27,6 +27,7 @@ const USER_EVENTS = [
27
27
  'USER_UPDATE_WEB3_ADDRESS',
28
28
  'USER_REMOVE',
29
29
  ];
30
+ const ADMIN_ROLE = 'admin';
30
31
  export const removeConfidentialServiceHashes = (rawUser) => {
31
32
  const user = { ...rawUser };
32
33
  delete user?.services;
@@ -88,6 +89,14 @@ export const configureUsersModule = async (moduleInput) => {
88
89
  registerEvents(USER_EVENTS);
89
90
  const Users = await UsersCollection(db);
90
91
  const webAuthn = await configureUsersWebAuthnModule(moduleInput);
92
+ const assertAnotherActiveAdminExists = async (userId) => {
93
+ const user = await Users.findOne({ _id: userId, deleted: null });
94
+ if (!user?.roles?.includes(ADMIN_ROLE))
95
+ return;
96
+ const activeAdminCount = await Users.countDocuments({ deleted: null, roles: ADMIN_ROLE }, { limit: 2 });
97
+ if (activeAdminCount <= 1)
98
+ throw new Error('At least one active administrator is required. Assign another administrator before removing this account or revoking its admin role.', { cause: 'LAST_ADMIN' });
99
+ };
91
100
  return {
92
101
  webAuthn,
93
102
  async count(query) {
@@ -606,6 +615,7 @@ export const configureUsersModule = async (moduleInput) => {
606
615
  return user;
607
616
  },
608
617
  markDeleted: async (userId) => {
618
+ await assertAnotherActiveAdminExists(userId);
609
619
  await db.collection('sessions').deleteMany({
610
620
  session: { $regex: `"user(Id)?":"${escapeRegexString(userId)}"` },
611
621
  });
@@ -635,6 +645,7 @@ export const configureUsersModule = async (moduleInput) => {
635
645
  return user;
636
646
  },
637
647
  deletePermanently: async ({ userId }) => {
648
+ await assertAnotherActiveAdminExists(userId);
638
649
  return Users.findOneAndDelete({ _id: userId });
639
650
  },
640
651
  updateProfile: async (userId, updatedData) => {
@@ -751,15 +762,14 @@ export const configureUsersModule = async (moduleInput) => {
751
762
  return updatedUser;
752
763
  },
753
764
  updateRoles: async (_id, roles) => {
754
- const modifier = {
765
+ if (!roles.includes(ADMIN_ROLE))
766
+ await assertAnotherActiveAdminExists(_id);
767
+ const user = await Users.findOneAndUpdate(generateDbFilterById(_id), {
755
768
  $set: {
756
769
  updated: new Date(),
757
770
  roles,
758
771
  },
759
- };
760
- const user = await Users.findOneAndUpdate(generateDbFilterById(_id), modifier, {
761
- returnDocument: 'after',
762
- });
772
+ }, { returnDocument: 'after' });
763
773
  if (!user)
764
774
  return null;
765
775
  await emit('USER_UPDATE_ROLE', {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@unchainedshop/core-users",
3
3
  "description": "User management module for the Unchained Engine with authentication support",
4
- "version": "4.8.25",
4
+ "version": "4.8.27",
5
5
  "main": "lib/users-index.js",
6
6
  "types": "lib/users-index.d.ts",
7
7
  "type": "module",
@@ -36,10 +36,10 @@
36
36
  "homepage": "https://github.com/unchainedshop/unchained#readme",
37
37
  "dependencies": {
38
38
  "@passwordless-id/webauthn": "^2.3.1",
39
- "@unchainedshop/events": "^4.8.12",
40
- "@unchainedshop/logger": "^4.8.12",
41
- "@unchainedshop/mongodb": "^4.8.12",
42
- "@unchainedshop/utils": "^4.8.12",
39
+ "@unchainedshop/events": "^4.8.27",
40
+ "@unchainedshop/logger": "^4.8.27",
41
+ "@unchainedshop/mongodb": "^4.8.27",
42
+ "@unchainedshop/utils": "^4.8.27",
43
43
  "bcryptjs": "^3.0.2"
44
44
  },
45
45
  "peerDependencies": {