Get player's previous names

Hello,

I think an important tool for administrators/moderators (now that we can change names) would be a command to get a player’s previous names. Thanks to mojang’s api that doesn’t seem to be very complicated to do.

The idea would be:

  • getting targeted player’s UUID
  • sending request to mojang (https://api.mojang.com/user/profiles/{uuid here}/names)
  • sending result to CommandSource instance

I’m posting this here so the people interested can eventually help. I’m not looking for people to do the work for me, I only thought it could be of use to the community. The thing is I’m absolutely not familliar with http request in java :sweat_smile: . Does anyone have any good tutorial about that ?

Also I presume the command process should be async, Is it possible to do it using the scheduler service ?

EDIT

Thanks to all your answers, I came up with this (special thanks to dualspiral’s Hammer). I tested it, it works fine but tell me if you see any mistake in the code (here we assume MyPluginClassHere is the plugin’s main class and its methods are correctly implemented).

public class PrevNamesExecutor implements CommandExecutor
{
	public CommandResult execute(CommandSource src, CommandContext ctx) throws CommandException
	{
		Player player = args.<Player>getOne("player").get();
		UUID uuid = player.getUniqueId();
		
		src.sendMessage(Texts.of(TextColors.AQUA, "Trying to get player's previous names"));
		
		MyPluginClassHere.getTaskBuilder().execute(new PreviousNamesFetcher(uuid, src)).async().submit(MyPluginClassHere.getInstance());
		
		return CommandResult.success();
	}
}

and somewhere else:

public class PrevNamesFetcher implements Runnable
{
	private CommandSource src;
	private UUID uuid;
	
	public PrevNamesFetcher(UUID uuid, CommandSource src)
	{
		this.uuid = uuid;
		this.src = src;
	}
	
	public void run()
	{
		String str = getPrevNames();
		if (str == null)
		{
			src.sendMessage(Texts.of(TextColors.RED, "Error while getting player's previous names"));
			return;
		}
		TextBuilder builder = Texts.builder("");
		Iterator<JsonElement> iter = (new JsonParser()).parse(str).getAsJsonArray().iterator();
		builder.append(
				Texts.of(TextColors.DARK_AQUA, "Previous names: "),
				Texts.of(TextColors.AQUA, iter.next().getAsJsonObject().get("name").getAsString().concat("\n")));
		while (iter.hasNext())
		{
			JsonObject obj = iter.next().getAsJsonObject();
			Date date = new Date(obj.get("changedToAt").getAsLong());
			String day = (new SimpleDateFormat("dd-MM-yyyy")).format(date);
			String time = (new SimpleDateFormat("HH:mm:ss")).format(date);
			builder.append(
					Texts.of(TextColors.DARK_AQUA, "changed to "),
					Texts.of(TextColors.AQUA, obj.get("name").getAsString()),
					Texts.of(TextColors.DARK_AQUA, " on "),
					Texts.of(TextColors.AQUA, day),
					Texts.of(TextColors.DARK_AQUA, " at "),
					Texts.of(TextColors.AQUA, time));
		}
		src.sendMessage(builder.build());
	}
	
	public String getPrevNames()
	{
		String target = String.format("https://api.mojang.com/user/profiles/%s/names", uuid.toString().replace("-", ""));
		String r = null;
		
		HttpURLConnection connection = null;
		try
		{
			URL url = new URL(target);
			connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("GET");
			
			connection.setUseCaches(false);
			connection.setDoOutput(true);
			
			connection.connect();
			
			if (connection.getResponseCode() != 200)
			{
				return null;
			}
			
			InputStream is = connection.getInputStream();
			BufferedReader rd = new BufferedReader(new InputStreamReader(is));
			StringBuilder response = new StringBuilder();
			String line;
			while ((line = rd.readLine()) != null)
			{
				response.append(line);
				response.append('\r').append('\n');
			}
			rd.close();
			
			r = response.toString();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		finally
		{
			if (connection != null)
			{
				connection.disconnect();
			}
		}
		return r;
	}
}

Hey

Great idea!

I’m currently running a whitelisted server and it’s a pain to whitelist/ban/unban and so on because you’ll need the correct name.

An idea for the plugin would be to allow to only show original names, so that when you join the server your name is only shown as the original.

I actually made a plugin for this a while back - WhoWas | Name History Fetcher. It’s been a while since I’ve updated it, though.

This might be worth adding to UserStorage, as I can see amny plugins wanting this kind of information.

I belive mojang apis require (from some unknown reasons) user-aget “minecraft” but i might be wrong.
Also do not send any http requests from server’s main thread. you will cause lot of lags.

The HTTPS format isn’t all that complicated


Introduction

HTTPS uses HTTP/1.1 formatted messages encrypted using TLS (Transport Layer Security), although I have no idea how that would work. The client (also referred to as "User-Agent" or a "Browser") sends a request to the server, which responds with a response formatted in a similar way.

Request / Response Format Similarities

Both the request and response are composed of the following two things:
  1. Header - The header contains information about the User-Agent, cookies, HTTP version, request type, etc. Line seperators in the header are represented by CRLF (\r\n). All content in the header is raw text encoded using US-ASCII. The first line is always reserved for special information (explained further). The following lines are key-value pairs. Valid pairs are different for the request and the response. At the end of the header, an empty line must be inserted. In other words, a header always ends with \r\n\r\n.
  2. Body - The body will not be read unless if Content-Length is indicated (in bytes), that is how either side knows when to stop reading input from the socket. The content of the body is also specified by Content-Type, which can also determine the encoding of files, notably HTML files. The Content-Type is specified as a MIME type and the character set can be defined afterwards. For example, if a server were sending a user agent a HTML file encoded with UTF-8, one of the lines in the header would be Content-Type: text/html charset=UTF-8.

HTTP/1.1 Request Header

  1. The first line of the header is always {METHOD} {RESOURCE} HTTP/1.1. METHOD is the request method (most often GET or POST) and RESOURCE is the path to the resource requested by the user agent (always starts with /)
  2. The rest of the header contains key-value pairs most often for keys like User-Agent (name of the user agent), Cookie (cookies stored for that web page), Host (name of the host used to connect) and Connection (either Keep-Alive or Close). If the user agent sends Connection: Close inside the header, the server will ignore the socket after having responded to the request, allowing the user agent to close it.

HTTP/1.1 Response Header

1. The first line of the response header is always `HTTP/1.1 {CODE} {MSG}`, where `CODE` is the status code and `MSG` is the status message. Even though the code is not a success code (2xx), there can still be a body. 2. The rest of the header contains key-value pairs most often for keys like `Server` (name of the server) and `Set-Cookie` (sets a certain cookie).

HTTPS is defined in RFC 2818, I recommend you read it.

1 Like

If it helps, I have written this to get a user’s current UUID from a name using another API endpoint - you mostly want the method marked (getJsonResponse()):

Hopefully this will get you off the ground to get the previous names from a UUID. Again, make sure you run this from an async thread. It might not be the most efficent code, but hey, there it is!

Thank you all for your answers. Thanks to your RESPONSE to my REQUEST in this POST, I finally GET it (bad joke :kissing_smiling_eyes: ). I’ll edit the post just now with what I came with.

5 Likes

thank you for this. I was also trying to figure out how to something similar to this aswell

Or you could do what anyone sane would do, and use either the standard libraries, or a commonly used 3rd party library to do the heavy lifting for you…

Posting a guide to HTTPS is very unhelpful.

It might help some people.

Ironically, my name states I am insane.