From 55eb4f46faea4b1be1df6e2dbb31ba2f4689e044 Mon Sep 17 00:00:00 2001 From: FireMasterK <20838718+FireMasterK@users.noreply.github.com> Date: Wed, 9 Jun 2021 21:16:56 +0530 Subject: [PATCH] Commit stash. --- build.gradle | 1 + src/main/java/me/kavin/piped/Main.java | 5 + .../java/me/kavin/piped/ServerLauncher.java | 38 ++++++ .../piped/utils/DatabaseSessionFactory.java | 33 +++++ .../me/kavin/piped/utils/RegisterRequest.java | 7 -- .../me/kavin/piped/utils/ResponseHelper.java | 114 +++++++++++++++++- .../me/kavin/piped/utils/obj/db/Channel.java | 23 ++++ .../me/kavin/piped/utils/obj/db/User.java | 13 ++ .../me/kavin/piped/utils/obj/db/Video.java | 48 -------- .../piped/utils/resp/AcceptedResponse.java | 7 ++ .../utils/resp/AlreadyRegisteredResponse.java | 7 ++ .../resp/AuthenticationFailureResponse.java | 7 ++ .../piped/utils/resp/DatabaseHelper.java | 21 ++++ .../resp/IncorrectCredentialsResponse.java | 7 ++ .../kavin/piped/utils/resp/LoginRequest.java | 7 ++ .../kavin/piped/utils/resp/LoginResponse.java | 10 ++ .../utils/resp/SubscriptionUpdateRequest.java | 7 ++ src/main/resources/hibernate.cfg.xml | 2 + 18 files changed, 300 insertions(+), 57 deletions(-) create mode 100644 src/main/java/me/kavin/piped/utils/DatabaseSessionFactory.java delete mode 100644 src/main/java/me/kavin/piped/utils/RegisterRequest.java create mode 100644 src/main/java/me/kavin/piped/utils/obj/db/Channel.java create mode 100644 src/main/java/me/kavin/piped/utils/resp/AcceptedResponse.java create mode 100644 src/main/java/me/kavin/piped/utils/resp/AlreadyRegisteredResponse.java create mode 100644 src/main/java/me/kavin/piped/utils/resp/AuthenticationFailureResponse.java create mode 100644 src/main/java/me/kavin/piped/utils/resp/DatabaseHelper.java create mode 100644 src/main/java/me/kavin/piped/utils/resp/IncorrectCredentialsResponse.java create mode 100644 src/main/java/me/kavin/piped/utils/resp/LoginRequest.java create mode 100644 src/main/java/me/kavin/piped/utils/resp/LoginResponse.java create mode 100644 src/main/java/me/kavin/piped/utils/resp/SubscriptionUpdateRequest.java diff --git a/build.gradle b/build.gradle index de433b0..d9240c0 100644 --- a/build.gradle +++ b/build.gradle @@ -33,6 +33,7 @@ dependencies { implementation 'io.activej:activej-launchers-http:4.3' implementation 'org.postgresql:postgresql:42.2.19' implementation 'org.hibernate:hibernate-core:5.4.30.Final' + implementation 'org.hibernate:hibernate-hikaricp:5.4.30.Final' implementation 'net.java.dev.jna:jna-platform:5.8.0' } diff --git a/src/main/java/me/kavin/piped/Main.java b/src/main/java/me/kavin/piped/Main.java index 62e83c4..e79c379 100644 --- a/src/main/java/me/kavin/piped/Main.java +++ b/src/main/java/me/kavin/piped/Main.java @@ -4,6 +4,7 @@ import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.localization.Localization; import io.activej.inject.Injector; +import me.kavin.piped.utils.DatabaseSessionFactory; import me.kavin.piped.utils.DownloaderImpl; public class Main { @@ -14,6 +15,10 @@ public class Main { Injector.useSpecializer(); + new Thread(() -> { + DatabaseSessionFactory.createSession().close(); + }).start(); + new ServerLauncher().launch(args); } diff --git a/src/main/java/me/kavin/piped/ServerLauncher.java b/src/main/java/me/kavin/piped/ServerLauncher.java index 19cb45f..c577886 100644 --- a/src/main/java/me/kavin/piped/ServerLauncher.java +++ b/src/main/java/me/kavin/piped/ServerLauncher.java @@ -1,6 +1,7 @@ package me.kavin.piped; import static io.activej.config.converter.ConfigConverters.ofInetSocketAddress; +import static io.activej.http.HttpHeaders.AUTHORIZATION; import static io.activej.http.HttpHeaders.CACHE_CONTROL; import static io.activej.http.HttpHeaders.CONTENT_TYPE; @@ -35,6 +36,8 @@ import me.kavin.piped.utils.CustomServletDecorator; import me.kavin.piped.utils.ResponseHelper; import me.kavin.piped.utils.SponsorBlockUtils; import me.kavin.piped.utils.resp.ErrorResponse; +import me.kavin.piped.utils.resp.LoginRequest; +import me.kavin.piped.utils.resp.SubscriptionUpdateRequest; public class ServerLauncher extends MultithreadedHttpServerLauncher { @@ -173,6 +176,41 @@ public class ServerLauncher extends MultithreadedHttpServerLauncher { } catch (Exception e) { return getErrorResponse(e); } + })).map("/register", AsyncServlet.ofBlocking(executor, request -> { + try { + LoginRequest body = Constants.mapper.readValue(request.loadBody().getResult().asArray(), + LoginRequest.class); + return getJsonResponse(ResponseHelper.registerResponse(body.username, body.password), "private"); + } catch (Exception e) { + return getErrorResponse(e); + } + })).map("/login", AsyncServlet.ofBlocking(executor, request -> { + try { + LoginRequest body = Constants.mapper.readValue(request.loadBody().getResult().asArray(), + LoginRequest.class); + return getJsonResponse(ResponseHelper.loginResponse(body.username, body.password), "private"); + } catch (Exception e) { + return getErrorResponse(e); + } + })).map("/subscribe", AsyncServlet.ofBlocking(executor, request -> { + try { + SubscriptionUpdateRequest body = Constants.mapper.readValue(request.loadBody().getResult().asArray(), + SubscriptionUpdateRequest.class); + return getJsonResponse( + ResponseHelper.subscribeResponse(request.getHeader(AUTHORIZATION), body.channelId), "private"); + } catch (Exception e) { + return getErrorResponse(e); + } + })).map("/unsubscribe", AsyncServlet.ofBlocking(executor, request -> { + try { + SubscriptionUpdateRequest body = Constants.mapper.readValue(request.loadBody().getResult().asArray(), + SubscriptionUpdateRequest.class); + return getJsonResponse( + ResponseHelper.unsubscribeResponse(request.getHeader(AUTHORIZATION), body.channelId), + "private"); + } catch (Exception e) { + return getErrorResponse(e); + } })); return new CustomServletDecorator(router); diff --git a/src/main/java/me/kavin/piped/utils/DatabaseSessionFactory.java b/src/main/java/me/kavin/piped/utils/DatabaseSessionFactory.java new file mode 100644 index 0000000..72a86cf --- /dev/null +++ b/src/main/java/me/kavin/piped/utils/DatabaseSessionFactory.java @@ -0,0 +1,33 @@ +package me.kavin.piped.utils; + +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.cfg.Configuration; + +import me.kavin.piped.utils.obj.db.User; +import me.kavin.piped.utils.obj.db.Video; + +public class DatabaseSessionFactory { + + private static final SessionFactory sessionFactory; + + static { + + final Configuration configuration = new Configuration(); + + configuration.setProperty("hibernate.connection.url", "jdbc:postgresql://"); + configuration.setProperty("hibernate.connection.driver_class", "org.postgresql.Driver"); + configuration.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect"); + configuration.setProperty("hibernate.connection.username", "piped"); + configuration.setProperty("hibernate.connection.password", "@8LQuf7JUabCker$zQYS"); + configuration.setProperty("hibernate.temp.use_jdbc_metadata_defaults", "false"); + configuration.configure(); + + sessionFactory = configuration.addAnnotatedClass(User.class).addAnnotatedClass(Video.class) + .buildSessionFactory(); + } + + public static final Session createSession() { + return sessionFactory.openSession(); + } +} diff --git a/src/main/java/me/kavin/piped/utils/RegisterRequest.java b/src/main/java/me/kavin/piped/utils/RegisterRequest.java deleted file mode 100644 index 7d75b25..0000000 --- a/src/main/java/me/kavin/piped/utils/RegisterRequest.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.kavin.piped.utils; - -public class RegisterRequest { - - public String username, password; - -} diff --git a/src/main/java/me/kavin/piped/utils/ResponseHelper.java b/src/main/java/me/kavin/piped/utils/ResponseHelper.java index 4aff0d7..06bbe87 100644 --- a/src/main/java/me/kavin/piped/utils/ResponseHelper.java +++ b/src/main/java/me/kavin/piped/utils/ResponseHelper.java @@ -8,12 +8,19 @@ import java.net.http.HttpRequest; import java.net.http.HttpRequest.BodyPublishers; import java.net.http.HttpResponse.BodyHandlers; import java.nio.charset.StandardCharsets; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + import org.apache.commons.lang3.exception.ExceptionUtils; +import org.hibernate.Session; import org.json.JSONObject; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage; @@ -58,10 +65,17 @@ import me.kavin.piped.utils.obj.StreamItem; import me.kavin.piped.utils.obj.Streams; import me.kavin.piped.utils.obj.StreamsPage; import me.kavin.piped.utils.obj.Subtitle; +import me.kavin.piped.utils.obj.db.User; import me.kavin.piped.utils.obj.search.SearchChannel; import me.kavin.piped.utils.obj.search.SearchItem; import me.kavin.piped.utils.obj.search.SearchPlaylist; import me.kavin.piped.utils.obj.search.SearchStream; +import me.kavin.piped.utils.resp.AcceptedResponse; +import me.kavin.piped.utils.resp.AlreadyRegisteredResponse; +import me.kavin.piped.utils.resp.AuthenticationFailureResponse; +import me.kavin.piped.utils.resp.DatabaseHelper; +import me.kavin.piped.utils.resp.IncorrectCredentialsResponse; +import me.kavin.piped.utils.resp.LoginResponse; public class ResponseHelper { @@ -461,9 +475,105 @@ public class ResponseHelper { } - public static final byte[] registerResponse(String user, String pass) throws IOException { + public static final byte[] registerResponse(String user, String pass) + throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { - return Constants.mapper.writeValueAsBytes(null); + user = user.toLowerCase(); + + Session s = DatabaseSessionFactory.createSession(); + CriteriaBuilder cb = s.getCriteriaBuilder(); + CriteriaQuery cr = cb.createQuery(User.class); + Root root = cr.from(User.class); + cr.select(root).where(root.get("username").in(user)); + boolean registered = s.createQuery(cr).uniqueResult() != null; + + if (registered) { + s.close(); + return Constants.mapper.writeValueAsBytes(new AlreadyRegisteredResponse()); + } + + User newuser = new User(user, PasswordHash.createHash(pass), Collections.emptyList()); + + s.save(newuser); + s.beginTransaction().commit(); + + s.close(); + + return Constants.mapper.writeValueAsBytes(new LoginResponse(newuser.getSessionId())); + + } + + public static final byte[] loginResponse(String user, String pass) + throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { + + user = user.toLowerCase(); + + Session s = DatabaseSessionFactory.createSession(); + CriteriaBuilder cb = s.getCriteriaBuilder(); + CriteriaQuery cr = cb.createQuery(User.class); + Root root = cr.from(User.class); + cr.select(root).where(root.get("username").in(user)); + + User dbuser = s.createQuery(cr).uniqueResult(); + + if (dbuser != null && PasswordHash.validatePassword(pass, dbuser.getPassword())) { + s.close(); + return Constants.mapper.writeValueAsBytes(new LoginResponse(dbuser.getSessionId())); + } + + User newuser = new User(user, PasswordHash.createHash(pass), Collections.emptyList()); + + s.save(newuser); + s.beginTransaction().commit(); + + s.close(); + + return Constants.mapper.writeValueAsBytes(new IncorrectCredentialsResponse()); + + } + + public static final byte[] subscribeResponse(String session, String channelId) + throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { + + Session s = DatabaseSessionFactory.createSession(); + + User user = DatabaseHelper.getUserFromSession(s, session); + + if (user != null) { + if (!user.getSubscribed().contains(channelId)) { + user.getSubscribed().add(channelId); + s.update(user); + s.beginTransaction().commit(); + } + s.close(); + return Constants.mapper.writeValueAsBytes(new AcceptedResponse()); + } + + s.close(); + + return Constants.mapper.writeValueAsBytes(new AuthenticationFailureResponse()); + + } + + public static final byte[] unsubscribeResponse(String session, String channelId) + throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { + + Session s = DatabaseSessionFactory.createSession(); + + User user = DatabaseHelper.getUserFromSession(s, session); + + if (user != null) { + if (user.getSubscribed().remove(channelId)) { + s.update(user); + s.beginTransaction().commit(); + } + s.close(); + return Constants.mapper.writeValueAsBytes(new AcceptedResponse()); + } + + s.close(); + + return Constants.mapper.writeValueAsBytes(new AuthenticationFailureResponse()); } diff --git a/src/main/java/me/kavin/piped/utils/obj/db/Channel.java b/src/main/java/me/kavin/piped/utils/obj/db/Channel.java new file mode 100644 index 0000000..e241a85 --- /dev/null +++ b/src/main/java/me/kavin/piped/utils/obj/db/Channel.java @@ -0,0 +1,23 @@ +package me.kavin.piped.utils.obj.db; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class Channel { + + @Id + @Column(name = "uploader_id", length = 30) + private String uploaderId; + + @Column(name = "uploader", length = 80) + private String uploader; + + @Column(name = "uploader_avatar", length = 150) + private String uploaderAvatar; + + @Column(name = "verified") + private boolean verified; + +} diff --git a/src/main/java/me/kavin/piped/utils/obj/db/User.java b/src/main/java/me/kavin/piped/utils/obj/db/User.java index 5b5c94b..73f050b 100644 --- a/src/main/java/me/kavin/piped/utils/obj/db/User.java +++ b/src/main/java/me/kavin/piped/utils/obj/db/User.java @@ -2,6 +2,7 @@ package me.kavin.piped.utils.obj.db; import java.io.Serializable; import java.util.List; +import java.util.UUID; import javax.persistence.CollectionTable; import javax.persistence.Column; @@ -32,6 +33,9 @@ public class User implements Serializable { @Column(name = "password", columnDefinition = "text") private String password; + @Column(name = "session_id", length = 36) + private String sessionId; + @ElementCollection @CollectionTable(name = "users_subscribed", joinColumns = @JoinColumn(name = "subscriber"), indexes = @Index(columnList = "subscriber", name = "subscriber_idx")) @Column(name = "channel", length = 30) @@ -44,6 +48,7 @@ public class User implements Serializable { this.username = username; this.password = password; this.subscribed_ids = subscribed_ids; + this.sessionId = String.valueOf(UUID.randomUUID()); } public long getId() { @@ -66,6 +71,14 @@ public class User implements Serializable { return password; } + public String getSessionId() { + return sessionId; + } + + public void setSessionId(String sessionId) { + this.sessionId = sessionId; + } + public void setPassword(String password) { this.password = password; } diff --git a/src/main/java/me/kavin/piped/utils/obj/db/Video.java b/src/main/java/me/kavin/piped/utils/obj/db/Video.java index c15eec5..7acb979 100644 --- a/src/main/java/me/kavin/piped/utils/obj/db/Video.java +++ b/src/main/java/me/kavin/piped/utils/obj/db/Video.java @@ -26,18 +26,6 @@ public class Video { @Column(name = "uploaded") private long uploaded; - @Column(name = "uploader", length = 80) - private String uploader; - - @Column(name = "uploader_url", length = 30) - private String uploaderUrl; - - @Column(name = "uploader_avatar", length = 150) - private String uploaderAvatar; - - @Column(name = "verified") - private boolean verified; - @Column(name = "thumbnail", length = 150) private String thumbnail; @@ -51,10 +39,6 @@ public class Video { this.views = views; this.duration = duration; this.uploaded = uploaded; - this.uploader = uploader; - this.uploaderUrl = uploaderUrl; - this.uploaderAvatar = uploaderAvatar; - this.verified = verified; this.thumbnail = thumbnail; } @@ -98,38 +82,6 @@ public class Video { this.uploaded = uploaded; } - public String getUploader() { - return uploader; - } - - public void setUploader(String uploader) { - this.uploader = uploader; - } - - public String getUploaderUrl() { - return uploaderUrl; - } - - public void setUploaderUrl(String uploaderUrl) { - this.uploaderUrl = uploaderUrl; - } - - public String getUploaderAvatar() { - return uploaderAvatar; - } - - public void setUploaderAvatar(String uploaderAvatar) { - this.uploaderAvatar = uploaderAvatar; - } - - public boolean isVerified() { - return verified; - } - - public void setVerified(boolean verified) { - this.verified = verified; - } - public String getThumbnail() { return thumbnail; } diff --git a/src/main/java/me/kavin/piped/utils/resp/AcceptedResponse.java b/src/main/java/me/kavin/piped/utils/resp/AcceptedResponse.java new file mode 100644 index 0000000..d8fb106 --- /dev/null +++ b/src/main/java/me/kavin/piped/utils/resp/AcceptedResponse.java @@ -0,0 +1,7 @@ +package me.kavin.piped.utils.resp; + +public class AcceptedResponse { + + public String message = "ok"; + +} diff --git a/src/main/java/me/kavin/piped/utils/resp/AlreadyRegisteredResponse.java b/src/main/java/me/kavin/piped/utils/resp/AlreadyRegisteredResponse.java new file mode 100644 index 0000000..c3bc0d7 --- /dev/null +++ b/src/main/java/me/kavin/piped/utils/resp/AlreadyRegisteredResponse.java @@ -0,0 +1,7 @@ +package me.kavin.piped.utils.resp; + +public class AlreadyRegisteredResponse { + + public String error = "The username you have used is already taken."; + +} diff --git a/src/main/java/me/kavin/piped/utils/resp/AuthenticationFailureResponse.java b/src/main/java/me/kavin/piped/utils/resp/AuthenticationFailureResponse.java new file mode 100644 index 0000000..ee47766 --- /dev/null +++ b/src/main/java/me/kavin/piped/utils/resp/AuthenticationFailureResponse.java @@ -0,0 +1,7 @@ +package me.kavin.piped.utils.resp; + +public class AuthenticationFailureResponse { + + public String error = "An invalid Session ID was provided."; + +} diff --git a/src/main/java/me/kavin/piped/utils/resp/DatabaseHelper.java b/src/main/java/me/kavin/piped/utils/resp/DatabaseHelper.java new file mode 100644 index 0000000..8243de0 --- /dev/null +++ b/src/main/java/me/kavin/piped/utils/resp/DatabaseHelper.java @@ -0,0 +1,21 @@ +package me.kavin.piped.utils.resp; + +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.hibernate.Session; + +import me.kavin.piped.utils.obj.db.User; + +public class DatabaseHelper { + + public static final User getUserFromSession(Session s, String session) { + CriteriaBuilder cb = s.getCriteriaBuilder(); + CriteriaQuery cr = cb.createQuery(User.class); + Root root = cr.from(User.class); + cr.select(root).where(root.get("sessionId").in(session)); + + return s.createQuery(cr).uniqueResult(); + } +} diff --git a/src/main/java/me/kavin/piped/utils/resp/IncorrectCredentialsResponse.java b/src/main/java/me/kavin/piped/utils/resp/IncorrectCredentialsResponse.java new file mode 100644 index 0000000..990c324 --- /dev/null +++ b/src/main/java/me/kavin/piped/utils/resp/IncorrectCredentialsResponse.java @@ -0,0 +1,7 @@ +package me.kavin.piped.utils.resp; + +public class IncorrectCredentialsResponse { + + public String error = "The username or password you have entered is incorrect."; + +} diff --git a/src/main/java/me/kavin/piped/utils/resp/LoginRequest.java b/src/main/java/me/kavin/piped/utils/resp/LoginRequest.java new file mode 100644 index 0000000..164a0db --- /dev/null +++ b/src/main/java/me/kavin/piped/utils/resp/LoginRequest.java @@ -0,0 +1,7 @@ +package me.kavin.piped.utils.resp; + +public class LoginRequest { + + public String username, password; + +} diff --git a/src/main/java/me/kavin/piped/utils/resp/LoginResponse.java b/src/main/java/me/kavin/piped/utils/resp/LoginResponse.java new file mode 100644 index 0000000..bf5128e --- /dev/null +++ b/src/main/java/me/kavin/piped/utils/resp/LoginResponse.java @@ -0,0 +1,10 @@ +package me.kavin.piped.utils.resp; + +public class LoginResponse { + + public String token; + + public LoginResponse(String token) { + this.token = token; + } +} diff --git a/src/main/java/me/kavin/piped/utils/resp/SubscriptionUpdateRequest.java b/src/main/java/me/kavin/piped/utils/resp/SubscriptionUpdateRequest.java new file mode 100644 index 0000000..79fdad8 --- /dev/null +++ b/src/main/java/me/kavin/piped/utils/resp/SubscriptionUpdateRequest.java @@ -0,0 +1,7 @@ +package me.kavin.piped.utils.resp; + +public class SubscriptionUpdateRequest { + + public String channelId; + +} diff --git a/src/main/resources/hibernate.cfg.xml b/src/main/resources/hibernate.cfg.xml index ad221e0..42df26a 100644 --- a/src/main/resources/hibernate.cfg.xml +++ b/src/main/resources/hibernate.cfg.xml @@ -8,5 +8,7 @@ true true + + org.hibernate.hikaricp.internal.HikariCPConnectionProvider