Initial Commit

This commit is contained in:
samnyan
2020-01-16 00:50:52 +09:00
commit 89771b7b51
331 changed files with 32076 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
package icu.samnyan.aqua.sega.aimedb;
import icu.samnyan.aqua.sega.aimedb.exception.InvalidRequestException;
import icu.samnyan.aqua.sega.aimedb.util.Encryption;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class AimeDbDecoder extends ByteToMessageDecoder {
private static final Logger logger = LoggerFactory.getLogger(AimeDbDecoder.class);
private int length = 0;
/**
* Decrypt the incoming request including frame management
*
* @param ctx
* @param in
* @param out
* @throws Exception
*/
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
if (in.readableBytes() < 16) {
return;
}
if (length == 0) {
length = getLength(in);
}
if (in.readableBytes() < length) {
return;
}
// Create a byte array to store the encrypted data
ByteBuf result = Encryption.decrypt(in.readBytes(length));
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("type", ((Short) result.getShortLE(0x04)).intValue());
resultMap.put("data", result);
logger.debug("Aime Server Request Type: " + resultMap.get("type"));
out.add(resultMap);
}
/**
* Get the length from request
*
* @param in the request
* @return int the length of this request
* @throws InvalidRequestException
* @throws IllegalBlockSizeException
* @throws InvalidKeyException
* @throws BadPaddingException
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
*/
private int getLength(ByteBuf in) throws InvalidRequestException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
int currentPos = in.readerIndex();
ByteBuf result = Encryption.decrypt(in);
// Check the header
if (result.getByte(0) != 0x3e) {
throw new InvalidRequestException();
}
// Read the length from offset 6
return result.getShortLE(currentPos + 6);
}
}

View File

@@ -0,0 +1,32 @@
package icu.samnyan.aqua.sega.aimedb;
import icu.samnyan.aqua.sega.aimedb.util.Encryption;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class AimeDbEncoder extends MessageToByteEncoder {
@Override
protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {
if (msg instanceof ByteBuf) {
ByteBuf resp = ((ByteBuf) msg);
resp.writerIndex(0);
resp.writeShortLE(0xa13e);
resp.writeShortLE(0x3087);
resp.setShortLE(0x0006, resp.capacity());
ByteBuf encryptedResp = Encryption.encrypt(resp);
ctx.writeAndFlush(encryptedResp);
}
}
}

View File

@@ -0,0 +1,96 @@
package icu.samnyan.aqua.sega.aimedb;
import icu.samnyan.aqua.sega.aimedb.handler.Impl.*;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
@Scope("prototype")
public class AimeDbRequestHandler extends ChannelInboundHandlerAdapter {
private static final Logger logger = LoggerFactory.getLogger(AimeDbRequestHandler.class);
private final CampaignHandler campaignHandler;
private final FeliCaLookupHandler feliCaLookupHandler;
private final GoodbyeHandler goodbyeHandler;
private final HelloHandler helloHandler;
private final LogHandler logHandler;
private final LookupHandler lookupHandler;
private final Lookup2Handler lookup2Handler;
private final RegisterHandler registerHandler;
@Autowired
public AimeDbRequestHandler(CampaignHandler campaignHandler, FeliCaLookupHandler feliCaLookupHandler, GoodbyeHandler goodbyeHandler, HelloHandler helloHandler, LogHandler logHandler, LookupHandler lookupHandler, Lookup2Handler lookup2Handler, RegisterHandler registerHandler) {
this.campaignHandler = campaignHandler;
this.feliCaLookupHandler = feliCaLookupHandler;
this.goodbyeHandler = goodbyeHandler;
this.helloHandler = helloHandler;
this.logHandler = logHandler;
this.lookupHandler = lookupHandler;
this.lookup2Handler = lookup2Handler;
this.registerHandler = registerHandler;
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof Map) {
int type = ((int) ((Map) msg).get("type"));
ByteBuf data = (ByteBuf) ((Map) msg).get("data");
switch (type) {
case 0x0001:
feliCaLookupHandler.handle(ctx, data);
break;
case 0x0004:
lookupHandler.handle(ctx, data);
break;
case 0x0005:
registerHandler.handle(ctx, data);
break;
case 0x0009:
logHandler.handle(ctx, data);
break;
case 0x000b:
campaignHandler.handle(ctx, data);
break;
case 0x000d:
registerHandler.handle(ctx, data);
break;
case 0x000f:
lookup2Handler.handle(ctx, data);
break;
case 0x0064:
helloHandler.handle(ctx, data);
break;
case 0x0066:
goodbyeHandler.handle(ctx, data);
break;
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
super.channelInactive(ctx);
logger.info("Connection closed");
}
}

View File

@@ -0,0 +1,54 @@
package icu.samnyan.aqua.sega.aimedb;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.net.InetSocketAddress;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class AimeDbServer {
private static final Logger logger = LoggerFactory.getLogger(AimeDbServer.class);
private final AimeDbServerInitializer aimeDbServerInitializer;
private final int port;
private final boolean enableAimeDb;
public AimeDbServer(AimeDbServerInitializer aimeDbServerInitializer,
@Value("${aimedb.server.port}") int port,
@Value("${aimedb.server.enable}") boolean enableAimeDb) {
this.aimeDbServerInitializer = aimeDbServerInitializer;
this.port = port;
this.enableAimeDb = enableAimeDb;
}
public void start() throws Exception {
if (enableAimeDb) {
ServerBootstrap bootstrap = new ServerBootstrap();
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup work = new NioEventLoopGroup();
bootstrap.group(boss, work)
.handler(new LoggingHandler(LogLevel.DEBUG))
.channel(NioServerSocketChannel.class)
.childHandler(aimeDbServerInitializer)
.option(ChannelOption.SO_BACKLOG, 128);
ChannelFuture f = bootstrap.bind(new InetSocketAddress(port)).sync();
logger.info("Aime DB start up on port : " + port);
f.channel().closeFuture();
}
}
}

View File

@@ -0,0 +1,50 @@
package icu.samnyan.aqua.sega.aimedb;
import icu.samnyan.aqua.sega.aimedb.handler.Impl.*;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class AimeDbServerInitializer extends ChannelInitializer<SocketChannel> {
private final CampaignHandler campaignHandler;
private final FeliCaLookupHandler feliCaLookupHandler;
private final GoodbyeHandler goodbyeHandler;
private final HelloHandler helloHandler;
private final LogHandler logHandler;
private final LookupHandler lookupHandler;
private final Lookup2Handler lookup2Handler;
private final RegisterHandler registerHandler;
@Autowired
public AimeDbServerInitializer(CampaignHandler campaignHandler, FeliCaLookupHandler feliCaLookupHandler, GoodbyeHandler goodbyeHandler, HelloHandler helloHandler, LogHandler logHandler, LookupHandler lookupHandler, Lookup2Handler lookup2Handler, RegisterHandler registerHandler) {
this.campaignHandler = campaignHandler;
this.feliCaLookupHandler = feliCaLookupHandler;
this.goodbyeHandler = goodbyeHandler;
this.helloHandler = helloHandler;
this.logHandler = logHandler;
this.lookupHandler = lookupHandler;
this.lookup2Handler = lookup2Handler;
this.registerHandler = registerHandler;
}
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("encoder", new AimeDbEncoder());
pipeline.addLast("decoder", new AimeDbDecoder());
pipeline.addLast("handler", new AimeDbRequestHandler(campaignHandler, feliCaLookupHandler, goodbyeHandler, helloHandler, logHandler, lookupHandler, lookup2Handler, registerHandler));
}
}

View File

@@ -0,0 +1,7 @@
package icu.samnyan.aqua.sega.aimedb.exception;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
public class InvalidRequestException extends Exception {
}

View File

@@ -0,0 +1,13 @@
package icu.samnyan.aqua.sega.aimedb.handler;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
public interface BaseHandler {
void handle(ChannelHandlerContext ctx, ByteBuf msg) throws JsonProcessingException;
}

View File

@@ -0,0 +1,53 @@
package icu.samnyan.aqua.sega.aimedb.handler.Impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler;
import icu.samnyan.aqua.sega.aimedb.util.AimeDbUtil;
import icu.samnyan.aqua.sega.aimedb.util.LogMapper;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class CampaignHandler implements BaseHandler {
private static final Logger logger = LoggerFactory.getLogger(CampaignHandler.class);
private final LogMapper logMapper;
@Autowired
public CampaignHandler(LogMapper logMapper) {
this.logMapper = logMapper;
}
@Override
public void handle(ChannelHandlerContext ctx, ByteBuf msg) throws JsonProcessingException {
Map<String, Object> requestMap = AimeDbUtil.getBaseInfo(msg);
requestMap.put("type", "campaign");
logger.info("Request: " + logMapper.write(requestMap));
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("type", "campaign");
resultMap.put("status", 1);
logger.info("Response: " + logMapper.write(resultMap));
ByteBuf respSrc = Unpooled.copiedBuffer(new byte[0x0200]);
respSrc.setShortLE(0x0004, 0x000c);
respSrc.setShortLE(0x0008, (int) resultMap.get("status"));
ctx.writeAndFlush(respSrc);
}
}

View File

@@ -0,0 +1,66 @@
package icu.samnyan.aqua.sega.aimedb.handler.Impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler;
import icu.samnyan.aqua.sega.aimedb.util.AimeDbUtil;
import icu.samnyan.aqua.sega.aimedb.util.LogMapper;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class FeliCaLookupHandler implements BaseHandler {
private static final Logger logger = LoggerFactory.getLogger(FeliCaLookupHandler.class);
private final LogMapper logMapper;
@Autowired
public FeliCaLookupHandler(LogMapper logMapper) {
this.logMapper = logMapper;
}
@Override
public void handle(ChannelHandlerContext ctx, ByteBuf msg) throws JsonProcessingException {
Map<String, Object> requestMap = AimeDbUtil.getBaseInfo(msg);
requestMap.put("type", "felica_lookup");
requestMap.put("idm", msg.slice(0x0020, 0x0028 - 0x0020));
requestMap.put("pmm", msg.slice(0x0028, 0x0030 - 0x0028));
logger.info("Request: " + logMapper.write(requestMap));
// Get the decimal represent of the hex value, same from minime
StringBuilder accessCode = new StringBuilder(String.valueOf(((ByteBuf) requestMap.get("idm")).getLong(0)));
while (accessCode.length() < 20) {
accessCode.insert(0, "0");
}
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("type", "felica_lookup");
resultMap.put("status", 1);
resultMap.put("accessCode", accessCode);
logger.info("Response: " + logMapper.write(resultMap));
ByteBuf respSrc = Unpooled.copiedBuffer(new byte[0x0030]);
respSrc.setShortLE(0x0004, 0x0003);
respSrc.setShortLE(0x0008, (int) resultMap.get("status"));
respSrc.setBytes(0x0024, ByteBufUtil.decodeHexDump(accessCode));
ctx.writeAndFlush(respSrc);
}
}

View File

@@ -0,0 +1,32 @@
package icu.samnyan.aqua.sega.aimedb.handler.Impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class GoodbyeHandler implements BaseHandler {
private static final Logger logger = LoggerFactory.getLogger(GoodbyeHandler.class);
@Override
public void handle(ChannelHandlerContext ctx, ByteBuf msg) throws JsonProcessingException {
Map<String, String> requestMap = new HashMap<>();
requestMap.put("type", "goodbye");
logger.info("Request: " + new ObjectMapper().writeValueAsString(requestMap));
ctx.flush();
}
}

View File

@@ -0,0 +1,53 @@
package icu.samnyan.aqua.sega.aimedb.handler.Impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler;
import icu.samnyan.aqua.sega.aimedb.util.AimeDbUtil;
import icu.samnyan.aqua.sega.aimedb.util.LogMapper;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class HelloHandler implements BaseHandler {
private static final Logger logger = LoggerFactory.getLogger(HelloHandler.class);
private final LogMapper logMapper;
@Autowired
public HelloHandler(LogMapper logMapper) {
this.logMapper = logMapper;
}
@Override
public void handle(ChannelHandlerContext ctx, ByteBuf msg) throws JsonProcessingException {
Map<String, Object> requestMap = AimeDbUtil.getBaseInfo(msg);
requestMap.put("type", "hello");
logger.info("Request: " + logMapper.write(requestMap));
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("type", "hello");
resultMap.put("status", 1);
logger.info("Response: " + logMapper.write(resultMap));
ByteBuf respSrc = Unpooled.copiedBuffer(new byte[0x0020]);
respSrc.setShortLE(0x0004, 0x0065);
respSrc.setShortLE(0x0008, (int) resultMap.get("status"));
ctx.writeAndFlush(respSrc);
}
}

View File

@@ -0,0 +1,54 @@
package icu.samnyan.aqua.sega.aimedb.handler.Impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler;
import icu.samnyan.aqua.sega.aimedb.util.AimeDbUtil;
import icu.samnyan.aqua.sega.aimedb.util.LogMapper;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class LogHandler implements BaseHandler {
private static final Logger logger = LoggerFactory.getLogger(LogHandler.class);
private final LogMapper logMapper;
@Autowired
public LogHandler(LogMapper logMapper) {
this.logMapper = logMapper;
}
@Override
public void handle(ChannelHandlerContext ctx, ByteBuf msg) throws JsonProcessingException {
Map<String, Object> requestMap = AimeDbUtil.getBaseInfo(msg);
requestMap.put("type", "log");
logger.info("Request: " + logMapper.write(requestMap));
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("type", "log");
resultMap.put("status", 1);
logger.info("Response: " + logMapper.write(resultMap));
ByteBuf respSrc = Unpooled.copiedBuffer(new byte[0x0020]);
respSrc.setShortLE(0x0004, 0x000a);
respSrc.setShortLE(0x0008, (int) resultMap.get("status"));
ctx.writeAndFlush(respSrc);
}
}

View File

@@ -0,0 +1,70 @@
package icu.samnyan.aqua.sega.aimedb.handler.Impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler;
import icu.samnyan.aqua.sega.aimedb.util.AimeDbUtil;
import icu.samnyan.aqua.sega.aimedb.util.LogMapper;
import icu.samnyan.aqua.sega.general.dao.CardRepository;
import icu.samnyan.aqua.sega.general.model.Card;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class Lookup2Handler implements BaseHandler {
private static final Logger logger = LoggerFactory.getLogger(Lookup2Handler.class);
private final LogMapper logMapper;
private final CardRepository cardRepository;
@Autowired
public Lookup2Handler(LogMapper logMapper, CardRepository cardRepository) {
this.logMapper = logMapper;
this.cardRepository = cardRepository;
}
@Override
public void handle(ChannelHandlerContext ctx, ByteBuf msg) throws JsonProcessingException {
Map<String, Object> requestMap = AimeDbUtil.getBaseInfo(msg);
requestMap.put("type", "lookup2");
requestMap.put("luid", ByteBufUtil.hexDump(msg.slice(0x0020, 0x002a - 0x0020)));
logger.info("Request: " + logMapper.write(requestMap));
long aimeId = -1;
Optional<Card> card = cardRepository.findByLuid((String) requestMap.get("luid"));
if (card.isPresent()) {
aimeId = card.get().getExtId();
}
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("type", "lookup2");
resultMap.put("status", 1);
resultMap.put("aimeId", aimeId);
resultMap.put("registerLevel", "none");
logger.info("Response: " + logMapper.write(resultMap));
ByteBuf respSrc = Unpooled.copiedBuffer(new byte[0x0130]);
respSrc.setShortLE(0x0004, 0x0010);
respSrc.setShortLE(0x0008, (int) resultMap.get("status"));
respSrc.setLongLE(0x0020, (long) resultMap.get("aimeId"));
respSrc.setByte(0x0024, 0);
ctx.writeAndFlush(respSrc);
}
}

View File

@@ -0,0 +1,29 @@
package icu.samnyan.aqua.sega.aimedb.handler.Impl;
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler;
import icu.samnyan.aqua.sega.aimedb.util.LogMapper;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Mifare Card lookup? idk
*
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class LookupHandler implements BaseHandler {
private final LogMapper logMapper;
@Autowired
public LookupHandler(LogMapper logMapper) {
this.logMapper = logMapper;
}
@Override
public void handle(ChannelHandlerContext ctx, ByteBuf msg) {
}
}

View File

@@ -0,0 +1,72 @@
package icu.samnyan.aqua.sega.aimedb.handler.Impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import icu.samnyan.aqua.sega.aimedb.handler.BaseHandler;
import icu.samnyan.aqua.sega.aimedb.util.AimeDbUtil;
import icu.samnyan.aqua.sega.aimedb.util.LogMapper;
import icu.samnyan.aqua.sega.general.dao.CardRepository;
import icu.samnyan.aqua.sega.general.model.Card;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class RegisterHandler implements BaseHandler {
private static final Logger logger = LoggerFactory.getLogger(RegisterHandler.class);
private final LogMapper logMapper;
private final CardRepository cardRepository;
@Autowired
public RegisterHandler(LogMapper logMapper, CardRepository cardRepository) {
this.logMapper = logMapper;
this.cardRepository = cardRepository;
}
@Override
public void handle(ChannelHandlerContext ctx, ByteBuf msg) throws JsonProcessingException {
Map<String, Object> requestMap = AimeDbUtil.getBaseInfo(msg);
requestMap.put("type", "register");
requestMap.put("luid", ByteBufUtil.hexDump(msg.slice(0x0020, 0x002a - 0x0020)));
logger.info("Request: " + logMapper.write(requestMap));
Card card = new Card();
card.setLuid((String) requestMap.get("luid"));
card.setExtId(ThreadLocalRandom.current().nextLong(99999999));
card.setRegisterTime(LocalDateTime.now());
card.setAccessTime(LocalDateTime.now());
cardRepository.save(card);
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("type", "register");
resultMap.put("status", 1);
resultMap.put("aimeId", card.getExtId());
logger.info("Response: " + logMapper.write(resultMap));
ByteBuf respSrc = Unpooled.copiedBuffer(new byte[0x0030]);
respSrc.setShortLE(0x0004, 0x0006);
respSrc.setShortLE(0x0008, (int) resultMap.get("status"));
respSrc.setLongLE(0x0020, (long) resultMap.get("aimeId"));
ctx.writeAndFlush(respSrc);
}
}

View File

@@ -0,0 +1,20 @@
package icu.samnyan.aqua.sega.aimedb.util;
import io.netty.buffer.ByteBuf;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
public class AimeDbUtil {
public static Map<String, Object> getBaseInfo(ByteBuf in) {
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("gameId", in.toString(0x000a, 0x000e - 0x000a, StandardCharsets.US_ASCII));
resultMap.put("keychipId", in.toString(0x0014, 0x001f - 0x0014, StandardCharsets.US_ASCII));
return resultMap;
}
}

View File

@@ -0,0 +1,41 @@
package icu.samnyan.aqua.sega.aimedb.util;
import icu.samnyan.aqua.sega.util.ByteBufUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
public class Encryption {
private static final Logger logger = LoggerFactory.getLogger(Encryption.class);
private static SecretKeySpec KEY = new SecretKeySpec("Copyright(C)SEGA".getBytes(StandardCharsets.UTF_8), "AES");
public static ByteBuf decrypt(ByteBuf src) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, KEY);
return Unpooled.copiedBuffer(cipher.doFinal(ByteBufUtil.toBytes(src)));
}
public static ByteBuf encrypt(ByteBuf src) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, KEY);
byte[] bytes = cipher.doFinal(ByteBufUtil.toAllBytes(src));
return Unpooled.copiedBuffer(bytes);
}
}

View File

@@ -0,0 +1,29 @@
package icu.samnyan.aqua.sega.aimedb.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import icu.samnyan.aqua.sega.util.jackson.ByteBufSerializer;
import io.netty.buffer.ByteBuf;
import org.springframework.stereotype.Component;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class LogMapper {
private final ObjectMapper mapper;
private final SimpleModule module;
public LogMapper() {
mapper = new ObjectMapper();
module = new SimpleModule();
module.addSerializer(ByteBuf.class, new ByteBufSerializer());
mapper.registerModule(module);
}
public String write(Object o) throws JsonProcessingException {
return mapper.writeValueAsString(o);
}
}