@twin.org/rights-management-plugins 0.0.3-next.52 → 0.0.3-next.54

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.
Files changed (29) hide show
  1. package/dist/es/models/IStaticPolicyInformationSource.js.map +1 -1
  2. package/dist/es/policyArbiters/defaultPolicyArbiter.js +126 -8
  3. package/dist/es/policyArbiters/defaultPolicyArbiter.js.map +1 -1
  4. package/dist/es/policyArbiters/passThroughPolicyArbiter.js.map +1 -1
  5. package/dist/es/policyInformationSources/identityPolicyInformationSource.js.map +1 -1
  6. package/dist/es/policyInformationSources/identityProfilePolicyInformationSource.js +4 -4
  7. package/dist/es/policyInformationSources/identityProfilePolicyInformationSource.js.map +1 -1
  8. package/dist/es/policyInformationSources/staticPolicyInformationSource.js.map +1 -1
  9. package/dist/es/policyNegotiators/passThroughPolicyNegotiator.js.map +1 -1
  10. package/dist/es/policyObligationEnforcers/passThroughPolicyObligationEnforcer.js.map +1 -1
  11. package/dist/types/models/IStaticPolicyInformationSource.d.ts +2 -5
  12. package/dist/types/policyArbiters/defaultPolicyArbiter.d.ts +2 -5
  13. package/dist/types/policyArbiters/passThroughPolicyArbiter.d.ts +2 -5
  14. package/dist/types/policyInformationSources/identityPolicyInformationSource.d.ts +2 -5
  15. package/dist/types/policyInformationSources/identityProfilePolicyInformationSource.d.ts +2 -5
  16. package/dist/types/policyInformationSources/staticPolicyInformationSource.d.ts +2 -5
  17. package/dist/types/policyNegotiators/passThroughPolicyNegotiator.d.ts +3 -8
  18. package/dist/types/policyObligationEnforcers/passThroughPolicyObligationEnforcer.d.ts +2 -5
  19. package/docs/changelog.md +44 -0
  20. package/docs/reference/classes/DefaultPolicyArbiter.md +2 -0
  21. package/docs/reference/classes/IdentityPolicyInformationSource.md +2 -2
  22. package/docs/reference/classes/IdentityProfilePolicyInformationSource.md +2 -2
  23. package/docs/reference/classes/PassThroughPolicyArbiter.md +2 -0
  24. package/docs/reference/classes/PassThroughPolicyNegotiator.md +4 -0
  25. package/docs/reference/classes/PassThroughPolicyObligationEnforcer.md +2 -0
  26. package/docs/reference/classes/StaticPolicyInformationSource.md +2 -2
  27. package/docs/reference/interfaces/IStaticPolicyInformationSource.md +1 -5
  28. package/locales/en.json +2 -1
  29. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"IStaticPolicyInformationSource.js","sourceRoot":"","sources":["../../../src/models/IStaticPolicyInformationSource.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IJsonLdNodeObject } from \"@twin.org/data-json-ld\";\nimport type { PolicyInformationAccessMode } from \"@twin.org/rights-management-models\";\n\n/**\n * Configuration for the Static Policy Information Source Component.\n */\nexport interface IStaticPolicyInformationSource {\n\t/**\n\t * Is the information public, if so it will be shared with negotiation requests.\n\t */\n\taccessMode: PolicyInformationAccessMode;\n\n\t/**\n\t * Information is only provided for the specified locator combination.\n\t */\n\tmatchLocators?: {\n\t\tassignee?: string;\n\t\tassigner?: string;\n\t\ttarget?: string;\n\t\taction?: string;\n\t}[];\n\n\t/**\n\t * The objects containing the information.\n\t */\n\tobjects: { [id: string]: IJsonLdNodeObject };\n}\n"]}
1
+ {"version":3,"file":"IStaticPolicyInformationSource.js","sourceRoot":"","sources":["../../../src/models/IStaticPolicyInformationSource.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type {\n\tIRightsManagementInformation,\n\tPolicyInformationAccessMode\n} from \"@twin.org/rights-management-models\";\n\n/**\n * Configuration for the Static Policy Information Source Component.\n */\nexport interface IStaticPolicyInformationSource {\n\t/**\n\t * Is the information public, if so it will be shared with negotiation requests.\n\t */\n\taccessMode: PolicyInformationAccessMode;\n\n\t/**\n\t * Information is only provided for the specified locator combination.\n\t */\n\tmatchLocators?: {\n\t\tassignee?: string;\n\t\tassigner?: string;\n\t\ttarget?: string;\n\t\taction?: string;\n\t}[];\n\n\t/**\n\t * The objects containing the information.\n\t */\n\tobjects: IRightsManagementInformation;\n}\n"]}
@@ -1,9 +1,9 @@
1
1
  // Copyright 2025 IOTA Stiftung.
2
2
  // SPDX-License-Identifier: Apache-2.0.
3
- import { ArrayHelper, Coerce, ComponentFactory, GeneralError, Guards, Is, ObjectHelper, StringHelper } from "@twin.org/core";
3
+ import { ArrayHelper, Coerce, ComponentFactory, Duration, GeneralError, Guards, Is, ObjectHelper, StringHelper } from "@twin.org/core";
4
4
  import { JsonPathHelper } from "@twin.org/data-json-path";
5
5
  import { OdrlPolicyHelper, OdrlProfiles, PolicyDecision, PolicyObligationEnforcerFactory } from "@twin.org/rights-management-models";
6
- import { OdrlConflictStrategyType, OdrlLogicalConstraintType, OdrlOperatorType, OdrlTypes } from "@twin.org/standards-w3c-odrl";
6
+ import { OdrlConflictStrategyType, OdrlLeftOperandType, OdrlLogicalConstraintType, OdrlOperatorType, OdrlTypes } from "@twin.org/standards-w3c-odrl";
7
7
  /**
8
8
  * Default Policy Arbiter.
9
9
  */
@@ -1244,8 +1244,8 @@ export class DefaultPolicyArbiter {
1244
1244
  throw new GeneralError(DefaultPolicyArbiter.CLASS_NAME, "constraintStatusNotSupported");
1245
1245
  }
1246
1246
  // Evaluate the main constraint condition
1247
- const leftValue = this.calculateOperandValue(regularConstraint.leftOperand, dataSources, regularConstraint);
1248
- const rightValue = this.calculateOperandValue(regularConstraint.rightOperand, dataSources, regularConstraint);
1247
+ const leftValue = this.calculateOperandValue(regularConstraint.leftOperand, dataSources, regularConstraint, true);
1248
+ const rightValue = this.calculateOperandValue(regularConstraint.rightOperand, dataSources, regularConstraint, false);
1249
1249
  const mainSatisfied = this.evaluateOperator(regularConstraint.operator, leftValue, rightValue);
1250
1250
  // If main constraint is not satisfied, the overall constraint fails
1251
1251
  return mainSatisfied;
@@ -1396,10 +1396,12 @@ export class DefaultPolicyArbiter {
1396
1396
  * @param operand The operand.
1397
1397
  * @param dataSources The available prefixed operand sources.
1398
1398
  * @param constraint Optional constraint providing additional context for operand resolution.
1399
+ * @param isLeftOperand True when resolving the left operand of the constraint.
1399
1400
  * @returns The resolved operand value.
1401
+ * @throws GeneralError When a known ODRL built-in left operand cannot be resolved.
1400
1402
  * @internal
1401
1403
  */
1402
- calculateOperandValue(operand, dataSources, constraint) {
1404
+ calculateOperandValue(operand, dataSources, constraint, isLeftOperand) {
1403
1405
  let jsonPath;
1404
1406
  let operandRoot;
1405
1407
  if (Is.stringValue(operand)) {
@@ -1417,6 +1419,30 @@ export class DefaultPolicyArbiter {
1417
1419
  jsonPath = lookup.jsonPath;
1418
1420
  operandRoot = lookup.source;
1419
1421
  }
1422
+ else {
1423
+ const builtIn = this.resolveOdrlBuiltInLeftOperand(operand);
1424
+ if (!Is.undefined(builtIn)) {
1425
+ return builtIn;
1426
+ }
1427
+ if (isLeftOperand) {
1428
+ if (this.operatorSupportsInformationLookup(constraint?.operator)) {
1429
+ const infoResult = this.resolveInformationKeyOperand(operand, dataSources);
1430
+ if (infoResult.found) {
1431
+ return infoResult.value;
1432
+ }
1433
+ if (this.isKnownOdrlBuiltInOperand(operand)) {
1434
+ throw new GeneralError(DefaultPolicyArbiter.CLASS_NAME, "leftOperandNotSupported", {
1435
+ leftOperand: operand
1436
+ });
1437
+ }
1438
+ }
1439
+ else if (this.isKnownOdrlBuiltInOperand(operand)) {
1440
+ throw new GeneralError(DefaultPolicyArbiter.CLASS_NAME, "leftOperandNotSupported", {
1441
+ leftOperand: operand
1442
+ });
1443
+ }
1444
+ }
1445
+ }
1420
1446
  }
1421
1447
  else if (Is.object(operand)) {
1422
1448
  const typedOperand = operand;
@@ -1560,9 +1586,9 @@ export class DefaultPolicyArbiter {
1560
1586
  const leftValues = ArrayHelper.fromObjectOrArray(left ?? []);
1561
1587
  switch (operator) {
1562
1588
  case OdrlOperatorType.Eq:
1563
- return leftValues.some(v => ObjectHelper.equal(v, right, false));
1589
+ return leftValues.some(v => ObjectHelper.equal(v, right, false) || this.compareDurationEq(v, right));
1564
1590
  case OdrlOperatorType.Neq:
1565
- return leftValues.every(v => !ObjectHelper.equal(v, right, false));
1591
+ return leftValues.every(v => !ObjectHelper.equal(v, right, false) && !this.compareDurationEq(v, right));
1566
1592
  case OdrlOperatorType.Gt:
1567
1593
  return leftValues.some(v => this.compareOrdered(v, right, (a, b) => a > b));
1568
1594
  case OdrlOperatorType.Gteq:
@@ -1583,7 +1609,10 @@ export class DefaultPolicyArbiter {
1583
1609
  return ObjectHelper.equal(leftValues, ArrayHelper.fromObjectOrArray(right) ?? [], false);
1584
1610
  }
1585
1611
  case OdrlOperatorType.IsNoneOf: {
1586
- return leftValues.every(v => !(ArrayHelper.fromObjectOrArray(right) ?? []).includes(v));
1612
+ return leftValues.every(v => {
1613
+ const stringValue = Is.string(v) || Is.number(v) || Is.boolean(v) ? String(v) : JSON.stringify(v);
1614
+ return !(ArrayHelper.fromObjectOrArray(right) ?? []).includes(stringValue);
1615
+ });
1587
1616
  }
1588
1617
  case OdrlOperatorType.LocTimeEq:
1589
1618
  return leftValues.some(v => ObjectHelper.equal(v, right, false));
@@ -1618,6 +1647,11 @@ export class DefaultPolicyArbiter {
1618
1647
  if (!Is.undefined(leftDate) && !Is.undefined(rightDate)) {
1619
1648
  return compare(leftDate.getTime(), rightDate.getTime());
1620
1649
  }
1650
+ const leftDuration = Coerce.duration(left);
1651
+ const rightDuration = Coerce.duration(right);
1652
+ if (!Is.undefined(leftDuration) && !Is.undefined(rightDuration)) {
1653
+ return compare(Duration.toSeconds(leftDuration), Duration.toSeconds(rightDuration));
1654
+ }
1621
1655
  // Only use string ordering when both operands are actual strings.
1622
1656
  // Avoid coercing other types into strings, as that can cause
1623
1657
  // unintended comparisons like 18 >= "$.minAge" evaluating to true.
@@ -1626,6 +1660,84 @@ export class DefaultPolicyArbiter {
1626
1660
  }
1627
1661
  return false;
1628
1662
  }
1663
+ /**
1664
+ * Test whether two values are equal when interpreted as ISO 8601 durations.
1665
+ * Returns false if either side cannot be coerced to a duration.
1666
+ * @param left The left value.
1667
+ * @param right The right value.
1668
+ * @returns True when both sides represent the same duration in seconds.
1669
+ * @internal
1670
+ */
1671
+ compareDurationEq(left, right) {
1672
+ const leftDuration = Coerce.duration(left);
1673
+ const rightDuration = Coerce.duration(right);
1674
+ if (!Is.undefined(leftDuration) && !Is.undefined(rightDuration)) {
1675
+ return Duration.toSeconds(leftDuration) === Duration.toSeconds(rightDuration);
1676
+ }
1677
+ return false;
1678
+ }
1679
+ /**
1680
+ * Resolve an ODRL built-in left operand to its runtime value.
1681
+ * Returns the resolved value for natively-handled operands and undefined for all others.
1682
+ * Callers are responsible for throwing when an unresolved known built-in is unacceptable.
1683
+ * @param operand The left operand string.
1684
+ * @returns The resolved value, or undefined when the operand has no native resolution.
1685
+ * @internal
1686
+ */
1687
+ resolveOdrlBuiltInLeftOperand(operand) {
1688
+ if (operand === OdrlLeftOperandType.DateTime) {
1689
+ return new Date();
1690
+ }
1691
+ return undefined;
1692
+ }
1693
+ /**
1694
+ * Determine whether the operand string is a recognised ODRL built-in left operand.
1695
+ * @param operand The operand string to test.
1696
+ * @returns True when the operand appears in the OdrlLeftOperandType vocabulary.
1697
+ * @internal
1698
+ */
1699
+ isKnownOdrlBuiltInOperand(operand) {
1700
+ return Object.values(OdrlLeftOperandType).includes(operand);
1701
+ }
1702
+ /**
1703
+ * Determine whether the operator supports resolving left operands from the information object.
1704
+ * Value-comparison and set operators are supported; structural/relationship operators are not.
1705
+ * @param operator The operator to test.
1706
+ * @returns True when information-key lookup is appropriate for this operator.
1707
+ * @internal
1708
+ */
1709
+ operatorSupportsInformationLookup(operator) {
1710
+ switch (operator) {
1711
+ case OdrlOperatorType.Eq:
1712
+ case OdrlOperatorType.Neq:
1713
+ case OdrlOperatorType.Gt:
1714
+ case OdrlOperatorType.Gteq:
1715
+ case OdrlOperatorType.Lt:
1716
+ case OdrlOperatorType.Lteq:
1717
+ case OdrlOperatorType.IsAnyOf:
1718
+ case OdrlOperatorType.IsAllOf:
1719
+ case OdrlOperatorType.IsNoneOf:
1720
+ case OdrlOperatorType.LocTimeEq:
1721
+ case OdrlOperatorType.LocTimeGteq:
1722
+ return true;
1723
+ default:
1724
+ return false;
1725
+ }
1726
+ }
1727
+ /**
1728
+ * Attempt to resolve a left operand string as a key in the information object.
1729
+ * @param operand The left operand string.
1730
+ * @param dataSources The available data sources.
1731
+ * @returns An object indicating whether the key was found and its value when present.
1732
+ * @internal
1733
+ */
1734
+ resolveInformationKeyOperand(operand, dataSources) {
1735
+ const information = dataSources[DefaultPolicyArbiter._INFORMATION_SOURCE_KEY];
1736
+ if (Is.object(information) && !Is.empty(information[operand])) {
1737
+ return { found: true, value: information[operand] };
1738
+ }
1739
+ return { found: false };
1740
+ }
1629
1741
  /**
1630
1742
  * Coerce a value to a specific XSD type.
1631
1743
  * @param value The value to coerce.
@@ -1666,6 +1778,12 @@ export class DefaultPolicyArbiter {
1666
1778
  // Handle standard xsd types
1667
1779
  return Coerce.dateTime(value);
1668
1780
  }
1781
+ else if (type === "xsd:duration") {
1782
+ // Handle standard xsd types - convert to total seconds for ordered comparison.
1783
+ // Falls back to numeric coercion for non-ISO values (e.g. bare seconds as a number).
1784
+ const dur = Coerce.duration(value);
1785
+ return Is.undefined(dur) ? Coerce.number(value) : Duration.toSeconds(dur);
1786
+ }
1669
1787
  return undefined;
1670
1788
  }
1671
1789
  }