client online state
This commit is contained in:
55
dbcreate.sql
55
dbcreate.sql
@@ -552,51 +552,16 @@ GO
|
||||
|
||||
|
||||
CREATE OR ALTER VIEW dbo.vPermissionOverview AS
|
||||
SELECT
|
||||
p.ID AS Permission_ID,
|
||||
p.Scope,
|
||||
p.Resource,
|
||||
p.Action,
|
||||
p.Scope + '.' + p.Resource + '.' + p.Action AS PermissionKey,
|
||||
|
||||
r.ID AS Role_ID,
|
||||
|
||||
|
||||
-- 🔥 NEU: Anzahl Rollen pro Permission
|
||||
COUNT(r.ID) OVER (PARTITION BY p.ID) AS RoleCount,
|
||||
|
||||
COUNT(gr.Group_ObjectGUID) AS GroupCount,
|
||||
COUNT(ar.Authentication_ObjectGUID) AS DirectUserCount,
|
||||
COUNT(ag.Authentication_ObjectGUID) AS GroupUserCount,
|
||||
|
||||
COUNT(
|
||||
COALESCE(ar.Authentication_ObjectGUID, ag.Authentication_ObjectGUID)
|
||||
) AS TotalUserCount
|
||||
|
||||
FROM dbo.Permission AS p
|
||||
|
||||
INNER JOIN dbo.RolePermissions AS rp
|
||||
ON rp.Permission_ID = p.ID
|
||||
|
||||
INNER JOIN dbo.Role AS r
|
||||
ON r.ID = rp.Role_ID
|
||||
|
||||
LEFT JOIN dbo.GroupRoles AS gr
|
||||
ON gr.Role_ID = r.ID
|
||||
|
||||
LEFT JOIN dbo.AuthenticationRoles AS ar
|
||||
ON ar.Role_ID = r.ID
|
||||
|
||||
LEFT JOIN dbo.AuthenticationGroups AS ag
|
||||
ON ag.Group_ObjectGUID = gr.Group_ObjectGUID
|
||||
|
||||
GROUP BY
|
||||
p.ID,
|
||||
p.Scope,
|
||||
p.Resource,
|
||||
p.Action,
|
||||
r.ID,
|
||||
r.Name;
|
||||
SELECT p.ID AS Permission_ID, p.Scope, p.Resource, p.Action, p.Scope + '.' + p.Resource + '.' + p.Action AS PermissionKey, r.ID AS Role_ID, /* 🔥 NEU: Anzahl Rollen pro Permission*/ COUNT(r.ID) OVER (PARTITION BY p.ID)
|
||||
AS RoleCount, COUNT(gr.Group_ObjectGUID) AS GroupCount, COUNT(ar.Authentication_ObjectGUID) AS DirectUserCount, COUNT(ag.Authentication_ObjectGUID) AS GroupUserCount,
|
||||
COUNT(COALESCE (ar.Authentication_ObjectGUID, ag.Authentication_ObjectGUID)) AS TotalUserCount
|
||||
FROM dbo.Permission AS p FULL JOIN
|
||||
dbo.RolePermissions AS rp ON rp.Permission_ID = p.ID LEFT JOIN
|
||||
dbo.Role AS r ON r.ID = rp.Role_ID LEFT JOIN
|
||||
dbo.GroupRoles AS gr ON gr.Role_ID = r.ID LEFT JOIN
|
||||
dbo.AuthenticationRoles AS ar ON ar.Role_ID = r.ID LEFT JOIN
|
||||
dbo.AuthenticationGroups AS ag ON ag.Group_ObjectGUID = gr.Group_ObjectGUID
|
||||
GROUP BY p.ID, p.Scope, p.Resource, p.Action, r.ID, r.Name;
|
||||
GO
|
||||
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ module.exports = {
|
||||
localPath,
|
||||
cache: {
|
||||
startMenuItems: [],
|
||||
clientsOnline: []
|
||||
},
|
||||
runtimeFile: {
|
||||
package: new HotReload(path.join(localPath.root, 'package.json')),
|
||||
|
||||
281
package-lock.json
generated
281
package-lock.json
generated
@@ -9,7 +9,6 @@
|
||||
"version": "0.9",
|
||||
"license": "UNLICENSED",
|
||||
"dependencies": {
|
||||
"activedirectory2": "^2.2.0",
|
||||
"bcryptjs": "^3.0.2",
|
||||
"body-parser": "^2.2.0",
|
||||
"child_process": "^1.0.2",
|
||||
@@ -21,7 +20,7 @@
|
||||
"fs-extra": "^11.3.2",
|
||||
"https": "^1.0.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"ldapjs": "^3.0.7",
|
||||
"ldapts": "^8.1.7",
|
||||
"module-alias": "^2.2.3",
|
||||
"multer": "^2.0.2",
|
||||
"net": "^1.0.2",
|
||||
@@ -298,92 +297,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@js-joda/core/-/core-5.6.5.tgz",
|
||||
"integrity": "sha512-3zwefSMwHpu8iVUW8YYz227sIv6UFqO31p1Bf1ZH/Vom7CmNyUsXjDBlnNzcuhmOL1XfxZ3nvND42kR23XlbcQ=="
|
||||
},
|
||||
"node_modules/@ldapjs/asn1": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@ldapjs/asn1/-/asn1-2.0.0.tgz",
|
||||
"integrity": "sha512-G9+DkEOirNgdPmD0I8nu57ygQJKOOgFEMKknEuQvIHbGLwP3ny1mY+OTUYLCbCaGJP4sox5eYgBJRuSUpnAddA==",
|
||||
"deprecated": "This package has been decomissioned. See https://github.com/ldapjs/node-ldapjs/blob/8ffd0bc9c149088a10ec4c1ec6a18450f76ad05d/README.md"
|
||||
},
|
||||
"node_modules/@ldapjs/attribute": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@ldapjs/attribute/-/attribute-1.0.0.tgz",
|
||||
"integrity": "sha512-ptMl2d/5xJ0q+RgmnqOi3Zgwk/TMJYG7dYMC0Keko+yZU6n+oFM59MjQOUht5pxJeS4FWrImhu/LebX24vJNRQ==",
|
||||
"deprecated": "This package has been decomissioned. See https://github.com/ldapjs/node-ldapjs/blob/8ffd0bc9c149088a10ec4c1ec6a18450f76ad05d/README.md",
|
||||
"dependencies": {
|
||||
"@ldapjs/asn1": "2.0.0",
|
||||
"@ldapjs/protocol": "^1.2.1",
|
||||
"process-warning": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ldapjs/change": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@ldapjs/change/-/change-1.0.0.tgz",
|
||||
"integrity": "sha512-EOQNFH1RIku3M1s0OAJOzGfAohuFYXFY4s73wOhRm4KFGhmQQ7MChOh2YtYu9Kwgvuq1B0xKciXVzHCGkB5V+Q==",
|
||||
"deprecated": "This package has been decomissioned. See https://github.com/ldapjs/node-ldapjs/blob/8ffd0bc9c149088a10ec4c1ec6a18450f76ad05d/README.md",
|
||||
"dependencies": {
|
||||
"@ldapjs/asn1": "2.0.0",
|
||||
"@ldapjs/attribute": "1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ldapjs/controls": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ldapjs/controls/-/controls-2.1.0.tgz",
|
||||
"integrity": "sha512-2pFdD1yRC9V9hXfAWvCCO2RRWK9OdIEcJIos/9cCVP9O4k72BY1bLDQQ4KpUoJnl4y/JoD4iFgM+YWT3IfITWw==",
|
||||
"deprecated": "This package has been decomissioned. See https://github.com/ldapjs/node-ldapjs/blob/8ffd0bc9c149088a10ec4c1ec6a18450f76ad05d/README.md",
|
||||
"dependencies": {
|
||||
"@ldapjs/asn1": "^1.2.0",
|
||||
"@ldapjs/protocol": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@ldapjs/controls/node_modules/@ldapjs/asn1": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ldapjs/asn1/-/asn1-1.2.0.tgz",
|
||||
"integrity": "sha512-KX/qQJ2xxzvO2/WOvr1UdQ+8P5dVvuOLk/C9b1bIkXxZss8BaR28njXdPgFCpj5aHaf1t8PmuVnea+N9YG9YMw==",
|
||||
"deprecated": "This package has been decomissioned. See https://github.com/ldapjs/node-ldapjs/blob/8ffd0bc9c149088a10ec4c1ec6a18450f76ad05d/README.md"
|
||||
},
|
||||
"node_modules/@ldapjs/dn": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ldapjs/dn/-/dn-1.1.0.tgz",
|
||||
"integrity": "sha512-R72zH5ZeBj/Fujf/yBu78YzpJjJXG46YHFo5E4W1EqfNpo1UsVPqdLrRMXeKIsJT3x9dJVIfR6OpzgINlKpi0A==",
|
||||
"deprecated": "This package has been decomissioned. See https://github.com/ldapjs/node-ldapjs/blob/8ffd0bc9c149088a10ec4c1ec6a18450f76ad05d/README.md",
|
||||
"dependencies": {
|
||||
"@ldapjs/asn1": "2.0.0",
|
||||
"process-warning": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ldapjs/filter": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@ldapjs/filter/-/filter-2.1.1.tgz",
|
||||
"integrity": "sha512-TwPK5eEgNdUO1ABPBUQabcZ+h9heDORE4V9WNZqCtYLKc06+6+UAJ3IAbr0L0bYTnkkWC/JEQD2F+zAFsuikNw==",
|
||||
"deprecated": "This package has been decomissioned. See https://github.com/ldapjs/node-ldapjs/blob/8ffd0bc9c149088a10ec4c1ec6a18450f76ad05d/README.md",
|
||||
"dependencies": {
|
||||
"@ldapjs/asn1": "2.0.0",
|
||||
"@ldapjs/protocol": "^1.2.1",
|
||||
"process-warning": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ldapjs/messages": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@ldapjs/messages/-/messages-1.3.0.tgz",
|
||||
"integrity": "sha512-K7xZpXJ21bj92jS35wtRbdcNrwmxAtPwy4myeh9duy/eR3xQKvikVycbdWVzkYEAVE5Ce520VXNOwCHjomjCZw==",
|
||||
"deprecated": "This package has been decomissioned. See https://github.com/ldapjs/node-ldapjs/blob/8ffd0bc9c149088a10ec4c1ec6a18450f76ad05d/README.md",
|
||||
"dependencies": {
|
||||
"@ldapjs/asn1": "^2.0.0",
|
||||
"@ldapjs/attribute": "^1.0.0",
|
||||
"@ldapjs/change": "^1.0.0",
|
||||
"@ldapjs/controls": "^2.1.0",
|
||||
"@ldapjs/dn": "^1.1.0",
|
||||
"@ldapjs/filter": "^2.1.1",
|
||||
"@ldapjs/protocol": "^1.2.1",
|
||||
"process-warning": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ldapjs/protocol": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ldapjs/protocol/-/protocol-1.2.1.tgz",
|
||||
"integrity": "sha512-O89xFDLW2gBoZWNXuXpBSM32/KealKCTb3JGtJdtUQc7RjAk8XzrRgyz02cPAwGKwKPxy0ivuC7UP9bmN87egQ==",
|
||||
"deprecated": "This package has been decomissioned. See https://github.com/ldapjs/node-ldapjs/blob/8ffd0bc9c149088a10ec4c1ec6a18450f76ad05d/README.md"
|
||||
},
|
||||
"node_modules/@socket.io/component-emitter": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
||||
@@ -455,11 +368,6 @@
|
||||
"node": ">=6.5"
|
||||
}
|
||||
},
|
||||
"node_modules/abstract-logging": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz",
|
||||
"integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA=="
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
|
||||
@@ -472,40 +380,6 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/activedirectory2": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/activedirectory2/-/activedirectory2-2.2.0.tgz",
|
||||
"integrity": "sha512-uGbw74xttFG6hgocU8T1a0oDofLsyTp44BPTn42JN5C2QlyO5kRl2E7ZoUdfpFzV+yxhaQTKI+8QqRB5HONYvA==",
|
||||
"deprecated": "Decomissioned.",
|
||||
"dependencies": {
|
||||
"abstract-logging": "^2.0.0",
|
||||
"async": "^3.1.0",
|
||||
"ldapjs": "^2.3.3",
|
||||
"merge-options": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/activedirectory2/node_modules/ldapjs": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/ldapjs/-/ldapjs-2.3.3.tgz",
|
||||
"integrity": "sha512-75QiiLJV/PQqtpH+HGls44dXweviFwQ6SiIK27EqzKQ5jU/7UFrl2E5nLdQ3IYRBzJ/AVFJI66u0MZ0uofKYwg==",
|
||||
"deprecated": "This package has been decomissioned. See https://github.com/ldapjs/node-ldapjs/blob/8ffd0bc9c149088a10ec4c1ec6a18450f76ad05d/README.md",
|
||||
"dependencies": {
|
||||
"abstract-logging": "^2.0.0",
|
||||
"asn1": "^0.2.4",
|
||||
"assert-plus": "^1.0.0",
|
||||
"backoff": "^2.5.0",
|
||||
"ldap-filter": "^0.3.3",
|
||||
"once": "^1.4.0",
|
||||
"vasync": "^2.2.0",
|
||||
"verror": "^1.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
|
||||
@@ -541,38 +415,6 @@
|
||||
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
|
||||
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="
|
||||
},
|
||||
"node_modules/asn1": {
|
||||
"version": "0.2.6",
|
||||
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
|
||||
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
|
||||
"dependencies": {
|
||||
"safer-buffer": "~2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/async": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
|
||||
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="
|
||||
},
|
||||
"node_modules/backoff": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz",
|
||||
"integrity": "sha512-wC5ihrnUXmR2douXmXLCe5O3zg3GKIyvRi/hi58a/XyRxVI+3/yM0PYueQOZXPXQ9pxBislYkw+sF9b7C/RuMA==",
|
||||
"dependencies": {
|
||||
"precond": "0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
|
||||
@@ -885,11 +727,6 @@
|
||||
"node": ">=6.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="
|
||||
},
|
||||
"node_modules/cors": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||
@@ -1219,14 +1056,6 @@
|
||||
"node": ">=22.15.0"
|
||||
}
|
||||
},
|
||||
"node_modules/extsprintf": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz",
|
||||
"integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==",
|
||||
"engines": [
|
||||
"node >=0.6.0"
|
||||
]
|
||||
},
|
||||
"node_modules/finalhandler": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
|
||||
@@ -1558,14 +1387,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-plain-obj": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
|
||||
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-promise": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
|
||||
@@ -1660,37 +1481,15 @@
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/ldap-filter": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/ldap-filter/-/ldap-filter-0.3.3.tgz",
|
||||
"integrity": "sha512-/tFkx5WIn4HuO+6w9lsfxq4FN3O+fDZeO9Mek8dCD8rTUpqzRa766BOBO7BcGkn3X86m5+cBm1/2S/Shzz7gMg==",
|
||||
"node_modules/ldapts": {
|
||||
"version": "8.1.7",
|
||||
"resolved": "https://registry.npmjs.org/ldapts/-/ldapts-8.1.7.tgz",
|
||||
"integrity": "sha512-TJl6T92eIwMf/OJ0hDfKVa6ISwzo+lqCWCI5Mf//ARlKa3LKQZaSrme/H2rCRBhW0DZCQlrsV+fgoW5YHRNLUw==",
|
||||
"dependencies": {
|
||||
"assert-plus": "^1.0.0"
|
||||
"strict-event-emitter-types": "2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/ldapjs": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/ldapjs/-/ldapjs-3.0.7.tgz",
|
||||
"integrity": "sha512-1ky+WrN+4CFMuoekUOv7Y1037XWdjKpu0xAPwSP+9KdvmV9PG+qOKlssDV6a+U32apwxdD3is/BZcWOYzN30cg==",
|
||||
"deprecated": "This package has been decomissioned. See https://github.com/ldapjs/node-ldapjs/blob/8ffd0bc9c149088a10ec4c1ec6a18450f76ad05d/README.md",
|
||||
"dependencies": {
|
||||
"@ldapjs/asn1": "^2.0.0",
|
||||
"@ldapjs/attribute": "^1.0.0",
|
||||
"@ldapjs/change": "^1.0.0",
|
||||
"@ldapjs/controls": "^2.1.0",
|
||||
"@ldapjs/dn": "^1.1.0",
|
||||
"@ldapjs/filter": "^2.1.1",
|
||||
"@ldapjs/messages": "^1.3.0",
|
||||
"@ldapjs/protocol": "^1.2.1",
|
||||
"abstract-logging": "^2.0.1",
|
||||
"assert-plus": "^1.0.0",
|
||||
"backoff": "^2.5.0",
|
||||
"once": "^1.4.0",
|
||||
"vasync": "^2.2.1",
|
||||
"verror": "^1.10.1"
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
@@ -1769,17 +1568,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-options": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-options/-/merge-options-2.0.0.tgz",
|
||||
"integrity": "sha512-S7xYIeWHl2ZUKF7SDeBhGg6rfv5bKxVBdk95s/I7wVF8d+hjLSztJ/B271cnUiF6CAFduEQ5Zn3HYwAjT16DlQ==",
|
||||
"dependencies": {
|
||||
"is-plain-obj": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.54.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
||||
@@ -3854,14 +3642,6 @@
|
||||
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz",
|
||||
"integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w=="
|
||||
},
|
||||
"node_modules/precond": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz",
|
||||
"integrity": "sha512-QCYG84SgGyGzqJ/vlMsxeXd/pgL/I94ixdNFyh1PusWmTCyVfPJjZ1K1jvHtsbfnXQs2TSkEP2fR7QiMZAnKFQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/process": {
|
||||
"version": "0.11.10",
|
||||
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||
@@ -3870,11 +3650,6 @@
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/process-warning": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.3.2.tgz",
|
||||
"integrity": "sha512-n9wh8tvBe5sFmsqlg+XQhaQLumwpqoAUruLwjCopgTmUBjJ/fjtBsJzKleCaIGBOMXYEhp1YfKl4d7rJ5ZKJGA=="
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
@@ -4402,6 +4177,11 @@
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/strict-event-emitter-types": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-event-emitter-types/-/strict-event-emitter-types-2.0.0.tgz",
|
||||
"integrity": "sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA=="
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
@@ -4629,43 +4409,6 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/vasync": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/vasync/-/vasync-2.2.1.tgz",
|
||||
"integrity": "sha512-Hq72JaTpcTFdWiNA4Y22Amej2GH3BFmBaKPPlDZ4/oC8HNn2ISHLkFrJU4Ds8R3jcUi7oo5Y9jcMHKjES+N9wQ==",
|
||||
"engines": [
|
||||
"node >=0.6.0"
|
||||
],
|
||||
"dependencies": {
|
||||
"verror": "1.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vasync/node_modules/verror": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
||||
"integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
|
||||
"engines": [
|
||||
"node >=0.6.0"
|
||||
],
|
||||
"dependencies": {
|
||||
"assert-plus": "^1.0.0",
|
||||
"core-util-is": "1.0.2",
|
||||
"extsprintf": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/verror": {
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz",
|
||||
"integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==",
|
||||
"dependencies": {
|
||||
"assert-plus": "^1.0.0",
|
||||
"core-util-is": "1.0.2",
|
||||
"extsprintf": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
"license": "UNLICENSED",
|
||||
"licensefile": "license_internal.txt",
|
||||
"dependencies": {
|
||||
"activedirectory2": "^2.2.0",
|
||||
"bcryptjs": "^3.0.2",
|
||||
"body-parser": "^2.2.0",
|
||||
"child_process": "^1.0.2",
|
||||
@@ -33,7 +32,7 @@
|
||||
"fs-extra": "^11.3.2",
|
||||
"https": "^1.0.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"ldapjs": "^3.0.7",
|
||||
"ldapts": "^8.1.7",
|
||||
"module-alias": "^2.2.3",
|
||||
"multer": "^2.0.2",
|
||||
"net": "^1.0.2",
|
||||
|
||||
@@ -30,11 +30,13 @@ const RBAC = {
|
||||
}))
|
||||
.sort((a, b) => a.sAMAccountName.localeCompare(b.sAMAccountName)),
|
||||
createUser: (data) => api('/api/rbac/auth/create', 'POST', data),
|
||||
syncUsersFromAD: () => api('/api/rbac/auth/syncFromAD', 'POST', { }),
|
||||
deleteUser: (guid) => api(`/api/rbac/auth/${guid}`, 'DELETE'),
|
||||
|
||||
// 👥 GROUPS
|
||||
loadGroups: () => api('/api/rbac/group/get', 'POST'),
|
||||
createGroup: (name) => api('/api/rbac/group/create', 'POST', { name }),
|
||||
syncGroupsFromAD: () => api('/api/rbac/group/syncFromAD', 'POST', { }),
|
||||
deleteGroup: (guid) => api(`/api/rbac/group/${guid}`, 'DELETE'),
|
||||
|
||||
// 🎭 ROLES
|
||||
@@ -193,7 +195,7 @@ const rbacPermissionsVT = virtualTable({
|
||||
data: [],
|
||||
rowHeight: 20,
|
||||
buffer: 5,
|
||||
groupKey: 'Scope',
|
||||
groupKey: null,
|
||||
rowKey: 'ID',
|
||||
filterConfig: {
|
||||
hideCounter: true,
|
||||
@@ -372,6 +374,13 @@ async function createUser() {
|
||||
loadUsers();
|
||||
}
|
||||
|
||||
|
||||
async function syncUsersFromAD() {
|
||||
const users = await RBAC.syncUsersFromAD();
|
||||
sendUserEvent('RBAC', `${users.length} Benutzer aus dem AD synchronisiert`, null, 0);
|
||||
loadUsers();
|
||||
}
|
||||
|
||||
async function deleteUser(guid, name) {
|
||||
feedbox({
|
||||
title: `<span>Benutzer löschen</span>`,
|
||||
@@ -420,6 +429,16 @@ async function deleteGroup(guid, name) {
|
||||
}
|
||||
|
||||
|
||||
async function syncGroupsFromAD() {
|
||||
const group = await RBAC.syncGroupsFromAD();
|
||||
|
||||
sendUserEvent('RBAC', `${group.length} Gruppen aus dem AD synchronisiert`, null, 0);
|
||||
|
||||
loadGroups();
|
||||
loadUsers();
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
// 🎭 ROLE ACTIONS
|
||||
//////////////////////////////
|
||||
|
||||
@@ -43,7 +43,7 @@ button:not(:disabled).yellowbutton:hover { background:var(--theme-button-yellow-
|
||||
.card.static.row { overflow:hidden; display:flex; flex-direction:row; flex-wrap: wrap;}
|
||||
.card.static { overflow:hidden; display:flex; flex-direction:column; }
|
||||
|
||||
.container { width:calc(100% - 20px); margin:10px auto; display:grid; grid-template-columns:100%; gap:12px; min-height:0; overflow:auto; max-height:100%; }
|
||||
.container:not(.static) { width:calc(100% - 20px); margin:10px auto; display:grid; grid-template-columns:100%; gap:12px; min-height:0; overflow:auto; max-height:100%; }
|
||||
.container:not(.static) * { box-sizing:border-box; }
|
||||
.card { border-width:1px; border-style:solid; border-radius:8px; padding:20px; }
|
||||
|
||||
|
||||
@@ -149,4 +149,24 @@
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/* Checks tab visibility
|
||||
document.addEventListener(
|
||||
'visibilitychange',
|
||||
() => {
|
||||
|
||||
if (document.hidden) {
|
||||
|
||||
alert('AWAY AT: ' + new Date().toISOString());
|
||||
|
||||
} else {
|
||||
|
||||
updateActivity();
|
||||
}
|
||||
}
|
||||
);
|
||||
*/
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
@@ -29,7 +29,7 @@ section {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 5px;
|
||||
width: 120px;
|
||||
width: 200px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 8px;
|
||||
margin: 0 2px 2px 0;
|
||||
@@ -62,12 +62,21 @@ input {
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- USERS -->
|
||||
<div class="container static" style="height:100vh;max-width:100vw;flex-direction:row;flex-wrap:wrap;">
|
||||
<div class="card" style="flex:1 1 auto;min-width:300px">
|
||||
Users <input id="newUserName" placeholder="sAMAccountName" /> <button class="bluebutton" onclick="createUser()">Create User</button>
|
||||
<div class="table-wrapper fit-table">
|
||||
<table id="rbacUsersTable" style="">
|
||||
|
||||
|
||||
<div class="container static" style="max-width:100vw;flex-direction:row;flex-wrap:wrap;flex: 1 1 100vh;">
|
||||
<!-- USERS -->
|
||||
<div class="card static row" style="align-items:center;height:fit-content;width:100%">
|
||||
AD Synchronisation:
|
||||
<button class="yellowbutton" data-tooltip="Synchronisiert die Benutzer aus dem AD" onclick="syncUsersFromAD()">Users</button>
|
||||
<button class="yellowbutton" data-tooltip="Synchronisiert die Gruppen aus dem AD" onclick="syncGroupsFromAD()">Groups</button>
|
||||
|
||||
</div>
|
||||
<div class="card" style="aflex-wrap:wrap;flex: 1 1 100%;justify-content: flex-start;">
|
||||
Users <input id="newUserName" placeholder="sAMAccountName" />
|
||||
<button class="bluebutton" onclick="createUser()">Create User</button>
|
||||
<div class="table-wrapper " style="max-height:300px;overflow:auto">
|
||||
<table id="rbacUsersTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-align:left"></th>
|
||||
@@ -88,8 +97,30 @@ input {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- GROUPS -->
|
||||
<div class="card static" style="min-width:300px;flex:1 1 calc(300px); max-height: 400px;overflow:auto">
|
||||
<input id="newGroupName" placeholder="Gruppenname" /> <button class="bluebutton" onclick="createGroup()">Create Group</button>
|
||||
|
||||
<div id="rbacGroupContainer">
|
||||
<span>GRUPPEN WERDEN GELADEN . . .</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ROLES -->
|
||||
<div class="card" style="min-width:300px;flex:1 1 calc(300px)">
|
||||
<input id="newRoleName" placeholder="Rollenname" />
|
||||
<button class="bluebutton" onclick="createRole()">Create Role</button>
|
||||
|
||||
<div id="rbacRoleContainer">
|
||||
<span>ROLLEN WERDEN GELADEN . . .</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- PERMISSIONS -->
|
||||
<div class="card" style="min-width:300px;flex:1 1 auto">
|
||||
<div class="card" style="min-width:300px;flex:1 1 auto;align-items:center;">
|
||||
<input id="permScope" placeholder="Scope" />.<input id="permResource" placeholder="Resource" />.<input id="permAction" placeholder="Action" />
|
||||
|
||||
<button class="bluebutton" onclick="createPermission()">Create Permission</button>
|
||||
@@ -115,24 +146,6 @@ input {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- GROUPS -->
|
||||
<div class="card" style="min-width:300px;flex:1 1 calc(300px)">
|
||||
<input id="newGroupName" placeholder="Gruppenname" /> <button class="bluebutton" onclick="createGroup()">Create Group</button>
|
||||
|
||||
<div id="rbacGroupContainer">
|
||||
<span>GRUPPEN WERDEN GELADEN . . .</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ROLES -->
|
||||
<div class="card" style="min-width:300px;flex:1 1 calc(300px)">
|
||||
<input id="newRoleName" placeholder="Rollenname" />
|
||||
<button class="bluebutton" onclick="createRole()">Create Role</button>
|
||||
|
||||
<div id="rbacRoleContainer">
|
||||
<span>ROLLEN WERDEN GELADEN . . .</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
||||
@@ -57,7 +57,8 @@ const server = https.createServer(httpsOptions, app);
|
||||
|
||||
|
||||
const io = new Server(server, {
|
||||
pingTimeout: 60000,
|
||||
pingInterval: 1000, // alle 25s Ping senden
|
||||
pingTimeout: 200, // 20s ohne Pong => disconnect
|
||||
maxHttpBufferSize: 1e8, // 100 MB
|
||||
});
|
||||
|
||||
|
||||
@@ -12,6 +12,15 @@ module.exports = (sequelize) => {
|
||||
}
|
||||
}, {
|
||||
tableName: 'AuthenticationGroups',
|
||||
indexes: [
|
||||
{
|
||||
unique: true,
|
||||
fields: [
|
||||
'Authentication_ObjectGUID',
|
||||
'Group_ObjectGUID'
|
||||
]
|
||||
}
|
||||
],
|
||||
timestamps: false
|
||||
});
|
||||
|
||||
|
||||
@@ -102,7 +102,6 @@ module.exports = {
|
||||
|
||||
app.post('/api/rbac/auth/get', async (req, res) => {
|
||||
try {
|
||||
console.log(await service.get('rbacManager').syncAuthByActiveDirectory());
|
||||
rbacUsers = await service.get('rbacManager').getAuth();
|
||||
res.json(rbacUsers);
|
||||
} catch (err) {
|
||||
@@ -138,6 +137,17 @@ module.exports = {
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/rbac/auth/syncFromAD', async (req, res) => {
|
||||
try {
|
||||
rbacUsers = await service.get('rbacManager').syncAuthByActiveDirectory();
|
||||
console.log(await service.get('rbacManager').syncAuthenticationGroupsFromAD());
|
||||
res.json(rbacUsers);
|
||||
} catch (err) {
|
||||
service.get('eventManager').writeLog(req.cookies.ObjectGUID, 4, 'RBAC', err.message);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/rbac/auth/:id', async (req, res) => {
|
||||
try {
|
||||
await service.get('rbacManager').updateAuth(req.params.id, req.body);
|
||||
@@ -190,6 +200,17 @@ module.exports = {
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/rbac/group/syncFromAD', async (req, res) => {
|
||||
try {
|
||||
console.log(await service.get('rbacManager').syncGroupClosureFromAD());
|
||||
rbacGroups = await service.get('rbacManager').syncGroupByActiveDirectory();
|
||||
res.json(rbacGroups);
|
||||
} catch (err) {
|
||||
service.get('eventManager').writeLog(req.cookies.ObjectGUID, 4, 'RBAC', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/rbac/group/:id', async (req, res) => {
|
||||
try {
|
||||
await service.get('rbacManager').updateGroup(req.params.id, req.body);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -57,6 +57,10 @@ class AuthenticationManager {
|
||||
return { token: null, levelId: 2, message: 'Falsches Passwort' };
|
||||
}
|
||||
|
||||
if(!user.active) {
|
||||
return { token: null, levelId: 2, message: 'Benutzer nicht aktiv' };
|
||||
}
|
||||
|
||||
const token = jwt.sign(
|
||||
{
|
||||
ObjectGUID: user.ObjectGUID,
|
||||
@@ -67,12 +71,26 @@ class AuthenticationManager {
|
||||
);
|
||||
|
||||
user.refreshtoken = token;
|
||||
user.online = true;
|
||||
await this.setOnline(sAMAccountName);
|
||||
await user.save();
|
||||
|
||||
return { token, levelId: 0, message: 'Erfolgreich angemeldet' };
|
||||
}
|
||||
|
||||
|
||||
async setOnline(sAMAccountName) {
|
||||
const user = await this.findUser(sAMAccountName);
|
||||
user.online = true;
|
||||
await user.save();
|
||||
}
|
||||
|
||||
async setOffline(sAMAccountName) {
|
||||
const user = await this.findUser(sAMAccountName);
|
||||
user.online = false;
|
||||
await user.save();
|
||||
}
|
||||
|
||||
|
||||
// =========================================================
|
||||
// LOGOUT
|
||||
// =========================================================
|
||||
@@ -85,8 +103,8 @@ class AuthenticationManager {
|
||||
}
|
||||
|
||||
user.refreshtoken = null;
|
||||
user.online = false;
|
||||
await user.save();
|
||||
await this.setOffline();
|
||||
|
||||
return { token: null, levelId: 0, message: 'Erfolgreich abgemeldet' };
|
||||
}
|
||||
|
||||
@@ -190,8 +190,9 @@ class RBACManager {
|
||||
return res.redirect('/login');
|
||||
}
|
||||
|
||||
const user = await this.db.get('authentication').findOne( { where: { sAMAccountName } } );
|
||||
req.user = {};
|
||||
|
||||
const user = await this.db.get('authentication').findOne( { where: { sAMAccountName } } );
|
||||
if (!user || !user.active) {
|
||||
return res.redirect('/login');
|
||||
}
|
||||
@@ -217,6 +218,7 @@ class RBACManager {
|
||||
permissions: normalized,
|
||||
isSuperAdmin
|
||||
};
|
||||
|
||||
next();
|
||||
|
||||
} catch (err) {
|
||||
@@ -254,19 +256,17 @@ async syncAuthByActiveDirectory() {
|
||||
const all = await this.service.get('activeDirectoryManager').getAllUsers();
|
||||
|
||||
all.forEach(async user => {
|
||||
user.userAccountControl = user.userAccountControl_ID;
|
||||
user.distinguishedName = user.distinguishedName;
|
||||
|
||||
await auth.upsert({
|
||||
objectGUID: user.ObjectGUID,
|
||||
ObjectSource_ID: 2,
|
||||
userAccountControl_ID: user.userAccountControl,
|
||||
mail: user.mail,
|
||||
displayName: user.displayName
|
||||
});
|
||||
try {
|
||||
if(user.objectGUID !== null) {
|
||||
await auth.upsert({...user, ObjectGUID: user.objectGUID});
|
||||
} else {
|
||||
}
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
})
|
||||
|
||||
// return all;
|
||||
return all;
|
||||
}
|
||||
|
||||
|
||||
@@ -319,6 +319,27 @@ async createGroup(data) {
|
||||
});
|
||||
}
|
||||
|
||||
async syncGroupByActiveDirectory() {
|
||||
const group = await this.db.get('group');
|
||||
const all = await this.service.get('activeDirectoryManager').getAllGroups({
|
||||
attributes: ['objectGUID', 'sAMAccountName', 'distinguishedName'],
|
||||
includeMembers: false
|
||||
});
|
||||
|
||||
all.forEach(async adGroup => {
|
||||
try {
|
||||
if(adGroup.objectGUID !== null) {
|
||||
await group.upsert({...adGroup, ObjectGUID: adGroup.objectGUID, Name: adGroup.sAMAccountName});
|
||||
} else {
|
||||
}
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
})
|
||||
|
||||
return all;
|
||||
}
|
||||
|
||||
async updateGroup(id, data) {
|
||||
const Group = this.db.get('group');
|
||||
|
||||
@@ -367,6 +388,225 @@ async removeUserFromGroup(authId, groupId) {
|
||||
});
|
||||
}
|
||||
|
||||
async syncAuthenticationGroupsFromAD() {
|
||||
|
||||
const AuthGroups = this.db.get('authenticationGroupsModel');
|
||||
|
||||
const users = await this.service
|
||||
.get('activeDirectoryManager')
|
||||
.getAllUsers([
|
||||
'objectGUID',
|
||||
'memberOf'
|
||||
]);
|
||||
|
||||
const groups = await this.service
|
||||
.get('activeDirectoryManager')
|
||||
.getAllGroups({
|
||||
attributes: [
|
||||
'objectGUID',
|
||||
'distinguishedName'
|
||||
]
|
||||
});
|
||||
|
||||
/**
|
||||
* -----------------------------------------------------
|
||||
* GROUP MAP (DN -> GUID)
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
|
||||
const groupMap = new Map();
|
||||
|
||||
for (const g of groups) {
|
||||
|
||||
if (g.distinguishedName && g.objectGUID) {
|
||||
groupMap.set(
|
||||
g.distinguishedName.toLowerCase(),
|
||||
g.objectGUID
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* -----------------------------------------------------
|
||||
* BUILD RELATIONS
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
|
||||
const relations = [];
|
||||
|
||||
for (const user of users) {
|
||||
|
||||
if (!user.objectGUID) continue;
|
||||
|
||||
const memberOf = Array.isArray(user.memberOf)
|
||||
? user.memberOf
|
||||
: user.memberOf
|
||||
? [user.memberOf]
|
||||
: [];
|
||||
|
||||
for (const dn of memberOf) {
|
||||
|
||||
const groupGuid = groupMap.get(dn.toLowerCase());
|
||||
|
||||
if (!groupGuid) continue;
|
||||
|
||||
relations.push({
|
||||
Authentication_ObjectGUID: user.objectGUID,
|
||||
Group_ObjectGUID: groupGuid
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* -----------------------------------------------------
|
||||
* DB SYNC (clean rebuild)
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
|
||||
// await AuthGroups.destroy({
|
||||
// where: {}
|
||||
// });
|
||||
|
||||
if (relations.length) {
|
||||
await AuthGroups.upsert(relations, {
|
||||
// ignoreDuplicates: true
|
||||
});
|
||||
}
|
||||
|
||||
return relations;
|
||||
}
|
||||
|
||||
|
||||
async syncGroupClosureFromAD() {
|
||||
|
||||
const GroupClosure = this.db.get('groupClosureModel');
|
||||
|
||||
const groups = await this.service
|
||||
.get('activeDirectoryManager')
|
||||
.getAllGroups({
|
||||
attributes: [
|
||||
'objectGUID',
|
||||
'distinguishedName',
|
||||
'member'
|
||||
],
|
||||
includeMembers: false
|
||||
});
|
||||
|
||||
/**
|
||||
* -----------------------------------------------------
|
||||
* MAP: DN -> GUID
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
|
||||
const groupMap = new Map();
|
||||
|
||||
for (const g of groups) {
|
||||
if (g.distinguishedName && g.objectGUID) {
|
||||
groupMap.set(
|
||||
g.distinguishedName.toLowerCase(),
|
||||
g.objectGUID
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* -----------------------------------------------------
|
||||
* BUILD DIRECT RELATIONS
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
|
||||
const edges = [];
|
||||
|
||||
for (const group of groups) {
|
||||
|
||||
if (!group.objectGUID) continue;
|
||||
|
||||
const members = Array.isArray(group.member)
|
||||
? group.member
|
||||
: group.member
|
||||
? [group.member]
|
||||
: [];
|
||||
|
||||
for (const memberDN of members) {
|
||||
|
||||
const childGUID = groupMap.get(
|
||||
memberDN.toLowerCase()
|
||||
);
|
||||
|
||||
if (!childGUID) continue;
|
||||
|
||||
edges.push({
|
||||
ParentGroup_ObjectGUID: group.objectGUID,
|
||||
ChildGroup_ObjectGUID: childGUID,
|
||||
Depth: 1
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* -----------------------------------------------------
|
||||
* TRANSITIVE CLOSURE (DFS)
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
|
||||
const closure = [...edges];
|
||||
|
||||
const adjacency = new Map();
|
||||
|
||||
for (const e of edges) {
|
||||
|
||||
if (!adjacency.has(e.ParentGroup_ObjectGUID)) {
|
||||
adjacency.set(e.ParentGroup_ObjectGUID, []);
|
||||
}
|
||||
|
||||
adjacency.get(e.ParentGroup_ObjectGUID)
|
||||
.push(e.ChildGroup_ObjectGUID);
|
||||
}
|
||||
|
||||
const visitedCache = new Map();
|
||||
|
||||
const dfs = (root, current, depth) => {
|
||||
|
||||
const children = adjacency.get(current) || [];
|
||||
|
||||
for (const child of children) {
|
||||
|
||||
closure.push({
|
||||
ParentGroup_ObjectGUID: root,
|
||||
ChildGroup_ObjectGUID: child,
|
||||
Depth: depth + 1
|
||||
});
|
||||
|
||||
dfs(root, child, depth + 1);
|
||||
}
|
||||
};
|
||||
|
||||
for (const group of groups) {
|
||||
|
||||
const root = group.objectGUID;
|
||||
if (!root) continue;
|
||||
|
||||
dfs(root, root, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* -----------------------------------------------------
|
||||
* CLEAN & SAVE
|
||||
* -----------------------------------------------------
|
||||
*/
|
||||
|
||||
// await GroupClosure.destroy({
|
||||
// where: {}
|
||||
// });
|
||||
|
||||
await GroupClosure.bulkCreate(closure, {
|
||||
ignoreDuplicates: true
|
||||
});
|
||||
|
||||
return closure.length;
|
||||
}
|
||||
|
||||
|
||||
// =========================================================
|
||||
// 🎭 ROLE CRUD
|
||||
// =========================================================
|
||||
|
||||
@@ -25,11 +25,11 @@ class SocketManager {
|
||||
userName: sAMAccountName
|
||||
});
|
||||
|
||||
// console.log(`${sAMAccountName} [${objectGuid}] connected to ${namespace}`);
|
||||
console.log(`${sAMAccountName} [${objectGuid}] connected to ${namespace}`);
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
clients.delete(objectGuid);
|
||||
// console.log(`${sAMAccountName} [${objectGuid}] disconnected from ${namespace}`);
|
||||
console.log(`${sAMAccountName} [${objectGuid}] disconnected from ${namespace}`);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const { cache } = require('@root/globalize.js');
|
||||
const { service } = require('@root/server.js');
|
||||
|
||||
|
||||
module.exports = (app, socketManager, namespace, pluginManager, authenticationModel, fileSystemManager, eventManager, activeDirectory) => {
|
||||
@@ -12,9 +14,26 @@ module.exports = (app, socketManager, namespace, pluginManager, authenticationMo
|
||||
// eventManager.write(data.objectGuid, data.levelId, data.pluginName, data.message)
|
||||
});
|
||||
|
||||
// global.json.configuration.onChange(info => {
|
||||
// console.log(info.delta)
|
||||
// });
|
||||
|
||||
|
||||
socketManager.io.on('connection', async (socket) => {
|
||||
if(!socket.handshake.auth.objectGuid) {
|
||||
return;
|
||||
}
|
||||
await service.get('authenticationManager').setOnline(socket.handshake.auth.sAMAccountName);
|
||||
});
|
||||
|
||||
socketManager.on(namespace, 'disconnect', (socket, data) => {
|
||||
if(!socket.handshake.auth.objectGuid) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(async () => {
|
||||
if(!socketManager.clients.get(namespace).has(socket.handshake.auth.objectGuid)) {
|
||||
await service.get('authenticationManager').setOffline(socket.handshake.auth.sAMAccountName);
|
||||
}
|
||||
}, 8000);
|
||||
});
|
||||
|
||||
|
||||
mainSocket.on('connection', socket => {
|
||||
|
||||
Reference in New Issue
Block a user