@litusarchieve18/agricore-utils 1.0.4 → 1.0.5
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/README.md +5 -6
- package/dist/index.js +15 -5
- package/dist/index.mjs +15 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ npm install @litusarchieve18/agricore-utils
|
|
|
14
14
|
|
|
15
15
|
For Base44 / Deno Environments
|
|
16
16
|
You do not need a .npmrc or GITHUB_TOKEN to use this library in Base44. Import it directly using the npm: protocol:
|
|
17
|
-
import { AgriLogger, AppError, MOD } from 'npm:@litusarchieve18/agricore-utils@^1.0.
|
|
17
|
+
import { AgriLogger, AppError, MOD } from 'npm:@litusarchieve18/agricore-utils@^1.0.4';
|
|
18
18
|
|
|
19
19
|
🏗️ Core Architecture & Features
|
|
20
20
|
This library is designed with the "Adapter Pattern" in mind. It defines strict contracts (AgriCoreSession) so that your business logic remains completely isolated from the underlying Base44 database infrastructure.
|
|
@@ -23,7 +23,7 @@ This library is designed with the "Adapter Pattern" in mind. It defines strict c
|
|
|
23
23
|
The universal contract for authenticated users. The v2 upgrade includes injected UI-ready navigation data (availableScopes) and tenant configurations to prevent unnecessary frontend API calls.
|
|
24
24
|
|
|
25
25
|
TypeScript
|
|
26
|
-
import { AgriCoreSession } from 'npm:@litusarchieve18/agricore-utils@^1.0.
|
|
26
|
+
import { AgriCoreSession } from 'npm:@litusarchieve18/agricore-utils@^1.0.4';
|
|
27
27
|
|
|
28
28
|
// Example of the v2 structure:
|
|
29
29
|
const session: AgriCoreSession = {
|
|
@@ -62,10 +62,6 @@ ErrorFactory
|
|
|
62
62
|
4. Domain Enums
|
|
63
63
|
The universal vocabulary of the AgriCore platform, ensuring type-safety across all microservices (e.g., UserRole, UserPrivilege, AccessLevel, FacilityType, NotificationMode, TaskStatus, RESOURCE_PATHS).
|
|
64
64
|
|
|
65
|
-
To document these powerful new security and architectural features in your README.md, you should add sections that explain why these tools exist. They move your library from being a "Type definition" to a "Security Framework."
|
|
66
|
-
|
|
67
|
-
Here are the suggested paragraphs to add to your README.md:
|
|
68
|
-
|
|
69
65
|
🔐 Security & Access Control
|
|
70
66
|
The library now includes a centralized logic layer to enforce granular permissions across all AgriCore services.
|
|
71
67
|
|
|
@@ -121,7 +117,10 @@ Run the publish command:
|
|
|
121
117
|
Bash
|
|
122
118
|
npm publish --access public
|
|
123
119
|
📝 Version History
|
|
120
|
+
v1.0.4 — refactor the code and edit readme
|
|
121
|
+
|
|
124
122
|
v1.0.4 — add generateInfrastructureFields, security access control and multi tenant boundary
|
|
123
|
+
|
|
125
124
|
v1.0.3 — add the base44Id
|
|
126
125
|
|
|
127
126
|
v1.0.2 — Breaking Change: Upgraded AgriCoreSession interface. Added companyConfig and UI-ready availableScopes arrays to support the frontend hierarchy dropdown without secondary API calls.
|
package/dist/index.js
CHANGED
|
@@ -873,21 +873,31 @@ function evaluateBaseAccess(resourcePath, session, requirements = {}) {
|
|
|
873
873
|
return isHighRole ? "WRITE" : "READ";
|
|
874
874
|
}
|
|
875
875
|
async function assertTenantBoundary(db, requesterCompanyId, targets) {
|
|
876
|
-
if (!requesterCompanyId)
|
|
876
|
+
if (!requesterCompanyId) {
|
|
877
|
+
throw ErrorFactory.internal(MOD.ADMIN, "Missing requester company context for boundary check.");
|
|
878
|
+
}
|
|
877
879
|
if (targets.targetUserId) {
|
|
878
|
-
const
|
|
880
|
+
const targetUserAssignments = await db.UserRoleAssignment.filter({
|
|
879
881
|
userId: targets.targetUserId,
|
|
880
882
|
companyId: requesterCompanyId
|
|
881
883
|
});
|
|
882
|
-
if (
|
|
884
|
+
if (targetUserAssignments.length === 0) {
|
|
885
|
+
console.error(`[SECURITY BREACH ATTEMPT] User tried to modify targetUserId ${targets.targetUserId} outside their company ${requesterCompanyId}`);
|
|
886
|
+
throw ErrorFactory.forbidden(MOD.ADMIN, ACT.EDIT, "Invalid target user or tenant boundary violation.");
|
|
887
|
+
}
|
|
883
888
|
}
|
|
884
889
|
if (targets.authScopeId) {
|
|
885
|
-
const [
|
|
890
|
+
const [companyMatch, leMatch, facMatch] = await Promise.all([
|
|
886
891
|
db.Company.filter({ canonicalId: targets.authScopeId, id: requesterCompanyId }),
|
|
892
|
+
// Base44 id must match requester
|
|
887
893
|
db.LegalEntity.filter({ canonicalId: targets.authScopeId, companyId: requesterCompanyId }),
|
|
888
894
|
db.Facility.filter({ canonicalId: targets.authScopeId, companyId: requesterCompanyId })
|
|
889
895
|
]);
|
|
890
|
-
|
|
896
|
+
const isValidScope = companyMatch.length > 0 || leMatch.length > 0 || facMatch.length > 0;
|
|
897
|
+
if (!isValidScope) {
|
|
898
|
+
console.error(`[SECURITY BREACH ATTEMPT] User tried to assign scope ${targets.authScopeId} outside company ${requesterCompanyId}`);
|
|
899
|
+
throw ErrorFactory.forbidden(MOD.ADMIN, ACT.EDIT, "Invalid authorization scope or tenant boundary violation.");
|
|
900
|
+
}
|
|
891
901
|
}
|
|
892
902
|
return true;
|
|
893
903
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -779,21 +779,31 @@ function evaluateBaseAccess(resourcePath, session, requirements = {}) {
|
|
|
779
779
|
return isHighRole ? "WRITE" : "READ";
|
|
780
780
|
}
|
|
781
781
|
async function assertTenantBoundary(db, requesterCompanyId, targets) {
|
|
782
|
-
if (!requesterCompanyId)
|
|
782
|
+
if (!requesterCompanyId) {
|
|
783
|
+
throw ErrorFactory.internal(MOD.ADMIN, "Missing requester company context for boundary check.");
|
|
784
|
+
}
|
|
783
785
|
if (targets.targetUserId) {
|
|
784
|
-
const
|
|
786
|
+
const targetUserAssignments = await db.UserRoleAssignment.filter({
|
|
785
787
|
userId: targets.targetUserId,
|
|
786
788
|
companyId: requesterCompanyId
|
|
787
789
|
});
|
|
788
|
-
if (
|
|
790
|
+
if (targetUserAssignments.length === 0) {
|
|
791
|
+
console.error(`[SECURITY BREACH ATTEMPT] User tried to modify targetUserId ${targets.targetUserId} outside their company ${requesterCompanyId}`);
|
|
792
|
+
throw ErrorFactory.forbidden(MOD.ADMIN, ACT.EDIT, "Invalid target user or tenant boundary violation.");
|
|
793
|
+
}
|
|
789
794
|
}
|
|
790
795
|
if (targets.authScopeId) {
|
|
791
|
-
const [
|
|
796
|
+
const [companyMatch, leMatch, facMatch] = await Promise.all([
|
|
792
797
|
db.Company.filter({ canonicalId: targets.authScopeId, id: requesterCompanyId }),
|
|
798
|
+
// Base44 id must match requester
|
|
793
799
|
db.LegalEntity.filter({ canonicalId: targets.authScopeId, companyId: requesterCompanyId }),
|
|
794
800
|
db.Facility.filter({ canonicalId: targets.authScopeId, companyId: requesterCompanyId })
|
|
795
801
|
]);
|
|
796
|
-
|
|
802
|
+
const isValidScope = companyMatch.length > 0 || leMatch.length > 0 || facMatch.length > 0;
|
|
803
|
+
if (!isValidScope) {
|
|
804
|
+
console.error(`[SECURITY BREACH ATTEMPT] User tried to assign scope ${targets.authScopeId} outside company ${requesterCompanyId}`);
|
|
805
|
+
throw ErrorFactory.forbidden(MOD.ADMIN, ACT.EDIT, "Invalid authorization scope or tenant boundary violation.");
|
|
806
|
+
}
|
|
797
807
|
}
|
|
798
808
|
return true;
|
|
799
809
|
}
|