From c471503ede9aad91193ff6f93966196e6aff15d6 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Wed, 4 Jan 2023 03:38:19 +0300 Subject: OAuth authentication for Mastodon and ActivityPub C2S --- src/main/java/com/juick/www/api/Mastodon.java | 118 +++++++++++++++++++++ src/main/java/com/juick/www/api/Messages.java | 18 ++-- src/main/java/com/juick/www/api/Notifications.java | 88 +++++---------- src/main/java/com/juick/www/api/PM.java | 12 +-- src/main/java/com/juick/www/api/Post.java | 21 ++-- src/main/java/com/juick/www/api/Service.java | 12 +-- src/main/java/com/juick/www/api/Tags.java | 8 +- src/main/java/com/juick/www/api/Users.java | 27 ++--- .../java/com/juick/www/api/activity/Profile.java | 13 +-- 9 files changed, 181 insertions(+), 136 deletions(-) create mode 100644 src/main/java/com/juick/www/api/Mastodon.java (limited to 'src/main/java/com/juick/www/api') 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 . + */ + +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 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 getHome(@Visitor User visitor, + @GetMapping({"/api/home"}) + public List getHome(@ModelAttribute User visitor, @RequestParam(defaultValue = "0") int before_mid) { int vuid = visitor.getUid(); List mids = messagesService.getMyFeed(vuid, before_mid, true); @@ -82,7 +78,7 @@ public class Messages { } @GetMapping("/api/messages") - public List getMessages(@Visitor User visitor, + public List 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 getDiscussions(@Visitor User visitor, + public List getDiscussions(@ModelAttribute User visitor, @RequestParam(required = false, defaultValue = "0") Long to) { List 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 getThread(@Visitor User visitor, @RequestParam(defaultValue = "0") int mid, + public List getThread(@ModelAttribute User visitor, @RequestParam(defaultValue = "0") int mid, @RequestParam(defaultValue = "true") boolean showReplies) { Optional 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 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 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 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 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 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 = 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 = 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 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 doGetUsers( - @Visitor User visitor, + @ModelAttribute User visitor, @RequestParam(value = "uname", required = false) List unames) { List 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 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 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 processInbox(@Visitor User visitor, InputStream inboxData) throws Exception { + public ResponseEntity 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()) -- cgit v1.2.3