aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/juick/www/api
diff options
context:
space:
mode:
authorGravatar Vitaly Takmazov2023-01-04 03:38:19 +0300
committerGravatar Vitaly Takmazov2023-01-04 05:46:16 +0300
commitc471503ede9aad91193ff6f93966196e6aff15d6 (patch)
tree8c70c8f58b140465be651cd019f26eadd476711f /src/main/java/com/juick/www/api
parent086d9a7625bfc5a386f5b1028d364fb546c2fa9d (diff)
OAuth authentication for Mastodon and ActivityPub C2S
Diffstat (limited to 'src/main/java/com/juick/www/api')
-rw-r--r--src/main/java/com/juick/www/api/Mastodon.java118
-rw-r--r--src/main/java/com/juick/www/api/Messages.java18
-rw-r--r--src/main/java/com/juick/www/api/Notifications.java88
-rw-r--r--src/main/java/com/juick/www/api/PM.java12
-rw-r--r--src/main/java/com/juick/www/api/Post.java21
-rw-r--r--src/main/java/com/juick/www/api/Service.java12
-rw-r--r--src/main/java/com/juick/www/api/Tags.java8
-rw-r--r--src/main/java/com/juick/www/api/Users.java27
-rw-r--r--src/main/java/com/juick/www/api/activity/Profile.java13
9 files changed, 181 insertions, 136 deletions
diff --git a/src/main/java/com/juick/www/api/Mastodon.java b/src/main/java/com/juick/www/api/Mastodon.java
new file mode 100644
index 00000000..69f0f4f6
--- /dev/null
+++ b/src/main/java/com/juick/www/api/Mastodon.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2008-2023, 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.fasterxml.jackson.annotation.JsonProperty;
+import com.juick.model.User;
+import com.juick.service.UserService;
+import com.juick.www.WebApp;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.MediaType;
+import org.springframework.security.oauth2.core.AuthorizationGrantType;
+import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
+import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
+import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
+import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
+import org.springframework.web.bind.annotation.*;
+
+import javax.inject.Inject;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.UUID;
+
+@RestController
+public class Mastodon {
+ @Value("${web_domain:localhost}")
+ private String domain;
+ @Inject
+ WebApp webApp;
+ @Inject
+ UserService userService;
+ @Inject
+ RegisteredClientRepository registeredClientRepository;
+
+ public record ApplicationRequest(@JsonProperty("client_name") String clientName,
+ @JsonProperty("redirect_uris") String redirectUris,
+ @JsonProperty("scopes") String scopes) {
+ }
+
+ public record ApplicationResponse(String id,
+ @JsonProperty("client_name") String name,
+ @JsonProperty("redirect_uri") String redirectUri,
+ @JsonProperty("client_id") String clientId,
+ @JsonProperty("client_secret") String clientSecret) {
+ }
+
+ public record CredentialAccount(String id, String username, String acct,
+ @JsonProperty("display_name") String displayName,
+ @JsonProperty("followers_count") Integer followersCount,
+ @JsonProperty("following_count") Integer followingCount,
+ String avatar) {
+
+ }
+ private Collection<String> parseScopes(String s) {
+ return s != null ? Arrays.asList(s.split(" ")) : Collections.emptyList();
+ }
+
+ @PostMapping(value = "/api/v1/apps", consumes = { MediaType.APPLICATION_JSON_VALUE })
+ public ApplicationResponse apps(@RequestBody ApplicationRequest application) {
+ return apps(application.clientName(), application.redirectUris(), application.scopes());
+ }
+
+ @PostMapping(value = "/api/v1/apps", consumes = { MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE })
+ public ApplicationResponse apps(@RequestParam("client_name") String clientName,
+ @RequestParam("redirect_uris") String redirectUris,
+ @RequestParam("scopes") String scopes) {
+ var secret = UUID.randomUUID().toString();
+ RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
+ .clientId(UUID.randomUUID().toString())
+ .clientSecret("{noop}" + secret)
+ .clientName(clientName)
+ .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
+ .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
+ .redirectUri(redirectUris)
+ .scopes((coll) -> coll.addAll(parseScopes(scopes)))
+ .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build()).build();
+ registeredClientRepository.save(registeredClient);
+ return new ApplicationResponse(
+ registeredClient.getId(),
+ registeredClient.getClientName(),
+ String.join(",", registeredClient.getRedirectUris()),
+ registeredClient.getClientId(),
+ secret
+ );
+ }
+ public record Instance(String domain) {}
+ @GetMapping("/api/v1/instance")
+ public Instance getInstance() {
+ return new Instance(domain);
+ }
+ @GetMapping("/api/v1/accounts/verify_credentials")
+ public CredentialAccount account(@ModelAttribute User visitor) {
+ return new CredentialAccount(
+ String.valueOf(visitor.getUid()),
+ visitor.getName(),
+ visitor.getName(),
+ visitor.getFullName(),
+ userService.getUserReaders(visitor.getUid()).size(),
+ userService.getUserFriends(visitor.getUid()).size(),
+ webApp.getAvatarUrl(visitor)
+ );
+ }
+}
diff --git a/src/main/java/com/juick/www/api/Messages.java b/src/main/java/com/juick/www/api/Messages.java
index 2993e805..c23976f4 100644
--- a/src/main/java/com/juick/www/api/Messages.java
+++ b/src/main/java/com/juick/www/api/Messages.java
@@ -30,14 +30,11 @@ import com.juick.service.MessagesService;
import com.juick.service.TagService;
import com.juick.service.UserService;
import com.juick.service.component.SystemEvent;
-import com.juick.service.security.annotation.Visitor;
import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
-import org.springframework.security.access.annotation.Secured;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
@@ -70,9 +67,8 @@ public class Messages {
// TODO: serialize image urls
- @GetMapping("/api/home")
- @Secured("ROLE_USER")
- public List<Message> getHome(@Visitor User visitor,
+ @GetMapping({"/api/home"})
+ public List<Message> getHome(@ModelAttribute User visitor,
@RequestParam(defaultValue = "0") int before_mid) {
int vuid = visitor.getUid();
List<Integer> mids = messagesService.getMyFeed(vuid, before_mid, true);
@@ -82,7 +78,7 @@ public class Messages {
}
@GetMapping("/api/messages")
- public List<Message> getMessages(@Visitor User visitor,
+ public List<Message> getMessages(@ModelAttribute User visitor,
@RequestParam(required = false) String uname,
@RequestParam(name = "before_mid", defaultValue = "0") Integer before,
@RequestParam(required = false, defaultValue = "0") Integer daysback,
@@ -140,7 +136,7 @@ public class Messages {
}
@DeleteMapping("/api/messages")
- public CommandResult deleteMessage(@Visitor User visitor, @RequestParam int mid,
+ public CommandResult deleteMessage(@ModelAttribute User visitor, @RequestParam int mid,
@RequestParam(required = false, defaultValue = "0") int rid) {
if (rid > 0) {
if (messagesService.deleteReply(visitor.getUid(), mid, rid)) {
@@ -154,7 +150,7 @@ public class Messages {
}
@GetMapping("/api/messages/discussions")
- public List<Message> getDiscussions(@Visitor User visitor,
+ public List<Message> getDiscussions(@ModelAttribute User visitor,
@RequestParam(required = false, defaultValue = "0") Long to) {
List<Message> msgs = messagesService.getMessages(visitor, messagesService.getDiscussions(visitor.getUid(), to));
msgs.forEach(m -> m.getUser().setAvatar(webApp.getAvatarUrl(m.getUser())));
@@ -162,7 +158,7 @@ public class Messages {
}
@GetMapping("/api/thread")
- public List<Message> getThread(@Visitor User visitor, @RequestParam(defaultValue = "0") int mid,
+ public List<Message> getThread(@ModelAttribute User visitor, @RequestParam(defaultValue = "0") int mid,
@RequestParam(defaultValue = "true") boolean showReplies) {
Optional<Message> message = messagesService.getMessage(mid);
if (message.isPresent()) {
@@ -192,7 +188,7 @@ public class Messages {
}
@GetMapping(value = "/api/thread/mark_read/{mid}-{rid}.gif", produces = MediaType.IMAGE_GIF_VALUE)
- public byte[] markThreadRead(@Visitor User visitor, @PathVariable int mid, @PathVariable int rid)
+ public byte[] markThreadRead(@ModelAttribute User visitor, @PathVariable int mid, @PathVariable int rid)
throws IOException {
if (!visitor.isAnonymous()) {
messagesService.setLastReadComment(visitor, mid, rid);
diff --git a/src/main/java/com/juick/www/api/Notifications.java b/src/main/java/com/juick/www/api/Notifications.java
index 09dad9e2..32ba3dc1 100644
--- a/src/main/java/com/juick/www/api/Notifications.java
+++ b/src/main/java/com/juick/www/api/Notifications.java
@@ -17,36 +17,19 @@
package com.juick.www.api;
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import javax.inject.Inject;
-
-import com.juick.model.AnonymousUser;
-import com.juick.model.ExternalToken;
-import com.juick.model.Message;
-import com.juick.model.Status;
-import com.juick.model.User;
-import com.juick.service.MessagesService;
-import com.juick.service.PushQueriesService;
-import com.juick.service.SubscriptionService;
-import com.juick.service.TelegramService;
-import com.juick.service.UserService;
-import com.juick.service.security.annotation.Visitor;
+import com.juick.model.*;
+import com.juick.service.*;
import com.juick.util.HttpBadRequestException;
import com.juick.util.HttpForbiddenException;
-
+import io.swagger.v3.oas.annotations.Hidden;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
-import io.swagger.v3.oas.annotations.Hidden;
+import javax.inject.Inject;
+import java.util.Collections;
+import java.util.List;
/**
* Created by vitalyster on 24.10.2016.
@@ -88,7 +71,7 @@ public class Notifications {
@Hidden
@RequestMapping(value = "/api/notifications", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<User> doGet(
- @Visitor User visitor,
+ @ModelAttribute(binding = false) User visitor,
@RequestParam(required = false, defaultValue = "0") int uid,
@RequestParam(required = false, defaultValue = "0") int mid,
@RequestParam(required = false, defaultValue = "0") int rid) {
@@ -127,24 +110,17 @@ public class Notifications {
@Hidden
@RequestMapping(value = "/api/notifications", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE)
public Status doDelete(
- @Visitor User visitor,
+ @ModelAttribute User visitor,
@RequestBody List<ExternalToken> list) {
if (!visitor.equals(serviceUser)) {
throw new HttpForbiddenException();
}
list.forEach(t -> {
switch (t.type()) {
- case "gcm":
- pushQueriesService.deleteGCMToken(t.token());
- break;
- case "apns":
- pushQueriesService.deleteAPNSToken(t.token());
- break;
- case "mpns":
- pushQueriesService.deleteMPNSToken(t.token());
- break;
- default:
- throw new HttpBadRequestException();
+ case "gcm" -> pushQueriesService.deleteGCMToken(t.token());
+ case "apns" -> pushQueriesService.deleteAPNSToken(t.token());
+ case "mpns" -> pushQueriesService.deleteMPNSToken(t.token());
+ default -> throw new HttpBadRequestException();
}
});
@@ -153,24 +129,17 @@ public class Notifications {
@Hidden
@RequestMapping(value = "/api/notifications/delete", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public Status doDeleteTokens(
- @Visitor User visitor,
+ @ModelAttribute User visitor,
@RequestBody List<ExternalToken> list) {
if (!visitor.equals(serviceUser)) {
throw new HttpForbiddenException();
}
list.forEach(t -> {
switch (t.type()) {
- case "gcm":
- pushQueriesService.deleteGCMToken(t.token());
- break;
- case "apns":
- pushQueriesService.deleteAPNSToken(t.token());
- break;
- case "mpns":
- pushQueriesService.deleteMPNSToken(t.token());
- break;
- default:
- throw new HttpBadRequestException();
+ case "gcm" -> pushQueriesService.deleteGCMToken(t.token());
+ case "apns" -> pushQueriesService.deleteAPNSToken(t.token());
+ case "mpns" -> pushQueriesService.deleteMPNSToken(t.token());
+ default -> throw new HttpBadRequestException();
}
});
@@ -180,21 +149,14 @@ public class Notifications {
@Hidden
@RequestMapping(value = "/api/notifications", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE)
public Status doPut(
- @Visitor User visitor,
+ @ModelAttribute User visitor,
@RequestBody List<ExternalToken> list) {
list.forEach(t -> {
switch (t.type()) {
- case "gcm":
- pushQueriesService.addGCMToken(visitor.getUid(), t.token());
- break;
- case "apns":
- pushQueriesService.addAPNSToken(visitor.getUid(), t.token());
- break;
- case "mpns":
- pushQueriesService.addMPNSToken(visitor.getUid(), t.token());
- break;
- default:
- throw new HttpBadRequestException();
+ case "gcm" -> pushQueriesService.addGCMToken(visitor.getUid(), t.token());
+ case "apns" -> pushQueriesService.addAPNSToken(visitor.getUid(), t.token());
+ case "mpns" -> pushQueriesService.addMPNSToken(visitor.getUid(), t.token());
+ default -> throw new HttpBadRequestException();
}
});
return Status.OK;
@@ -203,7 +165,7 @@ public class Notifications {
@Deprecated
@RequestMapping(value = "/api/android/register", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public Status doAndroidRegister(
- @Visitor User visitor,
+ @ModelAttribute User visitor,
@RequestParam(name = "regid") String regId) {
pushQueriesService.addGCMToken(visitor.getUid(), regId);
return Status.OK;
@@ -212,7 +174,7 @@ public class Notifications {
@Deprecated
@RequestMapping(value = "/api/winphone/register", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public Status doWinphoneRegister(
- @Visitor User visitor,
+ @ModelAttribute User visitor,
@RequestParam(name = "url") String regId) {
pushQueriesService.addMPNSToken(visitor.getUid(), regId);
return Status.OK;
diff --git a/src/main/java/com/juick/www/api/PM.java b/src/main/java/com/juick/www/api/PM.java
index 96387dce..c4acd4b3 100644
--- a/src/main/java/com/juick/www/api/PM.java
+++ b/src/main/java/com/juick/www/api/PM.java
@@ -29,13 +29,9 @@ import com.juick.www.WebApp;
import com.juick.service.ChatService;
import com.juick.service.UserService;
import com.juick.service.component.SystemEvent;
-import com.juick.service.security.annotation.Visitor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
import javax.inject.Inject;
import java.util.Collections;
@@ -57,7 +53,7 @@ public class PM {
@RequestMapping(value = "/api/pm", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<Message> doGetPM(
- @Visitor User visitor,
+ @ModelAttribute User visitor,
@RequestParam(required = false) String uname) {
int uid = 0;
if (uname != null && uname.matches("^[a-zA-Z0-9\\-]{2,16}$")) {
@@ -75,7 +71,7 @@ public class PM {
@RequestMapping(value = "/api/pm", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public Message doPostPM(
- @Visitor User visitor,
+ @ModelAttribute User visitor,
@RequestParam String uname,
@RequestParam String body) {
User userTo = AnonymousUser.INSTANCE;
@@ -107,7 +103,7 @@ public class PM {
}
@RequestMapping(value = "/api/groups_pms", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public PrivateChats doGetGroupsPMs(
- @Visitor User visitor,
+ @ModelAttribute User visitor,
@RequestParam(defaultValue = "5") int cnt) {
// TODO: ignore cnt param for now but make sure paging param will not be cnt
diff --git a/src/main/java/com/juick/www/api/Post.java b/src/main/java/com/juick/www/api/Post.java
index c840a590..2a92178d 100644
--- a/src/main/java/com/juick/www/api/Post.java
+++ b/src/main/java/com/juick/www/api/Post.java
@@ -37,7 +37,6 @@ import com.juick.service.MessagesService;
import com.juick.service.StorageService;
import com.juick.service.UserService;
import com.juick.service.activities.UpdateEvent;
-import com.juick.service.security.annotation.Visitor;
import com.juick.util.HttpBadRequestException;
import com.juick.util.HttpForbiddenException;
import com.juick.util.HttpNotFoundException;
@@ -49,13 +48,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.ResponseStatus;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
/**
@@ -81,7 +74,7 @@ public class Post {
@RequestMapping(value = "/api/post", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(value = HttpStatus.OK)
public CommandResult doPostMessage(
- @Visitor User visitor,
+ @ModelAttribute User visitor,
@RequestParam(required = false, defaultValue = StringUtils.EMPTY) String body,
@RequestParam(required = false) String img,
@RequestParam(required = false) MultipartFile attach) throws Exception {
@@ -112,7 +105,7 @@ public class Post {
@RequestMapping(value = "/api/comment", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public CommandResult doPostComment(
- @Visitor User visitor,
+ @ModelAttribute User visitor,
@RequestParam(defaultValue = "0") int mid,
@RequestParam(defaultValue = "0") int rid,
@RequestParam(required = false, defaultValue = StringUtils.EMPTY) final String body,
@@ -164,7 +157,7 @@ public class Post {
@PostMapping("/api/like")
@ResponseStatus(value = HttpStatus.OK)
- public Status doPostRecommendation(@Visitor User visitor, @RequestParam Integer mid) throws Exception {
+ public Status doPostRecommendation(@ModelAttribute User visitor, @RequestParam Integer mid) throws Exception {
Optional<Message> message = messagesService.getMessage(mid);
if (message.isEmpty()) {
throw new HttpNotFoundException();
@@ -180,7 +173,7 @@ public class Post {
@PostMapping("/api/subscribe")
@ResponseStatus(value = HttpStatus.OK)
- public Status doPostSubscribe(@Visitor User visitor,
+ public Status doPostSubscribe(@ModelAttribute User visitor,
@RequestParam Integer mid) throws Exception {
Optional<Message> message = messagesService.getMessage(mid);
if (message.isEmpty()) {
@@ -204,7 +197,7 @@ public class Post {
@PostMapping("/api/react")
@ResponseStatus(value = HttpStatus.OK)
public Status doPostReact(
- @Visitor User visitor,
+ @ModelAttribute User visitor,
@RequestParam Integer mid, @RequestParam @NotNull int reactionId,
@RequestParam(required = false, defaultValue = "1") int count) {
@@ -226,7 +219,7 @@ public class Post {
}
@PostMapping("/api/update")
- public CommandResult updateMessage(@Visitor User visitor,
+ public CommandResult updateMessage(@ModelAttribute User visitor,
@RequestParam Integer mid,
@RequestParam(required = false, defaultValue = "0") Integer rid,
@RequestParam String body) {
diff --git a/src/main/java/com/juick/www/api/Service.java b/src/main/java/com/juick/www/api/Service.java
index 3bb760ff..f4599a56 100644
--- a/src/main/java/com/juick/www/api/Service.java
+++ b/src/main/java/com/juick/www/api/Service.java
@@ -30,7 +30,6 @@ import com.juick.service.MessagesService;
import com.juick.service.StorageService;
import com.juick.service.UserService;
import com.juick.service.component.AccountVerificationEvent;
-import com.juick.service.security.annotation.Visitor;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.mail.Session;
import jakarta.mail.internet.AddressException;
@@ -49,10 +48,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
@@ -92,7 +88,7 @@ public class Service {
@Hidden
@PostMapping("/api/mail")
@ResponseStatus(value = HttpStatus.OK)
- public void processMail(@Visitor User current, InputStream data) throws Exception {
+ public void processMail(@ModelAttribute User current, InputStream data) throws Exception {
if (current.equals(serviceUser)) {
MimeMessage msg = new MimeMessage(session, data);
String[] returnPaths = msg.getHeader("Return-Path");
@@ -207,7 +203,7 @@ public class Service {
@Hidden
@PostMapping("/api/mail/unsubscribe")
@ResponseStatus(value = HttpStatus.OK)
- public void processMailUnsubscribe(@Visitor User current, InputStream data) throws Exception {
+ public void processMailUnsubscribe(@ModelAttribute User current, InputStream data) throws Exception {
if (current.equals(serviceUser)) {
MimeMessage msg = new MimeMessage(session, data);
String from = msg.getFrom() == null || msg.getFrom().length > 1
@@ -231,7 +227,7 @@ public class Service {
}
@GetMapping("/api/events")
- public SseEmitter handle(@Visitor User visitor) {
+ public SseEmitter handle(@ModelAttribute User visitor) {
logger.info("{} connected", visitor.getName());
if (!visitor.isAnonymous()) {
userService.updateLastSeen(visitor);
diff --git a/src/main/java/com/juick/www/api/Tags.java b/src/main/java/com/juick/www/api/Tags.java
index 7d934f38..2b6405ac 100644
--- a/src/main/java/com/juick/www/api/Tags.java
+++ b/src/main/java/com/juick/www/api/Tags.java
@@ -20,12 +20,8 @@ package com.juick.www.api;
import com.juick.model.User;
import com.juick.model.TagStats;
import com.juick.service.TagService;
-import com.juick.service.security.annotation.Visitor;
import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
import javax.inject.Inject;
import java.util.List;
@@ -40,7 +36,7 @@ public class Tags {
@RequestMapping(value = "/api/tags", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<TagStats> tags(
- @Visitor User visitor,
+ @ModelAttribute User visitor,
@RequestParam(required = false, defaultValue = "0") int user_id
) {
if (user_id > 0) {
diff --git a/src/main/java/com/juick/www/api/Users.java b/src/main/java/com/juick/www/api/Users.java
index dd620380..f7c24d8d 100644
--- a/src/main/java/com/juick/www/api/Users.java
+++ b/src/main/java/com/juick/www/api/Users.java
@@ -36,7 +36,6 @@ import com.juick.service.TelegramService;
import com.juick.service.UserService;
import com.juick.service.activities.UpdateUserEvent;
import com.juick.service.component.MailVerificationEvent;
-import com.juick.service.security.annotation.Visitor;
import com.juick.util.HttpBadRequestException;
import com.juick.util.HttpNotFoundException;
import com.juick.util.HttpUtils;
@@ -48,13 +47,7 @@ import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
/**
@@ -80,13 +73,13 @@ public class Users {
private ApplicationEventPublisher applicationEventPublisher;
@RequestMapping(value = "/api/auth", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
- public String getAuthToken(@Visitor User visitor) {
+ public String getAuthToken(@ModelAttribute User visitor) {
return userService.getHashByUID(visitor.getUid());
}
@RequestMapping(value = "/api/users", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<User> doGetUsers(
- @Visitor User visitor,
+ @ModelAttribute User visitor,
@RequestParam(value = "uname", required = false) List<String> unames) {
List<User> users = new ArrayList<>();
@@ -108,7 +101,7 @@ public class Users {
}
@GetMapping("/api/me")
- public SecureUser getMe(@Visitor User visitor) {
+ public SecureUser getMe(@ModelAttribute User visitor) {
SecureUser me = new SecureUser();
me.setUid(visitor.getUid());
me.setName(visitor.getName());
@@ -127,7 +120,7 @@ public class Users {
return (SecureUser)userService.getUserInfo(me);
}
@PostMapping("/api/me")
- public void updateMe(@Visitor User visitor,
+ public void updateMe(@ModelAttribute User visitor,
@RequestParam(required = false) String password,
@RequestParam(value = "jid-del", required = false) String jidForDeletion,
@RequestParam(value = "email-add", required = false) String newEmail,
@@ -171,12 +164,12 @@ public class Users {
}
}
@PostMapping("/api/me/subscribe")
- public void subscribeMe(@Visitor User visitor, String email) {
+ public void subscribeMe(@ModelAttribute User visitor, String email) {
// TODO: check status
emailService.setNotificationsEmail(visitor.getUid(), email);
}
@PostMapping("/api/me/upload")
- public void updateInfo(@Visitor User visitor,
+ public void updateInfo(@ModelAttribute User visitor,
@RequestParam MultipartFile avatar) throws IOException {
String avatarTmpPath = HttpUtils.receiveMultiPartFile(avatar, storageService.getTemporaryDirectory()).getHost();
if (StringUtils.isNotEmpty(avatarTmpPath)) {
@@ -187,7 +180,7 @@ public class Users {
@RequestMapping(value = "/api/users/read", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<User> doGetUserRead(
- @Visitor User visitor,
+ @ModelAttribute User visitor,
@RequestParam String uname) {
int uid = 0;
if (uname == null) {
@@ -211,7 +204,7 @@ public class Users {
@RequestMapping(value = "/api/users/readers", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<User> doGetUserReaders(
- @Visitor User visitor,
+ @ModelAttribute User visitor,
@RequestParam String uname) {
int uid = 0;
if (uname == null) {
@@ -234,7 +227,7 @@ public class Users {
}
@GetMapping("/api/info/{uname}")
- public User getUserInfo(@Visitor User visitor, @PathVariable String uname) {
+ public User getUserInfo(@ModelAttribute User visitor, @PathVariable String uname) {
User user = userService.getUserByName(uname);
if (!user.isBanned()) {
user.setRead(doGetUserRead(visitor, uname));
diff --git a/src/main/java/com/juick/www/api/activity/Profile.java b/src/main/java/com/juick/www/api/activity/Profile.java
index 404e0734..7a3fdf29 100644
--- a/src/main/java/com/juick/www/api/activity/Profile.java
+++ b/src/main/java/com/juick/www/api/activity/Profile.java
@@ -48,7 +48,6 @@ import com.juick.service.activities.DirectMessageEvent;
import com.juick.service.activities.FollowEvent;
import com.juick.service.activities.UndoAnnounceEvent;
import com.juick.service.activities.UndoFollowEvent;
-import com.juick.service.security.annotation.Visitor;
import com.overzealous.remark.Remark;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
@@ -61,11 +60,7 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.UriComponentsBuilder;
@@ -136,8 +131,8 @@ public class Profile {
@GetMapping(value = "/u/{userName}/blog", produces = { Context.LD_JSON_MEDIA_TYPE,
Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE })
- public OrderedCollectionPage getOutboxPage(@Visitor User visitor, @PathVariable String userName,
- @RequestParam(required = false, defaultValue = "0") int before) {
+ public OrderedCollectionPage getOutboxPage(@ModelAttribute User visitor, @PathVariable String userName,
+ @RequestParam(required = false, defaultValue = "0") int before) {
User user = userService.getUserByName(userName);
if (!user.isAnonymous() && !user.isBanned()) {
UriComponentsBuilder uri = UriComponentsBuilder.fromUriString(baseUri);
@@ -273,7 +268,7 @@ public class Profile {
@CacheEvict(cacheNames = "profiles", key = "{ #visitor.uri }")
@PostMapping(value = "/api/inbox", consumes = { Context.LD_JSON_MEDIA_TYPE,
Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE })
- public ResponseEntity<CommandResult> processInbox(@Visitor User visitor, InputStream inboxData) throws Exception {
+ public ResponseEntity<CommandResult> processInbox(@ModelAttribute User visitor, InputStream inboxData) throws Exception {
String inbox = IOUtils.toString(inboxData, StandardCharsets.UTF_8);
Activity activity = jsonMapper.readValue(inbox, Activity.class);
if ((StringUtils.isNotEmpty(visitor.getUri().toString())