Java tutorial
/* * This file is part of Telegram Server * Copyright (C) 2015 Aykut Alparslan KO * * Telegram Server is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Telegram Server is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.telegram.core; import com.hazelcast.core.IMap; import com.hazelcast.query.SqlPredicate; import io.netty.channel.ChannelHandlerContext; import org.telegram.data.HazelcastConnection; import org.telegram.mtproto.MessageKeyData; import org.telegram.mtproto.ProtocolBuffer; import org.telegram.mtproto.Utilities; import org.telegram.mtproto.secure.CryptoUtils; import org.telegram.server.TelegramServerHandler; import org.telegram.tl.TLObject; import java.util.concurrent.ConcurrentHashMap; /** * Created by aykut on 17/11/15. */ public class Router { IMap<Long, ActiveSession> activeSessions; ConcurrentHashMap<Long, ChannelHandlerContext> channelHandlers = new ConcurrentHashMap<>(); private static Router _instance; private Router() { activeSessions = HazelcastConnection.getInstance().getMap("telegram_active_sessions"); activeSessions.addIndex("phone", true); //activeSessions.addIndex("user_id", true); //activeSessions.addIndex("username", true); } public static Router getInstance() { if (_instance == null) { _instance = new Router(); } return _instance; } public void addActiveSession(ActiveSession session) { activeSessions.set(session.session_id, session); } public void addChannelHandler(long session_id, ChannelHandlerContext ctx) { channelHandlers.put(session_id, ctx); } public ActiveSession getActiveSession(long session_id) { return activeSessions.get(session_id); } public void removeActiveSession(long session_id) { activeSessions.delete(session_id); } public void Route(int user_id, TLObject msg, boolean rpc_response) { for (Object sess : activeSessions.values(new SqlPredicate("user_id = " + user_id)).toArray()) { //for now all sessions are on the same server ChannelHandlerContext ctx = channelHandlers.get(((ActiveSession) sess).session_id); long msg_id = ((TelegramServerHandler) ctx.handler()).generateMessageId(rpc_response); ctx.writeAndFlush(encryptRpc(msg, ((TelegramServerHandler) ctx.handler()).getMessageSeqNo(true), msg_id, ((ActiveSession) sess).session_id, ((ActiveSession) sess).auth_key_id)); } } private ProtocolBuffer encryptRpc(TLObject rpc, int seqNo, long messageId, long session_id, long auth_key_id) { ProtocolBuffer messageBody = rpc.serialize(); int messageSeqNo = seqNo; int len = 8 + 8 + 8 + 4 + 4 + messageBody.length(); int extraLen = 0; while ((len + extraLen) % 16 != 0) { extraLen++; } ProtocolBuffer buffer = new ProtocolBuffer(len + extraLen); buffer.writeLong(ServerSaltStore.getInstance().getServerSalt(auth_key_id)); buffer.writeLong(session_id); buffer.writeLong(messageId); buffer.writeInt(messageSeqNo); buffer.writeInt(messageBody.length()); buffer.write(messageBody.getBytes()); byte[] messageKeyFull = buffer.getSHA1(); byte[] messageKey = new byte[16]; System.arraycopy(messageKeyFull, messageKeyFull.length - 16, messageKey, 0, 16); MessageKeyData keyData = MessageKeyData.generateMessageKeyData( AuthKeyStore.getInstance().getAuthKey(auth_key_id).auth_key, messageKey, true); byte[] b = new byte[extraLen]; Utilities.random.nextBytes(b); buffer.write(b); byte[] dataForEncryption = buffer.getBytes(); byte[] encryptedData = CryptoUtils.AES256IGEEncrypt(dataForEncryption, keyData.aesIv, keyData.aesKey); ProtocolBuffer data = new ProtocolBuffer(8 + messageKey.length + encryptedData.length); data.writeLong(auth_key_id); data.write(messageKey); data.write(encryptedData); return data; } }