XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEServerManager

【Java】我的世界XFE服务器管理器

公开
关注 0 Fork 0 Star 0
UTF-8
package com.xfestudio.xfeservermanager.core.policy;

import com.xfestudio.xfeservermanager.api.policy.PolicyRule;
import com.xfestudio.xfeservermanager.api.policy.RuleTier;
import com.xfestudio.xfeservermanager.api.policy.DecisionEffect;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

public final class PolicyValidator {
    public PolicyValidationResult validate(List<PolicyRule> rules) {
        List<PolicyValidationIssue> issues = new ArrayList<>();
        Set<String> ids = new HashSet<>();
        var groups = new HashMap<String, GroupDefinition>();
        for (PolicyRule rule : rules) {
            if (!ids.add(rule.id())) {
                issues.add(issue(rule, "duplicate_rule_id", "Rule ids must be unique"));
            }
            validateTier(rule, issues);
            validateConstraints(rule, issues);
            validateGroup(rule, groups, issues);
        }
        return new PolicyValidationResult(issues);
    }

    private static void validateGroup(
            PolicyRule rule,
            java.util.Map<String, GroupDefinition> groups,
            List<PolicyValidationIssue> issues) {
        if (!rule.groupId().matches("[A-Za-z0-9._-]{1,64}")) {
            issues.add(issue(rule, "invalid_group_id",
                    "Policy group ids must use 1-64 letters, digits, dots, underscores, or hyphens"));
        }
        if (rule.groupName().length() > 128) {
            issues.add(issue(rule, "group_name_too_long", "Policy group names cannot exceed 128 characters"));
        }
        GroupDefinition definition = new GroupDefinition(rule.groupName(), rule.groupEnabled());
        GroupDefinition existing = groups.putIfAbsent(rule.groupId(), definition);
        if (existing != null && !existing.equals(definition)) {
            issues.add(issue(rule, "inconsistent_group_metadata",
                    "Rules in the same policy group must share its name and enabled state"));
        }
    }

    private static void validateTier(PolicyRule rule, List<PolicyValidationIssue> issues) {
        if (rule.tier() == RuleTier.UUID && rule.subject().actorIds().isEmpty()) {
            issues.add(issue(rule, "uuid_tier_without_uuid", "UUID rules must name at least one actor UUID"));
        }
        if (rule.tier() == RuleTier.ROLE && rule.subject().roles().isEmpty()) {
            issues.add(issue(rule, "role_tier_without_role", "Role rules must name at least one role"));
        }
        if (rule.tier() == RuleTier.OP_LEVEL
                && rule.subject().minimumOpLevel() == null && rule.subject().maximumOpLevel() == null) {
            issues.add(issue(rule, "op_tier_without_level", "OP rules must declare an OP level range"));
        }
        if (rule.tier() == RuleTier.DEFAULT
                && (!rule.subject().actorIds().isEmpty() || !rule.subject().roles().isEmpty()
                || rule.subject().minimumOpLevel() != null || rule.subject().maximumOpLevel() != null)) {
            issues.add(issue(rule, "default_tier_with_identity", "Default rules cannot match UUID, role, or OP level"));
        }
        if (rule.tier() == RuleTier.HARD_SAFETY && rule.effect() == DecisionEffect.GRANT) {
            issues.add(issue(rule, "hard_safety_grant", "Hard safety rules cannot grant permission"));
        }
    }

    private static void validateConstraints(PolicyRule rule, List<PolicyValidationIssue> issues) {
        Set<String> overlap = new HashSet<>(rule.constraints().selector().allowedEntityTypes());
        overlap.retainAll(rule.constraints().selector().deniedEntityTypes());
        if (!overlap.isEmpty()) {
            issues.add(issue(rule, "entity_type_overlap", "Entity types cannot be both allowed and denied: " + overlap));
        }
        overlap = new HashSet<>(rule.constraints().item().allowedItemIds());
        overlap.retainAll(rule.constraints().item().deniedItemIds());
        if (!overlap.isEmpty()) {
            issues.add(issue(rule, "item_id_overlap", "Items cannot be both allowed and denied: " + overlap));
        }
        overlap = new HashSet<>(rule.constraints().item().allowedItemTags());
        overlap.retainAll(rule.constraints().item().deniedItemTags());
        if (!overlap.isEmpty()) {
            issues.add(issue(rule, "item_tag_overlap", "Item tags cannot be both allowed and denied: " + overlap));
        }
        overlap = new HashSet<>(rule.constraints().item().allowedDataKeys());
        overlap.retainAll(rule.constraints().item().deniedDataKeys());
        if (!overlap.isEmpty()) {
            issues.add(issue(rule, "data_key_overlap", "Data keys cannot be both allowed and denied: " + overlap));
        }
    }

    private static PolicyValidationIssue issue(PolicyRule rule, String code, String message) {
        return new PolicyValidationIssue(rule.id(), code, message);
    }

    private record GroupDefinition(String name, Boolean enabled) { }
}