aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/juick
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/juick')
-rw-r--r--src/main/java/com/juick/config/SecurityConfig.java11
-rw-r--r--src/main/java/com/juick/service/MessagesServiceImpl.java23
-rw-r--r--src/main/java/com/juick/util/MessageUtils.java28
-rw-r--r--src/main/java/com/juick/www/api/ApiSocialLogin.java89
4 files changed, 124 insertions, 27 deletions
diff --git a/src/main/java/com/juick/config/SecurityConfig.java b/src/main/java/com/juick/config/SecurityConfig.java
index a93a4a5ca..7e37b7d8e 100644
--- a/src/main/java/com/juick/config/SecurityConfig.java
+++ b/src/main/java/com/juick/config/SecurityConfig.java
@@ -35,6 +35,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@@ -52,10 +53,10 @@ import org.springframework.security.oauth2.server.authorization.settings.Authori
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
-import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
@@ -115,9 +116,7 @@ public class SecurityConfig {
@Bean
AuthenticationEntryPoint apiAuthenticationEntryPoint() {
- var entryPoint = new BasicAuthenticationEntryPoint();
- entryPoint.setRealmName("Juick");
- return entryPoint;
+ return new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED);
}
@Value("${auth_remember_me_key:secret}")
@@ -201,7 +200,7 @@ public class SecurityConfig {
"/api/swagger-ui/**",
"/api/messages/discussions",
"/api/users", "/api/thread", "/api/tags",
- "/api/tlgmbtwbhk", "/api/fbwbhk", "/api/_patreon", "/api/_vk",
+ "/api/tlgmbtwbhk", "/api/fbwbhk", "/api/_patreon", "/api/_vk", "/api/_google",
"/api/skypebotendpoint", "/api/signup",
"/api/inbox", "/api/events", "/api/u/", "/u/**",
"/n/**",
@@ -228,6 +227,7 @@ public class SecurityConfig {
}
@Bean
+ @Order(Ordered.HIGHEST_PRECEDENCE + 1)
SecurityFilterChain h2ConsoleFilterChain(HttpSecurity http) throws Exception {
http.securityMatcher("/h2-console/**")
.authorizeHttpRequests(auth -> auth
@@ -294,6 +294,7 @@ public class SecurityConfig {
}
@Bean
+ @Order(Ordered.HIGHEST_PRECEDENCE + 1)
public SecurityFilterChain securityWebFilterChain(
HttpSecurity http) throws Exception {
return http.securityMatcher("/actuator/**")
diff --git a/src/main/java/com/juick/service/MessagesServiceImpl.java b/src/main/java/com/juick/service/MessagesServiceImpl.java
index de3429774..ebb8414e2 100644
--- a/src/main/java/com/juick/service/MessagesServiceImpl.java
+++ b/src/main/java/com/juick/service/MessagesServiceImpl.java
@@ -18,7 +18,6 @@
package com.juick.service;
import com.juick.model.*;
-import com.juick.model.User;
import com.juick.www.WebApp;
import com.juick.util.MessageUtils;
import com.juick.util.TagUtils;
@@ -103,16 +102,20 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ
msg.setReplyQuote(MessageUtils.formatQuote(rs.getString(17)));
msg.setUpdated(MessagesServiceImpl.this.getOffsetDateTime(rs, 18).toInstant());
int quoteUid = rs.getInt(19);
- User quoteUser = new User();
- quoteUser.setUid(quoteUid);
- quoteUser.setName(rs.getString(20));
- if (quoteUid == 0) {
- quoteUser.setName(AnonymousUser.INSTANCE.getName());
- quoteUser.setUri(URI.create(Optional.ofNullable(rs.getString(23)).orElse(StringUtils.EMPTY)));
+ if (rs.wasNull()) {
+ msg.setTo(archiveUser);
} else {
- quoteUser.setAvatar(webApp.getAvatarUrl(quoteUser));
+ User quoteUser = new User();
+ quoteUser.setUid(quoteUid);
+ quoteUser.setName(rs.getString(20));
+ if (quoteUid == 0) {
+ quoteUser.setName(AnonymousUser.INSTANCE.getName());
+ quoteUser.setUri(URI.create(Optional.ofNullable(rs.getString(23)).orElse(StringUtils.EMPTY)));
+ } else {
+ quoteUser.setAvatar(webApp.getAvatarUrl(quoteUser));
+ }
+ msg.setTo(quoteUser);
}
- msg.setTo(quoteUser);
msg.setUpdatedAt(MessagesServiceImpl.this.getOffsetDateTime(rs, 21).toInstant());
msg.setReplyUri(URI.create(Optional.ofNullable(rs.getString(24)).orElse(StringUtils.EMPTY)));
msg.setHtml(rs.getBoolean(25));
@@ -897,7 +900,7 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ
+ "replies.user_id, users.nick, users.banned, " + "replies.ts, "
+ "0 as readonly, 0 as privacy, 0 as replies, " + "replies.attach, 0 as likes, 0 as hidden, "
+ "NULL as tags, NULL as repliesby, replies.txt, " + "COALESCE(qw.txt, m.txt) as q, " + ":now, "
- + "COALESCE(qw.user_id, m.user_id) as to_uid, COALESCE(qu.nick, mu.nick) as to_name, "
+ + "qw.user_id as to_uid, qu.nick as to_name, "
+ "replies.updated_at, replies.user_uri as uri, "
+ "qw.user_uri as to_uri, replies.reply_uri, replies.html, 0 as unread, "
+ "0 as subscribed, users.premium "
diff --git a/src/main/java/com/juick/util/MessageUtils.java b/src/main/java/com/juick/util/MessageUtils.java
index 3c8001d81..fff97f662 100644
--- a/src/main/java/com/juick/util/MessageUtils.java
+++ b/src/main/java/com/juick/util/MessageUtils.java
@@ -42,13 +42,20 @@ public class MessageUtils {
}
public static String formatQuote(final String quote) {
+ return formatQuote(quote, false);
+ }
+
+ public static String formatQuote(final String quote, final boolean isHtml) {
String result = quote;
+ var prefix = isHtml ? "<blockquote>" : ">";
+ var suffix = isHtml ? "</blockquote>" : "\n";
+
if (quote != null) {
if (quote.length() > 50) {
- result = ">" + StringUtils.abbreviate(quote, "…", 47).replace('\n', ' ') + "\n";
+ result = prefix + StringUtils.abbreviate(quote, "…", 47).replace('\n', ' ') + suffix;
} else if (!quote.isEmpty()) {
- result = ">" + quote.replace('\n', ' ') + "\n";
+ result = prefix + quote.replace('\n', ' ') + suffix;
}
}
@@ -191,8 +198,9 @@ public class MessageUtils {
// /12
// <a href="#12">/12</a>
- msg = msg.replaceAll(replyNumberRegex, "$1<a href=\"#$2\">/$2</a>$3");
-
+ if (!compatibleWithDurov) {
+ msg = msg.replaceAll(replyNumberRegex, "$1<a href=\"#$2\">/$2</a>$3");
+ }
// @username@mastodon.social
// <a href="http://juick.com/mention?username=username@mastodon.social/">@username@mastodon.social</a>
@@ -220,11 +228,11 @@ public class MessageUtils {
m.appendTail(sb);
msg = sb.toString();
+
+ // > citate
+ msg = msg.replaceAll(citateRegex, "<blockquote>$1</blockquote>");
+ msg = msg.replaceAll("</blockquote><blockquote>", "\n");
if (!compatibleWithDurov) {
- // > citate
- msg = msg.replaceAll(citateRegex, "<blockquote>$1</blockquote>");
- msg = msg.replaceAll("</blockquote><blockquote>", "\n");
-
msg = msg.replaceAll("\n", "<br/>\n");
}
return msg;
@@ -283,10 +291,6 @@ public class MessageUtils {
return URLEncoder.encode(s, StandardCharsets.UTF_8).replace("+", "%20")
.replace("*", "%2A").replace("%7E", "~");
}
- public static String formatMarkdownText(final Message msg) {
- return StringUtils.defaultString(msg.getText())
- .replaceAll(replyNumberRegex, String.format("$1[/$2](https://juick.com/m/%d#$2)$3", msg.getMid()));
- }
public static String attachmentUrl(final Message jmsg) {
if (StringUtils.isEmpty(jmsg.getAttachmentType())) {
return StringUtils.EMPTY;
diff --git a/src/main/java/com/juick/www/api/ApiSocialLogin.java b/src/main/java/com/juick/www/api/ApiSocialLogin.java
new file mode 100644
index 000000000..5b48c52be
--- /dev/null
+++ b/src/main/java/com/juick/www/api/ApiSocialLogin.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2008-2024, Juick
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.juick.www.api;
+
+import com.github.scribejava.apis.GoogleTokenVerifier;
+import com.juick.model.AuthResponse;
+import com.juick.service.EmailService;
+import com.juick.service.UserService;
+import com.juick.util.HttpBadRequestException;
+import com.juick.util.HttpForbiddenException;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Controller;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import jakarta.inject.Inject;
+import java.util.Optional;
+
+@Controller
+public class ApiSocialLogin {
+
+ private static final Logger logger = LoggerFactory.getLogger(ApiSocialLogin.class);
+
+ @Value("${google_client_id:}")
+ private String googleClientId;
+
+ @Inject
+ private UserService userService;
+ @Inject
+ private EmailService emailService;
+ @Inject
+ private Users users;
+ @ResponseBody
+ @PostMapping("/api/signup")
+ public com.juick.model.User signupWithEmail(String username, String password, String verificationCode) {
+ if (username.length() < 2 || username.length() > 16 || !username.matches("^[a-zA-Z0-9\\-]+$")
+ || password.length() < 6 || password.length() > 32) {
+ throw new HttpBadRequestException();
+ }
+
+ String verifiedEmail = emailService.getEmailByAuthCode(verificationCode);
+ if (StringUtils.hasText(verifiedEmail)) {
+ com.juick.model.User newUser = userService.createUser(username, password).orElseThrow(HttpBadRequestException::new);
+ emailService.addEmail(newUser.getUid(), verifiedEmail);
+ emailService.deleteAuthCode(verificationCode);
+ return newUser;
+ } else {
+ throw new HttpForbiddenException();
+ }
+ }
+ @ResponseBody
+ @PostMapping("/api/_google")
+ public AuthResponse googleSignIn(@RequestParam(name = "idToken") String idTokenString) {
+ logger.info("Token: {}", idTokenString);
+ logger.info("Client: {}", googleClientId);
+ Optional<String> verifiedEmail = GoogleTokenVerifier.validateToken(googleClientId, idTokenString);
+ if (verifiedEmail.isPresent()) {
+ String email = verifiedEmail.get();
+ com.juick.model.User visitor = userService.getUserByEmail(email);
+ if (visitor.isAnonymous()) {
+ String verificationCode = RandomStringUtils.randomAlphanumeric(8).toUpperCase();
+ emailService.addVerificationCode(null, email, verificationCode);
+ return new AuthResponse(null, email, verificationCode);
+ } else {
+ return new AuthResponse(users.getMe(visitor), null, null);
+ }
+ }
+ throw new HttpForbiddenException();
+ }
+}