Authentication
This commit is contained in:
parent
cd63319aef
commit
4ca446621c
README.md
src/main
java/com/alterdekim/hearthhack
Application.java
component
GamePool.javaGameServer.javaStartupListener.javaTcpConnection.javaTcpServer.java
processor
AuthProcessor.java
client/request/generic
AccountLicensesInfo.javaAvailableFeatures.javaBoosters.javaCardBacks.javaCardValues.javaClientOptions.javaCollection.javaDeckList.javaDustBalance.javaFavoriteHeroes.javaGeneralGenericParser.javaGenericParser.javaGoldBalance.javaHeroXP.javaMedalInfo.javaNotSoMassiveLoginReply.javaPlayQueue.javaPlayerRecords.javaProfileNotices.javaProfileProgress.javaRewardProgress.java
config
controller
dto
entity
exception
handler
parser
repository
security
service
util
resources
static/css
templates
7
README.md
Normal file
7
README.md
Normal file
@ -0,0 +1,7 @@
|
||||
<h1 align="center">Hearthhack</h1>
|
||||
<p align="center"><i>A hearthstone server software project</i></p>
|
||||
<div align="center">
|
||||
<a href="stargazers"><img src="https://img.shields.io/github/stars/" alt="Stars Badge"/></a>
|
||||
<a href="blob/master/LICENSE"><img src="https://img.shields.io/github/license/?color=2b9348" alt="License Badge"/></a>
|
||||
</div>
|
||||
<p align="center" style="font-size:0.8em;">Loved the project?<br><a href="https://www.getmonero.org/">XMR</a>: <a href=""></a></p>
|
@ -1,6 +1,8 @@
|
||||
package com.alterdekim.hearthhack;
|
||||
|
||||
|
||||
import com.alterdekim.hearthhack.service.StorageService;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@ -15,4 +17,11 @@ public class Application {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
CommandLineRunner init(StorageService storageService) {
|
||||
return (args) -> {
|
||||
storageService.init();
|
||||
};
|
||||
}
|
||||
}
|
@ -1,18 +1,14 @@
|
||||
package com.alterdekim.hearthhack.component;
|
||||
|
||||
import com.alterdekim.hearthhack.entity.RoomPlayer;
|
||||
import com.alterdekim.hearthhack.entity.User;
|
||||
import com.alterdekim.hearthhack.service.RoomPlayerService;
|
||||
import com.alterdekim.hearthhack.service.RoomService;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
import com.alterdekim.hearthhack.util.Hash;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.alterdekim.hearthhack.component;
|
||||
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@ -14,15 +16,19 @@ import java.util.List;
|
||||
@Component
|
||||
public class GameServer {
|
||||
|
||||
private final int port = 3724;
|
||||
private int port;
|
||||
|
||||
private ServerSocket serverSocket;
|
||||
|
||||
private List<GameConnection> connections;
|
||||
|
||||
@Autowired
|
||||
private ServerConfig serverConfig;
|
||||
|
||||
@Scheduled(fixedDelay = 5000)
|
||||
private void start() {
|
||||
try {
|
||||
this.port = serverConfig.getGamePort();
|
||||
this.connections = new LinkedList<>();
|
||||
this.serverSocket = new ServerSocket(this.port);
|
||||
while(true) {
|
||||
|
@ -0,0 +1,42 @@
|
||||
package com.alterdekim.hearthhack.component;
|
||||
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.parser.DBFParser;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class StartupListener {
|
||||
|
||||
@Autowired
|
||||
private DBFConfig dbfConfig;
|
||||
|
||||
@Autowired
|
||||
private ServerConfig serverConfig;
|
||||
|
||||
@EventListener
|
||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
try {
|
||||
dbfConfig.setCards(DBFParser.parseCards(serverConfig.getDbfPath()));
|
||||
dbfConfig.setClientConfig(
|
||||
new String(
|
||||
Files.readAllBytes(
|
||||
Path.of(
|
||||
serverConfig.getClientConfigPath()
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package com.alterdekim.hearthhack.component;
|
||||
|
||||
import com.alterdekim.hearthhack.component.processor.*;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
import com.alterdekim.hearthhack.util.BattleNetPacket;
|
||||
@ -11,6 +12,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Map;
|
||||
@ -29,13 +31,18 @@ public class TcpConnection extends Thread {
|
||||
private final Map<Integer, Processor> processors;
|
||||
|
||||
@Getter
|
||||
private final ServerConfig serverConfig;
|
||||
private final DBFConfig dbfConfig;
|
||||
|
||||
@Getter
|
||||
private final UserService userService;
|
||||
|
||||
public void stopListeningAndDisconnect() {
|
||||
log.warn("Tried to stopListening");
|
||||
try {
|
||||
this.fromClient.close();
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void send(BattleNetPacket bp) throws Exception {
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component;
|
||||
|
||||
|
||||
import com.alterdekim.hearthhack.component.processor.Processor;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.reflect.ReflectionLoader;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
@ -22,11 +23,14 @@ import java.util.Set;
|
||||
@Component
|
||||
public class TcpServer extends ReflectionLoader<Processor> {
|
||||
|
||||
private final int socketPort = 1119;
|
||||
private int socketPort;
|
||||
|
||||
private SSLServerSocket serverSocket;
|
||||
private List<TcpConnection> connections;
|
||||
|
||||
@Autowired
|
||||
private DBFConfig dbfConfig;
|
||||
|
||||
@Autowired
|
||||
private ServerConfig serverConfig;
|
||||
|
||||
@ -36,6 +40,7 @@ public class TcpServer extends ReflectionLoader<Processor> {
|
||||
@Scheduled(fixedDelay = 5000)
|
||||
private void start() {
|
||||
try {
|
||||
this.socketPort = serverConfig.getBnetPort();
|
||||
this.initReflect(Processor.class);
|
||||
if( serverSocket != null && !serverSocket.isClosed() ) {
|
||||
serverSocket.close();
|
||||
@ -51,7 +56,7 @@ public class TcpServer extends ReflectionLoader<Processor> {
|
||||
|
||||
while(true) {
|
||||
SSLSocket s = (SSLSocket) serverSocket.accept();
|
||||
TcpConnection c = new TcpConnection(s, this.getParsers(), serverConfig, userService);
|
||||
TcpConnection c = new TcpConnection(s, this.getParsers(), dbfConfig, userService);
|
||||
connections.add(c);
|
||||
c.start();
|
||||
log.info("New Connection Established From {}", s.getInetAddress().toString());
|
||||
|
@ -70,9 +70,11 @@ public class AuthProcessor extends Processor {
|
||||
private void verifyWebCredentials(BattleNetPacket packet, TcpConnection conn) throws Exception {
|
||||
Protocol.VerifyWebCredentialsRequest verifyWebCredentialsRequest
|
||||
= Protocol.VerifyWebCredentialsRequest.parseFrom(packet.getBody());
|
||||
log.info( new String( verifyWebCredentialsRequest.getWebCredentials().toByteArray() ) );
|
||||
|
||||
String token = new String( verifyWebCredentialsRequest.getWebCredentials().toByteArray() );
|
||||
log.info(token);
|
||||
|
||||
if( !conn.getUserService().authMe(token) ) conn.stopListeningAndDisconnect();
|
||||
|
||||
Protocol.Header h = Processor.generateResponse(0, packet.getHeader().getToken(), 0, 0);
|
||||
|
||||
@ -99,9 +101,6 @@ public class AuthProcessor extends Processor {
|
||||
.build();
|
||||
|
||||
conn.send(new BattleNetPacket(h, Util.hexStringToByteArray("0800")));
|
||||
|
||||
// THIRD
|
||||
//Protocol.LogonResult lr = Protocol.LogonResult.parseFrom(Util.hexStringToByteArray("080012120900000000000000011193710E1A000000001A12094743545702000002116739AB040000000022002801280228032806286230023A0F517569726B794F72632332393638384202534B4A40AA15061771938C7790CDA59BD500BF2AA3205912148098F8B68ADA802F1122B2792D90FA2952A338032A03895322DD02C4E2F3CFE6CD72415466B3798C9ADB015000"));
|
||||
|
||||
Protocol.LogonResult logonResult = Protocol.LogonResult.newBuilder()
|
||||
.setErrorCode(0)
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
import com.alterdekim.hearthhack.util.BattleNetPacket;
|
||||
@ -13,7 +14,7 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.ACCOUNT_LICEN
|
||||
public class AccountLicensesInfo extends GenericParser {
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {}
|
||||
public void setResources(IService service, DBFConfig config) {}
|
||||
|
||||
@Override
|
||||
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
import com.alterdekim.hearthhack.util.BattleNetPacket;
|
||||
@ -16,7 +17,7 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.FEATURES;
|
||||
@Slf4j
|
||||
public class AvailableFeatures extends GenericParser {
|
||||
|
||||
private ServerConfig config;
|
||||
private DBFConfig config;
|
||||
private Executor executor;
|
||||
|
||||
private void executeFeatures(TcpConnection conn) throws Exception {
|
||||
@ -40,7 +41,7 @@ public class AvailableFeatures extends GenericParser {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {
|
||||
public void setResources(IService service, DBFConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
@ -14,11 +15,11 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.BOOSTERS;
|
||||
|
||||
public class Boosters extends GenericParser {
|
||||
|
||||
private ServerConfig config;
|
||||
private DBFConfig config;
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {
|
||||
public void setResources(IService service, DBFConfig config) {
|
||||
this.config = config;
|
||||
this.userService = (UserService) service;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
import com.alterdekim.hearthhack.util.BattleNetPacket;
|
||||
@ -12,10 +13,10 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.CARD_BACKS;
|
||||
|
||||
public class CardBacks extends GenericParser {
|
||||
|
||||
private ServerConfig config;
|
||||
private DBFConfig config;
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {
|
||||
public void setResources(IService service, DBFConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
|
8
src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/CardValues.java
8
src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/CardValues.java
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.dbf.CardsDBF;
|
||||
import com.alterdekim.hearthhack.dbf.DBFField;
|
||||
@ -21,17 +22,16 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.CARD_VALUES;
|
||||
@Slf4j
|
||||
public class CardValues extends GenericParser {
|
||||
|
||||
private ServerConfig config;
|
||||
private DBFConfig config;
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {
|
||||
public void setResources(IService service, DBFConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parseGenericRequest(int token, TcpConnection conn) throws Exception {
|
||||
|
||||
CardsDBF cards = DBFParser.parseCards(config.getDbfPath());
|
||||
CardsDBF cards = config.getCards();
|
||||
Protocol.CardValues.Builder cardVals = Protocol.CardValues.newBuilder();
|
||||
|
||||
cards.getRecords().forEach(c -> {
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
import com.alterdekim.hearthhack.util.BattleNetPacket;
|
||||
@ -12,10 +13,10 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.CLIENT_OPTION
|
||||
|
||||
public class ClientOptions extends GenericParser {
|
||||
|
||||
private ServerConfig config;
|
||||
private DBFConfig config;
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {
|
||||
public void setResources(IService service, DBFConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
|
5
src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/Collection.java
5
src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/Collection.java
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
@ -13,11 +14,11 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.COLLECTION;
|
||||
|
||||
public class Collection extends GenericParser {
|
||||
|
||||
private ServerConfig config;
|
||||
private DBFConfig config;
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {
|
||||
public void setResources(IService service, DBFConfig config) {
|
||||
this.config = config;
|
||||
this.userService = (UserService) service;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
@ -13,11 +14,11 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.DECK_LIST;
|
||||
|
||||
public class DeckList extends GenericParser {
|
||||
|
||||
private ServerConfig config;
|
||||
private DBFConfig config;
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {
|
||||
public void setResources(IService service, DBFConfig config) {
|
||||
this.userService = (UserService) service;
|
||||
this.config = config;
|
||||
}
|
||||
|
5
src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/DustBalance.java
5
src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/DustBalance.java
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
@ -13,11 +14,11 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.ARCANE_DUST_B
|
||||
|
||||
public class DustBalance extends GenericParser {
|
||||
|
||||
private ServerConfig config;
|
||||
private DBFConfig config;
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {
|
||||
public void setResources(IService service, DBFConfig config) {
|
||||
this.userService = (UserService) service;
|
||||
this.config = config;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
@ -14,10 +15,10 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.FAVORITE_HERO
|
||||
public class FavoriteHeroes extends GenericParser {
|
||||
|
||||
private UserService userService;
|
||||
private ServerConfig config;
|
||||
private DBFConfig config;
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {
|
||||
public void setResources(IService service, DBFConfig config) {
|
||||
this.config = config;
|
||||
this.userService = (UserService) service;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ public class GeneralGenericParser extends ReflectionLoader<GenericParser> {
|
||||
}
|
||||
try {
|
||||
GenericParser parser = this.getParsers().get(req.getValue());
|
||||
parser.setResources(conn.getUserService(), conn.getServerConfig());
|
||||
parser.setResources(conn.getUserService(), conn.getDbfConfig());
|
||||
parser.parseGenericRequest(token, conn);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.reflect.AbstractParser;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
@ -16,7 +17,7 @@ import static com.alterdekim.hearthhack.util.GameUtilities.generateNotification;
|
||||
@NoArgsConstructor
|
||||
public abstract class GenericParser implements AbstractParser {
|
||||
|
||||
public abstract void setResources(IService service, ServerConfig config);
|
||||
public abstract void setResources(IService service, DBFConfig config);
|
||||
|
||||
public abstract void parseGenericRequest(int token, TcpConnection conn) throws Exception;
|
||||
|
||||
|
5
src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/GoldBalance.java
5
src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/GoldBalance.java
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
@ -13,11 +14,11 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.GOLD_BALANCE;
|
||||
|
||||
public class GoldBalance extends GenericParser {
|
||||
|
||||
private ServerConfig config;
|
||||
private DBFConfig config;
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {
|
||||
public void setResources(IService service, DBFConfig config) {
|
||||
this.config = config;
|
||||
this.userService = (UserService) service;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
@ -13,11 +14,11 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.HERO_XP;
|
||||
|
||||
public class HeroXP extends GenericParser {
|
||||
|
||||
private ServerConfig config;
|
||||
private DBFConfig config;
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {
|
||||
public void setResources(IService service, DBFConfig config) {
|
||||
this.config = config;
|
||||
this.userService = (UserService) service;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
@ -13,11 +14,11 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.MEDAL_INFO;
|
||||
|
||||
public class MedalInfo extends GenericParser {
|
||||
|
||||
private ServerConfig config;
|
||||
private DBFConfig config;
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {
|
||||
public void setResources(IService service, DBFConfig config) {
|
||||
this.userService = (UserService) service;
|
||||
this.config = config;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
@ -13,11 +14,11 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.NOT_SO_MASSIV
|
||||
|
||||
public class NotSoMassiveLoginReply extends GenericParser {
|
||||
|
||||
private ServerConfig config;
|
||||
private DBFConfig config;
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {
|
||||
public void setResources(IService service, DBFConfig config) {
|
||||
this.userService = (UserService) service;
|
||||
this.config = config;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
@ -15,11 +16,11 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.PVP_QUEUE;
|
||||
@Slf4j
|
||||
public class PlayQueue extends GenericParser {
|
||||
|
||||
private ServerConfig config;
|
||||
private DBFConfig config;
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {
|
||||
public void setResources(IService service, DBFConfig config) {
|
||||
this.config = config;
|
||||
this.userService = (UserService) service;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
@ -13,11 +14,11 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.PLAYER_RECORD
|
||||
|
||||
public class PlayerRecords extends GenericParser {
|
||||
|
||||
private ServerConfig config;
|
||||
private DBFConfig config;
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {
|
||||
public void setResources(IService service, DBFConfig config) {
|
||||
this.config = config;
|
||||
this.userService = (UserService) service;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
@ -22,7 +23,7 @@ public class ProfileNotices extends GenericParser {
|
||||
|
||||
private Executor executor;
|
||||
private UserService userService;
|
||||
private ServerConfig config;
|
||||
private DBFConfig config;
|
||||
|
||||
private void sendNotices(TcpConnection conn) throws Exception {
|
||||
Protocol.ProfileNotices notices = Protocol.ProfileNotices.newBuilder()
|
||||
@ -43,7 +44,7 @@ public class ProfileNotices extends GenericParser {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {
|
||||
public void setResources(IService service, DBFConfig config) {
|
||||
this.config = config;
|
||||
this.userService = (UserService) service;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
@ -14,10 +15,10 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.CAMPAIGN_INFO
|
||||
public class ProfileProgress extends GenericParser {
|
||||
|
||||
private UserService userService;
|
||||
private ServerConfig config;
|
||||
private DBFConfig config;
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {
|
||||
public void setResources(IService service, DBFConfig config) {
|
||||
this.userService = (UserService) service;
|
||||
this.config = config;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.hearthhack.component.processor.client.request.generic;
|
||||
|
||||
import com.alterdekim.Protocol;
|
||||
import com.alterdekim.hearthhack.component.TcpConnection;
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.service.IService;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
@ -14,10 +15,10 @@ import static com.alterdekim.hearthhack.util.GetAccountInfoRequest.REWARD_PROGRE
|
||||
public class RewardProgress extends GenericParser {
|
||||
|
||||
private UserService userService;
|
||||
private ServerConfig config;
|
||||
private DBFConfig config;
|
||||
|
||||
@Override
|
||||
public void setResources(IService service, ServerConfig config) {
|
||||
public void setResources(IService service, DBFConfig config) {
|
||||
this.userService = (UserService) service;
|
||||
this.config = config;
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
package com.alterdekim.hearthhack.config;
|
||||
|
||||
import com.alterdekim.hearthhack.dbf.CardsDBF;
|
||||
import lombok.Data;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Data
|
||||
@Configuration
|
||||
public class DBFConfig {
|
||||
private CardsDBF cards;
|
||||
private String clientConfig;
|
||||
}
|
@ -8,4 +8,8 @@ import org.springframework.context.annotation.Configuration;
|
||||
@Configuration
|
||||
public class ServerConfig {
|
||||
@Value("${hearthhack.dbf_path}") private String dbfPath;
|
||||
@Value("${hearthhack.client_config_template}") private String clientConfigPath;
|
||||
@Value("${hearthhack.bnet_port}") private Integer bnetPort;
|
||||
@Value("${hearthhack.game_port}") private Integer gamePort;
|
||||
@Value("${hearthhack.host}") private String host;
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
package com.alterdekim.hearthhack.config;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@ConfigurationProperties("storage")
|
||||
public class StorageProperties {
|
||||
private String location = "static";
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.alterdekim.hearthhack.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.thymeleaf.extras.springsecurity6.dialect.SpringSecurityDialect;
|
||||
|
||||
@Configuration
|
||||
public class ThymeleafConfig {
|
||||
@Bean
|
||||
public SpringSecurityDialect springSecurityDialect(){
|
||||
return new SpringSecurityDialect();
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.alterdekim.hearthhack.controller;
|
||||
|
||||
import com.alterdekim.hearthhack.entity.User;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
@Slf4j
|
||||
@Controller
|
||||
public class AdminController {
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@GetMapping("/panel")
|
||||
public String adminPanel(Model model) {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if( authentication.isAuthenticated() ) {
|
||||
try {
|
||||
User u = userService.findByUsername(((org.springframework.security.core.userdetails.User) authentication.getPrincipal()).getUsername());
|
||||
if( !u.getRoles().get(0).getName().equals("ROLE_ADMIN") ) {
|
||||
return "redirect:/";
|
||||
}
|
||||
return "panel";
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
return "redirect:/";
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package com.alterdekim.hearthhack.controller;
|
||||
|
||||
import com.alterdekim.hearthhack.dto.UserDTO;
|
||||
import com.alterdekim.hearthhack.entity.User;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
||||
@Controller
|
||||
public class AuthController {
|
||||
|
||||
private final String base_title = " | Hearthhack";
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@GetMapping("/login")
|
||||
public String loginPage(Model model) {
|
||||
model.addAttribute("title", "Login" + base_title);
|
||||
return "login";
|
||||
}
|
||||
|
||||
@GetMapping("/signup")
|
||||
public String showRegistrationForm(Model model) {
|
||||
UserDTO userDto = new UserDTO();
|
||||
model.addAttribute("title", "Signup" + base_title);
|
||||
model.addAttribute("user", userDto);
|
||||
return "signup";
|
||||
}
|
||||
|
||||
@PostMapping("/signup")
|
||||
public String registration(
|
||||
@ModelAttribute("user") @Valid UserDTO userDto,
|
||||
BindingResult result,
|
||||
Model model) {
|
||||
User existingUser = userService.findByUsername(userDto.getUsername());
|
||||
|
||||
if(existingUser != null && existingUser.getUsername() != null && !existingUser.getUsername().isEmpty() ){
|
||||
result.rejectValue("username", null,
|
||||
"There is already an account registered with the same username");
|
||||
return "redirect:/signup?error=already_exists";
|
||||
}
|
||||
|
||||
if(result.hasErrors()) {
|
||||
model.addAttribute("user", new UserDTO());
|
||||
return "redirect:/signup?error=other";
|
||||
}
|
||||
|
||||
userService.saveUser(userDto);
|
||||
return "redirect:/";
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.alterdekim.hearthhack.controller;
|
||||
|
||||
import com.alterdekim.hearthhack.config.StorageProperties;
|
||||
import com.alterdekim.hearthhack.exception.StorageFileNotFoundException;
|
||||
import com.alterdekim.hearthhack.service.StorageService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@EnableConfigurationProperties(StorageProperties.class)
|
||||
public class FileServerController {
|
||||
|
||||
private final StorageService storageService;
|
||||
|
||||
@Autowired
|
||||
public FileServerController(StorageService storageService) {
|
||||
this.storageService = storageService;
|
||||
}
|
||||
|
||||
@GetMapping("/static/{assetspath}/{filename:.+}")
|
||||
@ResponseBody
|
||||
public ResponseEntity<Resource> serveFile(@PathVariable String filename, @PathVariable String assetspath) {
|
||||
Resource file = storageService.loadAsResource("static/" + assetspath + "/" + filename);
|
||||
if( assetspath.equals("images") ) {
|
||||
return ResponseEntity.ok().contentType(MediaType.IMAGE_PNG).header(HttpHeaders.CONTENT_DISPOSITION,
|
||||
"attachment; filename=\"" + file.getFilename() + "\"").body(file);
|
||||
}
|
||||
return ResponseEntity.ok().contentType(new MediaType("text", assetspath)).header(HttpHeaders.CONTENT_DISPOSITION,
|
||||
"attachment; filename=\"" + file.getFilename() + "\"").body(file);
|
||||
}
|
||||
|
||||
@ExceptionHandler(StorageFileNotFoundException.class)
|
||||
public ResponseEntity<?> handleStorageFileNotFound(StorageFileNotFoundException exc) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,68 @@
|
||||
package com.alterdekim.hearthhack.controller;
|
||||
|
||||
import com.alterdekim.hearthhack.config.DBFConfig;
|
||||
import com.alterdekim.hearthhack.config.ServerConfig;
|
||||
import com.alterdekim.hearthhack.entity.User;
|
||||
import com.alterdekim.hearthhack.service.UserService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
@Slf4j
|
||||
@Controller
|
||||
public class StaticController {
|
||||
|
||||
private final String base_title = " | Hearthhack";
|
||||
|
||||
@Autowired
|
||||
private DBFConfig dbfConfig;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
private ServerConfig serverConfig;
|
||||
|
||||
@GetMapping("/rules")
|
||||
public String rulesPage(Model model) {
|
||||
model.addAttribute("title", "Rules" + base_title);
|
||||
return "rules";
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public String homePage(Model model) {
|
||||
model.addAttribute("title", "Home" + base_title);
|
||||
return "index";
|
||||
}
|
||||
|
||||
@GetMapping("/access-denied")
|
||||
public String accessDenied(Model model) {
|
||||
model.addAttribute("title", "Access denied");
|
||||
return "403";
|
||||
}
|
||||
|
||||
@GetMapping("/config")
|
||||
public ResponseEntity<String> getConfig(Model model) {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if( !authentication.isAuthenticated() ) return ResponseEntity.badRequest().build();
|
||||
Long uid = 0L;
|
||||
try {
|
||||
uid = userService.findByUsername(
|
||||
((org.springframework.security.core.userdetails.User) authentication.getPrincipal()).getUsername()
|
||||
).getId();
|
||||
String c = dbfConfig.getClientConfig()
|
||||
.replace("${token}", userService.genHash(uid))
|
||||
.replace("${port}", serverConfig.getBnetPort()+"")
|
||||
.replace("${host}", serverConfig.getHost());
|
||||
return ResponseEntity.ok(c);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
}
|
@ -16,11 +16,6 @@ public class UserDTO {
|
||||
private String username;
|
||||
@NotEmpty(message = "Password should not be empty")
|
||||
private String password;
|
||||
@NotEmpty(message = "Invite code should not be empty")
|
||||
private String invite_code;
|
||||
private Boolean terms_and_conditions_accept;
|
||||
|
||||
private String lang;
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,8 +18,13 @@ public class CardBack {
|
||||
private Long id;
|
||||
|
||||
@Column(nullable=false)
|
||||
private Integer backId;
|
||||
private Integer backId = 0;
|
||||
|
||||
@Column(nullable=false)
|
||||
private Long userId;
|
||||
|
||||
public CardBack(Integer backId, Long userId) {
|
||||
this.backId = backId;
|
||||
this.userId = userId;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
package com.alterdekim.hearthhack.exception;
|
||||
|
||||
public class StorageException extends RuntimeException {
|
||||
|
||||
public StorageException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public StorageException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
package com.alterdekim.hearthhack.exception;
|
||||
|
||||
public class StorageFileNotFoundException extends StorageException {
|
||||
|
||||
public StorageFileNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public StorageFileNotFoundException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.alterdekim.hearthhack.handler;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
|
||||
@Override
|
||||
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
|
||||
response.sendRedirect("/403");
|
||||
}
|
||||
}
|
||||
|
@ -6,15 +6,14 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
import java.io.File;
|
||||
|
||||
@Slf4j
|
||||
public class DBFParser extends DefaultHandler {
|
||||
public static CardsDBF parseCards(String path) {
|
||||
try {
|
||||
XmlMapper xmlMapper = new XmlMapper();
|
||||
return xmlMapper.readValue(new File(path + "/CARD.xml"), CardsDBF.class);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
return new CardsDBF();
|
||||
|
||||
public static CardsDBF parseCards(String path) throws Exception {
|
||||
return parse(path + "/CARD.xml", CardsDBF.class);
|
||||
}
|
||||
|
||||
public static <T> T parse(String path, Class<T> cl) throws Exception {
|
||||
XmlMapper xmlMapper = new XmlMapper();
|
||||
return xmlMapper.readValue(new File(path), cl);
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,18 @@ package com.alterdekim.hearthhack.repository;
|
||||
|
||||
import com.alterdekim.hearthhack.entity.User;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Repository
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
User findByUsername(String username);
|
||||
|
||||
@Transactional
|
||||
@Modifying
|
||||
@Query(value = "UPDATE User u SET u.defaultCardBack = :cardBackId WHERE u.id = :userId")
|
||||
void updateCardBackOfUser(@Param("userId") Long userId, @Param("cardBackId") Long cardBackId);
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.alterdekim.hearthhack.security;
|
||||
|
||||
import com.alterdekim.hearthhack.handler.CustomAccessDeniedHandler;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -10,6 +11,7 @@ import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
|
||||
@ -26,14 +28,20 @@ public class SpringSecurity {
|
||||
http.csrf().disable()
|
||||
.authorizeHttpRequests((authorize) ->
|
||||
authorize
|
||||
.requestMatchers("/profile/**").hasAnyAuthority("ROLE_USER")
|
||||
.requestMatchers("/").permitAll()
|
||||
.requestMatchers("/panel").hasAnyAuthority("ROLE_ADMIN")
|
||||
.requestMatchers("/").hasAnyAuthority("ROLE_USER")
|
||||
.requestMatchers("/config").hasAnyAuthority("ROLE_USER")
|
||||
.requestMatchers("/403").permitAll()
|
||||
.requestMatchers("/signup").permitAll()
|
||||
.requestMatchers("/login").permitAll()
|
||||
.requestMatchers("/rules").permitAll()
|
||||
.requestMatchers("/static/**").permitAll()
|
||||
).formLogin(
|
||||
form -> form
|
||||
.loginPage("/login")
|
||||
.loginProcessingUrl("/login")
|
||||
.failureForwardUrl("/")
|
||||
.defaultSuccessUrl("/games")
|
||||
.defaultSuccessUrl("/")
|
||||
.permitAll()
|
||||
)
|
||||
.logout(
|
||||
@ -44,10 +52,18 @@ public class SpringSecurity {
|
||||
)
|
||||
.requestCache((cache) -> cache
|
||||
.requestCache(requestCache)
|
||||
);
|
||||
)
|
||||
.exceptionHandling((exc) -> exc
|
||||
.accessDeniedHandler(accessDeniedHandler())
|
||||
.accessDeniedPage("/403"));
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AccessDeniedHandler accessDeniedHandler() {
|
||||
return new CustomAccessDeniedHandler();
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
|
||||
|
@ -0,0 +1,43 @@
|
||||
package com.alterdekim.hearthhack.service;
|
||||
|
||||
import com.alterdekim.hearthhack.entity.Role;
|
||||
import com.alterdekim.hearthhack.entity.User;
|
||||
import com.alterdekim.hearthhack.repository.UserRepository;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class CustomUserDetailsService implements UserDetailsService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
public CustomUserDetailsService(UserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
|
||||
User user = userRepository.findByUsername(email);
|
||||
|
||||
if (user != null) {
|
||||
return new org.springframework.security.core.userdetails.User(user.getUsername(),
|
||||
user.getPassword(),
|
||||
mapRolesToAuthorities(user.getRoles()));
|
||||
}else{
|
||||
throw new UsernameNotFoundException("Invalid username or password.");
|
||||
}
|
||||
}
|
||||
|
||||
private Collection< ? extends GrantedAuthority> mapRolesToAuthorities(Collection <Role> roles) {
|
||||
return roles.stream()
|
||||
.map(role -> new SimpleGrantedAuthority(role.getName()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package com.alterdekim.hearthhack.service;
|
||||
|
||||
|
||||
import com.alterdekim.hearthhack.config.StorageProperties;
|
||||
import com.alterdekim.hearthhack.exception.StorageException;
|
||||
import com.alterdekim.hearthhack.exception.StorageFileNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Service
|
||||
public class FileSystemStorageService implements StorageService {
|
||||
|
||||
private final Path rootLocation;
|
||||
|
||||
@Autowired
|
||||
public FileSystemStorageService(StorageProperties properties) {
|
||||
|
||||
if(properties.getLocation().trim().isEmpty()){
|
||||
throw new StorageException("File upload location can not be Empty.");
|
||||
}
|
||||
|
||||
this.rootLocation = Paths.get(new ClassPathResource(properties.getLocation()).getPath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(MultipartFile file) {
|
||||
try {
|
||||
if (file.isEmpty()) {
|
||||
throw new StorageException("Failed to store empty file.");
|
||||
}
|
||||
Path destinationFile = this.rootLocation.resolve(
|
||||
Paths.get(file.getOriginalFilename()))
|
||||
.normalize().toAbsolutePath();
|
||||
if (!destinationFile.getParent().equals(this.rootLocation.toAbsolutePath())) {
|
||||
throw new StorageException(
|
||||
"Cannot store file outside current directory.");
|
||||
}
|
||||
try (InputStream inputStream = file.getInputStream()) {
|
||||
Files.copy(inputStream, destinationFile,
|
||||
StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new StorageException("Failed to store file.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<Path> loadAll() {
|
||||
try {
|
||||
return Files.walk(this.rootLocation, 1)
|
||||
.filter(path -> !path.equals(this.rootLocation))
|
||||
.map(this.rootLocation::relativize);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new StorageException("Failed to read stored files", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path load(String filename) {
|
||||
return rootLocation.resolve(filename);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource loadAsResource(String filename) {
|
||||
try {
|
||||
Resource resource = new ClassPathResource(filename);
|
||||
if (resource.exists() || resource.isReadable()) {
|
||||
return resource;
|
||||
}
|
||||
else {
|
||||
throw new StorageFileNotFoundException(
|
||||
"Could not read file: " + filename);
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new StorageFileNotFoundException("Could not read file: " + filename, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll() {
|
||||
FileSystemUtils.deleteRecursively(rootLocation.toFile());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
try {
|
||||
Files.createDirectories(rootLocation);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new StorageException("Could not initialize storage", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.alterdekim.hearthhack.service;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public interface StorageService {
|
||||
|
||||
void init();
|
||||
|
||||
void store(MultipartFile file);
|
||||
|
||||
Stream<Path> loadAll();
|
||||
|
||||
Path load(String filename);
|
||||
|
||||
Resource loadAsResource(String filename);
|
||||
|
||||
void deleteAll();
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
package com.alterdekim.hearthhack.service;
|
||||
|
||||
import com.alterdekim.hearthhack.dto.UserDTO;
|
||||
import com.alterdekim.hearthhack.entity.CardBack;
|
||||
import com.alterdekim.hearthhack.entity.Role;
|
||||
import com.alterdekim.hearthhack.entity.User;
|
||||
import com.alterdekim.hearthhack.repository.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.checkerframework.checker.units.qual.C;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@ -37,6 +39,9 @@ public class UserService implements IService {
|
||||
}
|
||||
user.setRoles(Collections.singletonList(role));
|
||||
userRepository.save(user);
|
||||
CardBack back = new CardBack(0, user.getId());
|
||||
cardBackRepository.save(back);
|
||||
userRepository.updateCardBackOfUser(user.getId(), back.getId());
|
||||
}
|
||||
|
||||
|
||||
@ -55,7 +60,12 @@ public class UserService implements IService {
|
||||
String[] arr = token.split("\\-");
|
||||
if( arr.length != 3 ) return false;
|
||||
String hash = arr[1];
|
||||
Long id = Long.parseLong(arr[2]);
|
||||
long id = 0L;
|
||||
try {
|
||||
id = Long.parseLong(arr[2]);
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
Optional<User> user = this.userRepository.findById(id);
|
||||
if( user.isEmpty() ) return false;
|
||||
String raw = user.get().getId() + user.get().getPassword() + user.get().getUsername();
|
||||
|
@ -1,35 +0,0 @@
|
||||
package com.alterdekim.hearthhack.util;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Hash {
|
||||
public static String sha256( byte[] b ) throws NoSuchAlgorithmException {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
return bytesToHex(digest.digest(b));
|
||||
}
|
||||
|
||||
private static String bytesToHex(byte[] hash) {
|
||||
StringBuilder hexString = new StringBuilder(2 * hash.length);
|
||||
for (byte b : hash) {
|
||||
String hex = Integer.toHexString(0xff & b);
|
||||
if (hex.length() == 1) {
|
||||
hexString.append('0');
|
||||
}
|
||||
hexString.append(hex);
|
||||
}
|
||||
return hexString.toString();
|
||||
}
|
||||
|
||||
public static String rnd() {
|
||||
return IntStream.generate(() -> new Random().nextInt(0, 62))
|
||||
.limit(32)
|
||||
.boxed()
|
||||
.map(i -> "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".charAt(i)+"")
|
||||
.collect(Collectors.joining());
|
||||
}
|
||||
}
|
||||
|
0
src/main/resources/static/css/index.css
Normal file
0
src/main/resources/static/css/index.css
Normal file
25
src/main/resources/static/css/login.css
Normal file
25
src/main/resources/static/css/login.css
Normal file
@ -0,0 +1,25 @@
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.form-signin {
|
||||
max-width: 330px;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.form-signin .form-floating:focus-within {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.form-signin input[type="text"] {
|
||||
margin-bottom: -1px;
|
||||
border-bottom-right-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.form-signin input[type="password"] {
|
||||
margin-bottom: 10px;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
0
src/main/resources/static/css/panel.css
Normal file
0
src/main/resources/static/css/panel.css
Normal file
13
src/main/resources/static/css/signup.css
Normal file
13
src/main/resources/static/css/signup.css
Normal file
@ -0,0 +1,13 @@
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.form-signup {
|
||||
max-width: 330px;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.form-signup .form-floating:focus-within {
|
||||
z-index: 2;
|
||||
}
|
13
src/main/resources/templates/403.html
Normal file
13
src/main/resources/templates/403.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/head}"></th:block>
|
||||
<link rel="stylesheet" href="/static/css/index.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container mt-5 min-vh-100" style="max-width: 330px;">
|
||||
<h4 class="text-center">Access denied</h4>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/essentials}"></th:block>
|
||||
</body>
|
||||
</html>
|
4
src/main/resources/templates/fragments/essentials.html
Normal file
4
src/main/resources/templates/fragments/essentials.html
Normal file
@ -0,0 +1,4 @@
|
||||
<th:block th:fragment="essentials">
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
|
||||
</th:block>
|
8
src/main/resources/templates/fragments/head.html
Normal file
8
src/main/resources/templates/fragments/head.html
Normal file
@ -0,0 +1,8 @@
|
||||
<th:block th:fragment="head">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title th:text="${title}"></title>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="/static/images/favicon.ico">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,500,800" rel="stylesheet">
|
||||
</th:block>
|
17
src/main/resources/templates/index.html
Normal file
17
src/main/resources/templates/index.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/head}"></th:block>
|
||||
<link rel="stylesheet" href="/static/css/index.css">
|
||||
</head>
|
||||
<body class="d-flex align-items-center py-4 bg-body-tertiary">
|
||||
<main class="form-signin w-100 m-auto">
|
||||
<form>
|
||||
<a class="btn btn-primary w-100 py-2" href="/config" download>Download client.config</a>
|
||||
|
||||
<p class="mt-3"><a th:href="@{/logout}" class="link-primary">Logout</a></p>
|
||||
</form>
|
||||
</main>
|
||||
<th:block th:insert="~{fragments/essentials}"></th:block>
|
||||
</body>
|
||||
</html>
|
37
src/main/resources/templates/login.html
Normal file
37
src/main/resources/templates/login.html
Normal file
@ -0,0 +1,37 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/head}"></th:block>
|
||||
<link rel="stylesheet" href="/static/css/login.css">
|
||||
</head>
|
||||
<body class="d-flex align-items-center py-4 bg-body-tertiary">
|
||||
<main class="form-signin w-100 m-auto">
|
||||
<div th:if="${param.error}">
|
||||
<div class="alert alert-danger" role="alert">Error
|
||||
</div>
|
||||
</div>
|
||||
<div th:if="${error}">
|
||||
<div class="alert alert-danger" role="alert">Error
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="post" th:action="@{/login}">
|
||||
<h1 class="h3 mb-3 fw-normal">Login</h1>
|
||||
|
||||
<div class="form-floating">
|
||||
<input type="text" name="username" class="form-control" id="floatingInput" placeholder="Username">
|
||||
<label for="floatingInput">Nickname</label>
|
||||
</div>
|
||||
<div class="form-floating">
|
||||
<input type="password" name="password" class="form-control" id="floatingPassword" placeholder="Password">
|
||||
<label for="floatingPassword">Password</label>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary w-100 py-2" type="submit">Login</button>
|
||||
|
||||
<p class="mt-3"><a th:href="@{/signup}" class="link-primary">Signup</a></p>
|
||||
</form>
|
||||
</main>
|
||||
<th:block th:insert="~{fragments/essentials}"></th:block>
|
||||
</body>
|
||||
</html>
|
10
src/main/resources/templates/panel.html
Normal file
10
src/main/resources/templates/panel.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/head}"></th:block>
|
||||
<link rel="stylesheet" href="/static/css/panel.css">
|
||||
</head>
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/essentials}"></th:block>
|
||||
</body>
|
||||
</html>
|
41
src/main/resources/templates/signup.html
Normal file
41
src/main/resources/templates/signup.html
Normal file
@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/head}"></th:block>
|
||||
<link rel="stylesheet" href="/static/css/signup.css">
|
||||
</head>
|
||||
<body class="d-flex align-items-center py-4 bg-body-tertiary">
|
||||
<main class="form-signup w-100 m-auto">
|
||||
<div th:if="${param.error}">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
error
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div th:if="${error}">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
error
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="post" th:action="@{/signup}" th:object="${user}">
|
||||
<h1 class="h3 mb-3 fw-normal" >Sign up</h1>
|
||||
|
||||
<div class="form-floating">
|
||||
<input type="text" name="username" class="form-control" id="floatingInput" placeholder="Username">
|
||||
<label for="floatingInput">Nickname</label>
|
||||
</div>
|
||||
|
||||
<div class="form-floating mt-1">
|
||||
<input type="password" name="password" class="form-control" id="floatingPassword" placeholder="Password">
|
||||
<label for="floatingPassword">Password</label>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary w-100 py-2 mt-3" type="submit">Sign up</button>
|
||||
|
||||
<p class="mt-3"><a th:href="@{/login}" class="link-primary">Login</a></p>
|
||||
</form>
|
||||
</main>
|
||||
<th:block th:insert="~{fragments/essentials}"></th:block>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user