@posiwise/common-services 0.2.4 → 0.2.6
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.
|
@@ -1478,15 +1478,29 @@ class PermissionService {
|
|
|
1478
1478
|
expr = this.handleNonBooleanPermissions(permission, expr, productKey, permission_key, productSlug);
|
|
1479
1479
|
// Now expr is made of true/false values with &&, ||, ()
|
|
1480
1480
|
// Safe parser: no eval() - CSP 'unsafe-eval' not required
|
|
1481
|
+
const ourResult = this.evaluateBooleanExpression(expr);
|
|
1482
|
+
let evalResult;
|
|
1483
|
+
try {
|
|
1484
|
+
evalResult = eval(expr.trim());
|
|
1485
|
+
}
|
|
1486
|
+
catch {
|
|
1487
|
+
evalResult = undefined;
|
|
1488
|
+
}
|
|
1489
|
+
if (ourResult !== evalResult) {
|
|
1490
|
+
console.warn('[PermissionService] MISMATCH - parser vs eval', {
|
|
1491
|
+
permission,
|
|
1492
|
+
expr: expr.trim(),
|
|
1493
|
+
ourResult,
|
|
1494
|
+
evalResult
|
|
1495
|
+
});
|
|
1496
|
+
}
|
|
1481
1497
|
return this.evaluateBooleanExpression(expr);
|
|
1482
1498
|
}
|
|
1483
1499
|
/** Safe boolean expression parser - replaces eval() for CSP compliance. */
|
|
1484
1500
|
evaluateBooleanExpression(expr) {
|
|
1485
1501
|
expr = expr.replace(/\s+/g, ' ').trim();
|
|
1486
|
-
if (!expr)
|
|
1487
|
-
console.warn('[evaluateBooleanExpression] empty expr', { expr: `"${expr}"` });
|
|
1502
|
+
if (!expr)
|
|
1488
1503
|
return false;
|
|
1489
|
-
}
|
|
1490
1504
|
if (expr === 'true')
|
|
1491
1505
|
return true;
|
|
1492
1506
|
if (expr === 'false')
|
|
@@ -1501,9 +1515,7 @@ class PermissionService {
|
|
|
1501
1515
|
else if (depth === 0 && expr.substring(i, i + 2) === '||') {
|
|
1502
1516
|
const left = expr.substring(0, i).trim();
|
|
1503
1517
|
const right = expr.substring(i + 2).trim();
|
|
1504
|
-
|
|
1505
|
-
console.debug('[evaluateBooleanExpression] ||', { expr, left, right, result });
|
|
1506
|
-
return result;
|
|
1518
|
+
return (this.evaluateBooleanExpression(left) || this.evaluateBooleanExpression(right));
|
|
1507
1519
|
}
|
|
1508
1520
|
}
|
|
1509
1521
|
depth = 0;
|
|
@@ -1516,41 +1528,27 @@ class PermissionService {
|
|
|
1516
1528
|
else if (depth === 0 && expr.substring(i, i + 2) === '&&') {
|
|
1517
1529
|
const left = expr.substring(0, i).trim();
|
|
1518
1530
|
const right = expr.substring(i + 2).trim();
|
|
1519
|
-
|
|
1520
|
-
console.debug('[evaluateBooleanExpression] &&', { expr, left, right, result });
|
|
1521
|
-
return result;
|
|
1531
|
+
return (this.evaluateBooleanExpression(left) && this.evaluateBooleanExpression(right));
|
|
1522
1532
|
}
|
|
1523
1533
|
}
|
|
1524
|
-
// Strip matching outer parens - only when first ( and last ) are a pair (fix for nested)
|
|
1525
1534
|
if (expr.startsWith('(') && expr.endsWith(')')) {
|
|
1526
1535
|
let d = 0;
|
|
1527
|
-
for (let j =
|
|
1536
|
+
for (let j = 1; j < expr.length - 1; j++) {
|
|
1528
1537
|
if (expr[j] === '(')
|
|
1529
1538
|
d++;
|
|
1530
|
-
|
|
1539
|
+
if (expr[j] === ')')
|
|
1531
1540
|
d--;
|
|
1532
|
-
if (d === 0) {
|
|
1533
|
-
if (j === expr.length - 1) {
|
|
1534
|
-
const inner = expr.substring(1, expr.length - 1);
|
|
1535
|
-
const result = this.evaluateBooleanExpression(inner);
|
|
1536
|
-
console.debug('[evaluateBooleanExpression] strip parens', { expr, inner, result });
|
|
1537
|
-
return result;
|
|
1538
|
-
}
|
|
1539
|
-
break;
|
|
1540
|
-
}
|
|
1541
1541
|
if (d < 0)
|
|
1542
|
-
|
|
1542
|
+
return false;
|
|
1543
1543
|
}
|
|
1544
|
+
return this.evaluateBooleanExpression(expr.substring(1, expr.length - 1));
|
|
1544
1545
|
}
|
|
1545
|
-
console.warn('[evaluateBooleanExpression] unrecognized', { expr });
|
|
1546
1546
|
return false;
|
|
1547
1547
|
}
|
|
1548
1548
|
handleNonBooleanPermissions(permission, expr, productKey, permission_key, productSlug) {
|
|
1549
1549
|
if (typeof permission !== 'boolean') {
|
|
1550
1550
|
permission.split(' ').forEach(x => {
|
|
1551
1551
|
const raw = x.trim();
|
|
1552
|
-
if (!raw)
|
|
1553
|
-
return;
|
|
1554
1552
|
if (['||', '&&', '(', ')'].includes(raw)) {
|
|
1555
1553
|
expr += ` ${raw} `;
|
|
1556
1554
|
}
|