14 Commits

Author SHA1 Message Date
eea38d578b Sort events at query 2022-01-19 09:40:29 +01:00
031c1cea2a Added refactored /event/ endpoints 2022-01-18 23:32:57 +01:00
154617ce88 Added refactored /event/ endpoints 2022-01-18 22:27:57 +01:00
35e7350962 Fixed named query 2022-01-18 15:04:13 +01:00
37d275d537 Added named native query 2022-01-18 08:18:58 +01:00
3796afb712 Added auth to the /event/del endpoint 2022-01-17 05:57:44 +01:00
e05faab31e Added auth to the /event/del endpoint 2022-01-14 19:59:16 +01:00
d5b6d6357e Added auth to a lot of the endpoints 2022-01-14 17:53:42 +01:00
0531f868d0 Save token in DB
Check for unique logins
2022-01-13 17:34:20 +01:00
de1dcf7673 Added edit-endpoint 2022-01-13 17:32:58 +01:00
e062d9254f Fixed isAdmin at addNewUser endpoint 2022-01-11 17:08:09 +01:00
eeef96ffb6 Fixed Spring security 2022-01-10 13:25:52 +01:00
68eb7e5863 Refactor 2022-01-10 12:11:52 +01:00
8d6a850d30 Added login endpoint 2021-12-20 19:44:01 +01:00
20 changed files with 754 additions and 217 deletions

View File

@@ -17,6 +17,17 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-web'
runtimeOnly 'mysql:mysql-connector-java' runtimeOnly 'mysql:mysql-connector-java'
testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.boot:spring-boot-starter-test'
// Spring security
//implementation 'org.springframework.boot:spring-boot-starter-security'
//implementation 'org.springframework.security:spring-security-test'
// JSON web token
implementation 'io.jsonwebtoken:jjwt-api:0.11.2'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2',
// Uncomment the next line if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms:
//'org.bouncycastle:bcprov-jdk15on:1.60',
'io.jsonwebtoken:jjwt-jackson:0.11.2' // or 'io.jsonwebtoken:jjwt-gson:0.11.2' for gson
} }
test { test {

View File

@@ -1,47 +0,0 @@
package com.vpr.server;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import javax.transaction.Transactional;
import java.util.List;
// This will be AUTO IMPLEMENTED by Spring into a Bean called eventRepository
// CRUD refers Create, Read, Update, Delete
public interface EventRepository extends CrudRepository<Event, Integer> {
@Query(value = "SELECT e.id AS eid, e.name AS ename, e.start, e.end, e.priority , e.is_full_day, " +
"ue.date, " +
"u.id AS uid, u.forename, u.name AS uname " +
"FROM event e " +
"INNER JOIN user_event ue " +
"ON e.id = ue.event_id " +
"INNER JOIN user u " +
"ON ue.user_id = u.id " +
"WHERE u.id = ?1 " +
"OR e.is_private = 0",
nativeQuery = true)
Object[] findAllVisibleByUserId(long id);
@Query(value = "SELECT * " +
"FROM event e " +
"INNER JOIN user_event ue " +
"ON e.id = ue.event_id " +
"WHERE ue.user_id = ?1",
nativeQuery = true)
Object[] findAllByUserId(long id);
@Modifying
@Transactional
@Query(value = "DELETE ue FROM user_event ue WHERE ue.event_id = ?1",
nativeQuery = true)
void deleteUserEventsById(long id);
@Modifying
@Transactional
@Query(value = "DELETE e FROM event e WHERE e.id = ?1",
nativeQuery = true)
void deleteById(long id);
}

View File

@@ -1,141 +0,0 @@
package com.vpr.server;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.sql.Date;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.Optional;
@Controller // This means that this class is a Controller
@RequestMapping(path="/vpr") // This means URL's start with /demo (after Application path)
public class MainController {
// This means to get the bean called userRepository
// Which is auto-generated by Spring, we will use it to handle the data
@Autowired
private com.vpr.server.UserRepository userRepository;
@Autowired
private EventRepository eventRepository;
@Autowired
private UserEventRepository userEventRepository;
// POST-request at /add with request parameter
// @ResponseBody means the returned String is the response, not a view name
@PostMapping(path="/add-user")
public @ResponseBody String addNewUser (
@RequestParam String name,
@RequestParam String forename,
@RequestParam String password,
@RequestParam String isAdmin
) {
com.vpr.server.User user = new com.vpr.server.User();
// TODO set correct token and password
user.setName(name);
user.setForename(forename);
user.setPassword(password);
user.setToken("test");
user.setAdmin(isAdmin.equals("1"));
userRepository.save(user);
return "Saved";
}
@PostMapping(path="/add-event")
public @ResponseBody String addEvent (
@RequestParam Integer userId,
@RequestParam String date,
@RequestParam String name,
@RequestParam String start,
@RequestParam String end,
@RequestParam Integer prority,
@RequestParam Boolean isFullDay,
@RequestParam Boolean isPrivate
) {
com.vpr.server.Event event = new com.vpr.server.Event();
event.setName(name);
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("hh:mm");
long ms = simpleDateFormat.parse(start).getTime();
event.setStart(new Time(ms));
}catch (Exception e){
event.setStart(null);
}
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("hh:mm");
long ms = simpleDateFormat.parse(end).getTime();
event.setEnd(new Time(ms));
}catch (Exception e){
event.setEnd(null);
}
event.setPriority(prority);
event.setFullDay(isFullDay);
event.setPrivate(isPrivate);
eventRepository.save(event);
com.vpr.server.UserEvent userEvent = new com.vpr.server.UserEvent();
try {
System.out.println("date " + date);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
userEvent.setDate(new java.sql.Date(simpleDateFormat.parse(date).getTime()));
}catch (Exception e){
System.out.println("DATE FORMAT NOT CORRECT");
}
userEvent.setEvent(event);
long uId = Long.valueOf(userId);
User user = userRepository.findById(uId);
userEvent.setUser(user);
System.out.println(userEvent);
System.out.println(user);
userEventRepository.save(userEvent);
return "Saved";
}
@PostMapping(path="/del-event")
public @ResponseBody String addEvent ( @RequestParam Integer eventId ) {
eventRepository.deleteUserEventsById(Long.valueOf(eventId));
eventRepository.deleteById(Long.valueOf(eventId));
return "Deleted";
}
// GET-request at /all-users
// returns JSON-data
@GetMapping(path="/all-users")
public @ResponseBody Object[] getAllUsers() {
return userRepository.findAllUsernames();
}
// POST-request at /all-events
// returns JSON-data
@PostMapping(path="/all-events")
public @ResponseBody Object[] getAllEvents(@RequestParam long userId) {
return eventRepository.findAllVisibleByUserId(userId);
}
@GetMapping(path="/all-events-test")
public @ResponseBody Iterable<com.vpr.server.Event> getAllEventsTest() {
return eventRepository.findAll();
}
}

View File

@@ -0,0 +1,172 @@
package com.vpr.server.controller;
import com.vpr.server.data.Event;
import com.vpr.server.data.User;
import com.vpr.server.data.UserEvent;
import com.vpr.server.dao.interfaces.EventDAO;
import com.vpr.server.json.JSONMapper;
import com.vpr.server.json.Validator;
import com.vpr.server.repository.EventRepository;
import com.vpr.server.repository.UserEventRepository;
import com.vpr.server.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.List;
@Controller
@RequestMapping(path = "/event")
public class EventController {
@Autowired
private UserRepository userRepository;
@Autowired
private EventRepository eventRepository;
@Autowired
private UserEventRepository userEventRepository;
@Autowired
private EventDAO eventDAO;
/******************
* POST-ENDPOINTS *
******************/
@PostMapping(path = "/add")
public @ResponseBody
ResponseEntity<String> addEvent(
@RequestHeader("Authorization") String authorizationHeader,
@RequestParam long userId,
@RequestParam String date,
@RequestParam String name,
@RequestParam String start,
@RequestParam String end,
@RequestParam Integer priority,
@RequestParam Boolean isFullDay,
@RequestParam Boolean isPrivate
) {
User authUser = userRepository.findByToken(authorizationHeader.split("\\s")[1]);
if (authUser == null || (!authUser.isAdmin() && authUser.getId() != userId)) {
return new ResponseEntity<>("Du hast keine Rechte um den Termin zu erstellen", HttpStatus.UNAUTHORIZED);
}
ResponseEntity<String> BAD_REQUEST = createEventAndUserEvent(userId, date, name, start, end, priority, isFullDay, isPrivate);
if (BAD_REQUEST != null) return BAD_REQUEST;
return new ResponseEntity<>("", HttpStatus.OK);
}
@PostMapping(path = "/del")
public @ResponseBody
ResponseEntity<String> delEvent(
@RequestHeader("Authorization") String authorizationHeader,
@RequestParam long eventId,
@RequestParam long userId,
@RequestParam String date
) {
User authUser = userRepository.findByToken(authorizationHeader.split("\\s")[1]);
if (authUser == null || (!authUser.isAdmin() && authUser.getId() != userId)) {
return new ResponseEntity<>("Du hast keine Rechte um den Termin zu löschen", HttpStatus.UNAUTHORIZED);
}
eventRepository.deleteUserEventsById(userId, eventId, date);
if(eventDAO.getAllEventsWithId(eventId).size() == 0){
eventRepository.deleteById(eventId);
}
return new ResponseEntity<>("", HttpStatus.OK);
}
@PostMapping(path = "/all")
public @ResponseBody
ResponseEntity<String> getAllEvents(
@RequestHeader("Authorization") String authorizationHeader,
@RequestParam String startDate,
@RequestParam String endDate
) {
User authUser = userRepository.findByToken(authorizationHeader.split("\\s")[1]);
if (authUser == null) {
return new ResponseEntity<>("Bitte erneut einloggen", HttpStatus.UNAUTHORIZED);
}
List<Event> eventList = eventDAO.getAllEventsInTimespan(authUser.getId(), startDate, endDate);
return new ResponseEntity<>(JSONMapper.ToJSON(eventList), HttpStatus.OK);
}
@PostMapping(path = "/edit")
public @ResponseBody
ResponseEntity<String> editEvent(
@RequestHeader("Authorization") String authorizationHeader,
@RequestParam Long eventId,
@RequestParam Long userId,
@RequestParam String date,
@RequestParam String newDate,
@RequestParam String newName,
@RequestParam String newStart,
@RequestParam String newEnd,
@RequestParam Integer newPriority,
@RequestParam Boolean newIsFullDay,
@RequestParam Boolean newIsPrivate
) {
User authUser = userRepository.findByToken(authorizationHeader.split("\\s")[1]);
if (authUser == null || (!authUser.isAdmin() && authUser.getId() != userId)) {
return new ResponseEntity<>("Du hast keine Rechte um den Termin zu bearbeiten", HttpStatus.UNAUTHORIZED);
}
List<Event> eventList = eventDAO.getAllEventsWithIdAndDate(userId, eventId, date);
if (eventList == null || eventList.size() == 0) {
return new ResponseEntity<>("Der Termin exestiert nicht in der Datenbank", HttpStatus.BAD_REQUEST);
}
if (eventList.size() > 1) {
return new ResponseEntity<>("Drr Termin ist doppelt vorhanden. (Um das zu lösen versuche den Termin zu löschen und erneut zu erstellen)", HttpStatus.BAD_REQUEST);
}
eventRepository.deleteUserEventsById(userId, eventId, date);
if(eventDAO.getAllEventsWithId(eventId).size() == 0){
eventRepository.deleteById(eventId);
}
ResponseEntity<String> BAD_REQUEST = createEventAndUserEvent(userId, newDate, newName, newStart, newEnd, newPriority, newIsFullDay, newIsPrivate);
if (BAD_REQUEST != null) return BAD_REQUEST;
return new ResponseEntity<>("", HttpStatus.OK);
}
private ResponseEntity<String> createEventAndUserEvent(long userId, String date, String name, String start, String end, Integer priority, Boolean isFullDay, Boolean isPrivate) {
User user = userRepository.findById(userId);
if(user == null){
return new ResponseEntity<>("UserId nicht korrekt", HttpStatus.BAD_REQUEST);
}
try {
Event event = new Event();
event.setName(Validator.ValidateEventName(name));
event.setStart(Validator.ValidateEventTime(start));
event.setEnd(Validator.ValidateEventTime(end));
event.setPriority(priority);
event.setFullDay(isFullDay);
event.setPrivate(isPrivate);
UserEvent userEvent = new UserEvent();
userEvent.setDate(Validator.ValidateEventDate(date));
userEvent.setEvent(event);
userEvent.setUser(user);
eventRepository.save(event);
userEventRepository.save(userEvent);
}catch (IllegalArgumentException exception){
return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
}
return null;
}
}

View File

@@ -0,0 +1,42 @@
package com.vpr.server.controller;
import com.vpr.server.data.Event;
import com.vpr.server.data.User;
import com.vpr.server.data.UserEvent;
import com.vpr.server.repository.EventRepository;
import com.vpr.server.repository.UserEventRepository;
import com.vpr.server.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
import java.sql.Time;
import java.text.SimpleDateFormat;
@Controller // This means that this class is a Controller
@RequestMapping(path = "/vpr") // This means URL's start with /demo (after Application path)
public class MainController {
// This means to get the bean called userRepository
// Which is auto-generated by Spring, we will use it to handle the data
@Autowired
private UserRepository userRepository;
@Autowired
private EventRepository eventRepository;
@Autowired
private UserEventRepository userEventRepository;
@GetMapping(path = "/status-test")
public String statusTest(){
throw new ResponseStatusException(HttpStatus.I_AM_A_TEAPOT, "TestTestTest");
}
@PostMapping(path = "/header-test")
public ResponseEntity<String> headerTest(@RequestHeader("Authorization") String authorizationHeader){
System.out.println("authorizationHeader: " + authorizationHeader);
return new ResponseEntity<>(authorizationHeader, HttpStatus.OK);
}
}

View File

@@ -0,0 +1,131 @@
package com.vpr.server.controller;
import com.vpr.server.data.User;
import com.vpr.server.repository.UserRepository;
import com.vpr.server.security.Hasher;
import com.vpr.server.security.Token;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
@Controller
@RequestMapping(path = "/user")
public class UserController {
@Autowired
private UserRepository userRepository;
/******************
* POST-ENDPOINTS *
******************/
@PostMapping(path = "/add")
public @ResponseBody
ResponseEntity<String> addNewUser(
@RequestHeader("Authorization") String authorizationHeader,
@RequestParam String name,
@RequestParam String forename,
@RequestParam String login,
@RequestParam String password,
@RequestParam Boolean isAdmin
) {
User authUser = userRepository.findByToken(authorizationHeader.split("\\s")[1]);
if(authUser == null || authUser.isAdmin()){
return new ResponseEntity<>( "Du hast keine Rechte um den Termin zu löschen", HttpStatus.UNAUTHORIZED);
}
if(userRepository.findByLogin(login) != null){
return new ResponseEntity<>( "Login exestiert bereits", HttpStatus.BAD_REQUEST);
}
byte[] salt = Hasher.GenerateSalt();
byte[] hash;
try {
hash = Hasher.HashPassword(password, salt);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
e.printStackTrace();
return new ResponseEntity<>( "Fehler beim hashen", HttpStatus.INTERNAL_SERVER_ERROR);
}
User user = new User();
user.setName(name);
user.setForename(forename);
user.setLogin(login);
user.setPassword(hash);
user.setSalt(salt);
user.setToken("");
user.setAdmin(isAdmin);
userRepository.save(user);
return new ResponseEntity<>( "" + user.getId(), HttpStatus.OK);
}
@PostMapping(path = "/login")
public @ResponseBody
ResponseEntity<String> login(
@RequestParam String login,
@RequestParam String password
) {
System.out.println(login + " tries to login.");
User user = userRepository.findByLogin(login);
if (user == null) {
System.out.println("Login for " + login + " failed.");
return new ResponseEntity<>( "Falscher login", HttpStatus.UNAUTHORIZED);
}
byte[] salt = user.getSalt();
byte[] hash;
try {
hash = Hasher.HashPassword(password, salt);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
e.printStackTrace();
return new ResponseEntity<>( "Fehler beim hashen", HttpStatus.INTERNAL_SERVER_ERROR);
}
if (Arrays.equals(user.getPassword(), hash)) {
String token = Token.Generate(user.getLogin());
user.setToken(token);
userRepository.save(user);
System.out.println(user.getLogin() + " is now logged in.");
System.out.println(Token.Verify(Token.Generate(user.getLogin()), user.getLogin()));
return new ResponseEntity<>( token + " " + user.getId(), HttpStatus.OK);
}
System.out.println(user.getLogin() + " failed to logged in.");
System.out.println("entered : " + javax.xml.bind.DatatypeConverter.printHexBinary(hash));
System.out.println("required: " + javax.xml.bind.DatatypeConverter.printHexBinary(user.getPassword()));
return new ResponseEntity<>( "Falscher login", HttpStatus.UNAUTHORIZED);
}
@PostMapping(path = "/del")
public @ResponseBody ResponseEntity<String> deleteUser(
@RequestHeader("Authorization") String authorizationHeader,
@RequestParam Integer userId
) {
User authUser = userRepository.findByToken(authorizationHeader.split("\\s")[1]);
if(authUser == null || authUser.isAdmin()){
return new ResponseEntity<>( "Du hast keine Rechte um den Termin zu löschen", HttpStatus.UNAUTHORIZED);
}
userRepository.deleteById(Long.valueOf(userId));
return new ResponseEntity<>( "", HttpStatus.OK);
}
/*****************
* GET-ENDPOINTS *
*****************/
@GetMapping(path = "/all")
public @ResponseBody
Object[] getAllUsers() {
return userRepository.findAllUsernames();
}
}

View File

@@ -0,0 +1,48 @@
package com.vpr.server.dao.implementation;
import com.vpr.server.dao.interfaces.EventDAO;
import com.vpr.server.data.Event;
import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import java.util.List;
@Repository
@Transactional
public class EventDAOImplementation implements EventDAO {
@PersistenceContext
private EntityManager manager;
@Override
public List<Event> getAllEvents() {
return manager.createNamedQuery("getAllEvents", Event.class).getResultList();
}
@Override
public List<Event> getAllEventsWithId(long eventId) {
return manager.createNamedQuery("getAllEventsWithId", Event.class)
.setParameter("eventId", eventId)
.getResultList();
}
@Override
public List<Event> getAllEventsInTimespan(long userId, String startDate, String endDate) {
return manager.createNamedQuery("getAllEventsInTimespan", Event.class)
.setParameter("userId", userId)
.setParameter("startDate", startDate)
.setParameter("endDate", endDate)
.getResultList();
}
@Override
public List<Event> getAllEventsWithIdAndDate(long userId, long eventId, String date) {
return manager.createNamedQuery("getAllEventsWithIdAndDate", Event.class)
.setParameter("userId", userId)
.setParameter("eventId", eventId)
.setParameter("date", date)
.getResultList();
}
}

View File

@@ -0,0 +1,16 @@
package com.vpr.server.dao.interfaces;
import com.vpr.server.data.Event;
import java.util.List;
public interface EventDAO {
List<Event> getAllEvents();
List<Event> getAllEventsInTimespan(long userId, String startDate, String endDate);
List<Event> getAllEventsWithIdAndDate(long userId, long eventId, String date);
List<Event> getAllEventsWithId(long eventId);
}

View File

@@ -1,4 +1,4 @@
package com.vpr.server; package com.vpr.server.data;
import java.sql.Date; import java.sql.Date;
import java.sql.Time; import java.sql.Time;

View File

@@ -1,33 +1,73 @@
package com.vpr.server; package com.vpr.server.data;
import javax.persistence.*; import javax.persistence.*;
import java.io.Serializable;
import java.sql.Time; import java.sql.Time;
import java.util.List; import java.util.List;
// @Entity creates a table out of this class with Hibernate @Entity(name = "Event") // @Entity creates a table out of this class with Hibernate
@Entity(name = "Event") @Table(name = "event")
public class Event { @NamedNativeQueries({
@NamedNativeQuery(
name = "getAllEvents",
query = "SELECT * FROM event",
resultClass = Event.class
),
@NamedNativeQuery(
name = "getAllEventsInTimespan",
query = "SELECT * " +
"FROM event e " +
"INNER JOIN user_event ue " +
"ON e.id = ue.event_id " +
"WHERE (ue.user_id = :userId OR e.is_private = 0) " +
"AND ue.date > :startDate " +
"AND ue.date < :endDate " +
"ORDER BY ue.date, e.priority DESC, e.start",
resultClass = Event.class
),
@NamedNativeQuery(
name = "getAllEventsWithIdAndDate",
query = "SELECT * " +
"FROM event e " +
"INNER JOIN user_event ue " +
"ON e.id = ue.event_id " +
"WHERE ue.user_id = :userId " +
"AND ue.event_id = :eventId " +
"AND ue.date = :date",
resultClass = Event.class
),
@NamedNativeQuery(
name = "getAllEventsWithId",
query = "SELECT * " +
"FROM event e " +
"INNER JOIN user_event ue " +
"ON e.id = ue.event_id " +
"WHERE ue.event_id = :eventId",
resultClass = Event.class
)
})
public class Event implements Serializable {
// Generate the primary key // Generate the primary key
@Id @Id
@GeneratedValue(strategy=GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private long id; private long id;
@Column(name="name", nullable=false) @Column(name = "name", nullable = false)
private String name; private String name;
@Column(name="priority", nullable=false) @Column(name = "priority", nullable = false)
private Integer priority; private Integer priority;
@Column(name="is_full_day", nullable=false) @Column(name = "is_full_day", nullable = false)
private boolean isFullDay; private boolean isFullDay;
@Column(name="is_private", nullable=false) @Column(name = "is_private", nullable = false)
private boolean isPrivate; private boolean isPrivate;
@Column(name="start") @Column(name = "start")
private Time start; private Time start;
@Column(name="end") @Column(name = "end")
private Time end; private Time end;
@OneToMany(mappedBy = "event") @OneToMany(mappedBy = "event")

View File

@@ -1,4 +1,4 @@
package com.vpr.server; package com.vpr.server.data;
import javax.persistence.*; import javax.persistence.*;
import java.util.List; import java.util.List;
@@ -17,8 +17,14 @@ public class User {
@Column(name="forename", nullable=false) @Column(name="forename", nullable=false)
private String forename; private String forename;
@Column(name="login", nullable=false)
private String login;
@Column(name="password", nullable=false) @Column(name="password", nullable=false)
private String password; private byte[] password;
@Column(name="salt", nullable=false)
private byte[] salt;
@Column(name="token") @Column(name="token")
private String token; private String token;
@@ -57,14 +63,30 @@ public class User {
this.forename = forename; this.forename = forename;
} }
public String getPassword() { public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public byte[] getPassword() {
return password; return password;
} }
public void setPassword(String password) { public void setPassword(byte[] password) {
this.password = password; this.password = password;
} }
public byte[] getSalt() {
return salt;
}
public void setSalt(byte[] salt) {
this.salt = salt;
}
public String getToken() { public String getToken() {
return token; return token;
} }

View File

@@ -1,8 +1,7 @@
package com.vpr.server; package com.vpr.server.data;
import javax.persistence.*; import javax.persistence.*;
import java.sql.Date; import java.sql.Date;
import java.util.List;
// @Entity creates a table out of this class with Hibernate // @Entity creates a table out of this class with Hibernate
// @Table defines the table-name // @Table defines the table-name

View File

@@ -1,4 +1,4 @@
package com.vpr.server; package com.vpr.server.data;
import java.io.Serializable; import java.io.Serializable;
import java.sql.Date; import java.sql.Date;

View File

@@ -0,0 +1,56 @@
package com.vpr.server.json;
import com.vpr.server.data.Event;
import com.vpr.server.data.UserEvent;
import java.sql.Time;
import java.util.ArrayList;
import java.util.List;
public class JSONMapper {
public static List<String> ToJSON(Event event){
List<String> eventListJSON = new ArrayList<>();
for (UserEvent userEvent : event.getUserEvent()) {
String eventJSON = "{" +
"\"ownerId\": " + userEvent.getUser().getId() + ", " +
"\"ownerName\": \"" + userEvent.getUser().getForename() + " " + userEvent.getUser().getName() + "\", " +
"\"date\": \"" + userEvent.getDate() + "\", " +
"\"id\": " + event.getId() + "," +
"\"name\": \"" + event.getName() + "\"," +
"\"priority\": " + event.getPriority() + "," +
"\"fullDay\": " + event.isFullDay() + "," +
"\"private\": " + event.isPrivate() + "," +
"\"start\": " + ToJSON(event.getStart()) + "," +
"\"end\": " + ToJSON(event.getEnd()) +
"}";
eventListJSON.add(eventJSON);
}
return eventListJSON;
}
public static String ToJSON(List<Event> eventList){
StringBuilder eventListJSON = new StringBuilder();
for(Event event : eventList){
List<String> eventsJSON = ToJSON(event);
for(String eventJSON : eventsJSON){
eventListJSON.append(", ");
eventListJSON.append(eventJSON);
}
}
eventListJSON.delete(0, 2);
return "[" + eventListJSON + "]";
}
public static String ToJSON(Time time){
if(time == null){
return "null";
}
return "\"" + time + "\"";
}
}

View File

@@ -0,0 +1,47 @@
package com.vpr.server.json;
import com.vpr.server.data.UserEvent;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import java.sql.Date;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Validator {
public static String ValidateEventName(String name) throws IllegalArgumentException {
if (name.length() < 3) {
System.out.println("NAME TO SHORT");
throw new IllegalArgumentException("Der Name ist zu kurz");
}
Pattern pattern = Pattern.compile("[A-Za-z\u00e4\u00f6\u00fc\u00c4\u00d6\u00dc\u00df0-9 =!?+*/$.:,;_<>()-]*");
Matcher matcher = pattern.matcher(name);
if(!matcher.matches()){
System.out.println("NAME HAS ILLEGALCHARS");
throw new IllegalArgumentException("Der Name enthält nicht erlaubte Zeichen");
}
return name;
}
public static Time ValidateEventTime(String time) throws IllegalArgumentException {
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("hh:mm");
long ms = simpleDateFormat.parse(time).getTime();
return new Time(ms);
} catch (Exception e) {
return null;
}
}
public static Date ValidateEventDate(String date) throws IllegalArgumentException {
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
return new Date(simpleDateFormat.parse(date).getTime());
} catch (Exception e) {
System.out.println("DATE FORMAT NOT CORRECT");
throw new IllegalArgumentException("Datumformat nicht korrekt");
}
}
}

View File

@@ -0,0 +1,84 @@
package com.vpr.server.repository;
import com.vpr.server.data.Event;
import com.vpr.server.data.UserEvent;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import javax.persistence.ColumnResult;
import javax.persistence.ConstructorResult;
import javax.persistence.NamedNativeQuery;
import javax.persistence.SqlResultSetMapping;
import javax.transaction.Transactional;
import java.util.List;
import java.util.Optional;
// This will be AUTO IMPLEMENTED by Spring into a Bean called eventRepository
// CRUD refers Create, Read, Update, Delete
public interface EventRepository extends CrudRepository<Event, Integer> {
@Query(
value = "SELECT e.id AS eid, e.name AS ename, e.start, e.end, e.priority , e.is_full_day, " +
"ue.date, " +
"u.id AS uid, u.forename, u.name AS uname " +
"FROM event e " +
"INNER JOIN user_event ue " +
"ON e.id = ue.event_id " +
"INNER JOIN user u " +
"ON ue.user_id = u.id " +
"WHERE u.id = ?1 " +
"OR e.is_private = 0",
nativeQuery = true
)
Object[] findAllVisibleByUserId(long id);
@Query(
value = "SELECT * " +
"FROM event e " +
"INNER JOIN user_event ue " +
"ON e.id = ue.event_id " +
"WHERE ue.user_id = ?1",
nativeQuery = true
)
Object[] findAllByUserId(long id);
@Query(
value = "SELECT ue.user_id as userId, ue.event_id as eventId, ue.date as date " +
"FROM event e " +
"INNER JOIN user_event ue " +
"ON e.id = ue.event_id " +
"WHERE ue.event_id = ?1 " +
"AND ue.user_id = ?2 " +
"AND ue.date = ?3",
nativeQuery = true
)
UserEventInterface findUserEventByEventIdUserIdAndDate(long eventId, long userId, String date);
interface UserEventInterface{
long getEventId();
long getUserId();
long getDate();
}
@Modifying
@Transactional
@Query(
value = "DELETE ue FROM user_event ue WHERE ue.event_id = :eventId AND ue.user_id = :userId AND ue.date = :date",
nativeQuery = true
)
void deleteUserEventsById(long userId, long eventId, String date);
@Modifying
@Transactional
@Query(
value = "DELETE e FROM event e WHERE e.id = ?1",
nativeQuery = true
)
void deleteById(long id);
//@Query(nativeQuery = true)
//List<Event> findEventsInDateRange(Long userId, String startDate, String endDate);
}

View File

@@ -1,11 +1,8 @@
package com.vpr.server; package com.vpr.server.repository;
import org.springframework.data.jpa.repository.Query; import com.vpr.server.data.UserEvent;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import java.sql.Date;
import java.util.List;
// This will be AUTO IMPLEMENTED by Spring into a Bean called eventListRepository // This will be AUTO IMPLEMENTED by Spring into a Bean called eventListRepository
// CRUD refers Create, Read, Update, Delete // CRUD refers Create, Read, Update, Delete

View File

@@ -1,13 +1,11 @@
package com.vpr.server; package com.vpr.server.repository;
import com.vpr.server.data.User;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import java.util.List;
// This will be AUTO IMPLEMENTED by Spring into a Bean called userRepository // This will be AUTO IMPLEMENTED by Spring into a Bean called userRepository
// CRUD refers Create, Read, Update, Delete // CRUD refers Create, Read, Update, Delete
public interface UserRepository extends CrudRepository<User, Integer> { public interface UserRepository extends CrudRepository<User, Integer> {
@Query(value = "SELECT u.id, u.name, u.forename " + @Query(value = "SELECT u.id, u.name, u.forename " +
@@ -15,5 +13,13 @@ public interface UserRepository extends CrudRepository<User, Integer> {
nativeQuery = true) nativeQuery = true)
Object[] findAllUsernames(); Object[] findAllUsernames();
com.vpr.server.User findById(long id); User findById(long id);
User findByLogin(String login);
User findByLoginAndPassword(String login, byte[] password);
void deleteById(long id);
User findByToken(String token);
} }

View File

@@ -0,0 +1,28 @@
package com.vpr.server.security;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
public class Hasher {
public static byte[] HashPassword(String password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
// Credit: https://www.baeldung.com/java-password-hashing
// Generate hash with PBKDF2
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
return factory.generateSecret(spec).getEncoded();
}
public static byte[] GenerateSalt(){
// Credit: https://www.baeldung.com/java-password-hashing
// Create a salt
SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);
return salt;
}
}

View File

@@ -0,0 +1,26 @@
package com.vpr.server.security;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
public class Token {
private static Key KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256);
public static String Generate(String subject){
return Jwts.builder().setSubject(subject).signWith(KEY).compact();
}
public static boolean Verify(String jws, String subject){
try {
assert Jwts.parserBuilder().setSigningKey(KEY).build().parseClaimsJws(jws)
.getBody().getSubject().equals(subject);
return true;
} catch (JwtException e) {
return false;
}
}
}