first commit

This commit is contained in:
Akito123321 2024-06-05 01:19:08 +02:00
commit 5a7951a131
57 changed files with 1238 additions and 0 deletions

34
.classpath Normal file
View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

23
.project Normal file
View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>valoStratsBackend</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@ -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/<project>=UTF-8

View File

@ -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

View File

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

90
pom.xml Normal file
View File

@ -0,0 +1,90 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.4</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>me.akito123321.valoStratsBackend</groupId>
<artifactId>valoStratsBackend</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!--
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.squareup.retrofit2/retrofit -->
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.10.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<!--
https://mvnrepository.com/artifact/com.squareup.retrofit2/converter-gson -->
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-gson</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!--
https://mvnrepository.com/artifact/org.springframework.data/spring-data-jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--
https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client -->
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
</dependency>
<dependency>
<groupId>com.sigpwned</groupId>
<artifactId>opengraph4j</artifactId>
<version>0.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.17.2</version>
</dependency>
</dependencies>
</project>

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,5 @@
package me.akito123321.valoStrats.db;
public record MySQLConfig(String host, int port, String username, String password, String database) {
}

View File

@ -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<Group, String> {
List<Group> findByOwnerUsername(String ownerId);
}

View File

@ -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<Strat, String> {
}

View File

@ -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<StratsUser, String> {
Optional<StratsUser> findByGoogleUserId(String googleUserId);
Optional<StratsUser> findByTokensIn(List<String> tokens);
}

View File

@ -0,0 +1,5 @@
package me.akito123321.valoStrats.rest;
public record ConfigResponse(String clientId, String redirect_url) {
}

View File

@ -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<AuthenticationResponse> 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));
}
}

View File

@ -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<ConfigResponse> getConfig() {
Config config = ValoStratsApplication.config;
return ResponseEntity.ok(new ConfigResponse(config.clientId(), config.redirect_url()));
}
}

View File

@ -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<Group> createGroup(@RequestBody GroupRequest request) {
StratsUser user = getUser();
Group group = new Group(request.name(), user);
groupService.saveGroup(group);
return ResponseEntity.ok(group);
}
@GetMapping("/")
public ResponseEntity<List<Group>> getGroups() {
StratsUser user = getUser();
List<Group> groups = user.getGroups();
return ResponseEntity.ok(groups);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> 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<Group> 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<Group> 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<Group> 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<Group> 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<Group> 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<Group> 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<Group> 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;
}
}

View File

@ -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<JsonObject> 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<JsonObject> getUserInfo(@Header("Authorization") String token);
}

View File

@ -0,0 +1,5 @@
package me.akito123321.valoStrats.rest.requests;
public record AuthenticationRequest(String code) {
}

View File

@ -0,0 +1,5 @@
package me.akito123321.valoStrats.rest.requests;
public record AuthenticationResponse(String username, String displayName, String token) {
}

View File

@ -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) {
}

View File

@ -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) {
}

View File

@ -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<Group> getGroups() {
return groupRepository.findAll();
}
public Group getGroupById(String id) {
return groupRepository.findById(id).orElse(null);
}
public void removeGroup(String id) {
groupRepository.deleteById(id);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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<JsonObject> 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;
}
}

View File

@ -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);
}
}

View File

@ -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<SimpleGrantedAuthority> authorities;
private boolean isAccountNonExpired;
private boolean isAccountNonLocked;
private boolean isCredentialsNonExpired;
private boolean isEnabled;
@ElementCollection(fetch = FetchType.EAGER)
private Set<String> tokens;
private String googleUserId;
private String displayName;
@ManyToMany(mappedBy = "members")
@ElementCollection(fetch = FetchType.EAGER)
@JsonIgnore
private List<Group> groups;
public StratsUser() {
}
public StratsUser(String googleUserId, String displayName, List<SimpleGrantedAuthority> 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<String> getTokens() {
return tokens;
}
@Override
public Collection<? extends GrantedAuthority> 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<Group> getGroups() {
return groups;
}
}

View File

@ -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;
}
}

View File

@ -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<StratsUser> members;
@ManyToMany
private List<Strat> strats;
public Group(String name, StratsUser owner) {
this.name = name;
this.owner = owner;
this.members = new ArrayList<StratsUser>();
this.strats = new ArrayList<Strat>();
}
public Group() {
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public StratsUser getOwner() {
return owner;
}
public List<StratsUser> getMembers() {
return members;
}
public List<Strat> getStrats() {
return strats;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,90 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.4</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>me.akito123321.valoStratsBackend</groupId>
<artifactId>valoStratsBackend</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!--
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.squareup.retrofit2/retrofit -->
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.10.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<!--
https://mvnrepository.com/artifact/com.squareup.retrofit2/converter-gson -->
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-gson</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!--
https://mvnrepository.com/artifact/org.springframework.data/spring-data-jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--
https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client -->
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
</dependency>
<dependency>
<groupId>com.sigpwned</groupId>
<artifactId>opengraph4j</artifactId>
<version>0.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.17.2</version>
</dependency>
</dependencies>
</project>

Binary file not shown.