Checking launcher that player is using

Discussion in 'Spigot Plugin Development' started by zNikke, Oct 12, 2018.

  1. Hi, I don't very expert about bukkit or mojang api, but I'm trying to create a plugin that say if a player is logged with a cracked account or premium.

    I searched on internt and so I make a function that return me if a USERNAME is a PAID ACCOUNT or NOT, but how to know if a player using the username because is the real account logged in premium launcher or player is using a cracked launcher with a premium username?
     
  2. You're unable to tell if they use the official launcher, multimc, or a cracked one
     
  3. Uhm... how to do auto-login plugin to verify if a player is premium....?
     
  4. You do not add a authentication plugin and you keep the server online-mode as true.
     
  5. Please read my question
     
  6. You're mixing up 2 things:
    • What client a player is using
      • Not surely tellable, since any client could fake things like the protocol version, etc...
    • If a player has a valid session, so is a premium-paid user account
      • Used client doesn't really matter (as long as it suppoprts mojang authentication)
      • Surely tellable, "just" need to check the player session by mojang sessionserver API
        • There are already many threads about it, we don't need another one! Search the forums for premium session check.
     
  7. So Give me a solution
     
    • Optimistic Optimistic x 3
  8. We won't. That's not what the forum is made for.
     
    • Like Like x 1
    • Agree Agree x 1
  9. Same thing goes for premium users and cracked users.
     
    • Optimistic Optimistic x 1
  10. I do not find anythink...

    this forum is to help users.... I'm don't asking you code, but to explain me somethink that I do not know yet... -.-
    You only bypassed my question
     
    #11 zNikke, Oct 12, 2018
    Last edited by a moderator: Oct 15, 2018
  11. You're able to tell if an account is premium or not :)
     
  12. I remember someone saying that it's not possible ;-; . Oh well, I've been misinformed.
     
  13. I think there has been enough things linked yet to solve the problem.

    However if you still can't figure it out (but try it first), i might post some tutorial as resource (i'm often thought of doing so, but it wasn't really necessary yet).
     
  14. yes, you should help me...

    I tried this code

    Code (Java):
    public boolean checkSession(String name) {  
           
            String serverId = (new BigInteger(MinecraftEncryption.a(LoginListener.b(this.a), LoginListener.c(this.a).K().getPublic(), LoginListener.d(this.a)))).toString(16);
           
           
            try {
                URL url= new URL("https://sessionserver.mojang.com/session/minecraft/hasJoined?username=" + name + "&serverId=" + serverId);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                    InputStream streamIn = connection.getInputStream();
                    byte[] buffer = new byte[streamIn.available()];
                    streamIn.read(buffer);
                    streamIn.close();
                    return true;
                } else {
                    Bukkit.getServer().getLogger().severe("Error: HTTP/" + Integer.toString(connection.getResponseCode()) + ", " + connection.getResponseMessage());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return false;
        }
    but I do not know what is this.a ....
     
    #16 zNikke, Oct 13, 2018
    Last edited by a moderator: Oct 15, 2018
  15. I've tried it for 2 hours not and still didn't manage to get it working.
    Unfortunately it's not as simple as it was at 1.10.2 anymore. Timing and packet order seems to be important now.
    All this is tested on 1.13.1.
    However, this is what i've done / what you need to know:

    1. Know what is the target to achieve:

    Based on this, you need to do a HTTP GET to https://sessionserver.mojang.com/session/minecraft/hasJoined?username=username&serverId=hash&ip=ip, while ip seems to be optional and username is self-explaining.
    The only tricky thing is "hash".
    The "second Encryption Response" is the PacketLoginInEncryptionBegin. It contains the client shared secret needed for the hash.


    2. Check the packets sent in online-mode and offline-mode, then compare them:

    > ONLINE <

    C -> S | net.minecraft.server.v1_13_R2.PacketHandshakingInSetProtocol
    C -> S | net.minecraft.server.v1_13_R2.PacketLoginInStart
    S -> C | net.minecraft.server.v1_13_R2.PacketLoginOutEncryptionBegin <-
    C -> S | net.minecraft.server.v1_13_R2.PacketLoginInEncryptionBegin <-
    S -> C | net.minecraft.server.v1_13_R2.PacketLoginOutSetCompression
    S -> C | net.minecraft.server.v1_13_R2.PacketLoginOutSuccess

    > OFFLINE <
    C -> S | net.minecraft.server.v1_13_R2.PacketHandshakingInSetProtocol
    C -> S | net.minecraft.server.v1_13_R2.PacketLoginInStart
    S -> C | net.minecraft.server.v1_13_R2.PacketLoginOutSetCompression
    S -> C | net.minecraft.server.v1_13_R2.PacketLoginOutSuccess

    As you can see the needed packet PacketLoginInEncryptionBegin is not received, because the server sends no PacketLoginOutEncryptionBegin.

    Of Course you can send the PacketLoginOutEncryptionBegin, if the server doesn't, to receive a PacketLoginInEncryptionBegin from the client to generate the hash and do the HTTP GET. So that's the plan i guess.


    3. Prepare the needed packet & url

    The PacketLoginOutEncryptionBegin:
    Code (Java):
    // Logic taken from net.minecraft.server.v1_13_R2.LoginListener.a(PacketLoginInStart)
    byte[] data = new byte[4];
    new Random().nextBytes(data);

    // Without ProtocolLib:
    Packet packet = new PacketLoginOutEncryptionBegin("", ((CraftServer) this.main.getServer()).getServer().E().getPublic(), data);

    // With ProtocolLib
    PacketContainer packet = this.main.getProtocolLib().createPacket(PacketType.Login.Server.ENCRYPTION_BEGIN);
    packet.getStrings().write(0, "");
    packet.getSpecificModifier(PublicKey.class).write(0, ((CraftServer) this.main.getServer()).getServer().E().getPublic());
    packet.getByteArrays().write(0, data);
    The URL:
    Code (Java):
    // Taken from net.minecraft.server.v1_13_R2.LoginListener.a(PacketLoginInEncryptionBegin)
    // This is the client packet you need to capture:
    PacketLoginInEncryptionBegin packet = // e.g. captured by ProtocolLib PacketEvent (PacketType.Login.Client.ENCRYPTION_BEGIN)

    String hash = new BigInteger(
        MinecraftEncryption.a("", ((CraftServer) this.main.getServer()).getServer().E().getPublic(),
                packet.a(((CraftServer) this.main.getServer()).getServer().E().getPrivate()))
            ).toString(16);
    // Taken from com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService.hasJoinedServer(GameProfile, String, InetAddress)
    String url = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=" + player.getName() + "&serverId=" + hash;

    4. Schedule the packet (PacketLoginOutEncryptionBegin)

    That's where i failed until now.
    I tried to use ProtocolLib to send it immediately after the PacketLoginOutSuccess, this causes the client to disconnect by a client error "Packet was larger than expected". I assume a compression error, like the packet is sent uncompressed (because it's normally sent before the compression start), but the client awaits compressed packets (because the compression start packet is already sent).
    Sending directly after the PacketLoginInStart packet (like online mode would do) causes the same client error (maybe because the compression start is sent within the same tick and the client still enables compression faster than handling the encryption packet).

    So i tried to block and buffer the PacketLoginOutSetCompression and PacketLoginOutSuccess, to first send the PacketLoginOutEncryptionBegin, which causes the client error "Bad packet id 37". The packet id of PacketLoginOutEncryptionBegin is 1. I tried with and without ProtocolLib, both resulted in this error (i guess because the server already compresses it and the client still awaits uncompressed).

    At last i tried to delay the PacketLoginOutEncryptionBegin for 1 or even 10 seconds, until all compression and handshake stuff is done. Resulting in the same "larger than expected" client error.
    Btw. this is how it worked in 1.10.2, i delayed just the PacketLoginOutEncryptionBegin packet for 20 ticks, received the PacketLoginInEncryptionBegin, build the URL like above and performed the HTTP GET.

    So i guess it's your part now to find out, how to properly schedule the PacketLoginOutEncryptionBegin and order the other login packets. Good luck, let us know your progress.
     
    #17 Michel_0, Oct 13, 2018
    Last edited: Oct 13, 2018
    • Winner Winner x 1
  16. I tried but unfortunately none of these methods works, it does not recognize the getPublic() and getPrivate() methods, and I am compiling the plugin in 1.8 even if I should make it compatible in 1.13, but this is a secondary thing ... I would first understand how to make it work in 1.8.
    If you know from my example above the method I wrote seems to work through the hash, I managed to compile that method through some posts on this forum, but I can not understand the parameter "to" what it refers to, is the only one I'm missing the factor to adjust the method, what do you think?
     
  17. From these referenced NMS methods you could find out the logic in 1.8.

    Maybe there are significant differences in 1.8, so i don't know if the code you posted could work out.
    However i'm pretty sure even in 1.8 you'll need the data out of the PacketLoginInEncryptionBegin, so need to send the PacketLoginOutEncryptionBegin.
     
  18. sorry but I can not apply your method, I do not know how to instantiate the packet parameter
     

Share This Page