diff --git a/README.md b/README.md new file mode 100644 index 0000000..ac817bd --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +

Hearthhack

+

A hearthstone server software project

+
+ Stars Badge + License Badge +
+

Loved the project?
XMR:

diff --git a/src/main/java/com/alterdekim/hearthhack/Application.java b/src/main/java/com/alterdekim/hearthhack/Application.java index e66cf75..b72191a 100644 --- a/src/main/java/com/alterdekim/hearthhack/Application.java +++ b/src/main/java/com/alterdekim/hearthhack/Application.java @@ -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(); + }; + } } \ No newline at end of file diff --git a/src/main/java/com/alterdekim/hearthhack/component/GamePool.java b/src/main/java/com/alterdekim/hearthhack/component/GamePool.java index 2ae4d6e..8caf5b6 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/GamePool.java +++ b/src/main/java/com/alterdekim/hearthhack/component/GamePool.java @@ -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; diff --git a/src/main/java/com/alterdekim/hearthhack/component/GameServer.java b/src/main/java/com/alterdekim/hearthhack/component/GameServer.java index f3e46f1..51c7a39 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/GameServer.java +++ b/src/main/java/com/alterdekim/hearthhack/component/GameServer.java @@ -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 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) { diff --git a/src/main/java/com/alterdekim/hearthhack/component/StartupListener.java b/src/main/java/com/alterdekim/hearthhack/component/StartupListener.java new file mode 100644 index 0000000..94f8f04 --- /dev/null +++ b/src/main/java/com/alterdekim/hearthhack/component/StartupListener.java @@ -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()); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/alterdekim/hearthhack/component/TcpConnection.java b/src/main/java/com/alterdekim/hearthhack/component/TcpConnection.java index dc6d1e1..b606d9f 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/TcpConnection.java +++ b/src/main/java/com/alterdekim/hearthhack/component/TcpConnection.java @@ -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 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 { diff --git a/src/main/java/com/alterdekim/hearthhack/component/TcpServer.java b/src/main/java/com/alterdekim/hearthhack/component/TcpServer.java index 3a08c92..56c5c3f 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/TcpServer.java +++ b/src/main/java/com/alterdekim/hearthhack/component/TcpServer.java @@ -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 { - private final int socketPort = 1119; + private int socketPort; private SSLServerSocket serverSocket; private List connections; + @Autowired + private DBFConfig dbfConfig; + @Autowired private ServerConfig serverConfig; @@ -36,6 +40,7 @@ public class TcpServer extends ReflectionLoader { @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 { 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()); diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/AuthProcessor.java b/src/main/java/com/alterdekim/hearthhack/component/processor/AuthProcessor.java index 5bfd387..0df284d 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/AuthProcessor.java +++ b/src/main/java/com/alterdekim/hearthhack/component/processor/AuthProcessor.java @@ -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) diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/AccountLicensesInfo.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/AccountLicensesInfo.java index 85afb80..016d193 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/AccountLicensesInfo.java +++ b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/AccountLicensesInfo.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.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 { diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/AvailableFeatures.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/AvailableFeatures.java index 977ddc3..5d5cb33 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/AvailableFeatures.java +++ b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/AvailableFeatures.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.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; } diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/Boosters.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/Boosters.java index a9039aa..511376b 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/Boosters.java +++ b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/Boosters.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; @@ -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; } diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/CardBacks.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/CardBacks.java index 50f06f8..bb777c0 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/CardBacks.java +++ b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/CardBacks.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.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; } diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/CardValues.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/CardValues.java index b40e229..01fabd0 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/CardValues.java +++ b/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 -> { diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/ClientOptions.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/ClientOptions.java index e51e19c..6cfa264 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/ClientOptions.java +++ b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/ClientOptions.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.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; } diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/Collection.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/Collection.java index e83cdc0..350663e 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/Collection.java +++ b/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; } diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/DeckList.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/DeckList.java index 0421c2d..44e739d 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/DeckList.java +++ b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/DeckList.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.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; } diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/DustBalance.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/DustBalance.java index b15d834..96aee46 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/DustBalance.java +++ b/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; } diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/FavoriteHeroes.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/FavoriteHeroes.java index ebff01b..79c93ab 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/FavoriteHeroes.java +++ b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/FavoriteHeroes.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; @@ -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; } diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/GeneralGenericParser.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/GeneralGenericParser.java index 56be37e..063fab7 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/GeneralGenericParser.java +++ b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/GeneralGenericParser.java @@ -20,7 +20,7 @@ public class GeneralGenericParser extends ReflectionLoader { } 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()); diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/GenericParser.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/GenericParser.java index a7bbc51..b261fdd 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/GenericParser.java +++ b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/GenericParser.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.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; diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/GoldBalance.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/GoldBalance.java index 2d1f070..4509bd8 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/GoldBalance.java +++ b/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; } diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/HeroXP.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/HeroXP.java index 14eaffe..ff49856 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/HeroXP.java +++ b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/HeroXP.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.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; } diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/MedalInfo.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/MedalInfo.java index 4b227c2..2f4cee4 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/MedalInfo.java +++ b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/MedalInfo.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.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; } diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/NotSoMassiveLoginReply.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/NotSoMassiveLoginReply.java index 8ea574d..c1d4912 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/NotSoMassiveLoginReply.java +++ b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/NotSoMassiveLoginReply.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.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; } diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/PlayQueue.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/PlayQueue.java index 93f26d6..b7e2229 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/PlayQueue.java +++ b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/PlayQueue.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; @@ -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; } diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/PlayerRecords.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/PlayerRecords.java index 9537c8f..e0e1786 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/PlayerRecords.java +++ b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/PlayerRecords.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.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; } diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/ProfileNotices.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/ProfileNotices.java index c88a005..c2cfa29 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/ProfileNotices.java +++ b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/ProfileNotices.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; @@ -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; } diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/ProfileProgress.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/ProfileProgress.java index 70cf21f..e465024 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/ProfileProgress.java +++ b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/ProfileProgress.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; @@ -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; } diff --git a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/RewardProgress.java b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/RewardProgress.java index b3b4484..7004dc1 100644 --- a/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/RewardProgress.java +++ b/src/main/java/com/alterdekim/hearthhack/component/processor/client/request/generic/RewardProgress.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; @@ -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; } diff --git a/src/main/java/com/alterdekim/hearthhack/config/DBFConfig.java b/src/main/java/com/alterdekim/hearthhack/config/DBFConfig.java new file mode 100644 index 0000000..cde10d3 --- /dev/null +++ b/src/main/java/com/alterdekim/hearthhack/config/DBFConfig.java @@ -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; +} diff --git a/src/main/java/com/alterdekim/hearthhack/config/ServerConfig.java b/src/main/java/com/alterdekim/hearthhack/config/ServerConfig.java index 2e50b69..94c770c 100644 --- a/src/main/java/com/alterdekim/hearthhack/config/ServerConfig.java +++ b/src/main/java/com/alterdekim/hearthhack/config/ServerConfig.java @@ -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; } diff --git a/src/main/java/com/alterdekim/hearthhack/config/StorageProperties.java b/src/main/java/com/alterdekim/hearthhack/config/StorageProperties.java new file mode 100644 index 0000000..f6827a6 --- /dev/null +++ b/src/main/java/com/alterdekim/hearthhack/config/StorageProperties.java @@ -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"; +} \ No newline at end of file diff --git a/src/main/java/com/alterdekim/hearthhack/config/ThymeleafConfig.java b/src/main/java/com/alterdekim/hearthhack/config/ThymeleafConfig.java new file mode 100644 index 0000000..5be5301 --- /dev/null +++ b/src/main/java/com/alterdekim/hearthhack/config/ThymeleafConfig.java @@ -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(); + } +} diff --git a/src/main/java/com/alterdekim/hearthhack/controller/AdminController.java b/src/main/java/com/alterdekim/hearthhack/controller/AdminController.java new file mode 100644 index 0000000..9e5ec3d --- /dev/null +++ b/src/main/java/com/alterdekim/hearthhack/controller/AdminController.java @@ -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:/"; + } +} diff --git a/src/main/java/com/alterdekim/hearthhack/controller/AuthController.java b/src/main/java/com/alterdekim/hearthhack/controller/AuthController.java new file mode 100644 index 0000000..020f6c2 --- /dev/null +++ b/src/main/java/com/alterdekim/hearthhack/controller/AuthController.java @@ -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:/"; + } +} diff --git a/src/main/java/com/alterdekim/hearthhack/controller/FileServerController.java b/src/main/java/com/alterdekim/hearthhack/controller/FileServerController.java new file mode 100644 index 0000000..93736bf --- /dev/null +++ b/src/main/java/com/alterdekim/hearthhack/controller/FileServerController.java @@ -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 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(); + } +} + diff --git a/src/main/java/com/alterdekim/hearthhack/controller/StaticController.java b/src/main/java/com/alterdekim/hearthhack/controller/StaticController.java new file mode 100644 index 0000000..6e18a94 --- /dev/null +++ b/src/main/java/com/alterdekim/hearthhack/controller/StaticController.java @@ -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 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(); + } +} diff --git a/src/main/java/com/alterdekim/hearthhack/dto/UserDTO.java b/src/main/java/com/alterdekim/hearthhack/dto/UserDTO.java index 9fe08ca..94e436a 100644 --- a/src/main/java/com/alterdekim/hearthhack/dto/UserDTO.java +++ b/src/main/java/com/alterdekim/hearthhack/dto/UserDTO.java @@ -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; } diff --git a/src/main/java/com/alterdekim/hearthhack/entity/CardBack.java b/src/main/java/com/alterdekim/hearthhack/entity/CardBack.java index a956b53..b783944 100644 --- a/src/main/java/com/alterdekim/hearthhack/entity/CardBack.java +++ b/src/main/java/com/alterdekim/hearthhack/entity/CardBack.java @@ -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; + } } diff --git a/src/main/java/com/alterdekim/hearthhack/exception/StorageException.java b/src/main/java/com/alterdekim/hearthhack/exception/StorageException.java new file mode 100644 index 0000000..440b25c --- /dev/null +++ b/src/main/java/com/alterdekim/hearthhack/exception/StorageException.java @@ -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); + } +} + diff --git a/src/main/java/com/alterdekim/hearthhack/exception/StorageFileNotFoundException.java b/src/main/java/com/alterdekim/hearthhack/exception/StorageFileNotFoundException.java new file mode 100644 index 0000000..9ee02f5 --- /dev/null +++ b/src/main/java/com/alterdekim/hearthhack/exception/StorageFileNotFoundException.java @@ -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); + } +} \ No newline at end of file diff --git a/src/main/java/com/alterdekim/hearthhack/handler/CustomAccessDeniedHandler.java b/src/main/java/com/alterdekim/hearthhack/handler/CustomAccessDeniedHandler.java new file mode 100644 index 0000000..6447246 --- /dev/null +++ b/src/main/java/com/alterdekim/hearthhack/handler/CustomAccessDeniedHandler.java @@ -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"); + } +} + diff --git a/src/main/java/com/alterdekim/hearthhack/parser/DBFParser.java b/src/main/java/com/alterdekim/hearthhack/parser/DBFParser.java index b8de9b5..c4ece85 100644 --- a/src/main/java/com/alterdekim/hearthhack/parser/DBFParser.java +++ b/src/main/java/com/alterdekim/hearthhack/parser/DBFParser.java @@ -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 parse(String path, Class cl) throws Exception { + XmlMapper xmlMapper = new XmlMapper(); + return xmlMapper.readValue(new File(path), cl); } } diff --git a/src/main/java/com/alterdekim/hearthhack/repository/UserRepository.java b/src/main/java/com/alterdekim/hearthhack/repository/UserRepository.java index 33b4b3a..b469c66 100644 --- a/src/main/java/com/alterdekim/hearthhack/repository/UserRepository.java +++ b/src/main/java/com/alterdekim/hearthhack/repository/UserRepository.java @@ -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 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); } \ No newline at end of file diff --git a/src/main/java/com/alterdekim/hearthhack/security/SpringSecurity.java b/src/main/java/com/alterdekim/hearthhack/security/SpringSecurity.java index 1462108..42b9507 100644 --- a/src/main/java/com/alterdekim/hearthhack/security/SpringSecurity.java +++ b/src/main/java/com/alterdekim/hearthhack/security/SpringSecurity.java @@ -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()); diff --git a/src/main/java/com/alterdekim/hearthhack/service/CustomUserDetailsService.java b/src/main/java/com/alterdekim/hearthhack/service/CustomUserDetailsService.java new file mode 100644 index 0000000..4124ad9 --- /dev/null +++ b/src/main/java/com/alterdekim/hearthhack/service/CustomUserDetailsService.java @@ -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 roles) { + return roles.stream() + .map(role -> new SimpleGrantedAuthority(role.getName())) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/alterdekim/hearthhack/service/FileSystemStorageService.java b/src/main/java/com/alterdekim/hearthhack/service/FileSystemStorageService.java new file mode 100644 index 0000000..d8d254c --- /dev/null +++ b/src/main/java/com/alterdekim/hearthhack/service/FileSystemStorageService.java @@ -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 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); + } + } +} diff --git a/src/main/java/com/alterdekim/hearthhack/service/StorageService.java b/src/main/java/com/alterdekim/hearthhack/service/StorageService.java new file mode 100644 index 0000000..e37fce0 --- /dev/null +++ b/src/main/java/com/alterdekim/hearthhack/service/StorageService.java @@ -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 loadAll(); + + Path load(String filename); + + Resource loadAsResource(String filename); + + void deleteAll(); + +} + diff --git a/src/main/java/com/alterdekim/hearthhack/service/UserService.java b/src/main/java/com/alterdekim/hearthhack/service/UserService.java index b73b56d..22a1a50 100644 --- a/src/main/java/com/alterdekim/hearthhack/service/UserService.java +++ b/src/main/java/com/alterdekim/hearthhack/service/UserService.java @@ -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 = this.userRepository.findById(id); if( user.isEmpty() ) return false; String raw = user.get().getId() + user.get().getPassword() + user.get().getUsername(); diff --git a/src/main/java/com/alterdekim/hearthhack/util/Hash.java b/src/main/java/com/alterdekim/hearthhack/util/Hash.java deleted file mode 100644 index a2c3aaf..0000000 --- a/src/main/java/com/alterdekim/hearthhack/util/Hash.java +++ /dev/null @@ -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()); - } -} - diff --git a/src/main/resources/static/css/index.css b/src/main/resources/static/css/index.css new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/static/css/login.css b/src/main/resources/static/css/login.css new file mode 100644 index 0000000..3a6e982 --- /dev/null +++ b/src/main/resources/static/css/login.css @@ -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; +} \ No newline at end of file diff --git a/src/main/resources/static/css/panel.css b/src/main/resources/static/css/panel.css new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/static/css/signup.css b/src/main/resources/static/css/signup.css new file mode 100644 index 0000000..a37e2c2 --- /dev/null +++ b/src/main/resources/static/css/signup.css @@ -0,0 +1,13 @@ +html, +body { + height: 100%; +} + +.form-signup { + max-width: 330px; + padding: 1rem; +} + +.form-signup .form-floating:focus-within { + z-index: 2; +} \ No newline at end of file diff --git a/src/main/resources/templates/403.html b/src/main/resources/templates/403.html new file mode 100644 index 0000000..631a22f --- /dev/null +++ b/src/main/resources/templates/403.html @@ -0,0 +1,13 @@ + + + + + + + +
+

Access denied

+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/fragments/essentials.html b/src/main/resources/templates/fragments/essentials.html new file mode 100644 index 0000000..1131800 --- /dev/null +++ b/src/main/resources/templates/fragments/essentials.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/main/resources/templates/fragments/head.html b/src/main/resources/templates/fragments/head.html new file mode 100644 index 0000000..c852193 --- /dev/null +++ b/src/main/resources/templates/fragments/head.html @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html new file mode 100644 index 0000000..79769ba --- /dev/null +++ b/src/main/resources/templates/index.html @@ -0,0 +1,17 @@ + + + + + + + +
+
+ Download client.config + +

Logout

+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html new file mode 100644 index 0000000..312b026 --- /dev/null +++ b/src/main/resources/templates/login.html @@ -0,0 +1,37 @@ + + + + + + + +
+
+ +
+
+ +
+ +
+

Login

+ +
+ + +
+
+ + +
+ + + +

Signup

+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/panel.html b/src/main/resources/templates/panel.html new file mode 100644 index 0000000..32c155d --- /dev/null +++ b/src/main/resources/templates/panel.html @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/signup.html b/src/main/resources/templates/signup.html new file mode 100644 index 0000000..1f1da62 --- /dev/null +++ b/src/main/resources/templates/signup.html @@ -0,0 +1,41 @@ + + + + + + + +
+
+ +
+ +
+ +
+ +
+

Sign up

+ +
+ + +
+ +
+ + +
+ + + +

Login

+
+
+ + + \ No newline at end of file