Skip to content

Commit

Permalink
chore: Better permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
phinner committed Mar 3, 2024
1 parent 6cb72d6 commit 72bd2e0
Show file tree
Hide file tree
Showing 14 changed files with 490 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
import com.xpdustry.distributor.command.cloud.parser.PlayerParser;
import com.xpdustry.distributor.command.cloud.parser.TeamParser;
import com.xpdustry.distributor.command.cloud.specifier.AllTeams;
import com.xpdustry.distributor.core.DistributorProvider;
import com.xpdustry.distributor.core.command.CommandSender;
import com.xpdustry.distributor.core.permission.PermissionManager;
import com.xpdustry.distributor.core.plugin.MindustryPlugin;
import com.xpdustry.distributor.core.plugin.PluginAware;
import io.leangen.geantyref.TypeToken;
Expand Down Expand Up @@ -105,7 +107,16 @@ public ArcCommandManager(

@Override
public boolean hasPermission(final @NonNull C sender, final String permission) {
return permission.isEmpty() || senderMapper().reverse(sender).isServer(); // TODO Add permission
if (permission.isEmpty()) {
return true;
}
final var reversed = senderMapper().reverse(sender);
return reversed.isServer()
|| DistributorProvider.get()
.getService(PermissionManager.class)
.orElseThrow()
.getPermission(reversed.getPlayer(), permission)
.asBoolean();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Distributor, a feature-rich framework for Mindustry plugins.
*
* Copyright (C) 2024 Xpdustry
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.xpdustry.distributor.core.permission;

import java.util.Map;

final class ImmutablePermissionTree implements PermissionTree {

private final PermissionTree inner;

ImmutablePermissionTree(final PermissionTree inner) {
this.inner = inner;
}

@Override
public TriState getPermission(final String permission) {
return inner.getPermission(permission);
}

@Override
public void setPermission(final String permission, final TriState state) {
throw new UnsupportedOperationException();
}

@Override
public Map<String, Boolean> getPermissions() {
return inner.getPermissions();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Distributor, a feature-rich framework for Mindustry plugins.
*
* Copyright (C) 2024 Xpdustry
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.xpdustry.distributor.core.permission;

import java.util.regex.Pattern;
import mindustry.gen.Player;

public interface PermissionManager {

/**
* Regex pattern used to validate permission strings.
* <p>
* <strong>Notes:</strong>
* <blockquote>
* Permission strings are composed of a series of nodes separated by dots with alphanumeric characters and minus
* signs, such as {@code "plugin.command"}.
* <br>
* A parent node is always overridden by a child node, such as {@code "plugin.command"} overriding {@code "plugin"}.
* <br>
* Wildcards are also allowed, but they currently have the same effect as a normal node, such as {@code "plugin.command.*"} equals {@code "plugin.command"}.
* <br>
* The only relevant use of wildcards is the root permission {@code "*"} permission. It
* allows you to set a default value for all permissions.
* </blockquote>
*/
String PERMISSION_REGEX = "^(\\*|[a-z\\d\\-]+)(\\.(\\*|[a-z\\d\\-]+))*$";

Pattern PERMISSION_PATTERN = Pattern.compile(PERMISSION_REGEX);

TriState getPermission(final Player player, final String permission);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Distributor, a feature-rich framework for Mindustry plugins.
*
* Copyright (C) 2024 Xpdustry
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.xpdustry.distributor.core.permission;

import java.util.Map;

public interface PermissionTree {

static PermissionTree simple() {
return new SimplePermissionTree();
}

static PermissionTree immutable(final PermissionTree tree) {
return (tree instanceof ImmutablePermissionTree) ? tree : new ImmutablePermissionTree(tree);
}

TriState getPermission(final String permission);

void setPermission(final String permission, final TriState state);

Map<String, Boolean> getPermissions();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Distributor, a feature-rich framework for Mindustry plugins.
*
* Copyright (C) 2024 Xpdustry
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.xpdustry.distributor.core.permission;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.jspecify.annotations.Nullable;

final class SimplePermissionTree implements PermissionTree {

private final @Nullable SimplePermissionTree parent;
private final Map<String, SimplePermissionTree> children = new HashMap<>();
private TriState value = TriState.UNDEFINED;

SimplePermissionTree() {
this.parent = null;
}

private SimplePermissionTree(final @Nullable SimplePermissionTree parent) {
this.parent = parent;
}

public TriState getPermission(final String permission) {
if (!PermissionManager.PERMISSION_PATTERN.matcher(permission).matches()) {
throw new IllegalArgumentException("The permission doesn't match the regex: " + permission);
}
var state = TriState.UNDEFINED;
var node = this;
for (final var part : permission.split("\\.", -1)) {
if (node.children.containsKey("*") && node.children.get("*").value != TriState.UNDEFINED) {
state = node.children.get("*").value;
}
node = node.children.get(part);
if (node == null) {
return state;
} else if (node.value != TriState.UNDEFINED) {
state = node.value;
}
}
return state;
}

public void setPermission(final String permission, final TriState state) {
if (!PermissionManager.PERMISSION_PATTERN.matcher(permission).matches()) {
throw new IllegalArgumentException("The permission doesn't match the regex: " + permission);
}
final var parts = permission.split("\\.", -1);
var node = this;
if (state != TriState.UNDEFINED) {
for (final var part : parts) {
final var parent = node;
node = node.children.computeIfAbsent(part, k -> new SimplePermissionTree(parent));
}
node.value = state;
} else {
for (final var part : parts) {
node = node.children.get(part);
if (node == null) {
return;
}
}
node.value = state;
var index = parts.length - 1;
while (node.parent != null && node.children.isEmpty()) {
node = node.parent;
node.children.remove(parts[index--]);
}
}
}

public Map<String, Boolean> getPermissions() {
final Map<String, Boolean> permissions = new HashMap<>();
for (final var child : this.children.entrySet()) {
if (child.getValue().value != TriState.UNDEFINED) {
permissions.put(child.getKey(), child.getValue().value.asBoolean());
}
for (final var entry : child.getValue().getPermissions().entrySet()) {
permissions.put(child.getKey() + "." + entry.getKey(), entry.getValue());
}
}
return Collections.unmodifiableMap(permissions);
}

@Override
public boolean equals(final @Nullable Object o) {
if (this == o) {
return true;
}
if (!(o instanceof final SimplePermissionTree that)) {
return false;
}
if (!this.children.equals(that.children)) {
return false;
}
return this.value == that.value;
}

@Override
public int hashCode() {
int result = this.children.hashCode();
result = 31 * result + this.value.hashCode();
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Distributor, a feature-rich framework for Mindustry plugins.
*
* Copyright (C) 2024 Xpdustry
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.xpdustry.distributor.core.permission;

import org.jspecify.annotations.Nullable;

/**
* A ternary boolean type, used by the permission system.
*/
public enum TriState {
FALSE(false),
TRUE(true),
UNDEFINED(false);

private final boolean value;

TriState(final boolean value) {
this.value = value;
}

public static TriState of(final @Nullable Boolean state) {
return state == null ? UNDEFINED : state ? TRUE : FALSE;
}

public boolean asBoolean() {
return this.value;
}
}
15 changes: 15 additions & 0 deletions distributor-permission-rank/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
plugins {
id("distributor4.base-conventions")
id("distributor4.mindustry-conventions")
}

module {
identifier = "distributor-permission"
display = "DistributorLoggerSimple"
main = "com.xpdustry.distributor.logger.simple.DistributorLoggerPlugin"
description = "Simple permission system based on linear ranks."
}

dependencies {
compileOnly(project(":distributor-common"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Distributor, a feature-rich framework for Mindustry plugins.
*
* Copyright (C) 2024 Xpdustry
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.xpdustry.distributor.permission;

import java.util.function.Function;
import org.jspecify.annotations.Nullable;

record LinearEnumRankNode<E extends Enum<E>>(E value, Function<E, String> nameProvider, boolean ascending)
implements RankNode {

@Override
public String getName() {
return nameProvider.apply(value);
}

@Override
public @Nullable RankNode getPrevious() {
@SuppressWarnings("unchecked")
final var constants = (E[]) value.getClass().getEnumConstants();
if (ascending) {
return (value.ordinal() > 0)
? new LinearEnumRankNode<>(constants[value.ordinal() - 1], nameProvider, true)
: null;
} else {
return (value.ordinal() + 1 < constants.length)
? new LinearEnumRankNode<>(constants[value.ordinal() + 1], nameProvider, false)
: null;
}
}
}
Loading

0 comments on commit 72bd2e0

Please sign in to comment.