@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 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.2';
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.2';
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) throw new Error("Missing requester company context");
876
+ if (!requesterCompanyId) {
877
+ throw ErrorFactory.internal(MOD.ADMIN, "Missing requester company context for boundary check.");
878
+ }
877
879
  if (targets.targetUserId) {
878
- const assignments = await db.UserRoleAssignment.filter({
880
+ const targetUserAssignments = await db.UserRoleAssignment.filter({
879
881
  userId: targets.targetUserId,
880
882
  companyId: requesterCompanyId
881
883
  });
882
- if (assignments.length === 0) throw new Error("Tenant boundary violation: User");
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 [c, le, fac] = await Promise.all([
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
- if (!c.length && !le.length && !fac.length) throw new Error("Tenant boundary violation: Scope");
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) throw new Error("Missing requester company context");
782
+ if (!requesterCompanyId) {
783
+ throw ErrorFactory.internal(MOD.ADMIN, "Missing requester company context for boundary check.");
784
+ }
783
785
  if (targets.targetUserId) {
784
- const assignments = await db.UserRoleAssignment.filter({
786
+ const targetUserAssignments = await db.UserRoleAssignment.filter({
785
787
  userId: targets.targetUserId,
786
788
  companyId: requesterCompanyId
787
789
  });
788
- if (assignments.length === 0) throw new Error("Tenant boundary violation: User");
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 [c, le, fac] = await Promise.all([
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
- if (!c.length && !le.length && !fac.length) throw new Error("Tenant boundary violation: Scope");
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litusarchieve18/agricore-utils",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Canonical Backend Utility Library for AgriCore",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",