Expose uuid/username lookups and validity checks as events in the API

This commit is contained in:
Luck 2020-11-23 23:54:02 +00:00
parent d136359cd9
commit 53fb46ee85
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
15 changed files with 601 additions and 74 deletions

View File

@ -0,0 +1,86 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* 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 net.luckperms.api.event.player.lookup;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.type.ResultEvent;
import net.luckperms.api.event.util.Param;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Objects;
import java.util.UUID;
/**
* Called when the platform needs to determine the type of a player's {@link UUID unique id}.
*
* @since 5.3
*/
public interface UniqueIdDetermineTypeEvent extends LuckPermsEvent, ResultEvent<String> {
/**
* The players UUID has been obtained by authenticating with the Mojang session servers.
*
* <p>Usually indicated by the UUID being {@link UUID#version() version} 4.</p>
*/
String TYPE_AUTHENTICATED = "authenticated";
/**
* The players UUID has not been obtained through authentication, and instead is likely based
* on the username they connected with.
*
* <p>Usually indicated by the UUID being {@link UUID#version() version} 3.</p>
*/
String TYPE_UNAUTHENTICATED = "unauthenticated";
/**
* Gets the {@link UUID unique id} being queried.
*
* @return the unique id
*/
@Param(0)
@NonNull UUID getUniqueId();
/**
* Gets the current result unique id type.
*
* @return the type
*/
default @NonNull String getType() {
return result().get();
}
/**
* Sets the result unique id type.
*
* @param type the type
*/
default void setType(@NonNull String type) {
Objects.requireNonNull(type, "type");
result().set(type);
}
}

View File

@ -0,0 +1,61 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* 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 net.luckperms.api.event.player.lookup;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.type.ResultEvent;
import net.luckperms.api.event.util.Param;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.UUID;
/**
* Called when the platform needs a unique id for a given username.
*
* @since 5.3
*/
public interface UniqueIdLookupEvent extends LuckPermsEvent, ResultEvent<UUID> {
/**
* Gets the username being looked up.
*
* @return the username
*/
@Param(0)
@NonNull String getUsername();
/**
* Sets the result unique id.
*
* @param uniqueId the unique id
*/
default void setUniqueId(@Nullable UUID uniqueId) {
result().set(uniqueId);
}
}

View File

@ -0,0 +1,61 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* 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 net.luckperms.api.event.player.lookup;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.type.ResultEvent;
import net.luckperms.api.event.util.Param;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.UUID;
/**
* Called when the platform needs a username for a given unique id.
*
* @since 5.3
*/
public interface UsernameLookupEvent extends LuckPermsEvent, ResultEvent<String> {
/**
* Gets the {@link UUID unique id} being looked up.
*
* @return the unique id
*/
@Param(0)
@NonNull UUID getUniqueId();
/**
* Sets the result username.
*
* @param username the username
*/
default void setUsername(@Nullable String username) {
result().set(username);
}
}

View File

@ -0,0 +1,76 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* 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 net.luckperms.api.event.player.lookup;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.util.Param;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Called when the validity of a username is being tested.
*
* @since 5.3
*/
public interface UsernameValidityCheckEvent extends LuckPermsEvent {
/**
* Gets the username being tested.
*
* @return the username
*/
@Param(0)
@NonNull String getUsername();
/**
* Gets the current validity state for the username.
*
* @return the validity state
*/
@Param(1)
@NonNull AtomicBoolean validityState();
/**
* Gets if the username is currently considered to be valid.
*
* @return if the username is valid
*/
default boolean isValid() {
return validityState().get();
}
/**
* Sets if the username should be considered valid or not.
*
* @param valid whether the username is valid
*/
default void setValid(boolean valid) {
validityState().set(valid);
}
}

View File

@ -0,0 +1,59 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* 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 net.luckperms.api.event.type;
import net.luckperms.api.event.util.Param;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.concurrent.atomic.AtomicReference;
/**
* Represents an event that has a result.
*
* @param <T> the type of the result
* @since 5.3
*/
public interface ResultEvent<T> {
/**
* Gets an {@link AtomicReference} containing the result.
*
* @return the result
*/
@Param(-1)
@NonNull AtomicReference<T> result();
/**
* Gets if a result has been set for the event.
*
* @return if there is a result
*/
default boolean hasResult() {
return result().get() != null;
}
}

View File

@ -42,6 +42,7 @@ import me.lucko.luckperms.common.model.manager.group.GroupManager;
import me.lucko.luckperms.common.node.factory.NodeBuilders;
import me.lucko.luckperms.common.node.types.Inheritance;
import me.lucko.luckperms.common.query.QueryOptionsImpl;
import me.lucko.luckperms.common.util.UniqueIdType;
import me.lucko.luckperms.common.util.Uuids;
import me.lucko.luckperms.common.verbose.event.MetaCheckEvent;
import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
@ -124,10 +125,7 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
}
// lookup a username from the database
uuid = this.plugin.getStorage().getPlayerUniqueId(player.toLowerCase()).join();
if (uuid == null) {
uuid = this.plugin.getBootstrap().lookupUniqueId(player).orElse(null);
}
uuid = this.plugin.lookupUniqueId(player).orElse(null);
// unable to find a user, throw an exception
if (uuid == null) {
@ -146,10 +144,8 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
return user;
}
// if the uuid is version 2, assume it is an NPC
// see: https://github.com/lucko/LuckPerms/issues/1470
// and https://github.com/lucko/LuckPerms/issues/1470#issuecomment-475403162
if (uuid.version() == 2) {
// is it an npc?
if (UniqueIdType.determineType(uuid, this.plugin).getType().equals("npc")) {
String npcGroupName = this.plugin.getConfiguration().get(ConfigKeys.VAULT_NPC_GROUP);
Group npcGroup = this.plugin.getGroupManager().getIfLoaded(npcGroupName);
if (npcGroup == null) {
@ -380,7 +376,7 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
boolean op = false;
if (player != null) {
op = player.isOp();
} else if (uuid != null && uuid.version() == 2) { // npc
} else if (uuid != null && UniqueIdType.determineType(uuid, this.plugin).getType().equals("npc")) {
op = this.plugin.getConfiguration().get(ConfigKeys.VAULT_NPC_OP_STATUS);
}

View File

@ -34,7 +34,6 @@ import me.lucko.luckperms.common.command.access.ArgumentPermissions;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.command.spec.CommandSpec;
import me.lucko.luckperms.common.command.utils.ArgumentList;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.HolderType;
@ -104,21 +103,7 @@ public class GroupListMembers extends ChildCommand<Group> {
Message.SEARCH_RESULT.send(sender, users + groups, users, groups);
if (!matchedUsers.isEmpty()) {
Map<UUID, String> uuidLookups = LoadingMap.of(u -> {
String s = plugin.getStorage().getPlayerName(u).join();
if (s != null && !s.isEmpty() && !s.equals("null")) {
return s;
}
if (plugin.getConfiguration().get(ConfigKeys.USE_SERVER_UUID_CACHE)) {
s = plugin.getBootstrap().lookupUsername(u).orElse(null);
if (s != null) {
return s;
}
}
return u.toString();
});
Map<UUID, String> uuidLookups = LoadingMap.of(u -> plugin.lookupUsername(u).orElseGet(u::toString));
sendResult(sender, matchedUsers, uuidLookups::get, Message.SEARCH_SHOWING_USERS, HolderType.USER, label, page);
}

View File

@ -38,7 +38,6 @@ import me.lucko.luckperms.common.command.spec.CommandSpec;
import me.lucko.luckperms.common.command.tabcomplete.TabCompleter;
import me.lucko.luckperms.common.command.tabcomplete.TabCompletions;
import me.lucko.luckperms.common.command.utils.ArgumentList;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.HolderType;
import me.lucko.luckperms.common.node.comparator.NodeEntryComparator;
@ -86,21 +85,7 @@ public class SearchCommand extends SingleCommand {
Message.SEARCH_RESULT.send(sender, users + groups, users, groups);
if (!matchedUsers.isEmpty()) {
Map<UUID, String> uuidLookups = LoadingMap.of(u -> {
String s = plugin.getStorage().getPlayerName(u).join();
if (s != null && !s.isEmpty() && !s.equals("null")) {
return s;
}
if (plugin.getConfiguration().get(ConfigKeys.USE_SERVER_UUID_CACHE)) {
s = plugin.getBootstrap().lookupUsername(u).orElse(null);
if (s != null) {
return s;
}
}
return u.toString();
});
Map<UUID, String> uuidLookups = LoadingMap.of(u -> plugin.lookupUsername(u).orElseGet(u::toString));
sendResult(sender, matchedUsers, uuidLookups::get, Message.SEARCH_SHOWING_USERS, HolderType.USER, label, page, comparison);
}

View File

@ -37,6 +37,7 @@ import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.Predicates;
import me.lucko.luckperms.common.util.UniqueIdType;
import me.lucko.luckperms.common.verbose.event.MetaCheckEvent;
import net.luckperms.api.context.ContextSet;
@ -63,7 +64,7 @@ public class UserInfo extends ChildCommand<User> {
Message.USER_INFO_GENERAL.send(sender,
target.getUsername().orElse("Unknown"),
target.getUniqueId().toString(),
target.getUniqueId().version() == 4,
UniqueIdType.determineType(target.getUniqueId(), plugin).describe(),
plugin.getBootstrap().isPlayerOnline(target.getUniqueId())
);

View File

@ -37,14 +37,12 @@ import me.lucko.luckperms.common.commands.generic.other.HolderEditor;
import me.lucko.luckperms.common.commands.generic.other.HolderShowTracks;
import me.lucko.luckperms.common.commands.generic.parent.CommandParent;
import me.lucko.luckperms.common.commands.generic.permission.CommandPermission;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.HolderType;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.model.UserIdentifier;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.storage.misc.DataConstraints;
import me.lucko.luckperms.common.util.CaffeineFactory;
import me.lucko.luckperms.common.util.Uuids;
@ -81,36 +79,23 @@ public class UserParentCommand extends ParentCommand<User, UserIdentifier> {
}
public static UUID parseTargetUniqueId(String target, LuckPermsPlugin plugin, Sender sender) {
UUID uniqueId = Uuids.parse(target);
if (uniqueId == null) {
if (!plugin.getConfiguration().get(ConfigKeys.ALLOW_INVALID_USERNAMES)) {
if (!DataConstraints.PLAYER_USERNAME_TEST.test(target)) {
Message.USER_INVALID_ENTRY.send(sender, target);
return null;
}
} else {
if (!DataConstraints.PLAYER_USERNAME_TEST_LENIENT.test(target)) {
Message.USER_INVALID_ENTRY.send(sender, target);
return null;
}
}
uniqueId = plugin.getStorage().getPlayerUniqueId(target.toLowerCase()).join();
if (uniqueId == null) {
if (!plugin.getConfiguration().get(ConfigKeys.USE_SERVER_UUID_CACHE)) {
Message.USER_NOT_FOUND.send(sender, target);
return null;
}
uniqueId = plugin.getBootstrap().lookupUniqueId(target).orElse(null);
if (uniqueId == null) {
Message.USER_NOT_FOUND.send(sender, target);
return null;
}
}
UUID parsed = Uuids.parse(target);
if (parsed != null) {
return parsed;
}
return uniqueId;
if (!plugin.testUsernameValidity(target)) {
Message.USER_INVALID_ENTRY.send(sender, target);
return null;
}
UUID lookup = plugin.lookupUniqueId(target).orElse(null);
if (lookup == null) {
Message.USER_NOT_FOUND.send(sender, target);
return null;
}
return lookup;
}
@Override

View File

@ -64,6 +64,10 @@ import net.luckperms.api.event.node.NodeClearEvent;
import net.luckperms.api.event.node.NodeRemoveEvent;
import net.luckperms.api.event.player.PlayerDataSaveEvent;
import net.luckperms.api.event.player.PlayerLoginProcessEvent;
import net.luckperms.api.event.player.lookup.UniqueIdDetermineTypeEvent;
import net.luckperms.api.event.player.lookup.UniqueIdLookupEvent;
import net.luckperms.api.event.player.lookup.UsernameLookupEvent;
import net.luckperms.api.event.player.lookup.UsernameValidityCheckEvent;
import net.luckperms.api.event.source.Source;
import net.luckperms.api.event.sync.ConfigReloadEvent;
import net.luckperms.api.event.sync.PostSyncEvent;
@ -95,6 +99,7 @@ import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
public final class EventDispatcher {
@ -313,6 +318,46 @@ public final class EventDispatcher {
post(PlayerDataSaveEvent.class, () -> generate(PlayerDataSaveEvent.class, uniqueId, username, result));
}
public String dispatchUniqueIdDetermineType(UUID uniqueId, String initialType) {
if (!shouldPost(UniqueIdDetermineTypeEvent.class)) {
return initialType;
}
AtomicReference<String> result = new AtomicReference<>(initialType);
post(generate(UniqueIdDetermineTypeEvent.class, result, uniqueId));
return result.get();
}
public UUID dispatchUniqueIdLookup(String username, UUID initial) {
if (!shouldPost(UniqueIdLookupEvent.class)) {
return initial;
}
AtomicReference<UUID> result = new AtomicReference<>(initial);
post(generate(UniqueIdLookupEvent.class, result, username));
return result.get();
}
public String dispatchUsernameLookup(UUID uniqueId, String initial) {
if (!shouldPost(UsernameLookupEvent.class)) {
return initial;
}
AtomicReference<String> result = new AtomicReference<>(initial);
post(generate(UsernameLookupEvent.class, result, uniqueId));
return result.get();
}
public boolean dispatchUsernameValidityCheck(String username, boolean initialState) {
if (!shouldPost(UsernameValidityCheckEvent.class)) {
return initialState;
}
AtomicBoolean result = new AtomicBoolean(initialState);
post(generate(UsernameValidityCheckEvent.class, username, result));
return result.get();
}
public void dispatchUserLoad(User user) {
post(UserLoadEvent.class, () -> generate(UserLoadEvent.class, user.getApiProxy()));
}
@ -361,6 +406,10 @@ public final class EventDispatcher {
NodeRemoveEvent.class,
PlayerDataSaveEvent.class,
PlayerLoginProcessEvent.class,
UniqueIdDetermineTypeEvent.class,
UniqueIdLookupEvent.class,
UsernameLookupEvent.class,
UsernameValidityCheckEvent.class,
ConfigReloadEvent.class,
PostSyncEvent.class,
PreNetworkSyncEvent.class,

View File

@ -2757,7 +2757,7 @@ public interface Message {
.append(FULL_STOP)
);
Args4<String, String, Boolean, Boolean> USER_INFO_GENERAL = (username, uuid, mojang, online) -> join(newline(),
Args4<String, String, Component, Boolean> USER_INFO_GENERAL = (username, uuid, uuidType, online) -> join(newline(),
// "&b&l> &bUser Info: &f{}"
// "&f- &3UUID: &f{}"
// "&f &7(type: {}&7)"
@ -2781,7 +2781,7 @@ public interface Message {
.append(OPEN_BRACKET)
.append(translatable("luckperms.command.user.info.uuid-type-key"))
.append(text(": "))
.append(mojang ? translatable("luckperms.command.user.info.uuid-type.mojang", DARK_GREEN) : translatable("luckperms.command.user.info.uuid-type.not-mojang", DARK_GRAY))
.append(uuidType)
.append(CLOSE_BRACKET)),
prefixed(text()
.color(DARK_AQUA)

View File

@ -51,6 +51,7 @@ import me.lucko.luckperms.common.storage.Storage;
import me.lucko.luckperms.common.storage.StorageFactory;
import me.lucko.luckperms.common.storage.StorageType;
import me.lucko.luckperms.common.storage.implementation.file.watcher.FileWatcher;
import me.lucko.luckperms.common.storage.misc.DataConstraints;
import me.lucko.luckperms.common.tasks.SyncTask;
import me.lucko.luckperms.common.treeview.PermissionRegistry;
import me.lucko.luckperms.common.verbose.VerboseHandler;
@ -66,6 +67,7 @@ import java.time.Month;
import java.util.EnumSet;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
@ -291,6 +293,53 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
}
}
@Override
public Optional<UUID> lookupUniqueId(String username) {
// get a result from the DB cache
UUID uniqueId = getStorage().getPlayerUniqueId(username.toLowerCase()).join();
// fire the event
uniqueId = getEventDispatcher().dispatchUniqueIdLookup(username, uniqueId);
// try the servers cache
if (uniqueId == null && getConfiguration().get(ConfigKeys.USE_SERVER_UUID_CACHE)) {
uniqueId = getBootstrap().lookupUniqueId(username).orElse(null);
}
return Optional.ofNullable(uniqueId);
}
@Override
public Optional<String> lookupUsername(UUID uniqueId) {
// get a result from the DB cache
String username = getStorage().getPlayerName(uniqueId).join();
// fire the event
username = getEventDispatcher().dispatchUsernameLookup(uniqueId, username);
// try the servers cache
if (username == null && getConfiguration().get(ConfigKeys.USE_SERVER_UUID_CACHE)) {
username = getBootstrap().lookupUsername(uniqueId).orElse(null);
}
return Optional.ofNullable(username);
}
@Override
public boolean testUsernameValidity(String username) {
// if the username doesn't even pass the lenient test, don't bother going any further
// it's either empty, or too long to fit in the sql column
if (!DataConstraints.PLAYER_USERNAME_TEST_LENIENT.test(username)) {
return false;
}
// if invalid usernames are allowed in the config, set valid to true, otherwise, use the more strict test
boolean valid = getConfiguration().get(ConfigKeys.ALLOW_INVALID_USERNAMES) || DataConstraints.PLAYER_USERNAME_TEST.test(username);
// fire the event & return
return getEventDispatcher().dispatchUsernameValidityCheck(username, valid);
}
@Override
public DependencyManager getDependencyManager() {
return this.dependencyManager;

View File

@ -61,6 +61,7 @@ import net.luckperms.api.query.QueryOptions;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Stream;
/**
@ -255,6 +256,30 @@ public interface LuckPermsPlugin {
*/
Optional<QueryOptions> getQueryOptionsForUser(User user);
/**
* Lookup a uuid from a username.
*
* @param username the username to lookup
* @return an optional uuid, if found
*/
Optional<UUID> lookupUniqueId(String username);
/**
* Lookup a username from a uuid.
*
* @param uniqueId the uuid to lookup
* @return an optional username, if found
*/
Optional<String> lookupUsername(UUID uniqueId);
/**
* Tests whether the given username is valid.
*
* @param username the username
* @return true if valid
*/
boolean testUsernameValidity(String username);
/**
* Gets a list of online Senders on the platform
*

View File

@ -0,0 +1,109 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* 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.common.util;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.luckperms.api.event.player.lookup.UniqueIdDetermineTypeEvent;
import java.util.UUID;
/**
* Encapsulates the type of a players unique id.
*/
public final class UniqueIdType {
public static final UniqueIdType AUTHENTICATED = new UniqueIdType(
UniqueIdDetermineTypeEvent.TYPE_AUTHENTICATED,
Component.translatable("luckperms.command.user.info.uuid-type.mojang", NamedTextColor.DARK_GREEN)
);
public static final UniqueIdType UNAUTHENTICATED = new UniqueIdType(
UniqueIdDetermineTypeEvent.TYPE_UNAUTHENTICATED,
Component.translatable("luckperms.command.user.info.uuid-type.not-mojang", NamedTextColor.DARK_GRAY)
);
private static final String TYPE_NPC = "npc";
public static final UniqueIdType NPC = new UniqueIdType(TYPE_NPC);
public static UniqueIdType determineType(UUID uniqueId, LuckPermsPlugin plugin) {
// determine initial type based on the uuid version
String type;
switch (uniqueId.version()) {
case 4:
type = UniqueIdDetermineTypeEvent.TYPE_AUTHENTICATED;
break;
case 3:
type = UniqueIdDetermineTypeEvent.TYPE_UNAUTHENTICATED;
break;
case 2:
// if the uuid is version 2, assume it is an NPC
// see: https://github.com/lucko/LuckPerms/issues/1470
// and https://github.com/lucko/LuckPerms/issues/1470#issuecomment-475403162
type = TYPE_NPC;
break;
default:
type = "unknown";
break;
}
// call the event
type = plugin.getEventDispatcher().dispatchUniqueIdDetermineType(uniqueId, type);
switch (type) {
case UniqueIdDetermineTypeEvent.TYPE_AUTHENTICATED:
return AUTHENTICATED;
case UniqueIdDetermineTypeEvent.TYPE_UNAUTHENTICATED:
return UNAUTHENTICATED;
case TYPE_NPC:
return NPC;
default:
return new UniqueIdType(type);
}
}
private final String type;
private final Component component;
private UniqueIdType(String type) {
this(type, Component.text(type, NamedTextColor.GOLD));
}
private UniqueIdType(String type, Component component) {
this.type = type;
this.component = component;
}
public String getType() {
return this.type;
}
public Component describe() {
return this.component;
}
}