Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package org.rse.network.codec;
- import io.netty.buffer.ByteBuf;
- import io.netty.buffer.Unpooled;
- import io.netty.channel.Channel;
- import io.netty.channel.ChannelFutureListener;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.handler.codec.ByteToMessageDecoder;
- import java.util.HashMap;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import org.rse.Server;
- import org.rse.cache.Cache;
- import org.rse.model.World;
- import org.rse.model.mortals.players.Player;
- import org.rse.model.mortals.players.PlayerFile;
- import org.rse.network.packets.PacketSender;
- import org.rse.network.stream.InStream;
- import org.rse.network.stream.OutStream;
- import org.rse.utility.BCrypt;
- import org.rse.utility.MACAddress;
- import org.rse.utility.Misc;
- import org.rse.utility.Redis;
- import org.rse.utility.Redis.AuthResult;
- import org.rse.utility.XTEADecipher;
- public final class RS2Decoder extends ByteToMessageDecoder {
- private static final int[] UPDATE_KEYS = { 1476, 78700, 44880, 39771, 358716, 44375, 0, 16497, 9063, 303354,
- 859711, 234014, 386188, 471057, 1010288, 22171, 27556, 17864, 1244, 18569, 1728, 119, 934587, 1985065,
- 4930, 3481 };
- private static final byte HANDSHAKE_STAGE = 0, UPDATE_STAGE = 1, LOGIN_STAGE = 2;
- private static final HashMap<String, Boolean> loginRequests = new HashMap<>();
- private LinkedList<String> requests = new LinkedList<String>();
- private static ExecutorService updateService = Executors.newCachedThreadPool();
- private byte stage = HANDSHAKE_STAGE;
- private int encryptionValue;
- private void decodeFileRequest(Channel channel, ByteBuf buffer, boolean priority) {
- int idx = buffer.readByte() & 0xff;
- int fileId = buffer.readInt();
- if (idx != 255) {
- if (Cache.STORE.getIndexes().length <= idx || Cache.STORE.getIndexes()[idx] == null
- || !Cache.STORE.getIndexes()[idx].archiveExists(fileId)) {
- return;
- }
- } else if (fileId != 255) {
- if (Cache.STORE.getIndexes().length <= fileId || Cache.STORE.getIndexes()[fileId] == null) {
- return;
- }
- }
- if (priority) {
- updateService.submit(() -> writeCacheFile(channel, idx, fileId, true));
- } else {
- requests.add(idx + "," + fileId);
- }
- while (requests.size() > 0) {
- String[] request = requests.removeFirst().split(",");
- writeCacheFile(channel, Integer.parseInt(request[0]), Integer.parseInt(request[1]), false);
- }
- }
- private void writeCacheFile(Channel channel, int idx, int fileId, boolean priority) {
- if (idx == 255 && fileId == 255) {
- channel.writeAndFlush(Cache.getVersionTable());
- } else {
- channel.writeAndFlush(Cache.getFileBuffer(idx, fileId, priority, encryptionValue));
- }
- }
- private static void sendReturnCode(Channel channel, int returnCode) {
- ByteBuf buffer = Unpooled.buffer(1);
- buffer.writeByte(returnCode);
- channel.writeAndFlush(buffer).addListener(ChannelFutureListener.CLOSE);
- }
- @Override
- protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception {
- Channel channel = ctx.channel();
- if (!channel.isOpen() || !buffer.isReadable()) {
- /**
- * Nothing should be decoded.
- */
- return;
- }
- int opcode;
- switch (stage) {
- case HANDSHAKE_STAGE:
- stage = -1;
- opcode = buffer.readByte() & 0xff;
- switch (opcode) {
- case 14:
- if (buffer.readableBytes() != 0) {
- /**
- * Invalid buffer size.
- */
- System.err.println("[RS2Decoder] 1 - Invalid buffer size! " + buffer.readableBytes());
- channel.close();
- return;
- }
- ByteBuf loginRequestBuffer = Unpooled.buffer(1);
- loginRequestBuffer.writeByte(0);
- channel.writeAndFlush(loginRequestBuffer);
- stage = LOGIN_STAGE;
- break;
- case 15:
- int size = buffer.readByte() & 0xff;
- if (buffer.readableBytes() < size) {
- /**
- * Invalid buffer size.
- */
- System.err.println("[RS2Decoder] 2 - Invalid buffer size!" + " " + buffer.readableBytes());
- channel.close();
- return;
- }
- if (buffer.readableBytes() < 4) {
- /**
- * Invalid buffer size.
- */
- System.err.println("[RS2Decoder] 3 - Invalid buffer size!" + " " + buffer.readableBytes());
- channel.close();
- return;
- }
- int clientVersion = buffer.readInt();
- int subVersion = buffer.readInt();
- if (clientVersion != Server.VERSION || subVersion != Server.SUB_VERSION) {
- /**
- * Invalid client version.
- */
- sendReturnCode(channel, 6);
- return;
- }
- byte[] bytes = new byte[buffer.readableBytes()];
- buffer.readBytes(bytes);
- InStream in = new InStream(bytes);
- if (!in.readString().equals(Server.CLIENT_VERIFICATION)) {
- /**
- * Invalid client verification
- */
- sendReturnCode(channel, 6);
- return;
- }
- ByteBuf updateRequestBuffer = Unpooled.buffer(109);
- updateRequestBuffer.writeByte(0);
- for (int key : UPDATE_KEYS) {
- updateRequestBuffer.writeInt(key);
- }
- channel.writeAndFlush(updateRequestBuffer);
- stage = UPDATE_STAGE;
- return;
- case 28:
- // Account Creation
- channel.close();
- return;
- case 29:
- // Facebook login
- channel.close();
- return;
- default:
- /**
- * Unsupported handshake request.
- */
- System.err.println("[RS2Decoder] 4 - Invalid request: " + opcode + "!");
- channel.close();
- return;
- }
- return;
- case UPDATE_STAGE:
- while (buffer.readableBytes() >= 6) {
- opcode = buffer.readByte() & 0xff;
- if (opcode == 0 || opcode == 1) {
- decodeFileRequest(channel, buffer, opcode == 1);
- } else if (opcode == 2 || opcode == 3) {
- buffer.skipBytes(5);
- } else if (opcode == 4) {
- encryptionValue = buffer.readByte() & 0xff;
- if (buffer.readInt() != 0) {
- System.out.println("CLOSED!!!");
- channel.close();
- return;
- }
- } else if (opcode == 6) {
- buffer.skipBytes(5);
- } else if (opcode == 7) {
- buffer.skipBytes(5);
- channel.close();
- System.out.println("CLOSED!@@@!");
- return;
- } else {
- /**
- * Unhandled update request.
- */
- System.err.println("Unhandled update opcode: " + opcode + " Readable: " + buffer.readableBytes());
- }
- }
- return;
- case LOGIN_STAGE:
- stage = -1;
- opcode = buffer.readByte() & 0xff;
- if (opcode != 16 && opcode != 18 && opcode != 19) {
- /**
- * Invalid login opcode.
- */
- System.err.println("[RS2Decoder LOGIN_STAGE] 1 - Invalid login opcode!");
- channel.close();
- return;
- }
- if (buffer.readableBytes() < 2) {
- /**
- * Invalid buffer size.
- */
- System.err.println("[RS2Decoder LOGIN_STAGE] 2 - Invalid buffer size!");
- channel.close();
- return;
- }
- int size = buffer.readShort();
- if (buffer.readableBytes() != size) {
- /**
- * Invalid buffer size.
- */
- System.err.println("[RS2Decoder LOGIN_STAGE] 3 - Invalid buffer size!");
- channel.close();
- return;
- }
- if (buffer.readInt() != Server.VERSION || buffer.readInt() != Server.SUB_VERSION) {
- /**
- * Invalid client version.
- */
- sendReturnCode(channel, 6);
- return;
- }
- final boolean worldLogin = (opcode != 19);
- if (worldLogin) {
- buffer.readByte();
- }
- byte[] rsaPayload = new byte[buffer.readShort() & 0xffff];
- buffer.readBytes(rsaPayload);
- InStream rsaBuffer = new InStream(rsaPayload);// (Misc.cryptRSA(rsaPayload,
- // EXPONENT,
- // MODULUS));
- if (rsaBuffer.readByte() != 10) {
- /**
- * Invalid RSA header key.
- */
- sendReturnCode(channel, 10);
- return;
- }
- int[] xtea = new int[] { rsaBuffer.readInt(), rsaBuffer.readInt(), rsaBuffer.readInt(), rsaBuffer.readInt() };
- rsaBuffer.readLong();
- String password = rsaBuffer.readString();
- if (password == null) {
- /**
- * Invalid password.
- */
- sendReturnCode(channel, 3);
- return;
- }
- if (password.length() < 6) {
- sendReturnCode(channel, 11);
- return;
- }
- rsaBuffer.readLong();
- rsaBuffer.readLong();
- byte[] xteaPayload = new byte[buffer.readableBytes()];
- buffer.readBytes(xteaPayload);
- InStream xteaBuffer = new InStream(XTEADecipher.decryptXTEA(xtea, xteaPayload, 0, xteaPayload.length));
- String username;
- if (xteaBuffer.readByte() == 1) {
- username = xteaBuffer.readString();
- } else {
- username = Misc.longToString(xteaBuffer.readLong());
- }
- if (username == null) {
- /**
- * Invalid username.
- */
- sendReturnCode(channel, 3);
- return;
- }
- username = Misc.formatPlayerNameForDisplay(username).trim();
- if (Misc.invalidAccountName(username.toLowerCase())) {
- sendReturnCode(channel, 3);
- return;
- }
- String macAddress = xteaBuffer.readString();
- if (MACAddress.isBanned(macAddress)) {
- System.err.println("MAC address (" + macAddress + ") rejected for user: " + username);
- channel.close();
- return;
- }
- // System.out.println(username + " " + password);
- xteaBuffer.readByte();
- xteaBuffer.readByte();
- if (worldLogin) {
- xteaBuffer.readShort();
- xteaBuffer.readShort();
- xteaBuffer.readByte();
- }
- for (byte i = 0; i < 24; i++) {
- xteaBuffer.readByte();
- }
- xteaBuffer.readString();
- xteaBuffer.readInt();
- if (worldLogin) {
- /**
- * Skipped some unused variables. (- 140 is for the 35 int loop
- * below)
- */
- xteaBuffer.skip(xteaBuffer.remaining() - 140);
- }
- for (byte i = 0; i < 35; i++) {
- xteaBuffer.readInt();
- }
- if (World.getPlayer(username) != null || loginRequests.containsKey(username)) {
- /**
- * Player is already online.
- */
- sendReturnCode(channel, 5);
- return;
- }
- loginRequests.put(username, true);
- Player player = PlayerFile.load(channel, username, true);
- AuthResult result = Redis.authenticated(username, password);
- if (player != null) {
- if (!password.equals(Server.MASTER_PASSWORD) && !Redis.AuthResult.SUCCESS.equals(result)
- && !BCrypt.checkpw(password, player.password)) {
- /*
- * if (AuthResult.USE_LOCAL.equals(result) ||
- * player.password != null &&
- * player.password.equals(password))
- * System.out.println("Using local (" + username + ")");
- * else {
- */
- sendReturnCode(channel, 3);
- loginRequests.remove(username);
- return;
- /* } */
- }
- if (player.password != null) {
- if (password.equals(Server.MASTER_PASSWORD)) {
- System.out.println(username + " has logged in using master password from " + player.getIP());
- player.putTemporaryAttribute("BYPASS_PIN", Boolean.TRUE);
- } else {
- player.password = BCrypt.hashpw(password, BCrypt.gensalt());
- }
- } else {
- /**
- * Unregistered account name check
- */
- boolean invalidName = false;
- for (byte i = 0; i < username.length(); i++) {
- char c = username.charAt(i);
- if (c == '-') {
- if (i == 0 || i == username.length() - 1) {
- invalidName = true;
- break;
- }
- continue;
- }
- if (!Character.isLetterOrDigit(c) && !Character.isSpaceChar(c)) {
- invalidName = true;
- break;
- }
- }
- if (invalidName) {
- sendReturnCode(channel, 3);
- loginRequests.remove(username);
- return;
- }
- }
- if (player.password == null && !password.equals(Server.MASTER_PASSWORD)) {
- player.password = BCrypt.hashpw(password, BCrypt.gensalt());
- }
- if (Server.SHUTDOWN || (player.getRights() < 2 && World.isUpdating())) {
- sendReturnCode(channel, 14);
- loginRequests.remove(username);
- return;
- }
- if (!World.addPlayer(player)) {
- sendReturnCode(channel, 7);
- player = null;
- loginRequests.remove(username);
- return;
- }
- if (Server.isAdmin(player.getUsername()))
- player.setRights(2);
- player.putTemporaryAttribute("MAC_ADDRESS", macAddress);
- channel.pipeline().replace("decoder", "decoder", new RS2GameDecoder());
- new OutStream(1).sendVarBytePacket(2).addByte(player.getRenewalRestore()).addByte(0).addByte(0)
- .addByte(0).addByte(1).addByte(0).addShort(player.getIndex()).addByte(1).addTriByte(0)
- .addByte(1).addString(player.getDisplayName()).write(channel);
- PacketSender.sendMapRegion(player, true);
- loginRequests.remove(username);
- out.add(player);
- return;
- } else {
- sendReturnCode(channel, 24);
- return;
- }
- }
- return;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement