Partially implement PermissionService

This commit is contained in:
Luck 2016-08-25 17:23:27 +01:00
parent de5fda6a18
commit 44d14001e1
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
8 changed files with 811 additions and 0 deletions

View File

@ -44,6 +44,7 @@ public class Patterns {
public static final Pattern NON_USERNAME = Pattern.compile("[^A-Za-z0-9_]"); public static final Pattern NON_USERNAME = Pattern.compile("[^A-Za-z0-9_]");
public static final Pattern SHORTHAND_NODE = Pattern.compile("\\.\\([^.]+\\)"); public static final Pattern SHORTHAND_NODE = Pattern.compile("\\.\\([^.]+\\)");
public static final Pattern STRIP_COLOR_PATTERN = Pattern.compile("(?i)" + String.valueOf('§') + "[0-9A-FK-OR]"); public static final Pattern STRIP_COLOR_PATTERN = Pattern.compile("(?i)" + String.valueOf('§') + "[0-9A-FK-OR]");
public static final Pattern NODE_CONTEXTS = Pattern.compile("\\(.+\\).*");
public static Pattern compile(String regex) throws PatternSyntaxException { public static Pattern compile(String regex) throws PatternSyntaxException {
if (!CACHE.containsKey(regex)) { if (!CACHE.containsKey(regex)) {

View File

@ -815,6 +815,7 @@ public abstract class PermissionHolder {
return input; return input;
} }
// TODO Support the "Sponge way" of doing wildcards
private static Map<String, Boolean> applyWildcards(Map<String, Boolean> input, List<String> possibleNodes) { private static Map<String, Boolean> applyWildcards(Map<String, Boolean> input, List<String> possibleNodes) {
SortedMap<Integer, Map<String, Boolean>> wildcards = new TreeMap<>(Collections.reverseOrder()); SortedMap<Integer, Map<String, Boolean>> wildcards = new TreeMap<>(Collections.reverseOrder());
for (Map.Entry<String, Boolean> e : input.entrySet()) { for (Map.Entry<String, Boolean> e : input.entrySet()) {

View File

@ -0,0 +1,194 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.service;
import com.google.common.collect.ImmutableSet;
import lombok.*;
import me.lucko.luckperms.LPSpongePlugin;
import me.lucko.luckperms.service.collections.GroupCollection;
import me.lucko.luckperms.service.collections.UserCollection;
import me.lucko.luckperms.service.simple.SimpleCollection;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.service.context.ContextCalculator;
import org.spongepowered.api.service.permission.*;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.util.Tristate;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class LuckPermsService implements PermissionService {
public static final String SERVER_CONTEXT = "server";
private final LPSpongePlugin plugin;
@Getter
private final UserCollection userSubjects;
@Getter
private final GroupCollection groupSubjects;
@Getter
private final Set<PermissionDescription> descriptionSet;
private final Map<String, SubjectCollection> subjects;
private final Set<ContextCalculator<Subject>> contextCalculators;
public LuckPermsService(LPSpongePlugin plugin) {
this.plugin = plugin;
userSubjects = new UserCollection(this, plugin.getUserManager());
groupSubjects = new GroupCollection(this, plugin.getGroupManager());
subjects = new ConcurrentHashMap<>();
subjects.put(PermissionService.SUBJECTS_USER, userSubjects);
subjects.put(PermissionService.SUBJECTS_GROUP, groupSubjects);
descriptionSet = ConcurrentHashMap.newKeySet();
contextCalculators = ConcurrentHashMap.newKeySet();
}
@Override
public SubjectData getDefaultData() {
return null; // TODO
}
@Override
public SubjectCollection getSubjects(String s) {
if (!subjects.containsKey(s)) {
subjects.put(s, new SimpleCollection(this, s));
}
return subjects.get(s);
}
@Override
public Map<String, SubjectCollection> getKnownSubjects() {
return subjects;
}
@Override
public Optional<PermissionDescription.Builder> newDescriptionBuilder(@NonNull Object o) {
Optional<PluginContainer> container = plugin.getGame().getPluginManager().fromInstance(o);
if (!container.isPresent()) {
throw new IllegalArgumentException("Couldn't find a plugin container for " + o.getClass().getSimpleName());
}
return Optional.of(new DescriptionBuilder(this, container.get()));
}
@Override
public Optional<PermissionDescription> getDescription(String s) {
for (PermissionDescription d : descriptionSet) {
if (d.getId().equals(s)) {
return Optional.of(d);
}
}
return Optional.empty();
}
@Override
public Collection<PermissionDescription> getDescriptions() {
return ImmutableSet.copyOf(descriptionSet);
}
@Override
public void registerContextCalculator(ContextCalculator<Subject> contextCalculator) {
contextCalculators.add(contextCalculator);
}
public List<String> getPossiblePermissions() {
return getDescriptions().stream().map(PermissionDescription::getId).collect(Collectors.toList());
}
@RequiredArgsConstructor
@EqualsAndHashCode
@ToString
public static class DescriptionBuilder implements PermissionDescription.Builder {
private final LuckPermsService service;
private final PluginContainer container;
private String id = null;
private Text description = null;
private final Map<String, Tristate> roles = new HashMap<>();
@Override
public PermissionDescription.Builder id(@NonNull String s) {
id = s;
return this;
}
@Override
public PermissionDescription.Builder description(@NonNull Text text) {
description = text;
return this;
}
@Override
public PermissionDescription.Builder assign(@NonNull String s, boolean b) {
roles.put(s, Tristate.fromBoolean(b));
return this;
}
@Override
public PermissionDescription register() throws IllegalStateException {
if (id == null) {
throw new IllegalStateException("id cannot be null");
}
if (description == null) {
throw new IllegalStateException("description cannot be null");
}
Description d = new Description(service, container, id, description);
service.getDescriptionSet().add(d);
// Set role-templates
SubjectCollection subjects = service.getSubjects(PermissionService.SUBJECTS_ROLE_TEMPLATE);
for (Map.Entry<String, Tristate> assignment : roles.entrySet()) {
Subject subject = subjects.get(assignment.getKey());
subject.getTransientSubjectData().setPermission(SubjectData.GLOBAL_CONTEXT, id, assignment.getValue());
}
return d;
}
}
@Getter
@AllArgsConstructor
@EqualsAndHashCode
@ToString
public static class Description implements PermissionDescription {
private final LuckPermsService service;
private final PluginContainer owner;
private final String id;
private final Text description;
@Override
public Map<Subject, Boolean> getAssignedSubjects(String id) {
SubjectCollection subjects = service.getSubjects(id);
return subjects.getAllWithPermission(this.id);
}
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.service.collections;
import lombok.AllArgsConstructor;
import lombok.NonNull;
import me.lucko.luckperms.groups.GroupManager;
import me.lucko.luckperms.service.LuckPermsService;
import me.lucko.luckperms.service.simple.SimpleSubject;
import me.lucko.luckperms.service.wrapping.LuckPermsSubject;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.service.permission.SubjectData;
import java.util.AbstractMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@AllArgsConstructor
public class GroupCollection implements SubjectCollection {
private final LuckPermsService service;
private final GroupManager manager;
@Override
public String getIdentifier() {
return PermissionService.SUBJECTS_GROUP;
}
@Override
public Subject get(@NonNull String id) {
if (manager.isLoaded(id)) {
return new LuckPermsSubject(manager.get(id), service);
}
return new SimpleSubject(id, service, this);
}
@Override
public boolean hasRegistered(@NonNull String id) {
return manager.isLoaded(id);
}
@Override
public Iterable<Subject> getAllSubjects() {
return manager.getAll().values().stream()
.map(u -> new LuckPermsSubject(u, service))
.collect(Collectors.toList());
}
@Override
public Map<Subject, Boolean> getAllWithPermission(@NonNull String node) {
return getAllWithPermission(SubjectData.GLOBAL_CONTEXT, node);
}
@Override
public Map<Subject, Boolean> getAllWithPermission(@NonNull Set<Context> contexts, @NonNull String node) {
return manager.getAll().values().stream()
.map(u -> new LuckPermsSubject(u, service))
.filter(sub -> sub.hasPermission(contexts, node))
.map(sub -> new AbstractMap.SimpleEntry<Subject, Boolean>(sub, sub.getPermissionValue(contexts, node).asBoolean()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
}

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.service.collections;
import lombok.AllArgsConstructor;
import lombok.NonNull;
import me.lucko.luckperms.service.LuckPermsService;
import me.lucko.luckperms.service.simple.SimpleSubject;
import me.lucko.luckperms.service.wrapping.LuckPermsSubject;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.users.UserManager;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.service.permission.SubjectData;
import java.util.AbstractMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
@AllArgsConstructor
public class UserCollection implements SubjectCollection {
private final LuckPermsService service;
private final UserManager manager;
@Override
public String getIdentifier() {
return PermissionService.SUBJECTS_USER;
}
@Override
public Subject get(@NonNull String id) {
try {
UUID u = UUID.fromString(id);
if (manager.isLoaded(u)) {
return new LuckPermsSubject(manager.get(u), service);
}
} catch (IllegalArgumentException e) {
User user = manager.get(id);
if (user != null) {
return new LuckPermsSubject(user, service);
}
}
// Wtf am I meant to do here? What if no user is loaded? Load it? Create it?
return new SimpleSubject(id, service, this);
}
@Override
public boolean hasRegistered(@NonNull String id) {
try {
UUID u = UUID.fromString(id);
return manager.isLoaded(u);
} catch (IllegalArgumentException e) {
User user = manager.get(id);
return user != null;
}
}
@Override
public Iterable<Subject> getAllSubjects() {
return manager.getAll().values().stream()
.map(u -> new LuckPermsSubject(u, service))
.collect(Collectors.toList());
}
@Override
public Map<Subject, Boolean> getAllWithPermission(@NonNull String id) {
return getAllWithPermission(SubjectData.GLOBAL_CONTEXT, id);
}
@Override
public Map<Subject, Boolean> getAllWithPermission(@NonNull Set<Context> contexts, @NonNull String node) {
return manager.getAll().values().stream()
.map(u -> new LuckPermsSubject(u, service))
.filter(sub -> sub.hasPermission(contexts, node))
.map(sub -> new AbstractMap.SimpleEntry<Subject, Boolean>(sub, sub.getPermissionValue(contexts, node).asBoolean()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
}

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.service.simple;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.util.Tristate;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@RequiredArgsConstructor
public class SimpleCollection implements SubjectCollection {
private final PermissionService service;
@Getter
private final String identifier;
private final Map<String, Subject> subjects = new ConcurrentHashMap<>();
@Override
public Subject get(@NonNull String id) {
if (!subjects.containsKey(id)) {
subjects.put(id, new SimpleSubject(id, service, this));
}
return subjects.get(id);
}
@Override
public boolean hasRegistered(@NonNull String id) {
return subjects.containsKey(id);
}
@Override
public Iterable<Subject> getAllSubjects() {
return subjects.values();
}
@Override
public Map<Subject, Boolean> getAllWithPermission(@NonNull String id) {
return getAllWithPermission(Collections.emptySet(), id);
}
@Override
public Map<Subject, Boolean> getAllWithPermission(@NonNull Set<Context> contexts, @NonNull String node) {
Map<Subject, Boolean> m = new HashMap<>();
for (Subject subject : subjects.values()) {
Tristate ts = subject.getPermissionValue(contexts, node);
if (ts != Tristate.UNDEFINED) {
m.put(subject, ts.asBoolean());
}
}
return m;
}
}

View File

@ -0,0 +1,125 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.service.simple;
import lombok.Getter;
import lombok.NonNull;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.*;
import org.spongepowered.api.util.Tristate;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* Super simple Subject implementation.
*/
@Getter
public class SimpleSubject implements Subject {
private final String identifier;
private final PermissionService service;
private final SubjectCollection containingCollection;
private final SubjectData subjectData;
private final Map<Set<Context>, Map<String, Tristate>> perms = new ConcurrentHashMap<>();
private final Map<Set<Context>, Set<Subject>> parents = new ConcurrentHashMap<>();
public SimpleSubject(String identifier, PermissionService service, SubjectCollection containingCollection) {
this.identifier = identifier;
this.service = service;
this.containingCollection = containingCollection;
this.subjectData = new MemorySubjectData(service);
}
@Override
public Optional<CommandSource> getCommandSource() {
return Optional.empty();
}
@Override
public SubjectData getTransientSubjectData() {
return getSubjectData();
}
@Override
public boolean hasPermission(@NonNull Set<Context> contexts, @NonNull String node) {
return getPermissionValue(contexts, node).asBoolean();
}
@Override
public boolean hasPermission(@NonNull String permission) {
return getPermissionValue(getActiveContexts(), permission).asBoolean();
}
@Override
public Tristate getPermissionValue(@NonNull Set<Context> contexts, @NonNull String node) {
if (!perms.containsKey(contexts)) {
return Tristate.UNDEFINED;
}
Map<String, Tristate> context = perms.get(contexts);
if (context.containsKey(node)) {
return context.get(node);
}
for (Subject parent : getParents(contexts)) {
Tristate ts = parent.getPermissionValue(contexts, node);
if (ts != Tristate.UNDEFINED) {
return ts;
}
}
return Tristate.UNDEFINED;
}
@Override
public boolean isChildOf(@NonNull Subject parent) {
return isChildOf(getActiveContexts(), parent);
}
@Override
public boolean isChildOf(@NonNull Set<Context> contexts, @NonNull Subject subject) {
return parents.containsKey(contexts) && parents.get(contexts).contains(subject);
}
@Override
public List<Subject> getParents() {
return getParents(getActiveContexts());
}
@Override
public List<Subject> getParents(@NonNull Set<Context> contexts) {
if (!parents.containsKey(contexts)) {
return Collections.emptyList();
}
return new ArrayList<>(parents.get(contexts));
}
@Override
public Set<Context> getActiveContexts() {
return SubjectData.GLOBAL_CONTEXT;
}
}

View File

@ -0,0 +1,215 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.service.wrapping;
import lombok.AllArgsConstructor;
import lombok.NonNull;
import me.lucko.luckperms.constants.Patterns;
import me.lucko.luckperms.core.PermissionHolder;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.service.LuckPermsService;
import me.lucko.luckperms.users.User;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.service.permission.SubjectData;
import org.spongepowered.api.util.Tristate;
import java.util.*;
import java.util.stream.Collectors;
@AllArgsConstructor
public class LuckPermsSubject implements Subject {
private final PermissionHolder holder;
private final LuckPermsService service;
@Override
public String getIdentifier() {
return holder.getObjectName();
}
@Override
public Optional<CommandSource> getCommandSource() {
if (holder instanceof User) {
final UUID uuid = ((User) holder).getUuid();
Optional<Player> p = Sponge.getServer().getPlayer(uuid);
if (p.isPresent()) {
return Optional.of(p.get());
}
}
return Optional.empty();
}
@Override
public SubjectCollection getContainingCollection() {
if (holder instanceof Group) {
return service.getGroupSubjects();
} else {
return service.getUserSubjects();
}
}
@Override
public SubjectData getSubjectData() {
return null; // TODO
}
@Override
public SubjectData getTransientSubjectData() {
return null; // TODO
}
@Override
public boolean hasPermission(@NonNull Set<Context> contexts, @NonNull String node) {
return getPermissionValue(contexts, node).asBoolean();
}
@Override
public boolean hasPermission(String permission) {
return getPermissionValue(getActiveContexts(), permission).asBoolean();
}
private Map<String, Boolean> applyContexts(@NonNull Set<Context> set) {
final Map<String, Boolean> map = new HashMap<>();
String world = null;
String server = null;
Map<String, String> contexts = new HashMap<>();
for (Context context : set) {
if (context.getType().equals(Context.WORLD_KEY)) {
world = context.getName();
continue;
}
if (context.getType().equals(LuckPermsService.SERVER_CONTEXT)) {
server = context.getName();
continue;
}
contexts.put(context.getType(), context.getName());
}
Map<String, Boolean> local = holder.getLocalPermissions(server, world, null, service.getPossiblePermissions());
perms:
for (Map.Entry<String, Boolean> e : local.entrySet()) {
if (!contexts.isEmpty()) {
if (!Patterns.NODE_CONTEXTS.matcher(e.getKey()).matches()) {
continue;
}
String[] parts = e.getKey().substring(1).split("\\)", 2);
// 0 = context, 1 = node
// Parse the context values from this node
Map<String, String> contextValues = new HashMap<>();
for (String s : parts[0].split("\\,")) {
if (!s.contains("=")) {
// Not valid
continue;
}
// contextKey=value
String[] con = s.split("\\=", 2);
contextValues.put(con[0], con[1]);
}
// Check that all of the requested contexts are met
for (Map.Entry<String, String> req : contexts.entrySet()) {
if (!contextValues.containsKey(e.getKey())) {
continue;
}
if (!contextValues.get(req.getKey()).equalsIgnoreCase(req.getValue())) {
// Not valid within the current contexts
continue perms;
}
}
// Passed all da tests.
map.put(parts[1], e.getValue());
} else {
map.put(e.getKey(), e.getValue());
}
}
return map;
}
@Override
public Tristate getPermissionValue(@NonNull Set<Context> contexts, @NonNull String node) {
final Map<String, Boolean> nodes = applyContexts(contexts);
if (nodes.containsKey(node)) {
return Tristate.fromBoolean(nodes.get(node));
} else {
return Tristate.UNDEFINED;
}
}
@Override
public boolean isChildOf(@NonNull Subject parent) {
return isChildOf(getActiveContexts(), parent);
}
@Override
public boolean isChildOf(@NonNull Set<Context> contexts, @NonNull Subject parent) {
return parent instanceof PermissionHolder && getPermissionValue(contexts, "group." + parent.getIdentifier()).asBoolean();
}
@Override
public List<Subject> getParents() {
return getParents(getActiveContexts());
}
@Override
public List<Subject> getParents(@NonNull Set<Context> contexts) {
final Set<String> parents = new HashSet<>();
final Map<String, Boolean> nodes = applyContexts(contexts);
for (Map.Entry<String, Boolean> e : nodes.entrySet()) {
if (!e.getValue()) {
continue;
}
if (Patterns.GROUP_MATCH.matcher(e.getKey()).matches()) {
final String groupName = e.getKey().substring("group.".length());
parents.add(groupName);
}
}
return parents.stream().map(s -> service.getGroupSubjects().get(s)).collect(Collectors.toList());
}
@Override
public Set<Context> getActiveContexts() {
return SubjectData.GLOBAL_CONTEXT;
}
}