From 5a7951a131fd0ffa9bafa65c9d9e1193e5755d73 Mon Sep 17 00:00:00 2001 From: Akito123321 Date: Wed, 5 Jun 2024 01:19:08 +0200 Subject: [PATCH] first commit --- .classpath | 34 +++ .project | 23 ++ .settings/org.eclipse.core.resources.prefs | 5 + .settings/org.eclipse.jdt.core.prefs | 9 + .settings/org.eclipse.m2e.core.prefs | 4 + pom.xml | 90 +++++++ .../me/akito123321/valoStrats/Config.java | 50 ++++ .../valoStrats/ValoStratsApplication.java | 22 ++ .../valoStrats/db/MySQLConfig.java | 5 + .../db/repositories/GroupRepository.java | 11 + .../db/repositories/StratRepository.java | 8 + .../db/repositories/UserRepository.java | 14 ++ .../valoStrats/rest/ConfigResponse.java | 5 + .../controller/AuthenticationController.java | 43 ++++ .../rest/controller/ConfigController.java | 21 ++ .../rest/controller/GroupRestAPI.java | 227 ++++++++++++++++++ .../valoStrats/rest/oauth2/GoogleService.java | 24 ++ .../rest/requests/AuthenticationRequest.java | 5 + .../rest/requests/AuthenticationResponse.java | 5 + .../rest/requests/GroupRequest.java | 10 + .../rest/requests/StratRequest.java | 11 + .../rest/services/GroupService.java | 33 +++ .../rest/services/StratService.java | 23 ++ .../valoStrats/rest/util/AuthTokenFilter.java | 37 +++ .../util/GoogleAuthenticationManager.java | 70 ++++++ .../rest/util/JDBCUserDetailsService.java | 62 +++++ .../valoStrats/rest/util/StratsUser.java | 115 +++++++++ .../rest/util/TokenAuthenticationManager.java | 27 +++ .../akito123321/valoStrats/schemas/Group.java | 62 +++++ .../akito123321/valoStrats/schemas/Strat.java | 80 ++++++ target/classes/META-INF/MANIFEST.MF | 6 + .../valoStratsBackend/pom.properties | 7 + .../valoStratsBackend/pom.xml | 90 +++++++ .../me/akito123321/valoStrats/Config.class | Bin 0 -> 4173 bytes .../valoStrats/ValoStratsApplication.class | Bin 0 -> 1506 bytes .../valoStrats/db/MySQLConfig.class | Bin 0 -> 1904 bytes .../db/repositories/GroupRepository.class | Bin 0 -> 570 bytes .../db/repositories/StratRepository.class | Bin 0 -> 371 bytes .../db/repositories/UserRepository.class | Bin 0 -> 799 bytes .../valoStrats/rest/ConfigResponse.class | Bin 0 -> 1553 bytes .../controller/AuthenticationController.class | Bin 0 -> 3528 bytes .../rest/controller/ConfigController.class | Bin 0 -> 1325 bytes .../rest/controller/GroupRestAPI.class | Bin 0 -> 9580 bytes .../rest/oauth2/GoogleService.class | Bin 0 -> 1117 bytes .../rest/requests/AuthenticationRequest.class | Bin 0 -> 1479 bytes .../requests/AuthenticationResponse.class | Bin 0 -> 1776 bytes .../rest/requests/GroupRequest.class | Bin 0 -> 1859 bytes .../rest/requests/StratRequest.class | Bin 0 -> 2565 bytes .../rest/services/GroupService.class | Bin 0 -> 1669 bytes .../rest/services/StratService.class | Bin 0 -> 1289 bytes .../rest/util/AuthTokenFilter.class | Bin 0 -> 2924 bytes .../util/GoogleAuthenticationManager.class | Bin 0 -> 5500 bytes .../rest/util/JDBCUserDetailsService.class | Bin 0 -> 3543 bytes .../valoStrats/rest/util/StratsUser.class | Bin 0 -> 3246 bytes .../util/TokenAuthenticationManager.class | Bin 0 -> 2115 bytes .../valoStrats/schemas/Group.class | Bin 0 -> 2032 bytes .../valoStrats/schemas/Strat.class | Bin 0 -> 2137 bytes 57 files changed, 1238 insertions(+) create mode 100644 .classpath create mode 100644 .project create mode 100644 .settings/org.eclipse.core.resources.prefs create mode 100644 .settings/org.eclipse.jdt.core.prefs create mode 100644 .settings/org.eclipse.m2e.core.prefs create mode 100644 pom.xml create mode 100644 src/main/java/me/akito123321/valoStrats/Config.java create mode 100644 src/main/java/me/akito123321/valoStrats/ValoStratsApplication.java create mode 100644 src/main/java/me/akito123321/valoStrats/db/MySQLConfig.java create mode 100644 src/main/java/me/akito123321/valoStrats/db/repositories/GroupRepository.java create mode 100644 src/main/java/me/akito123321/valoStrats/db/repositories/StratRepository.java create mode 100644 src/main/java/me/akito123321/valoStrats/db/repositories/UserRepository.java create mode 100644 src/main/java/me/akito123321/valoStrats/rest/ConfigResponse.java create mode 100644 src/main/java/me/akito123321/valoStrats/rest/controller/AuthenticationController.java create mode 100644 src/main/java/me/akito123321/valoStrats/rest/controller/ConfigController.java create mode 100644 src/main/java/me/akito123321/valoStrats/rest/controller/GroupRestAPI.java create mode 100644 src/main/java/me/akito123321/valoStrats/rest/oauth2/GoogleService.java create mode 100644 src/main/java/me/akito123321/valoStrats/rest/requests/AuthenticationRequest.java create mode 100644 src/main/java/me/akito123321/valoStrats/rest/requests/AuthenticationResponse.java create mode 100644 src/main/java/me/akito123321/valoStrats/rest/requests/GroupRequest.java create mode 100644 src/main/java/me/akito123321/valoStrats/rest/requests/StratRequest.java create mode 100644 src/main/java/me/akito123321/valoStrats/rest/services/GroupService.java create mode 100644 src/main/java/me/akito123321/valoStrats/rest/services/StratService.java create mode 100644 src/main/java/me/akito123321/valoStrats/rest/util/AuthTokenFilter.java create mode 100644 src/main/java/me/akito123321/valoStrats/rest/util/GoogleAuthenticationManager.java create mode 100644 src/main/java/me/akito123321/valoStrats/rest/util/JDBCUserDetailsService.java create mode 100644 src/main/java/me/akito123321/valoStrats/rest/util/StratsUser.java create mode 100644 src/main/java/me/akito123321/valoStrats/rest/util/TokenAuthenticationManager.java create mode 100644 src/main/java/me/akito123321/valoStrats/schemas/Group.java create mode 100644 src/main/java/me/akito123321/valoStrats/schemas/Strat.java create mode 100644 target/classes/META-INF/MANIFEST.MF create mode 100644 target/classes/META-INF/maven/me.akito123321.valoStratsBackend/valoStratsBackend/pom.properties create mode 100644 target/classes/META-INF/maven/me.akito123321.valoStratsBackend/valoStratsBackend/pom.xml create mode 100644 target/classes/me/akito123321/valoStrats/Config.class create mode 100644 target/classes/me/akito123321/valoStrats/ValoStratsApplication.class create mode 100644 target/classes/me/akito123321/valoStrats/db/MySQLConfig.class create mode 100644 target/classes/me/akito123321/valoStrats/db/repositories/GroupRepository.class create mode 100644 target/classes/me/akito123321/valoStrats/db/repositories/StratRepository.class create mode 100644 target/classes/me/akito123321/valoStrats/db/repositories/UserRepository.class create mode 100644 target/classes/me/akito123321/valoStrats/rest/ConfigResponse.class create mode 100644 target/classes/me/akito123321/valoStrats/rest/controller/AuthenticationController.class create mode 100644 target/classes/me/akito123321/valoStrats/rest/controller/ConfigController.class create mode 100644 target/classes/me/akito123321/valoStrats/rest/controller/GroupRestAPI.class create mode 100644 target/classes/me/akito123321/valoStrats/rest/oauth2/GoogleService.class create mode 100644 target/classes/me/akito123321/valoStrats/rest/requests/AuthenticationRequest.class create mode 100644 target/classes/me/akito123321/valoStrats/rest/requests/AuthenticationResponse.class create mode 100644 target/classes/me/akito123321/valoStrats/rest/requests/GroupRequest.class create mode 100644 target/classes/me/akito123321/valoStrats/rest/requests/StratRequest.class create mode 100644 target/classes/me/akito123321/valoStrats/rest/services/GroupService.class create mode 100644 target/classes/me/akito123321/valoStrats/rest/services/StratService.class create mode 100644 target/classes/me/akito123321/valoStrats/rest/util/AuthTokenFilter.class create mode 100644 target/classes/me/akito123321/valoStrats/rest/util/GoogleAuthenticationManager.class create mode 100644 target/classes/me/akito123321/valoStrats/rest/util/JDBCUserDetailsService.class create mode 100644 target/classes/me/akito123321/valoStrats/rest/util/StratsUser.class create mode 100644 target/classes/me/akito123321/valoStrats/rest/util/TokenAuthenticationManager.class create mode 100644 target/classes/me/akito123321/valoStrats/schemas/Group.class create mode 100644 target/classes/me/akito123321/valoStrats/schemas/Strat.class diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..28df922 --- /dev/null +++ b/.classpath @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..1e3952b --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + valoStratsBackend + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..cdfe4f1 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..5e4ec05 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,9 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.methodParameters=generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=17 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..6cf3334 --- /dev/null +++ b/pom.xml @@ -0,0 +1,90 @@ + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.4 + + + me.akito123321.valoStratsBackend + valoStratsBackend + 0.0.1-SNAPSHOT + + 17 + + + + + org.springframework.boot + spring-boot-starter-oauth2-client + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + + com.squareup.retrofit2 + retrofit + 2.10.0 + + + + com.google.code.gson + gson + + + + + com.squareup.retrofit2 + converter-gson + 2.10.0 + + + org.springframework.boot + spring-boot-starter-validation + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.mariadb.jdbc + mariadb-java-client + + + com.sigpwned + opengraph4j + 0.0.0 + + + + org.jsoup + jsoup + 1.17.2 + + + \ No newline at end of file diff --git a/src/main/java/me/akito123321/valoStrats/Config.java b/src/main/java/me/akito123321/valoStrats/Config.java new file mode 100644 index 0000000..c81cd09 --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/Config.java @@ -0,0 +1,50 @@ +package me.akito123321.valoStrats; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.nimbusds.jose.util.StandardCharset; + +import me.akito123321.valoStrats.db.MySQLConfig; + +public record Config( + String host, + int port, + String clientId, + String clientSecret, + String redirect_url, + MySQLConfig sqlConfig) { + + public static Config loadConfig(String path) throws IOException { + Path configPath = Path.of(path); + if (!Files.exists(configPath)) { + Files.createFile(configPath); + } + + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + String configStr = Files.readString(configPath); + if (configStr.isEmpty()) { + Config config = new Config( + "0.0.0.0", + 8080, + "", + "", + "", + new MySQLConfig( + "", + 3306, + "root", + "root", + "")); + Files.writeString(configPath, gson.toJson(config), StandardCharset.UTF_8); + System.out.println("Config file created. Please edit it accordingly"); + System.exit(0); + } + + return gson.fromJson(configStr, Config.class); + } + } diff --git a/src/main/java/me/akito123321/valoStrats/ValoStratsApplication.java b/src/main/java/me/akito123321/valoStrats/ValoStratsApplication.java new file mode 100644 index 0000000..cb3a730 --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/ValoStratsApplication.java @@ -0,0 +1,22 @@ +package me.akito123321.valoStrats; + +import java.io.IOException; +import java.util.Properties; + +import org.springframework.boot.builder.SpringApplicationBuilder; + +public class ValoStratsApplication { + public static Config config; + + public static void main(String[] args) throws IOException { + config = Config.loadConfig("config.json"); + + Properties props = new Properties(); + props.put("spring.jpa.generate-ddl", true); + + new SpringApplicationBuilder(ValoStratsApplication.class) + .properties(props) + .build() + .run(args); + } +} diff --git a/src/main/java/me/akito123321/valoStrats/db/MySQLConfig.java b/src/main/java/me/akito123321/valoStrats/db/MySQLConfig.java new file mode 100644 index 0000000..6e55d91 --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/db/MySQLConfig.java @@ -0,0 +1,5 @@ +package me.akito123321.valoStrats.db; + +public record MySQLConfig(String host, int port, String username, String password, String database) { + +} diff --git a/src/main/java/me/akito123321/valoStrats/db/repositories/GroupRepository.java b/src/main/java/me/akito123321/valoStrats/db/repositories/GroupRepository.java new file mode 100644 index 0000000..5a10566 --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/db/repositories/GroupRepository.java @@ -0,0 +1,11 @@ +package me.akito123321.valoStrats.db.repositories; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; + +import me.akito123321.valoStrats.schemas.Group; + +public interface GroupRepository extends JpaRepository { + List findByOwnerUsername(String ownerId); +} diff --git a/src/main/java/me/akito123321/valoStrats/db/repositories/StratRepository.java b/src/main/java/me/akito123321/valoStrats/db/repositories/StratRepository.java new file mode 100644 index 0000000..d192893 --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/db/repositories/StratRepository.java @@ -0,0 +1,8 @@ +package me.akito123321.valoStrats.db.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; + +import me.akito123321.valoStrats.schemas.Strat; + +public interface StratRepository extends JpaRepository { +} diff --git a/src/main/java/me/akito123321/valoStrats/db/repositories/UserRepository.java b/src/main/java/me/akito123321/valoStrats/db/repositories/UserRepository.java new file mode 100644 index 0000000..2b2c854 --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/db/repositories/UserRepository.java @@ -0,0 +1,14 @@ +package me.akito123321.valoStrats.db.repositories; + +import java.util.List; +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; + +import me.akito123321.valoStrats.rest.util.StratsUser; + +public interface UserRepository extends JpaRepository { + Optional findByGoogleUserId(String googleUserId); + + Optional findByTokensIn(List tokens); +} diff --git a/src/main/java/me/akito123321/valoStrats/rest/ConfigResponse.java b/src/main/java/me/akito123321/valoStrats/rest/ConfigResponse.java new file mode 100644 index 0000000..42040f6 --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/rest/ConfigResponse.java @@ -0,0 +1,5 @@ +package me.akito123321.valoStrats.rest; + +public record ConfigResponse(String clientId, String redirect_url) { + +} diff --git a/src/main/java/me/akito123321/valoStrats/rest/controller/AuthenticationController.java b/src/main/java/me/akito123321/valoStrats/rest/controller/AuthenticationController.java new file mode 100644 index 0000000..430a4ae --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/rest/controller/AuthenticationController.java @@ -0,0 +1,43 @@ +package me.akito123321.valoStrats.rest.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import me.akito123321.valoStrats.rest.requests.AuthenticationRequest; +import me.akito123321.valoStrats.rest.requests.AuthenticationResponse; +import me.akito123321.valoStrats.rest.util.JDBCUserDetailsService; +import me.akito123321.valoStrats.rest.util.StratsUser; + +@RestController +@RequestMapping("/api/auth") +public class AuthenticationController { + + @Autowired + private JDBCUserDetailsService userDetailsService; + + @Autowired + private AuthenticationManager authManager; + + @PostMapping(value = "/login", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity login(@RequestBody AuthenticationRequest request) { + Authentication auth = authManager.authenticate(new UsernamePasswordAuthenticationToken("", request.code())); + SecurityContextHolder.getContext().setAuthentication(auth); + + StratsUser user = (StratsUser) auth.getPrincipal(); + String token = userDetailsService.createToken(user.getUsername()); + if (token == null) + return ResponseEntity.internalServerError().build(); + + return ResponseEntity.ok(new AuthenticationResponse(user.getUsername(), user.getDisplayName(), token)); + } + +} diff --git a/src/main/java/me/akito123321/valoStrats/rest/controller/ConfigController.java b/src/main/java/me/akito123321/valoStrats/rest/controller/ConfigController.java new file mode 100644 index 0000000..8dc911b --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/rest/controller/ConfigController.java @@ -0,0 +1,21 @@ +package me.akito123321.valoStrats.rest.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import me.akito123321.valoStrats.Config; +import me.akito123321.valoStrats.ValoStratsApplication; +import me.akito123321.valoStrats.rest.ConfigResponse; + +@RestController +@RequestMapping("/api/config") +public class ConfigController { + + @GetMapping + public ResponseEntity getConfig() { + Config config = ValoStratsApplication.config; + return ResponseEntity.ok(new ConfigResponse(config.clientId(), config.redirect_url())); + } +} diff --git a/src/main/java/me/akito123321/valoStrats/rest/controller/GroupRestAPI.java b/src/main/java/me/akito123321/valoStrats/rest/controller/GroupRestAPI.java new file mode 100644 index 0000000..b58bbc6 --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/rest/controller/GroupRestAPI.java @@ -0,0 +1,227 @@ +package me.akito123321.valoStrats.rest.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import me.akito123321.valoStrats.rest.requests.GroupRequest; +import me.akito123321.valoStrats.rest.requests.StratRequest; +import me.akito123321.valoStrats.rest.services.GroupService; +import me.akito123321.valoStrats.rest.services.StratService; +import me.akito123321.valoStrats.rest.util.JDBCUserDetailsService; +import me.akito123321.valoStrats.rest.util.StratsUser; +import me.akito123321.valoStrats.schemas.Group; +import me.akito123321.valoStrats.schemas.Strat; + +@RestController +@RequestMapping("/api/group") +public class GroupRestAPI { + + @Autowired + private JDBCUserDetailsService userService; + + @Autowired + private GroupService groupService; + + @Autowired + private StratService stratService; + + @PostMapping("/") + public ResponseEntity createGroup(@RequestBody GroupRequest request) { + StratsUser user = getUser(); + Group group = new Group(request.name(), user); + groupService.saveGroup(group); + return ResponseEntity.ok(group); + } + + @GetMapping("/") + public ResponseEntity> getGroups() { + StratsUser user = getUser(); + List groups = user.getGroups(); + return ResponseEntity.ok(groups); + } + + @DeleteMapping("/{id}") + public ResponseEntity removeGroup(@PathVariable String id) { + StratsUser user = getUser(); + + Group group = groupService.getGroupById(id); + if (group == null) { + return ResponseEntity.notFound().build(); + } + if (!group.getOwner().getUsername().equals(user.getUsername())) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + + groupService.removeGroup(id); + + return ResponseEntity.ok(null); + } + + @PutMapping("/{id}") + public ResponseEntity updateGroup(@PathVariable String id, @RequestBody GroupRequest request) { + StratsUser user = getUser(); + + Group group = groupService.getGroupById(id); + if (group == null) { + return ResponseEntity.notFound().build(); + } + if (!group.getOwner().getUsername().equals(user.getUsername())) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + + group.setName(request.name()); + + groupService.saveGroup(group); + + return ResponseEntity.ok(group); + } + + @GetMapping("/{id}") + public ResponseEntity getGroup(@PathVariable String id) { + StratsUser user = getUser(); + + Group group = groupService.getGroupById(id); + if (group == null) { + return ResponseEntity.notFound().build(); + } + if (!group.getMembers().contains(user)) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + + return ResponseEntity.ok(group); + } + + @PostMapping("/{id}/member") + public ResponseEntity addUserToGroup(@PathVariable String id, @RequestBody String userId) { + StratsUser user = getUser(); + + Group group = groupService.getGroupById(id); + if (group == null) { + return ResponseEntity.notFound().build(); + } + if (!group.getOwner().getUsername().equals(user.getUsername())) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + + group.getMembers().add(userService.loadUserByUsername(userId)); + + groupService.saveGroup(group); + + return ResponseEntity.ok(group); + } + + @DeleteMapping("/{id}/member/{userId}") + public ResponseEntity removeUserFromGroup(@PathVariable String id, @PathVariable String userId) { + StratsUser user = getUser(); + + Group group = groupService.getGroupById(id); + if (group == null) { + return ResponseEntity.notFound().build(); + } + if (!group.getOwner().getUsername().equals(user.getUsername()) || !user.getUsername().equals(userId)) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + + group.getMembers().remove(userService.loadUserByUsername(userId)); + + groupService.saveGroup(group); + + return ResponseEntity.ok(group); + } + + @PostMapping("/{id}/strat") + public ResponseEntity addStrat(@PathVariable String id, @RequestBody StratRequest strat) { + StratsUser user = getUser(); + + Group group = groupService.getGroupById(id); + if (group == null) { + return ResponseEntity.notFound().build(); + } + if (!group.getMembers().contains(user)) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + + group.getStrats().add(new Strat(strat.title(), strat.description(), group, strat.stratStates(), strat.lineups())); + + groupService.saveGroup(group); + + return ResponseEntity.ok(group); + } + + @DeleteMapping("/{id}/strat/{stratId}") + public ResponseEntity removeStrat(@PathVariable String id, @PathVariable String stratId) { + StratsUser user = getUser(); + + Group group = groupService.getGroupById(id); + if (group == null) { + return ResponseEntity.notFound().build(); + } + if (!group.getMembers().contains(user)) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + + Strat strat = stratService.getStratById(stratId); + if (strat == null) { + return ResponseEntity.notFound().build(); + } + + group.getStrats().remove(strat); + + groupService.saveGroup(group); + + return ResponseEntity.ok(group); + } + + @PatchMapping("/{id}/strat/{stratId}") + public ResponseEntity editStrat(@PathVariable String id, @PathVariable String stratId, @RequestBody StratRequest newStrat) { + StratsUser user = getUser(); + + Group group = groupService.getGroupById(id); + if (group == null) { + return ResponseEntity.notFound().build(); + } + if (!group.getMembers().contains(user)) { + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + + Strat strat = stratService.getStratById(stratId); + if (strat == null){ + return ResponseEntity.notFound().build(); + }if (!group.getStrats().contains(strat)) { + return ResponseEntity.badRequest().build(); + } + + strat.setDescription(newStrat.description()); + strat.setTitle(newStrat.title()); + strat.setStratStates(newStrat.stratStates()); + strat.setLineups(newStrat.lineups()); + + stratService.saveStrat(strat); + + groupService.saveGroup(group); + + return ResponseEntity.ok(group); + } + + + private StratsUser getUser() { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + StratsUser user = (StratsUser) auth.getPrincipal(); + return user; + } + +} diff --git a/src/main/java/me/akito123321/valoStrats/rest/oauth2/GoogleService.java b/src/main/java/me/akito123321/valoStrats/rest/oauth2/GoogleService.java new file mode 100644 index 0000000..22ed1b2 --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/rest/oauth2/GoogleService.java @@ -0,0 +1,24 @@ +package me.akito123321.valoStrats.rest.oauth2; + +import com.google.gson.JsonObject; + +import retrofit2.Call; +import retrofit2.http.Field; +import retrofit2.http.FormUrlEncoded; +import retrofit2.http.Header; +import retrofit2.http.POST; + +public interface GoogleService { + + @POST("https://oauth2.googleapis.com/token") + @FormUrlEncoded + public Call getAuthorizationToken( + @Field("client_id") String client_id, + @Field("client_secret") String client_secret, + @Field("code") String code, + @Field("grant_type") String grant_type, + @Field("redirect_uri") String redirect_uri); + + @POST("https://www.googleapis.com/oauth2/v3/userinfo") + public Call getUserInfo(@Header("Authorization") String token); +} diff --git a/src/main/java/me/akito123321/valoStrats/rest/requests/AuthenticationRequest.java b/src/main/java/me/akito123321/valoStrats/rest/requests/AuthenticationRequest.java new file mode 100644 index 0000000..0ff6cc3 --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/rest/requests/AuthenticationRequest.java @@ -0,0 +1,5 @@ +package me.akito123321.valoStrats.rest.requests; + +public record AuthenticationRequest(String code) { + +} diff --git a/src/main/java/me/akito123321/valoStrats/rest/requests/AuthenticationResponse.java b/src/main/java/me/akito123321/valoStrats/rest/requests/AuthenticationResponse.java new file mode 100644 index 0000000..5953c91 --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/rest/requests/AuthenticationResponse.java @@ -0,0 +1,5 @@ +package me.akito123321.valoStrats.rest.requests; + +public record AuthenticationResponse(String username, String displayName, String token) { + +} diff --git a/src/main/java/me/akito123321/valoStrats/rest/requests/GroupRequest.java b/src/main/java/me/akito123321/valoStrats/rest/requests/GroupRequest.java new file mode 100644 index 0000000..6c117ae --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/rest/requests/GroupRequest.java @@ -0,0 +1,10 @@ +package me.akito123321.valoStrats.rest.requests; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +public record GroupRequest( + @Size(max = 50, message = "{title longer than 50 chars}") + @NotBlank String name) { +} + diff --git a/src/main/java/me/akito123321/valoStrats/rest/requests/StratRequest.java b/src/main/java/me/akito123321/valoStrats/rest/requests/StratRequest.java new file mode 100644 index 0000000..51f2b89 --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/rest/requests/StratRequest.java @@ -0,0 +1,11 @@ +package me.akito123321.valoStrats.rest.requests; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +public record StratRequest( + @Size(max = 50, message = "{title longer than 50 chars}") @NotBlank String title, + @Size(max = 512, message = "{title longer than 50 chars}") @NotBlank String description, + @NotBlank byte[][] stratStates, + byte[][] lineups) { +} diff --git a/src/main/java/me/akito123321/valoStrats/rest/services/GroupService.java b/src/main/java/me/akito123321/valoStrats/rest/services/GroupService.java new file mode 100644 index 0000000..1a535c0 --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/rest/services/GroupService.java @@ -0,0 +1,33 @@ +package me.akito123321.valoStrats.rest.services; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import me.akito123321.valoStrats.db.repositories.GroupRepository; +import me.akito123321.valoStrats.schemas.Group; + +@Service +public class GroupService { + + @Autowired + private GroupRepository groupRepository; + + public void saveGroup(Group group) { + groupRepository.save(group); + } + + public List getGroups() { + return groupRepository.findAll(); + } + + public Group getGroupById(String id) { + return groupRepository.findById(id).orElse(null); + } + + public void removeGroup(String id) { + groupRepository.deleteById(id); + } + +} diff --git a/src/main/java/me/akito123321/valoStrats/rest/services/StratService.java b/src/main/java/me/akito123321/valoStrats/rest/services/StratService.java new file mode 100644 index 0000000..778fdfa --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/rest/services/StratService.java @@ -0,0 +1,23 @@ +package me.akito123321.valoStrats.rest.services; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import me.akito123321.valoStrats.db.repositories.StratRepository; +import me.akito123321.valoStrats.schemas.Strat; + +@Service +public class StratService { + + @Autowired + private StratRepository stratRepository; + + public Strat getStratById(String id) { + return stratRepository.findById(id).orElse(null); + } + + public void saveStrat(Strat strat) { + stratRepository.save(strat); + } + +} diff --git a/src/main/java/me/akito123321/valoStrats/rest/util/AuthTokenFilter.java b/src/main/java/me/akito123321/valoStrats/rest/util/AuthTokenFilter.java new file mode 100644 index 0000000..bb19a10 --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/rest/util/AuthTokenFilter.java @@ -0,0 +1,37 @@ +package me.akito123321.valoStrats.rest.util; + +import java.io.IOException; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.web.filter.OncePerRequestFilter; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +public class AuthTokenFilter extends OncePerRequestFilter { + + @Autowired + private JDBCUserDetailsService userDetailsService; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + String authenticationHeader = request.getHeader("Authorization"); + if (authenticationHeader != null && authenticationHeader.startsWith("Bearer ")) { + String token = authenticationHeader.substring("Bearer ".length()); + StratsUser user = userDetailsService.loadUserByToken(token); + if (user != null) { + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + } + + filterChain.doFilter(request, response); + } + +} diff --git a/src/main/java/me/akito123321/valoStrats/rest/util/GoogleAuthenticationManager.java b/src/main/java/me/akito123321/valoStrats/rest/util/GoogleAuthenticationManager.java new file mode 100644 index 0000000..ff68be5 --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/rest/util/GoogleAuthenticationManager.java @@ -0,0 +1,70 @@ +package me.akito123321.valoStrats.rest.util; + +import java.util.UUID; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.InsufficientAuthenticationException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.UserDetails; + +import com.google.gson.JsonObject; + +import me.akito123321.valoStrats.Config; +import me.akito123321.valoStrats.ValoStratsApplication; +import me.akito123321.valoStrats.rest.oauth2.GoogleService; +import okhttp3.OkHttpClient; +import retrofit2.Call; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +public class GoogleAuthenticationManager extends AbstractUserDetailsAuthenticationProvider { + + @Autowired + private JDBCUserDetailsService userDetailsService; + + private OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); + private Retrofit retrofit = new Retrofit.Builder() + .baseUrl("https://cringe-studios.com") + .addConverterFactory(GsonConverterFactory.create()) + .client(httpClient.build()) + .build(); + private GoogleService service = retrofit.create(GoogleService.class); + + @Override + protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { + } + + @Override + protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { + Config config = ValoStratsApplication.config; + String accessToken = (String) authentication.getCredentials(); + Call tokenRequest = service.getAuthorizationToken(config.clientId(), config.clientSecret(), accessToken, "authorization_code", config.redirect_url()); + + UserDetails details = null; + try { + JsonObject response = tokenRequest.execute().body(); + System.out.println(response.toString()); + + JsonObject userInfo = service.getUserInfo("Bearer " + response.get("access_token").getAsString()).execute().body(); + System.out.println(userInfo.toString()); + + String googleUserId = userInfo.get("sub").getAsString(); + String name = userInfo.get("name").getAsString(); + + details = userDetailsService.loadByGoogleId(googleUserId); + if (details == null) { + details = userDetailsService.createUser(UUID.randomUUID().toString(), "", googleUserId, name); + } + } catch (Exception e) { + e.printStackTrace(); + throw new InsufficientAuthenticationException("Failed to authenticate"); + } + + System.out.println(details); + + return details; + } + +} diff --git a/src/main/java/me/akito123321/valoStrats/rest/util/JDBCUserDetailsService.java b/src/main/java/me/akito123321/valoStrats/rest/util/JDBCUserDetailsService.java new file mode 100644 index 0000000..8c865e6 --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/rest/util/JDBCUserDetailsService.java @@ -0,0 +1,62 @@ +package me.akito123321.valoStrats.rest.util; + +import java.util.List; +import java.util.UUID; + +import org.springframework.beans.factory.annotation.Autowired; +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.security.crypto.password.PasswordEncoder; + +import me.akito123321.valoStrats.db.repositories.UserRepository; + +public class JDBCUserDetailsService implements UserDetailsService { + + @Autowired + private UserRepository userRepository; + + private PasswordEncoder passwordEncoder; + + public JDBCUserDetailsService(PasswordEncoder passwordEncoder) { + this.passwordEncoder = passwordEncoder; + } + + public StratsUser createUser(String username, String password, String googleUserId, String displayName) { + StratsUser user = new StratsUser(googleUserId, displayName, List.of(new SimpleGrantedAuthority("ROLE_USER")), username, passwordEncoder.encode(password), true, true, true, true); + userRepository.save(user); + return user; + } + + public String createToken(String username) { + StratsUser user = userRepository.findById(username).orElse(null); + if (user == null) + return null; + + String token = UUID.randomUUID().toString(); + user.getTokens().add(token); + + userRepository.save(user); + + return token; + } + + @Override + public StratsUser loadUserByUsername(String username) throws UsernameNotFoundException { + StratsUser user = userRepository.findById(username).orElse(null); + if (user == null) + throw new UsernameNotFoundException("User not found"); + return user; + } + + public UserDetails loadByGoogleId(String googleId) { + UserDetails user = userRepository.findByGoogleUserId(googleId).orElse(null); + return user; + } + + public StratsUser loadUserByToken(String token) { + return userRepository.findByTokensIn(List.of(token)).orElse(null); + } + +} diff --git a/src/main/java/me/akito123321/valoStrats/rest/util/StratsUser.java b/src/main/java/me/akito123321/valoStrats/rest/util/StratsUser.java new file mode 100644 index 0000000..4b5ac51 --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/rest/util/StratsUser.java @@ -0,0 +1,115 @@ +package me.akito123321.valoStrats.rest.util; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToMany; +import me.akito123321.valoStrats.schemas.Group; + +@Entity(name = "user") +public class StratsUser implements UserDetails { + + private static final long serialVersionUID = 6175503410592822108L; + + @Id + private String username; + private String password; + @ElementCollection(fetch = FetchType.EAGER) + private List authorities; + private boolean isAccountNonExpired; + private boolean isAccountNonLocked; + private boolean isCredentialsNonExpired; + private boolean isEnabled; + + @ElementCollection(fetch = FetchType.EAGER) + private Set tokens; + private String googleUserId; + private String displayName; + + @ManyToMany(mappedBy = "members") + @ElementCollection(fetch = FetchType.EAGER) + @JsonIgnore + private List groups; + + public StratsUser() { + + } + + public StratsUser(String googleUserId, String displayName, List authorities, String username, String password, boolean isAccountNonExpired, boolean isAccountNonLocked, boolean isCredentialsNonExpired, boolean isEnabled) { + super(); + this.googleUserId = googleUserId; + this.displayName = displayName; + this.authorities = authorities; + this.username = username; + this.password = password; + this.isAccountNonExpired = isAccountNonExpired; + this.isAccountNonLocked = isAccountNonLocked; + this.isCredentialsNonExpired = isCredentialsNonExpired; + this.isEnabled = isEnabled; + this.tokens = new HashSet<>(); + } + + public String getGoogleId() { + return googleUserId; + } + + public String getDisplayName() { + return displayName; + } + + public Set getTokens() { + return tokens; + } + + @Override + public Collection getAuthorities() { + return authorities; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public boolean isAccountNonExpired() { + return isAccountNonExpired; + } + + @Override + public boolean isAccountNonLocked() { + return isAccountNonLocked; + } + + @Override + public boolean isCredentialsNonExpired() { + return isCredentialsNonExpired; + } + + @Override + public boolean isEnabled() { + return isEnabled; + } + + public List getGroups() { + return groups; + } + +} diff --git a/src/main/java/me/akito123321/valoStrats/rest/util/TokenAuthenticationManager.java b/src/main/java/me/akito123321/valoStrats/rest/util/TokenAuthenticationManager.java new file mode 100644 index 0000000..27557cd --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/rest/util/TokenAuthenticationManager.java @@ -0,0 +1,27 @@ +package me.akito123321.valoStrats.rest.util; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.UserDetails; + +public class TokenAuthenticationManager extends AbstractUserDetailsAuthenticationProvider { + + @Autowired + private JDBCUserDetailsService userDetailsService; + + @Override + protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { + } + + @Override + protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { + UserDetails details = userDetailsService.loadUserByToken((String) authentication.getCredentials()); + if (details == null) + throw new BadCredentialsException("Invalid token"); + return details; + } + +} diff --git a/src/main/java/me/akito123321/valoStrats/schemas/Group.java b/src/main/java/me/akito123321/valoStrats/schemas/Group.java new file mode 100644 index 0000000..035f211 --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/schemas/Group.java @@ -0,0 +1,62 @@ +package me.akito123321.valoStrats.schemas; + +import java.util.ArrayList; +import java.util.List; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import me.akito123321.valoStrats.rest.util.StratsUser; + +@Entity(name = "wishlist_group") +public class Group { + @Id + @GeneratedValue(strategy = GenerationType.UUID) + private String id; + private String name; + @ManyToOne + private StratsUser owner; + @ManyToMany + private List members; + @ManyToMany + private List strats; + + public Group(String name, StratsUser owner) { + this.name = name; + this.owner = owner; + this.members = new ArrayList(); + this.strats = new ArrayList(); + } + + public Group() { + + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public StratsUser getOwner() { + return owner; + } + + public List getMembers() { + return members; + } + + public List getStrats() { + return strats; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/src/main/java/me/akito123321/valoStrats/schemas/Strat.java b/src/main/java/me/akito123321/valoStrats/schemas/Strat.java new file mode 100644 index 0000000..dd2981b --- /dev/null +++ b/src/main/java/me/akito123321/valoStrats/schemas/Strat.java @@ -0,0 +1,80 @@ +package me.akito123321.valoStrats.schemas; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; + +@Entity +public class Strat { + @Id + @GeneratedValue(strategy = GenerationType.UUID) + private String id; + private String title; + private String description; + @ManyToOne + private Group group; + + @Lob + @Column(name = "imagedata", length = 1000) + @OneToMany + private byte[][] stratStates; + + @Lob + @Column(name = "imagedata", length = 1000) + @OneToMany + private byte[][] lineups; + + public Strat(String title, String description, Group group, byte[][] stratStates, byte[][] lineups) { + this.title = title; + this.description = description; + this.group = group; + this.stratStates = stratStates; + this.lineups = lineups; + } + + public Strat() { + + } + + public String getId() { + return id; + } + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setTitle(String title) { + this.title = title; + } + + public byte[][] getStratStates() { + return stratStates; + } + + public void setStratStates(byte[][] stratStates) { + this.stratStates = stratStates; + } + + public byte[][] getLineups() { + return lineups; + } + + public void setLineups(byte[][] lineups) { + this.lineups = lineups; + } + +} diff --git a/target/classes/META-INF/MANIFEST.MF b/target/classes/META-INF/MANIFEST.MF new file mode 100644 index 0000000..940ba88 --- /dev/null +++ b/target/classes/META-INF/MANIFEST.MF @@ -0,0 +1,6 @@ +Manifest-Version: 1.0 +Build-Jdk-Spec: 21 +Implementation-Title: valoStratsBackend +Implementation-Version: 0.0.1-SNAPSHOT +Created-By: Maven Integration for Eclipse + diff --git a/target/classes/META-INF/maven/me.akito123321.valoStratsBackend/valoStratsBackend/pom.properties b/target/classes/META-INF/maven/me.akito123321.valoStratsBackend/valoStratsBackend/pom.properties new file mode 100644 index 0000000..a1e619f --- /dev/null +++ b/target/classes/META-INF/maven/me.akito123321.valoStratsBackend/valoStratsBackend/pom.properties @@ -0,0 +1,7 @@ +#Generated by Maven Integration for Eclipse +#Tue Jun 04 23:56:43 CEST 2024 +artifactId=valoStratsBackend +groupId=me.akito123321.valoStratsBackend +m2e.projectLocation=C\:\\Users\\ronny\\eclipse-workspace\\valoStratsBackend +m2e.projectName=valoStratsBackend +version=0.0.1-SNAPSHOT diff --git a/target/classes/META-INF/maven/me.akito123321.valoStratsBackend/valoStratsBackend/pom.xml b/target/classes/META-INF/maven/me.akito123321.valoStratsBackend/valoStratsBackend/pom.xml new file mode 100644 index 0000000..6cf3334 --- /dev/null +++ b/target/classes/META-INF/maven/me.akito123321.valoStratsBackend/valoStratsBackend/pom.xml @@ -0,0 +1,90 @@ + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.4 + + + me.akito123321.valoStratsBackend + valoStratsBackend + 0.0.1-SNAPSHOT + + 17 + + + + + org.springframework.boot + spring-boot-starter-oauth2-client + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + + com.squareup.retrofit2 + retrofit + 2.10.0 + + + + com.google.code.gson + gson + + + + + com.squareup.retrofit2 + converter-gson + 2.10.0 + + + org.springframework.boot + spring-boot-starter-validation + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.mariadb.jdbc + mariadb-java-client + + + com.sigpwned + opengraph4j + 0.0.0 + + + + org.jsoup + jsoup + 1.17.2 + + + \ No newline at end of file diff --git a/target/classes/me/akito123321/valoStrats/Config.class b/target/classes/me/akito123321/valoStrats/Config.class new file mode 100644 index 0000000000000000000000000000000000000000..b4f8d5820080cccd0d8db1aa210aac014316db7e GIT binary patch literal 4173 zcmbVO`Bxj)75*LwjS!PyWK6&drfE!&0Lx1fr%{|b#v6_>*fKb_>$-#VfH9Iro*7}& zG)=c8-J7mylJ5K7+6_zX)1Lm^Kc#;|+tcsOjKqM2%juD3-kbN{z3<-duK)PYy}toC zioa-R66h<*v@vhG*1&d%)T~EGtG~8ON8F$7(b4A5_Uh2_h(LSREX#A%(zLWM z8q-CofVT2Ramuhw^&Kom+&R+`c>E!F)p6Q3Cfzx!Fk#q6NxIS|UA$-+g&OG3G=ML; z6~^(CxAU^%npWA-kQCVNd4y@DN5|_s8V1*Sk?$&P7)Dydero5@lu0yW7G-+EaOZR! zz(Ii~Yepc`K(?z78ZzlGtz(nXa9E&wJ%6G*KkkVf$J02X;hCD)b=p&u!_o09K13Ij zw@t?-V21)Z>Zg>TnLv{I;u`l%@`?uf=)U#W8!jVdy6Vcby5+^%my+eEju-G@nubAQ zxKiy4T-egJn{dr+g35~myYf~kJ!@IBgnZVq%IVX59j}_jg0$l}hJ<>Z&~Xx{1Uek) zPB3!a#R-PF%Sad4JCMvighxivpV2XjvjoxCh_={-h^L=MR>v65QGcpm@V!J}prQVO zUS3uTQcoNyOz1d|3j&(yoGew`MK2t$#Bh;I2ljiv7#Ot-$d}1_tC1eV6-K&kS#BJc z@DUa1*95W+9P|IoImxLw)5CSexIGR7c@5J7osHntQ2^Z{>RM-MFoFKC6ywu3m{e<4 z52MqHS(qB;NT9fu&C+z$DLCmHmLtB^dAZ#A@RD6-WBIeD`x%XyjE{Qiw0 zxOR69h}m`q-xu zR-fky(i%Mg~UJx`Eeqyn#1aa%XI-77fR#0pxi~;5_77 zVP;cl$ZG-=X7t51{FTyPmR8kXr4E6vhM9o-tv(Oxppt;cPv8-{T7G`as05X)lS#o# zl3|DSLYGa%5I46Pr@S!csuqTzC)ntGTgNx?9RZfN%~|+0a2*l>Ks7C6Cf|jUp?@I&;=S^onBn10C<-hXS@m-{?}lRAEhU(tHgH4XxI!tP|27p!@i z_D`Q--eA3aB5PUm)k+YkVN-@A4+t+VR^$okjCAsdc2m#P3Hl;chfj??v0`^?bVcbo1HCXE&c-wy&e*va~%> zCHtQDYejxD>1x<$SSI}%_6-!FyF`5;Iq~~#9As^1rnf|qP(3AQ3Dr@0Bl}5jWH;%J z>?OUCog~LLQnI9=3ETMfWsVxh{?rOOQiDtAOzmDmS88|(-Kn0)5_YC~T9&Xo)e~Jp z?;W0OLLc8zasl~$fbTOt2Rx1s@{7DYiPV0-CsUI*Q&K63`&E~Vh&NM`wRkfnTNF=l z-s3MRp<4OG`LyxTz3+V_Z^o0HM<~F6QbD{#brh2~Qq6xwY86A-K~4^>;;DC`tLbyA zc>dCT9J{=NUSTPE+-~C^nWHU^EbJI zt1I~EbCJQJp2#vjb{8|`SX@Q<(p}hz+spWP^C~_yG@KC2_}t$i{zOTdJ&2~!&3PBK zcnqDK@4+q%@_hikID);%@YGQPc#OauCv+#M{weIkS?ZXjj^ottJd((9puK|Ss literal 0 HcmV?d00001 diff --git a/target/classes/me/akito123321/valoStrats/ValoStratsApplication.class b/target/classes/me/akito123321/valoStrats/ValoStratsApplication.class new file mode 100644 index 0000000000000000000000000000000000000000..b261aee67532a5506c5f2322dcde939752f4329a GIT binary patch literal 1506 zcmbVM+foxj5IqA48^S6f+!RzU-jX0$35sAq1q8*4f)xu2eVQag*s$42Z8pd!_&b(W zKuPHb_)(TUyAc8etny`drn_fOpVQs*>-YDc0Os&ULkojZ76#ujT{)4OoJ>s^yWEml z*Wqr}SU+CQS1Oj7=dLMj4FQHoiSKg5;&#zk&6PynWoXMwd&?{`jAkyranXxOQ}nE9 zo9;7))>wRi=**b5cvmaug!6&tEWr@X$UL{!xnrt*-57AU%__sh zC6G-?PzHfAH*JQ#*r&`186s}l#k5K(ytJ1W6~(x!p@*T{i!!CLvU=3x@uT~VvWU0cFMPUmnwHPlHtT684zJ_}YT_=JpNNEXf>xd!Fpiy(w z#Ojuk?PI(l*Lql5p^WKxfN`p9rABQr-AKvrm2|_wx~1{1x=Dk3vZ6+J#hz>UZC7*DAT}sZX6071#hoIJWp|U&BBn}K^7i>{a8^)y zT;2+ITNc*1s<pQ@sQOO-DMZYK;*Zg;sjq7~0i5(5i*j^rUzez@R@P zYcO$u@K?{R)3?nthH!<}x*ve6=%igcBIu$kqqGi?r<*Lm7dp{G|LJJ&A^N}J<`ITA z4=|D$i;e~kac3WijUyyC13&O^vo*@H2S|u&DBre2^+r zR`K8m_)(TUyNPU(n1YAd>FJr%-E+Eo_V=HYUjUwAJp>;^`atCPzGfTw`Gtk~eD09f zjV;^cww0@vbDKw7?@B9%{z=;n!Osxi26aS-Kz6wGCLH*icu9& z3?QyR!4ShhIy^PnuuZCo&vG`=bCiHcpwe2}K+ z6l9TOSh|2|4;TMzF+{hFrdbhdn#@MrQ>=5c7)iBk7`8>#+;9oDqPUNTAv|E1I4xJR zsoNT5%Qf6Sso)VFGepWA3k=8J8)^EXu`hD&>2%y8U8ODCIQSb!YZUv8~4ctCz zh*e=#Os!!XrWdkOr}pqF+BQCR8}WKCcyrq3C>F#*7*t?WvPlcF8w;I2EOffC(CNV# zRWywxjS(87G{zW|4P6(e6O^z*SYenxrLGSPA-rU`(f=rwi%S^^?t6kfb>RRNNdO7i zo+Kq?b2>A%rZZDxIy1E;&9ZM5T!IgmY4w$6shw1RBBo|rNT}m2B-Pm#M%0wQg;6yX zXkqM_&iF7+-yq>ZKCjca=wfjL6SN{LP7HE?(uu<7NHPu?B)N$8G5dSYbcRu4$>TOUZIryhw|V9_)x|v zU?3(Y#KZ1pW-{M=-#7dD_5J|>H_-5)BH(JQB#yK*%~reJYRU?17SKp=f-=P{mfe1$Lg&GbfJ;NMv^nW49uSVz)X+#q=ujp(u0Ut< zF~=34fa8JAqT5+_nkjm8O_*D552;QIvyHJ4|M-`~UKEG7~d-L#MejhH2N8gEkv9kaG literal 0 HcmV?d00001 diff --git a/target/classes/me/akito123321/valoStrats/db/repositories/StratRepository.class b/target/classes/me/akito123321/valoStrats/db/repositories/StratRepository.class new file mode 100644 index 0000000000000000000000000000000000000000..13fab9098baed12c7640f0f644d51bb9bc9f3d7d GIT binary patch literal 371 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 E0n})7F#rGn literal 0 HcmV?d00001 diff --git a/target/classes/me/akito123321/valoStrats/rest/controller/GroupRestAPI.class b/target/classes/me/akito123321/valoStrats/rest/controller/GroupRestAPI.class new file mode 100644 index 0000000000000000000000000000000000000000..9e2a65dae421c09e2f6695244698169909ba621d GIT binary patch literal 9580 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 literal 0 HcmV?d00001 diff --git a/target/classes/me/akito123321/valoStrats/rest/oauth2/GoogleService.class b/target/classes/me/akito123321/valoStrats/rest/oauth2/GoogleService.class new file mode 100644 index 0000000000000000000000000000000000000000..29d06404fa08d8256d62f26971ecbc52d3b618d4 GIT binary patch literal 1117 zcmcgr&2AGh5FUr5A%8SYo0jrd2{_P0V>P)T0!Rf>eiYP-ZF{ZU-Rah?*N(j2MDPea z5(gfDheFJ5LYIU}a6lZ!9*<_`8-FwN?faLn0PqYp%1~g?i;#;8>CASw*XwTckx<5S zR=Aj3j2$;3ac5or+L%zGhjt`=EJKk&^IVJsS3-w;@8leP$Dkde+aY&j++XEsXl{>Cqpe5cg;yT(R`R=v``2{531_h)O^7gj{*(9RUI`db=_DvhrAN}_hhGGNe{ z>M{D%0tUqtfQlqu;T7$= zqQfu#!tIaU*!s!ncs!n`b2{~-9#5z?nbo#7Ps$q<0a{|EF*EekvuQV~o=L2ayHXJq zt(g_-qzkdYfWb9dMt}lsR0$TK2<7wz*P%l9B576fsl`x-1{rRUJT8%Cabj)e>Qb(@ za&&?ob8> Jcj+v^y&vggKBxcy literal 0 HcmV?d00001 diff --git a/target/classes/me/akito123321/valoStrats/rest/requests/AuthenticationRequest.class b/target/classes/me/akito123321/valoStrats/rest/requests/AuthenticationRequest.class new file mode 100644 index 0000000000000000000000000000000000000000..dc6df7eef2497c42d87e0e7b169d8fb163ae4b3e GIT binary patch literal 1479 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 literal 0 HcmV?d00001 diff --git a/target/classes/me/akito123321/valoStrats/rest/services/StratService.class b/target/classes/me/akito123321/valoStrats/rest/services/StratService.class new file mode 100644 index 0000000000000000000000000000000000000000..4052633e72a6bdcbfe26b9805a2882b20f8298c8 GIT binary patch literal 1289 zcmbVLZBG+H5PtUBQYfbs1Qg%#1zJE>z!*)%1Ybx@su(c!^R`{e!u7V<+m`UJG%*_e zVEpWlGR|I4T7xCTFFQAT&pb2p%qWGREFP>Hdgi7(W^ScdZFA?l)c@0zQrnKahqX&a5sNR!Qd&9bK<0$w6m|J-P85A!Yz!I zhQ>D%iH?lNz_3&}v);vu(|N(iqH8GaNEkBl{xh6?Yz(;_-8MD3sob88$Au)XY}x6@ zQ26JfM^wGk_NXO!0xw~fb|6J>n-p-1KsHOBv%_RlWNE$W93_vFWn?o8U*LbF4-e<* zbYKu@j84A`Kpx}dk)pUjC>Oj*)+0Ny@ClQPUoq{0ea6)vxb=Z<`8MdjmJH?BebmX#Pol zMygUMu__<^kl&O_rDtzJ?s&;*UDeFZYt zQY#GcaW5wls6vB@IwTk_&q`O!7k0A3U*>c!1vl&2+*#qi)az(7uJV!`8K@}6GN8$e z#++BgZrUZ}UG6Xh9kW|}oBN7e1jn8ul$BR%*P5b1V@ewl>gfsugIxkjoR%z}I-cj! zP3!m*PhQ$$H-y!|Ck*Z7K14?!iy3HPxVpvnxFtPndg1s(Ev_>(=ukah{uk;WOOTxX@`1cQ-A{Vam*O>hxAEZZQ~Rg8Ra6Pv8sO zHE@T3F4r}24;>VDpa|+=)!%<8b`RBT9mS8T7T#^VWEdS4GP&H zbV{3Fs)NDSIo z+Q1OQ!db-?2)p1*MRi3tET}T=@QN+1<`PjX@*p6x$ms-l|2gz6fnhu{Fv8GXN!;(< zG4UARFkGT+i1JEFK~>k%5#b!t*tq97!qzFAPGAsYx{${iMo!|fkli8?T@FW?RI*cU zC$(bW3B&w_KxkGh17lTWOXEM{M6cl6L^Bg;(8H98Y0NN~*@AR(kqkpYdt4akPF=eIcsn(rk#h_}n&d{5@iSP4I?aY}E|9W=idyL&DUb zYUz~_b`XZn3e=+W80t5|XF}Lt7}`#$o`{%EX)Z0FBgStcwWBhP2%n)^>6Z#M>;e%E zL(hjY8_`JVX$(&*QL88RN@PMdASmc@ z(X8|3#3QU*hmM=nGpgu0#}LzvgJy$Pdak88Ml-!tXsoA|MKhzhy7M*6-^0(BXwK1^RlZcd5G2+hT_TiJ1i&TO*ap4`!~!K z|D_J_V5qwD5A-Ih570kUldO4%?zb3ROV+St%>mM{F*;-yl0_*gse| XsK0x(YN#T!AcG)N`Z9KDjN!$9=?ZjL literal 0 HcmV?d00001 diff --git a/target/classes/me/akito123321/valoStrats/rest/util/GoogleAuthenticationManager.class b/target/classes/me/akito123321/valoStrats/rest/util/GoogleAuthenticationManager.class new file mode 100644 index 0000000000000000000000000000000000000000..1b994dd9d7aee7a9946e1a6e6478e30faa799abe GIT binary patch literal 5500 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 literal 0 HcmV?d00001 diff --git a/target/classes/me/akito123321/valoStrats/rest/util/StratsUser.class b/target/classes/me/akito123321/valoStrats/rest/util/StratsUser.class new file mode 100644 index 0000000000000000000000000000000000000000..ebb5fa14910cdf0b9e71579d4f224d63e36987e4 GIT binary patch literal 3246 zcmb_dZBr9h6h0U8LU2_?Q9-S?){0SB72gR|2mxawS_4$A)?PN3u(H|B>~5_2DgD?F z{niidv>9jGnf`$G7xhc0&$$~RBui^MWhQ&iJ@-84{TzP#^XFfQXqv1v^$D7&DN}CR zp?CSpWDX2e(tl%J-Apuv~&l{6jcR?P=%FO?OhDJAHZ z=U2_3?%Qs4-Iq1>mFI7ofwCID9X3tN^Of0vhKdTM?F1%kn~!K{#Ko4*s`3Ndb61M< zg2X*R`|_R}gwhRHrPEN!l^=iq=8vx@p9$(`O)iWG8Y*pj13zJXO3=uoh8x;7wQ2|U znxkf2*9&C`)q$X60BlM>lxCgH1)*{+Wfm)d_19$(!0(Eny|NK*cyQfTzzjx4bTUeS zKsHmhtF8sp@L3G#tsUuM4BO$3cXFmSw7H_lCt82o!QCBMOWQL?YeQqM%DAGj^gep zav3UiP^C0fRRU31Kr(%K9>*OXiBW!}TRSas3tP?E~ot{u(@ z+B0^3RZt@DRn!3Op>c!GQF^d6lO zbYy2?F^TQs4&GPTGnI#uS0?%jh2C3L;i8@bo`Az+=X(Pcv>!tAowJbvW4S$i2j60% z?XAb}Y&UP00c6E*myq6l$94dBES(3tJmoID!vc(5cpUq~?InyGZ-QvkV~VhxI8Hsv z$kfmd`|ZU%-NXDh+kuPr+@LcwBxs=QHGE4g*gTpCw*LuEaJ>bcKwWy*NC68n>IlHgH|_zF9%9AK?%A0B?C# zl)ccRtJ#Y!x}F_x(ar2gqD8l}Bgq!!vcsts&18quExMB(?r+gtb~w|b`Rp&W@Z=5M zZBdck*aPDPBL=>caN{Z}a1F6thtV5I;!ULK7Gk^&<5O@d2ktb@(TsL?J#wY(E}Y_Z zqC?2@I?=)9d7Z!xzj93zn&L_(HN}NWX^Kmg))W`3UsGJJ41EGRN)2l}3~eQF&Sqea zV2HqE0m7CdI8E40gq=j#Mx4d_w1h90!NeJr;U~KKJs5pDe(o@$+1L_1hy`Eo1{Y$% z59!mbmU-0UL9ts&F;+>Lmba9w^eDO6tz;=y$!csExo&Vd7W`Q(_;xq=aV&U*9>-*V z=DV)!KaT|;j|Jc92Cv0}PsD=fy1~_0@X1*4d^gyM1wWyuTP6Fvr)1B%6IYK>(nnwD S4872sW-n6sC4MrXwZ8zGzPZi- literal 0 HcmV?d00001 diff --git a/target/classes/me/akito123321/valoStrats/rest/util/TokenAuthenticationManager.class b/target/classes/me/akito123321/valoStrats/rest/util/TokenAuthenticationManager.class new file mode 100644 index 0000000000000000000000000000000000000000..0fcccd9492d51f3c18a35b5721df4d518a3a04c9 GIT binary patch literal 2115 zcmb_dYflqF6g|@x7itm3_Y-^<6h^=|_<*8`rYMS%_;I>Bma)qYnVnYo=r8au_!BfS znrNbaGx0YW^>JNN9@@9#eXxPmJlQVdrYB^MQC^~mVh*ysqa ziBQj3BW%o#j4iKP74iqVBBRNwU67GgzOYJ1Ga?dYX*^^Y9%)nN@sd$d`LPj;@~Jiz z9!tM!lwIbc=^PJ)=98tELiqM!EX}mELWOZN`mE746-dL-Tm7|XPMVtXCBsBcA;k+=)%^QmuyP$~3 z^$ltKb7hFoArS=16-$K8=`Acszd|uy*}|T~l>;Fruq5 zE8>{0N6^eCQ8Dh4mc8-JmrIUw>|qzfrB>Bw=GP3ha-LzcW8S!44D0Z1E0tkOvmSf__$>B7HsI5aS0#}}?<>VeSOt+}gz=qnn?z|3+h;xR*-=uCz z1gr9~(g>XxVd%aUk+Z9y-#RPLVi;r2mCiEkY(Vh@d<$D43z*YYn9-Px$mT`1H`X e3$#0pi-gt*_6-L;T>8oL94$JY!{wD) zZDrYit2*J1jg*c3xOt$vD)wJSVehbjtcS_h>aFrSDro!L`>%D=ddQfThpEl80Eh|$}RIuOf@u5^?_x3iP^AV`7_K*vYi0I+T=D!ON>Dc-`YdU_S$X=`? z0^LhxxTS*Q-EcdQR)wza?(u=*kYwI z0cu>rW#nabzl1BeTEK@Mt~-}GEuTe^Iu=2Tcz_wn`>2F#n3C0E3AZri;p(Od^sAms zVpq|D;?uCHIt>*W+4m2#_P|h?%6s?^lyGkXb(q}J_8@G1uOfQMx@0-}6>`e&O(c8Ek@$k~hG^+DMQC z;m#~nhzHldnc^YwL~$qVMNR#kk%<+Z67k^u43f6Tix$ujFuJHekqjeWq z%#iOa>CF-H9_CR-mGN={iX}Yaj_~dxo?FRPGWeM53ArCw4997f|H7%pr=;eD(^=0V ztH75k%P!KRlqB_gcz6uI4*l;ggik<>6vK zwfIwfMt;c@pSt^>r~hymq?QWu`8kj;E`TfygFHrkt?|d7r zt#53suX*ov5bfJo+r&$nho++w&n+jBRhWCL-)k?>VcUCk@YXb~LdI_?T-ZH1V6-2$ zHx(9t>4nzsn1-MD2Z7lR!^mpuM`5C{z=U@?w%Y5OIPnu}!lv z7kICD;|f|}*vVo)>cvg-+!wbBF8iKTd0dY@<5RUqo47`SY$oK95tUp`a&?}oDUKq) zU@(IsH&{Y$Wu$;^Wch~Sl6Kzhv5>>P1;Sq9-aIodC%A%z8W!=Ti(-+_jGAG@624~k zRpxx)D7UUu|G;wfb|0(NJAIU@cl)?mUCj1Tt}f>KsQ%{g@9=xo30Xmw5~s0B*4KG! zi5zZV88>m4FV_>C&k71>1iVQaS6}G2ME{{sxPL=wI|Eeic%cGp0k<;@roCYuEJ_%5& wbdMtaG)~n~PPJ4{Kc;g!^)d#1w?|Gd$8Z|F&mkx2<_vyv-);A(#Kb4Se`RQT761SM literal 0 HcmV?d00001