package cc.blynk.server.application.handlers.sharing.auth; import cc.blynk.server.Holder; import cc.blynk.server.application.handlers.main.auth.AppLoginHandler; import cc.blynk.server.application.handlers.main.auth.GetServerHandler; import cc.blynk.server.application.handlers.main.auth.OsType; import cc.blynk.server.application.handlers.main.auth.RegisterHandler; import cc.blynk.server.application.handlers.sharing.AppShareHandler; import cc.blynk.server.core.dao.SharedTokenValue; import cc.blynk.server.core.model.DashBoard; import cc.blynk.server.core.model.auth.Session; import cc.blynk.server.core.model.auth.User; import cc.blynk.server.core.protocol.model.messages.appllication.sharing.ShareLoginMessage; import cc.blynk.server.handlers.DefaultReregisterHandler; import cc.blynk.server.handlers.common.UserNotLoggedHandler; import io.netty.channel.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import static cc.blynk.server.core.protocol.enums.Response.ILLEGAL_COMMAND; import static cc.blynk.server.core.protocol.enums.Response.NOT_ALLOWED; import static cc.blynk.utils.BlynkByteBufUtil.makeResponse; import static cc.blynk.utils.BlynkByteBufUtil.ok; /** * Handler responsible for managing apps sharing login messages. * * The Blynk Project. * Created by Dmitriy Dumanskiy. * Created on 2/1/2015. * */ @ChannelHandler.Sharable public class AppShareLoginHandler extends SimpleChannelInboundHandler<ShareLoginMessage> implements DefaultReregisterHandler { private static final Logger log = LogManager.getLogger(AppShareLoginHandler.class); private final Holder holder; public AppShareLoginHandler(Holder holder) { this.holder = holder; } @Override protected void channelRead0(ChannelHandlerContext ctx, ShareLoginMessage message) throws Exception { //warn: split may be optimized String[] messageParts = message.body.split("\0"); if (messageParts.length < 2) { log.error("Wrong income message format."); ctx.writeAndFlush(makeResponse(message.id, ILLEGAL_COMMAND), ctx.voidPromise()); } else { OsType osType = null; String version = null; String uid = null; if (messageParts.length > 3) { osType = OsType.parse(messageParts[2]); version = messageParts[3]; } if (messageParts.length == 5) { uid = messageParts[4]; } appLogin(ctx, message.id, messageParts[0], messageParts[1], osType, version, uid); } } private void appLogin(ChannelHandlerContext ctx, int messageId, String email, String token, OsType osType, String version, String uid) { String userName = email.toLowerCase(); SharedTokenValue tokenValue = holder.tokenManager.getUserBySharedToken(token); if (tokenValue == null || !tokenValue.user.email.equals(userName)) { log.debug("Share token is invalid. User : {}, token {}, {}", userName, token, ctx.channel().remoteAddress()); ctx.writeAndFlush(makeResponse(messageId, NOT_ALLOWED), ctx.voidPromise()); return; } final User user = tokenValue.user; final int dashId = tokenValue.dashId; DashBoard dash = user.profile.getDashById(dashId); if (!dash.isShared) { log.debug("Dashboard is not shared. User : {}, token {}, {}", userName, token, ctx.channel().remoteAddress()); ctx.writeAndFlush(makeResponse(messageId, NOT_ALLOWED), ctx.voidPromise()); return; } cleanPipeline(ctx.pipeline()); AppShareStateHolder appShareStateHolder = new AppShareStateHolder(user, osType, version, token, dashId); ctx.pipeline().addLast("AAppSHareHandler", new AppShareHandler(holder, appShareStateHolder)); Session session = holder.sessionDao.getOrCreateSessionByUser(appShareStateHolder.userKey, ctx.channel().eventLoop()); if (session.initialEventLoop != ctx.channel().eventLoop()) { log.debug("Re registering app channel. {}", ctx.channel()); reRegisterChannel(ctx, session, channelFuture -> completeLogin(channelFuture.channel(), session, user.email, messageId)); } else { completeLogin(ctx.channel(), session, user.email, messageId); } } private void completeLogin(Channel channel, Session session, String userName, int msgId) { session.addAppChannel(channel); channel.writeAndFlush(ok(msgId), channel.voidPromise()); log.info("Shared {} app joined.", userName); } private void cleanPipeline(ChannelPipeline pipeline) { pipeline.remove(this); pipeline.remove(UserNotLoggedHandler.class); pipeline.remove(RegisterHandler.class); pipeline.remove(AppLoginHandler.class); pipeline.remove(GetServerHandler.class); } }