forked from Cookies_Github_mirror/AquaDX
Initial Commit
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
54
src/main/java/icu/samnyan/aqua/sega/aimedb/AimeDbServer.java
Normal file
54
src/main/java/icu/samnyan/aqua/sega/aimedb/AimeDbServer.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package icu.samnyan.aqua.sega.aimedb.exception;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
public class InvalidRequestException extends Exception {
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user