Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e0d74cdf authored by Khaled Abdelmohsen's avatar Khaled Abdelmohsen
Browse files

Validate rules in DNF

Ensure that rules passed to the evaluation engine are in DNF before
being evaluated against app install metadata.

Bug: 141971373
Test: atest FrameworksServicesTests:RuleEvaluatorTest
Change-Id: I42d1353ef13c1c9ccb6e6b4ecea5d58c8fc5dab5
parent 60029db8
Loading
Loading
Loading
Loading
+25 −1
Original line number Diff line number Diff line
@@ -37,6 +37,9 @@ final class RuleEvaluator {
    /**
     * Match the list of rules against an app install metadata.
     *
     * <p>Rules must be in disjunctive normal form (DNF). A rule should contain AND'ed formulas
     * only. All rules are OR'ed together by default.
     *
     * @param rules              The list of rules to evaluate.
     * @param appInstallMetadata Metadata of the app to be installed, and to evaluate the rules
     *                           against.
@@ -45,7 +48,7 @@ final class RuleEvaluator {
     */
    static Rule evaluateRules(List<Rule> rules, AppInstallMetadata appInstallMetadata) {
        for (Rule rule : rules) {
            if (isMatch(rule, appInstallMetadata)) {
            if (isConjunctionOfFormulas(rule.getFormula()) && isMatch(rule, appInstallMetadata)) {
                return rule;
            }
        }
@@ -99,4 +102,25 @@ final class RuleEvaluator {

        return false;
    }

    private static boolean isConjunctionOfFormulas(Formula formula) {
        if (formula == null) {
            return false;
        }
        if (isAtomicFormula(formula)) {
            return true;
        }
        OpenFormula openFormula = (OpenFormula) formula;
        return openFormula.getConnector() == OpenFormula.Connector.AND
                && openFormula.getFormulas().stream().allMatch(RuleEvaluator::isAtomicFormula);
    }

    private static boolean isAtomicFormula(Formula formula) {
        if (formula instanceof AtomicFormula) {
            return true;
        }
        OpenFormula openFormula = (OpenFormula) formula;
        return openFormula.getConnector() == OpenFormula.Connector.NOT
                && openFormula.getFormulas().get(0) instanceof AtomicFormula;
    }
}
+53 −0
Original line number Diff line number Diff line
@@ -127,4 +127,57 @@ public class RuleEvaluatorTest {

        assertEquals(rule1, matchedRule);
    }

    @Test
    public void testMatchRules_validForm() {
        OpenFormula openFormula = new OpenFormula(OpenFormula.Connector.AND, Arrays.asList(
                new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
                        PACKAGE_NAME_1),
                new AtomicFormula(AtomicFormula.Key.APP_CERTIFICATE,
                        AtomicFormula.Operator.EQ,
                        APP_CERTIFICATE)));
        Rule rule = new Rule(
                openFormula, Rule.Effect.DENY);

        Rule matchedRule = RuleEvaluator.evaluateRules(Collections.singletonList(rule),
                APP_INSTALL_METADATA);

        assertEquals(rule, matchedRule);
    }

    @Test
    public void testMatchRules_ruleNotInDNF() {
        OpenFormula openFormula = new OpenFormula(OpenFormula.Connector.OR, Arrays.asList(
                new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
                        PACKAGE_NAME_1),
                new AtomicFormula(AtomicFormula.Key.APP_CERTIFICATE,
                        AtomicFormula.Operator.EQ,
                        APP_CERTIFICATE)));
        Rule rule = new Rule(
                openFormula, Rule.Effect.DENY);

        Rule matchedRule = RuleEvaluator.evaluateRules(Collections.singletonList(rule),
                APP_INSTALL_METADATA);

        assertEquals(Rule.EMPTY, matchedRule);
    }

    @Test
    public void testMatchRules_openFormulaWithNot() {
        OpenFormula openSubFormula = new OpenFormula(OpenFormula.Connector.AND, Arrays.asList(
                new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
                        PACKAGE_NAME_2),
                new AtomicFormula(AtomicFormula.Key.APP_CERTIFICATE,
                        AtomicFormula.Operator.EQ,
                        APP_CERTIFICATE)));
        OpenFormula openFormula = new OpenFormula(OpenFormula.Connector.NOT,
                Collections.singletonList(openSubFormula));
        Rule rule = new Rule(
                openFormula, Rule.Effect.DENY);

        Rule matchedRule = RuleEvaluator.evaluateRules(Collections.singletonList(rule),
                APP_INSTALL_METADATA);

        assertEquals(Rule.EMPTY, matchedRule);
    }
}