diff --git a/README.md b/README.md index ba6bb56..73743b7 100755 --- a/README.md +++ b/README.md @@ -103,6 +103,22 @@ DATABASE_HOST= DATABASE_PORT=3306 SERVER_NAME=http://example.com + + +# Optional +PASTEFY_INFO_CUSTOM_LOGO=https://urltoimage +PASTEFY_INFO_CUSTOM_NAME=Custom Name +PASTEFY_INFO_CUSTOM_FOOTER=WEBSITE=https://example.org,SEPERATED BY COMMA=https://example.org + +# Requires login for read and creation of pastes +PASTEFY_LOGIN_REQUIRED=false +# Login-requirements for specific access types +PASTEFY_LOGIN_REQUIRED_CREATE=false +# This will disable the raw mode as well for browser users +PASTEFY_LOGIN_REQUIRED_READ=false + +# Check the encryption checkbox by default +PASTEFY_ENCRYPTION_DEFAULT=false ``` ### Adding login You can choose between [INTERAAPPS](https://accounts.interaapps.de/developers/projects) (best integration), [GOOGLE](https://support.google.com/cloud/answer/6158849?hl=en), [GITHUB](https://docs.github.com/en/developers/apps/building-oauth-apps/creating-an-oauth-app), [DISCORD](https://discord.com/developers/docs/topics/oauth2) or [TWITCH](https://dev.twitch.tv/docs/authentication) for the provider (You can use all of them at the same time). diff --git a/backend/dependency-reduced-pom.xml b/backend/dependency-reduced-pom.xml new file mode 100644 index 0000000..c0214da --- /dev/null +++ b/backend/dependency-reduced-pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + de.interaapps.pastefy + core + 6.0 + + + + src/main/resources + + static/**/*.* + + + + backend + + + maven-compiler-plugin + + 8 + 8 + + + + maven-shade-plugin + 3.0.0 + + + package + + shade + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + + + maven-jar-plugin + + + + de.interaapps.pastefy.Pastefy + true + + + + + + + + + jitpack.io + https://jitpack.io + + + + diff --git a/backend/pom.xml b/backend/pom.xml index faa3582..608b803 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -23,6 +23,11 @@ http-server 1.0.1 + + org.javawebstack + abstract-data + 1.0.1 + org.javawebstack http-client diff --git a/backend/src/main/java/de/interaapps/pastefy/Pastefy.java b/backend/src/main/java/de/interaapps/pastefy/Pastefy.java index 4dd657c..d64e480 100644 --- a/backend/src/main/java/de/interaapps/pastefy/Pastefy.java +++ b/backend/src/main/java/de/interaapps/pastefy/Pastefy.java @@ -32,6 +32,7 @@ import java.io.File; import java.io.IOException; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.logging.ConsoleHandler; import java.util.logging.Handler; @@ -48,6 +49,9 @@ public static Pastefy getInstance() { private Passport passport; private OAuth2Strategy oAuth2Strategy; private HTTPServer httpServer; + private boolean loginRequired = false; + private boolean loginRequiredForRead = false; + private boolean loginRequiredForCreate = false; public Pastefy(){ config = new Config(); @@ -107,12 +111,27 @@ protected void setupConfig() { map.put("OAUTH2_DISCORD_CLIENT_ID", "oauth2.discord.id"); map.put("OAUTH2_DISCORD_CLIENT_SECRET", "oauth2.discord.secret"); + map.put("PASTEFY_INFO_CUSTOM_LOGO", "pastefy.info.custom.logo"); + map.put("PASTEFY_INFO_CUSTOM_NAME", "pastefy.info.custom.name"); + map.put("PASTEFY_INFO_CUSTOM_FOOTER", "pastefy.info.custom.footer"); + + map.put("PASTEFY_ENCRYPTION_DEFAULT", "pastefy.encryption.default"); + + map.put("PASTEFY_LOGIN_REQUIRED", "pastefy.loginrequired"); + map.put("PASTEFY_LOGIN_REQUIRED_CREATE", "pastefy.loginrequired.create"); + map.put("PASTEFY_LOGIN_REQUIRED_READ", "pastefy.loginrequired.read"); + + File file = new File(".env"); if (file.exists()) { config.add(new EnvFile(file).withVariables(), map); } else { config.add(new EnvFile().withVariables(), map); } + + loginRequired = config.get("pastefy.loginrequired", "false").toLowerCase(Locale.ROOT).equals("true"); + loginRequiredForCreate = loginRequired || config.get("pastefy.loginrequired.create", "false").toLowerCase(Locale.ROOT).equals("true"); + loginRequiredForRead = loginRequired || config.get("pastefy.loginrequired.read", "false").toLowerCase(Locale.ROOT).equals("true"); } protected void setupModels(){ @@ -166,6 +185,16 @@ protected void setupServer() { return new ExceptionResponse(throwable); }); httpServer.middleware("auth", new AuthMiddleware()); + httpServer.middleware("auth-login-required-read", exchange -> { + if (loginRequiredForRead && exchange.attrib("user") == null) + throw new AuthenticationException(); + return null; + }); + httpServer.middleware("auth-login-required-create", exchange -> { + if (loginRequiredForCreate && exchange.attrib("user") == null) + throw new AuthenticationException(); + return null; + }); if (getConfig().has("ratelimiter.millis")) httpServer.middleware("rate-limiter", new RateLimitMiddleware(getConfig().getInt("ratelimiter.millis", 5000), getConfig().getInt("ratelimiter.limit", 5)).createAutoDeadRateLimitsRemover(1000*60*10)); @@ -239,4 +268,16 @@ public OAuth2Strategy getOAuth2Strategy() { public Config getConfig() { return config; } + + public boolean isLoginRequired() { + return loginRequired; + } + + public boolean isLoginRequiredForCreate() { + return loginRequiredForCreate; + } + + public boolean isLoginRequiredForRead() { + return loginRequiredForRead; + } } diff --git a/backend/src/main/java/de/interaapps/pastefy/controller/AppController.java b/backend/src/main/java/de/interaapps/pastefy/controller/AppController.java new file mode 100644 index 0000000..950be48 --- /dev/null +++ b/backend/src/main/java/de/interaapps/pastefy/controller/AppController.java @@ -0,0 +1,14 @@ +package de.interaapps.pastefy.controller; + +import de.interaapps.pastefy.Pastefy; +import de.interaapps.pastefy.model.responses.app.AppInfoResponse; +import org.javawebstack.httpserver.router.annotation.PathPrefix; +import org.javawebstack.httpserver.router.annotation.verbs.Get; + +@PathPrefix("/api/v2/app") +public class AppController extends HttpController { + @Get("/info") + public AppInfoResponse appInfo(){ + return new AppInfoResponse(Pastefy.getInstance()); + } +} diff --git a/backend/src/main/java/de/interaapps/pastefy/controller/FolderController.java b/backend/src/main/java/de/interaapps/pastefy/controller/FolderController.java index 30b6e6d..e2471e2 100644 --- a/backend/src/main/java/de/interaapps/pastefy/controller/FolderController.java +++ b/backend/src/main/java/de/interaapps/pastefy/controller/FolderController.java @@ -42,6 +42,7 @@ public CreateFolderResponse createFolder(Exchange exchange, @Body CreateFolderRe } @Get("/{id}") + @With("auth-login-required-read") public FolderResponse getFolder(Exchange exchange, @Path("id") String id, @Attrib("user") User user) { Folder folder = Repo.get(Folder.class).where("key", id).first(); if (folder == null) diff --git a/backend/src/main/java/de/interaapps/pastefy/controller/PasteController.java b/backend/src/main/java/de/interaapps/pastefy/controller/PasteController.java index fb4d87e..ce9c05f 100644 --- a/backend/src/main/java/de/interaapps/pastefy/controller/PasteController.java +++ b/backend/src/main/java/de/interaapps/pastefy/controller/PasteController.java @@ -28,7 +28,7 @@ public class PasteController extends HttpController { @Post - @With("rate-limiter") + @With({"rate-limiter", "auth-login-required-create"}) public CreatePasteResponse create(Exchange exchange, @Body CreatePasteRequest request, @Attrib("user") User user, @Path("id") String pasteId) { CreatePasteResponse response = new CreatePasteResponse(); @@ -79,6 +79,7 @@ public ActionResponse putPaste(@Body EditPasteRequest request, @Path("id") Strin } @Get("/{id}") + @With("auth-login-required-read") public PasteResponse getPaste(Exchange exchange, @Path("id") String id, @Attrib("user") User user) { Paste paste = Repo.get(Paste.class).where("key", id).first(); if (paste == null) diff --git a/backend/src/main/java/de/interaapps/pastefy/controller/RawController.java b/backend/src/main/java/de/interaapps/pastefy/controller/RawController.java index def18af..7acd6b2 100644 --- a/backend/src/main/java/de/interaapps/pastefy/controller/RawController.java +++ b/backend/src/main/java/de/interaapps/pastefy/controller/RawController.java @@ -3,6 +3,7 @@ import de.interaapps.pastefy.model.database.Paste; import org.javawebstack.httpserver.Exchange; import org.javawebstack.httpserver.helper.MimeType; +import org.javawebstack.httpserver.router.annotation.With; import org.javawebstack.httpserver.router.annotation.params.Path; import org.javawebstack.httpserver.router.annotation.verbs.Get; import org.javawebstack.orm.Repo; @@ -10,6 +11,7 @@ public class RawController extends HttpController { @Get("/{id}/raw") + @With("auth-login-required-read") public String getPasteRaw(Exchange exchange, @Path("id") String id) { Paste paste = Repo.get(Paste.class).where("key", id).first(); exchange.contentType(MimeType.PLAIN); diff --git a/backend/src/main/java/de/interaapps/pastefy/model/database/Paste.java b/backend/src/main/java/de/interaapps/pastefy/model/database/Paste.java index 74023b0..adb42db 100644 --- a/backend/src/main/java/de/interaapps/pastefy/model/database/Paste.java +++ b/backend/src/main/java/de/interaapps/pastefy/model/database/Paste.java @@ -21,7 +21,7 @@ public class Paste extends Model { @Column private String title; - @Column(size = 0) // Sets MySQL Field type to TEXT + @Column(size = 16777215) private String content; @Column(size = 8) diff --git a/backend/src/main/java/de/interaapps/pastefy/model/database/User.java b/backend/src/main/java/de/interaapps/pastefy/model/database/User.java index 46c8103..f2e668c 100644 --- a/backend/src/main/java/de/interaapps/pastefy/model/database/User.java +++ b/backend/src/main/java/de/interaapps/pastefy/model/database/User.java @@ -38,6 +38,9 @@ public class User extends Model { @Column public AuthenticationProvider authProvider; + @Column + public Type type = Type.USER; + @Column public Timestamp createdAt; @@ -104,6 +107,13 @@ public String getName() { } } + public enum Type { + USER, + ADMIN, + BLOCKED, + AWAITING_ACCESS + } + public String getId() { return id; } diff --git a/backend/src/main/java/de/interaapps/pastefy/model/responses/app/AppInfoResponse.java b/backend/src/main/java/de/interaapps/pastefy/model/responses/app/AppInfoResponse.java new file mode 100644 index 0000000..fe9c0e2 --- /dev/null +++ b/backend/src/main/java/de/interaapps/pastefy/model/responses/app/AppInfoResponse.java @@ -0,0 +1,43 @@ +package de.interaapps.pastefy.model.responses.app; + +import de.interaapps.pastefy.Pastefy; +import org.javawebstack.webutils.config.Config; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +public class AppInfoResponse { + + public String customLogo; + public String customName; + public Map customFooter; + public boolean loginRequiredForRead; + public boolean loginRequiredForCreate; + + public boolean encryptionIsDefault; + + public AppInfoResponse(Pastefy pastefy) { + Config config = pastefy.getConfig(); + + if (config.has("pastefy.info.custom.logo")) + customLogo = config.get("pastefy.info.custom.logo"); + + if (config.has("pastefy.info.custom.name")) + customName = config.get("pastefy.info.custom.name"); + + encryptionIsDefault = config.get("pastefy.encryption.default", "false").toLowerCase(Locale.ROOT).equals("true"); + + loginRequiredForRead = pastefy.isLoginRequiredForRead(); + loginRequiredForCreate = pastefy.isLoginRequiredForCreate(); + + String footerString = config.get("pastefy.info.custom.footer", ""); + customFooter = new HashMap<>(); + for (String str : footerString.split(",")) { + if (str.contains("=")) { + String[] split = str.split("="); + customFooter.put(split[0], split[1]); + } + } + } +} diff --git a/backend/src/main/java/de/interaapps/pastefy/model/responses/user/UserResponse.java b/backend/src/main/java/de/interaapps/pastefy/model/responses/user/UserResponse.java index f2f589d..35d68ce 100644 --- a/backend/src/main/java/de/interaapps/pastefy/model/responses/user/UserResponse.java +++ b/backend/src/main/java/de/interaapps/pastefy/model/responses/user/UserResponse.java @@ -15,6 +15,7 @@ public class UserResponse { public String profilePicture; public String authType; public List authTypes = new ArrayList<>(Pastefy.getInstance().getOAuth2Strategy().getProviders().keySet()); + public User.Type type; public UserResponse(User user) { if (user == null) @@ -27,5 +28,6 @@ public UserResponse(User user) { profilePicture = user.getAvatar(); id = user.getId(); loggedIn = true; + type = user.type; } } diff --git a/frontend/src/components/Sidebar.vue b/frontend/src/components/Sidebar.vue index 312f2ca..195c6e8 100644 --- a/frontend/src/components/Sidebar.vue +++ b/frontend/src/components/Sidebar.vue @@ -1,10 +1,10 @@