From 670913698776e09b7ff44f44ccdcf56303d79be3 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Thu, 6 Sep 2018 13:58:40 +0300 Subject: merge legacy www --- .../java/com/juick/server/api/ApiSocialLogin.java | 302 +++++++++++++++++++++ .../src/main/java/com/juick/server/api/Index.java | 4 +- .../main/java/com/juick/server/api/Messages.java | 12 +- .../java/com/juick/server/api/Notifications.java | 14 +- .../src/main/java/com/juick/server/api/PM.java | 6 +- .../src/main/java/com/juick/server/api/Post.java | 12 +- .../main/java/com/juick/server/api/Service.java | 2 +- .../java/com/juick/server/api/SocialLogin.java | 302 --------------------- .../src/main/java/com/juick/server/api/Tags.java | 2 +- .../src/main/java/com/juick/server/api/Users.java | 12 +- .../com/juick/server/api/activity/Profile.java | 14 +- 11 files changed, 341 insertions(+), 341 deletions(-) create mode 100644 juick-server/src/main/java/com/juick/server/api/ApiSocialLogin.java delete mode 100644 juick-server/src/main/java/com/juick/server/api/SocialLogin.java (limited to 'juick-server/src/main/java/com/juick/server/api') diff --git a/juick-server/src/main/java/com/juick/server/api/ApiSocialLogin.java b/juick-server/src/main/java/com/juick/server/api/ApiSocialLogin.java new file mode 100644 index 00000000..2e484e3d --- /dev/null +++ b/juick-server/src/main/java/com/juick/server/api/ApiSocialLogin.java @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2008-2017, 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.server.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.scribejava.apis.FacebookApi; +import com.github.scribejava.apis.VkontakteApi; +import com.github.scribejava.core.builder.ServiceBuilder; +import com.github.scribejava.core.model.OAuth2AccessToken; +import com.github.scribejava.core.model.OAuthRequest; +import com.github.scribejava.core.model.Verb; +import com.github.scribejava.core.oauth.OAuth20Service; +import com.juick.facebook.User; +import com.juick.server.util.HttpBadRequestException; +import com.juick.service.CrosspostService; +import com.juick.service.EmailService; +import com.juick.service.TelegramService; +import com.juick.service.UserService; +import com.juick.vk.UsersResponse; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.util.UriComponentsBuilder; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import java.io.IOException; +import java.util.UUID; +import java.util.concurrent.ExecutionException; + +/** + * + * @author Ugnich Anton + */ +@Controller +public class ApiSocialLogin { + + private static final Logger logger = LoggerFactory.getLogger(ApiSocialLogin.class); + + @Value("${facebook_appid:appid}") + private String FACEBOOK_APPID; + @Value("${facebook_secret:secret}") + private String FACEBOOK_SECRET; + private static final String FACEBOOK_REDIRECT = "https://api.juick.com/_fblogin"; + private static final String VK_REDIRECT = "https://api.juick.com/_vklogin"; + private static final String TWITTER_VERIFY_URL = "https://api.twitter.com/1.1/account/verify_credentials.json"; + @Inject + private ObjectMapper jsonMapper; + private ServiceBuilder facebookBuilder, twitterBuilder, vkBuilder; + + @Value("${twitter_consumer_key:appid}") + private String twitterConsumerKey; + @Value("${twitter_consumer_secret:secret}") + private String twitterConsumerSecret; + @Value("${vk_appid:appid}") + private String VK_APPID; + @Value("${vk_secret:secret}") + private String VK_SECRET; + @Value("${telegram_token:secret}") + private String telegramToken; + + @Inject + private CrosspostService crosspostService; + @Inject + private UserService userService; + @Inject + private EmailService emailService; + @Inject + private TelegramService telegramService; + + @PostConstruct + public void init() { + facebookBuilder = new ServiceBuilder(FACEBOOK_APPID); + twitterBuilder = new ServiceBuilder(twitterConsumerKey); + vkBuilder = new ServiceBuilder(VK_APPID); + } + + @GetMapping("/api/_fblogin") + protected String doFacebookLogin(@RequestParam(required = false) String code, + @RequestParam(required = false) String state) throws IOException, ExecutionException, InterruptedException { + if (StringUtils.isBlank(code)) { + String fbstate = UUID.randomUUID().toString(); + crosspostService.addFacebookState(fbstate, state); + OAuth20Service facebookAuthService = facebookBuilder + .apiSecret(FACEBOOK_SECRET) + .callback(FACEBOOK_REDIRECT) + .scope("email") + .state(fbstate) + .build(FacebookApi.instance()); + return "redirect:" + facebookAuthService.getAuthorizationUrl(); + } + + String redirectUrl = crosspostService.verifyFacebookState(state); + + if (StringUtils.isEmpty(redirectUrl)) { + logger.error("state is missing"); + throw new HttpBadRequestException(); + } + OAuth20Service facebookService = facebookBuilder + .apiKey(FACEBOOK_APPID) + .apiSecret(FACEBOOK_SECRET) + .callback(FACEBOOK_REDIRECT) + .scope("email") + .state(state) + .build(FacebookApi.instance()); + OAuth2AccessToken token = facebookService.getAccessToken(code); + final OAuthRequest meRequest = new OAuthRequest(Verb.GET, "https://graph.facebook.com/v2.10/me?fields=id,name,link,verified,email"); + facebookService.signRequest(token, meRequest); + String graph = facebookService.execute(meRequest).getBody(); + if (StringUtils.isBlank(graph)) { + logger.error("FACEBOOK GRAPH ERROR"); + throw new HttpBadRequestException(); + } + User fb = jsonMapper.readValue(graph, User.class); + long fbID = NumberUtils.toLong(fb.getId(), 0); + if (fbID == 0 || StringUtils.isBlank(fb.getName()) || StringUtils.isBlank(fb.getLink())) { + logger.error("Missing required fields, id: {}, name: {}, link: {}", fbID, fb.getName(), fb.getLink()); + throw new HttpBadRequestException(); + } + + int uid = crosspostService.getUIDbyFBID(fbID); + if (uid > 0) { + if (!crosspostService.updateFacebookUser(fbID, token.getAccessToken(), fb.getName(), fb.getLink())) { + logger.error("error updating facebook user, id: {}, token: {}", fbID, token.getAccessToken()); + throw new HttpBadRequestException(); + } + UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(redirectUrl); + uriComponentsBuilder.queryParam("hash", userService.getHashByUID(uid)); + return "redirect:" + uriComponentsBuilder.build().toUriString(); + } else if (fb.getVerified()) { + if (!crosspostService.createFacebookUser(fbID, state, token.getAccessToken(), fb.getName(), fb.getLink())) { + if (StringUtils.isNotEmpty(fb.getEmail())) { + logger.info("found {} for facebook user {}", fb.getEmail(), fb.getLink()); + Integer userId = crosspostService.getUIDbyFBID(fbID); + if (!emailService.getEmails(userId, false).contains(fb.getEmail())) { + emailService.addEmail(userId, fb.getEmail()); + } + } + logger.info("email not found for facebook user {}", fb.getLink()); + throw new HttpBadRequestException(); + } + return "redirect:/signup?type=fb&hash=" + state; + } else { + logger.error("Facebook account is not verified, id: {}", fbID); + throw new HttpBadRequestException(); + } + }/* + @GetMapping("/_twitter") + protected void doTwitterLogin(HttpServletRequest request, HttpServletResponse response) + throws IOException, ExecutionException, InterruptedException { + String hash = StringUtils.EMPTY, request_token = StringUtils.EMPTY, request_token_secret = StringUtils.EMPTY; + String verifier = request.getParameter("oauth_verifier"); + Cookie[] cookies = request.getCookies(); + for (Cookie cookie : cookies) { + if (cookie.getName().equals("hash")) { + hash = cookie.getValue(); + } + if (cookie.getName().equals("request_token")) { + request_token = cookie.getValue(); + } + if (cookie.getName().equals("request_token_secret")) { + request_token_secret = cookie.getValue(); + } + } + com.juick.User user = UserUtils.getCurrentUser(); + OAuth10aService oAuthService = twitterBuilder + .apiSecret(twitterConsumerSecret) + .callback("http://juick.com/_twitter") + .build(TwitterApi.instance()); + + if (request_token.isEmpty() && request_token_secret.isEmpty() + && (verifier == null || verifier.isEmpty())) { + OAuth1RequestToken requestToken = oAuthService.getRequestToken(); + String authUrl = oAuthService.getAuthorizationUrl(requestToken); + response.addCookie(new Cookie("request_token", requestToken.getToken())); + response.addCookie(new Cookie("request_token_secret", requestToken.getTokenSecret())); + response.setStatus(HttpServletResponse.SC_FOUND); + response.setHeader("Location", authUrl); + } else { + if (verifier != null && verifier.length() > 0) { + OAuth1RequestToken requestToken = new OAuth1RequestToken(request_token, request_token_secret); + OAuth1AccessToken accessToken = oAuthService.getAccessToken(requestToken, verifier); + OAuthRequest oAuthRequest = new OAuthRequest(Verb.GET, TWITTER_VERIFY_URL); + oAuthService.signRequest(accessToken, oAuthRequest); + com.juick.twitter.User twitterUser = jsonMapper.readValue(oAuthService.execute(oAuthRequest).getBody(), + com.juick.twitter.User.class); + if (userService.linkTwitterAccount(user, accessToken.getToken(), accessToken.getTokenSecret(), + twitterUser.getScreenName())) { + response.setStatus(HttpServletResponse.SC_FOUND); + response.setHeader("Location", "http://juick.com/settings"); + } else { + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + } + } + }*/ + @GetMapping("/api/_vklogin") + protected String doVKLogin(@RequestParam(required = false) String code, + @RequestParam String state) throws IOException, ExecutionException, InterruptedException { + if (StringUtils.isBlank(code)) { + String vkstate = UUID.randomUUID().toString(); + crosspostService.addVKState(vkstate, state); + OAuth20Service vkAuthService = vkBuilder + .apiSecret(VK_SECRET) + .scope("friends,wall,offline") + .state(vkstate) + .callback(VK_REDIRECT) + .build(VkontakteApi.instance()); + return "redirect:" + vkAuthService.getAuthorizationUrl(); + } + + String redirectUrl = crosspostService.verifyVKState(state); + if (StringUtils.isBlank(redirectUrl)) { + logger.error("state is missing"); + throw new HttpBadRequestException(); + } + + OAuth20Service vkService = vkBuilder + .apiKey(VK_APPID) + .apiSecret(VK_SECRET) + .build(VkontakteApi.instance()); + OAuth2AccessToken token = vkService.getAccessToken(code); + + OAuthRequest meRequest = new OAuthRequest(Verb.GET, "https://api.vk.com/method/users.get?fields=screen_name&v=5.73"); + vkService.signRequest(token, meRequest); + String graph = vkService.execute(meRequest).getBody(); + + com.juick.vk.User jsonUser = jsonMapper.readValue(graph, UsersResponse.class).getUsers().get(0); + String vkName = jsonUser.getFirstName() + " " + jsonUser.getLastName(); + String vkLink = jsonUser.getScreenName(); + + if (vkName.length() == 1 || StringUtils.isBlank(vkLink)) { + logger.error("vk user error"); + throw new HttpBadRequestException(); + } + + Long vkID = NumberUtils.toLong(jsonUser.getId(), 0); + int uid = crosspostService.getUIDbyVKID(vkID); + if (uid > 0) { + UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(redirectUrl); + uriComponentsBuilder.queryParam("hash", userService.getHashByUID(uid)); + return "redirect:" + uriComponentsBuilder.build().toUriString(); + } else { + String loginhash = UUID.randomUUID().toString(); + if (!crosspostService.createVKUser(vkID, loginhash, token.getAccessToken(), vkName, vkLink)) { + logger.error("create vk user error"); + throw new HttpBadRequestException(); + } + return "redirect:/signup?type=vk&hash=" + loginhash; + } + } + /* + @GetMapping("/_tglogin") + public String doDurovLogin(HttpServletRequest request, + @RequestParam Map params, + HttpServletResponse response) { + String dataCheckString = params.entrySet().stream() + .filter(p -> !p.getKey().equals("hash")) + .sorted(Map.Entry.comparingByKey()) + .map(p -> p.getKey() + "=" + p.getValue()) + .collect(Collectors.joining("\n")); + String hash = params.get("hash"); + byte[] secretKey = DigestUtils.sha256(telegramToken); + String resultString = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, secretKey).hmacHex(dataCheckString); + if (hash.equals(resultString)) { + Long tgUser = Long.valueOf(params.get("id")); + int uid = telegramService.getUser(tgUser); + if (uid > 0) { + Cookie c = new Cookie("hash", userService.getHashByUID(uid)); + c.setMaxAge(50 * 24 * 60 * 60); + response.addCookie(c); + return Utils.getPreviousPageByRequest(request).orElse("redirect:/"); + } else { + String username = StringUtils.defaultString(params.get("username"), params.get("first_name")); + telegramService.createTelegramUser(tgUser, username); + return "redirect:/signup?type=durov&hash=" + userService.getSignUpHashByTelegramID(tgUser, username); + } + } else { + logger.warn("invalid tg hash {} for {}", resultString, hash); + } + throw new HttpBadRequestException(); + }*/ +} diff --git a/juick-server/src/main/java/com/juick/server/api/Index.java b/juick-server/src/main/java/com/juick/server/api/Index.java index 5ffa6341..0faf270f 100644 --- a/juick-server/src/main/java/com/juick/server/api/Index.java +++ b/juick-server/src/main/java/com/juick/server/api/Index.java @@ -46,7 +46,7 @@ public class Index { @Inject private XMPPServer xmpp; - @RequestMapping(value = { "/", "/ws/" }, method = RequestMethod.GET, headers = "Connection!=Upgrade") + @RequestMapping(value = { "/api/", "/ws/" }, method = RequestMethod.GET, headers = "Connection!=Upgrade") public ResponseEntity description() { URI redirectUri = ServletUriComponentsBuilder.fromCurrentRequestUri().path("/swagger-ui.html").build().toUri(); return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY).location(redirectUri).build(); @@ -56,7 +56,7 @@ public class Index { public Status status() { return Status.getStatus(String.valueOf(wsHandler.getClients().size())); } - @RequestMapping(method = RequestMethod.GET, value = "/xmpp/status", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @RequestMapping(method = RequestMethod.GET, value = "/api/xmpp-status", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public XMPPStatus xmppStatus() { XMPPStatus status = new XMPPStatus(); if (xmpp != null) { diff --git a/juick-server/src/main/java/com/juick/server/api/Messages.java b/juick-server/src/main/java/com/juick/server/api/Messages.java index 2b171489..672f328f 100644 --- a/juick-server/src/main/java/com/juick/server/api/Messages.java +++ b/juick-server/src/main/java/com/juick/server/api/Messages.java @@ -71,7 +71,7 @@ public class Messages { // TODO: serialize image urls - @GetMapping("/home") + @GetMapping("/api/home") public ResponseEntity> getHome( @RequestParam(defaultValue = "0") int before_mid) { User visitor = UserUtils.getCurrentUser(); @@ -83,7 +83,7 @@ public class Messages { return FORBIDDEN; } - @GetMapping("/messages") + @GetMapping("/api/messages") public ResponseEntity> getMessages( @RequestParam(required = false) String uname, @RequestParam(name = "before_mid", defaultValue = "0") Integer before, @@ -142,7 +142,7 @@ public class Messages { } return ResponseEntity.ok(messagesService.getMessages(visitor, mids)); } - @DeleteMapping("/messages") + @DeleteMapping("/api/messages") public CommandResult deleteMessage(@RequestParam int mid, @RequestParam(required = false, defaultValue = "0") int rid) { User visitor = UserUtils.getCurrentUser(); if (rid > 0) { @@ -155,12 +155,12 @@ public class Messages { } throw new HttpBadRequestException(); } - @GetMapping("/messages/discussions") + @GetMapping("/api/messages/discussions") public List getDiscussions( @RequestParam(required = false, defaultValue = "0") Long to) { return messagesService.getMessages(UserUtils.getCurrentUser(), messagesService.getDiscussions(UserUtils.getCurrentUser().getUid(), to)); } - @GetMapping("/thread") + @GetMapping("/api/thread") public ResponseEntity> getThread( @RequestParam(defaultValue = "0") int mid) { User visitor = UserUtils.getCurrentUser(); @@ -183,7 +183,7 @@ public class Messages { } return NOT_FOUND; } - @GetMapping(value = "/thread/mark_read/{mid}-{rid}.gif", produces = MediaType.IMAGE_GIF_VALUE) + @GetMapping(value = "/api/thread/mark_read/{mid}-{rid}.gif", produces = MediaType.IMAGE_GIF_VALUE) public byte[] markThreadRead(@PathVariable int mid, @PathVariable int rid) throws IOException { User visitor = UserUtils.getCurrentUser(); if (!visitor.isAnonymous()) { diff --git a/juick-server/src/main/java/com/juick/server/api/Notifications.java b/juick-server/src/main/java/com/juick/server/api/Notifications.java index e068cbe9..0b34f275 100644 --- a/juick-server/src/main/java/com/juick/server/api/Notifications.java +++ b/juick-server/src/main/java/com/juick/server/api/Notifications.java @@ -67,7 +67,7 @@ public class Notifications { } @ApiIgnore - @RequestMapping(value = "/notifications", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @RequestMapping(value = "/api/notifications", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity> doGet( @RequestParam(required = false, defaultValue = "0") int uid, @RequestParam(required = false, defaultValue = "0") int mid, @@ -101,7 +101,7 @@ public class Notifications { } @ApiIgnore - @RequestMapping(value = "/notifications", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @RequestMapping(value = "/api/notifications", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public Status doDelete( @RequestBody List list) { User visitor = UserUtils.getCurrentUser(); @@ -129,7 +129,7 @@ public class Notifications { } @ApiIgnore - @RequestMapping(value = "/notifications", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @RequestMapping(value = "/api/notifications", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public Status doPut( @RequestBody List list) throws IOException { User visitor = UserUtils.getCurrentUser(); @@ -155,7 +155,7 @@ public class Notifications { } @Deprecated - @RequestMapping(value = "/android/register", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @RequestMapping(value = "/api/android/register", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public Status doAndroidRegister( @RequestParam(name = "regid") String regId) { User visitor = UserUtils.getCurrentUser(); @@ -167,14 +167,14 @@ public class Notifications { } @Deprecated - @RequestMapping(value = "/android/unregister", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @RequestMapping(value = "/api/android/unregister", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public Status doAndroidUnRegister(@RequestParam(name = "regid") String regId) { pushQueriesService.deleteGCMToken(regId); return Status.OK; } @Deprecated - @RequestMapping(value = "/winphone/register", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @RequestMapping(value = "/api/winphone/register", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public Status doWinphoneRegister( Principal principal, @RequestParam(name = "url") String regId) { @@ -184,7 +184,7 @@ public class Notifications { } @Deprecated - @RequestMapping(value = "/winphone/unregister", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @RequestMapping(value = "/api/winphone/unregister", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public Status doWinphoneUnRegister(@RequestParam(name = "url") String regId) { pushQueriesService.deleteMPNSToken(regId); return Status.OK; diff --git a/juick-server/src/main/java/com/juick/server/api/PM.java b/juick-server/src/main/java/com/juick/server/api/PM.java index cbd70bed..d3619662 100644 --- a/juick-server/src/main/java/com/juick/server/api/PM.java +++ b/juick-server/src/main/java/com/juick/server/api/PM.java @@ -47,7 +47,7 @@ public class PM { @Inject private ApplicationEventPublisher applicationEventPublisher; - @RequestMapping(value = "/pm", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @RequestMapping(value = "/api/pm", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public List doGetPM( @RequestParam(required = false) String uname) { User visitor = UserUtils.getCurrentUser(); @@ -66,7 +66,7 @@ public class PM { return pmQueriesService.getPMMessages(visitor.getUid(), uid); } - @RequestMapping(value = "/pm", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @RequestMapping(value = "/api/pm", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public com.juick.Message doPostPM( @RequestParam String uname, @RequestParam String body) { @@ -98,7 +98,7 @@ public class PM { } throw new HttpBadRequestException(); } - @RequestMapping(value = "groups_pms", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @RequestMapping(value = "/api/groups_pms", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public PrivateChats doGetGroupsPMs( @RequestParam(defaultValue = "5") int cnt) { User visitor = UserUtils.getCurrentUser(); diff --git a/juick-server/src/main/java/com/juick/server/api/Post.java b/juick-server/src/main/java/com/juick/server/api/Post.java index b0be50b6..99d118c3 100644 --- a/juick-server/src/main/java/com/juick/server/api/Post.java +++ b/juick-server/src/main/java/com/juick/server/api/Post.java @@ -62,7 +62,7 @@ public class Post { @Inject CommandsManager commandsManager; - @RequestMapping(value = "/post", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @RequestMapping(value = "/api/post", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) @ResponseStatus(value = HttpStatus.OK) public CommandResult doPostMessage( @RequestParam(required = false, defaultValue = StringUtils.EMPTY) String body, @@ -101,7 +101,7 @@ public class Post { return commandsManager.processCommand(visitor, body, attachmentFName); } - @RequestMapping(value = "/comment", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @RequestMapping(value = "/api/comment", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public com.juick.Message doPostComment( @RequestParam(defaultValue = "0") int mid, @RequestParam(defaultValue = "0") int rid, @@ -154,7 +154,7 @@ public class Post { return commandsManager.processCommand(visitor, String.format("#%d/%d %s", mid, rid, body), attachmentFName).getNewMessage().get(); } - @PostMapping("/like") + @PostMapping("/api/like") @ResponseStatus(value = HttpStatus.OK) public Status doPostRecomm(@RequestParam Integer mid) throws Exception { com.juick.User visitor = UserUtils.getCurrentUser(); @@ -173,13 +173,13 @@ public class Post { return Status.getStatus(status.getText()); } - @GetMapping("/reactions") + @GetMapping("/api/reactions") @ResponseStatus(value = HttpStatus.OK) public List reactionsList() { return messagesService.listReactions(); } - @PostMapping("/react") + @PostMapping("/api/react") @ResponseStatus(value = HttpStatus.OK) public Status doPostReact(@RequestParam Integer mid,@RequestParam @NotNull int reactionId, @RequestParam (required = false, defaultValue = "1") int count) { @@ -204,7 +204,7 @@ public class Post { return recommendStatus == MessagesService.RecommendStatus.Error ? Status.ERROR :Status.OK; } - @PostMapping("/update") + @PostMapping("/api/update") public CommandResult updateMessage(@RequestParam Integer mid, @RequestParam(required = false, defaultValue = "0") Integer rid, @RequestParam String body) { diff --git a/juick-server/src/main/java/com/juick/server/api/Service.java b/juick-server/src/main/java/com/juick/server/api/Service.java index 3a01317b..0da5d46c 100644 --- a/juick-server/src/main/java/com/juick/server/api/Service.java +++ b/juick-server/src/main/java/com/juick/server/api/Service.java @@ -54,7 +54,7 @@ public class Service { Session session = Session.getDefaultInstance(new Properties()); @ApiIgnore - @PostMapping("/mail") + @PostMapping("/api/mail") @ResponseStatus(value = HttpStatus.OK) public void processMail(InputStream data) throws Exception { if (UserUtils.getCurrentUser().getName().equals(serviceUser)) { diff --git a/juick-server/src/main/java/com/juick/server/api/SocialLogin.java b/juick-server/src/main/java/com/juick/server/api/SocialLogin.java deleted file mode 100644 index dc7425e1..00000000 --- a/juick-server/src/main/java/com/juick/server/api/SocialLogin.java +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (C) 2008-2017, 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.server.api; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.scribejava.apis.FacebookApi; -import com.github.scribejava.apis.VkontakteApi; -import com.github.scribejava.core.builder.ServiceBuilder; -import com.github.scribejava.core.model.OAuth2AccessToken; -import com.github.scribejava.core.model.OAuthRequest; -import com.github.scribejava.core.model.Verb; -import com.github.scribejava.core.oauth.OAuth20Service; -import com.juick.facebook.User; -import com.juick.server.util.HttpBadRequestException; -import com.juick.service.CrosspostService; -import com.juick.service.EmailService; -import com.juick.service.TelegramService; -import com.juick.service.UserService; -import com.juick.vk.UsersResponse; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.math.NumberUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.util.UriComponentsBuilder; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import java.io.IOException; -import java.util.UUID; -import java.util.concurrent.ExecutionException; - -/** - * - * @author Ugnich Anton - */ -@Controller -public class SocialLogin { - - private static final Logger logger = LoggerFactory.getLogger(SocialLogin.class); - - @Value("${facebook_appid:appid}") - private String FACEBOOK_APPID; - @Value("${facebook_secret:secret}") - private String FACEBOOK_SECRET; - private static final String FACEBOOK_REDIRECT = "https://api.juick.com/_fblogin"; - private static final String VK_REDIRECT = "https://api.juick.com/_vklogin"; - private static final String TWITTER_VERIFY_URL = "https://api.twitter.com/1.1/account/verify_credentials.json"; - @Inject - private ObjectMapper jsonMapper; - private ServiceBuilder facebookBuilder, twitterBuilder, vkBuilder; - - @Value("${twitter_consumer_key:appid}") - private String twitterConsumerKey; - @Value("${twitter_consumer_secret:secret}") - private String twitterConsumerSecret; - @Value("${vk_appid:appid}") - private String VK_APPID; - @Value("${vk_secret:secret}") - private String VK_SECRET; - @Value("${telegram_token:secret}") - private String telegramToken; - - @Inject - private CrosspostService crosspostService; - @Inject - private UserService userService; - @Inject - private EmailService emailService; - @Inject - private TelegramService telegramService; - - @PostConstruct - public void init() { - facebookBuilder = new ServiceBuilder(FACEBOOK_APPID); - twitterBuilder = new ServiceBuilder(twitterConsumerKey); - vkBuilder = new ServiceBuilder(VK_APPID); - } - - @GetMapping("/_fblogin") - protected String doFacebookLogin(@RequestParam(required = false) String code, - @RequestParam(required = false) String state) throws IOException, ExecutionException, InterruptedException { - if (StringUtils.isBlank(code)) { - String fbstate = UUID.randomUUID().toString(); - crosspostService.addFacebookState(fbstate, state); - OAuth20Service facebookAuthService = facebookBuilder - .apiSecret(FACEBOOK_SECRET) - .callback(FACEBOOK_REDIRECT) - .scope("email") - .state(fbstate) - .build(FacebookApi.instance()); - return "redirect:" + facebookAuthService.getAuthorizationUrl(); - } - - String redirectUrl = crosspostService.verifyFacebookState(state); - - if (StringUtils.isEmpty(redirectUrl)) { - logger.error("state is missing"); - throw new HttpBadRequestException(); - } - OAuth20Service facebookService = facebookBuilder - .apiKey(FACEBOOK_APPID) - .apiSecret(FACEBOOK_SECRET) - .callback(FACEBOOK_REDIRECT) - .scope("email") - .state(state) - .build(FacebookApi.instance()); - OAuth2AccessToken token = facebookService.getAccessToken(code); - final OAuthRequest meRequest = new OAuthRequest(Verb.GET, "https://graph.facebook.com/v2.10/me?fields=id,name,link,verified,email"); - facebookService.signRequest(token, meRequest); - String graph = facebookService.execute(meRequest).getBody(); - if (StringUtils.isBlank(graph)) { - logger.error("FACEBOOK GRAPH ERROR"); - throw new HttpBadRequestException(); - } - User fb = jsonMapper.readValue(graph, User.class); - long fbID = NumberUtils.toLong(fb.getId(), 0); - if (fbID == 0 || StringUtils.isBlank(fb.getName()) || StringUtils.isBlank(fb.getLink())) { - logger.error("Missing required fields, id: {}, name: {}, link: {}", fbID, fb.getName(), fb.getLink()); - throw new HttpBadRequestException(); - } - - int uid = crosspostService.getUIDbyFBID(fbID); - if (uid > 0) { - if (!crosspostService.updateFacebookUser(fbID, token.getAccessToken(), fb.getName(), fb.getLink())) { - logger.error("error updating facebook user, id: {}, token: {}", fbID, token.getAccessToken()); - throw new HttpBadRequestException(); - } - UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(redirectUrl); - uriComponentsBuilder.queryParam("hash", userService.getHashByUID(uid)); - return "redirect:" + uriComponentsBuilder.build().toUriString(); - } else if (fb.getVerified()) { - if (!crosspostService.createFacebookUser(fbID, state, token.getAccessToken(), fb.getName(), fb.getLink())) { - if (StringUtils.isNotEmpty(fb.getEmail())) { - logger.info("found {} for facebook user {}", fb.getEmail(), fb.getLink()); - Integer userId = crosspostService.getUIDbyFBID(fbID); - if (!emailService.getEmails(userId, false).contains(fb.getEmail())) { - emailService.addEmail(userId, fb.getEmail()); - } - } - logger.info("email not found for facebook user {}", fb.getLink()); - throw new HttpBadRequestException(); - } - return "redirect:/signup?type=fb&hash=" + state; - } else { - logger.error("Facebook account is not verified, id: {}", fbID); - throw new HttpBadRequestException(); - } - }/* - @GetMapping("/_twitter") - protected void doTwitterLogin(HttpServletRequest request, HttpServletResponse response) - throws IOException, ExecutionException, InterruptedException { - String hash = StringUtils.EMPTY, request_token = StringUtils.EMPTY, request_token_secret = StringUtils.EMPTY; - String verifier = request.getParameter("oauth_verifier"); - Cookie[] cookies = request.getCookies(); - for (Cookie cookie : cookies) { - if (cookie.getName().equals("hash")) { - hash = cookie.getValue(); - } - if (cookie.getName().equals("request_token")) { - request_token = cookie.getValue(); - } - if (cookie.getName().equals("request_token_secret")) { - request_token_secret = cookie.getValue(); - } - } - com.juick.User user = UserUtils.getCurrentUser(); - OAuth10aService oAuthService = twitterBuilder - .apiSecret(twitterConsumerSecret) - .callback("http://juick.com/_twitter") - .build(TwitterApi.instance()); - - if (request_token.isEmpty() && request_token_secret.isEmpty() - && (verifier == null || verifier.isEmpty())) { - OAuth1RequestToken requestToken = oAuthService.getRequestToken(); - String authUrl = oAuthService.getAuthorizationUrl(requestToken); - response.addCookie(new Cookie("request_token", requestToken.getToken())); - response.addCookie(new Cookie("request_token_secret", requestToken.getTokenSecret())); - response.setStatus(HttpServletResponse.SC_FOUND); - response.setHeader("Location", authUrl); - } else { - if (verifier != null && verifier.length() > 0) { - OAuth1RequestToken requestToken = new OAuth1RequestToken(request_token, request_token_secret); - OAuth1AccessToken accessToken = oAuthService.getAccessToken(requestToken, verifier); - OAuthRequest oAuthRequest = new OAuthRequest(Verb.GET, TWITTER_VERIFY_URL); - oAuthService.signRequest(accessToken, oAuthRequest); - com.juick.twitter.User twitterUser = jsonMapper.readValue(oAuthService.execute(oAuthRequest).getBody(), - com.juick.twitter.User.class); - if (userService.linkTwitterAccount(user, accessToken.getToken(), accessToken.getTokenSecret(), - twitterUser.getScreenName())) { - response.setStatus(HttpServletResponse.SC_FOUND); - response.setHeader("Location", "http://juick.com/settings"); - } else { - response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } - } - } - }*/ - @GetMapping("/_vklogin") - protected String doVKLogin(@RequestParam(required = false) String code, - @RequestParam String state) throws IOException, ExecutionException, InterruptedException { - if (StringUtils.isBlank(code)) { - String vkstate = UUID.randomUUID().toString(); - crosspostService.addVKState(vkstate, state); - OAuth20Service vkAuthService = vkBuilder - .apiSecret(VK_SECRET) - .scope("friends,wall,offline") - .state(vkstate) - .callback(VK_REDIRECT) - .build(VkontakteApi.instance()); - return "redirect:" + vkAuthService.getAuthorizationUrl(); - } - - String redirectUrl = crosspostService.verifyVKState(state); - if (StringUtils.isBlank(redirectUrl)) { - logger.error("state is missing"); - throw new HttpBadRequestException(); - } - - OAuth20Service vkService = vkBuilder - .apiKey(VK_APPID) - .apiSecret(VK_SECRET) - .build(VkontakteApi.instance()); - OAuth2AccessToken token = vkService.getAccessToken(code); - - OAuthRequest meRequest = new OAuthRequest(Verb.GET, "https://api.vk.com/method/users.get?fields=screen_name&v=5.73"); - vkService.signRequest(token, meRequest); - String graph = vkService.execute(meRequest).getBody(); - - com.juick.vk.User jsonUser = jsonMapper.readValue(graph, UsersResponse.class).getUsers().get(0); - String vkName = jsonUser.getFirstName() + " " + jsonUser.getLastName(); - String vkLink = jsonUser.getScreenName(); - - if (vkName.length() == 1 || StringUtils.isBlank(vkLink)) { - logger.error("vk user error"); - throw new HttpBadRequestException(); - } - - Long vkID = NumberUtils.toLong(jsonUser.getId(), 0); - int uid = crosspostService.getUIDbyVKID(vkID); - if (uid > 0) { - UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(redirectUrl); - uriComponentsBuilder.queryParam("hash", userService.getHashByUID(uid)); - return "redirect:" + uriComponentsBuilder.build().toUriString(); - } else { - String loginhash = UUID.randomUUID().toString(); - if (!crosspostService.createVKUser(vkID, loginhash, token.getAccessToken(), vkName, vkLink)) { - logger.error("create vk user error"); - throw new HttpBadRequestException(); - } - return "redirect:/signup?type=vk&hash=" + loginhash; - } - } - /* - @GetMapping("/_tglogin") - public String doDurovLogin(HttpServletRequest request, - @RequestParam Map params, - HttpServletResponse response) { - String dataCheckString = params.entrySet().stream() - .filter(p -> !p.getKey().equals("hash")) - .sorted(Map.Entry.comparingByKey()) - .map(p -> p.getKey() + "=" + p.getValue()) - .collect(Collectors.joining("\n")); - String hash = params.get("hash"); - byte[] secretKey = DigestUtils.sha256(telegramToken); - String resultString = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, secretKey).hmacHex(dataCheckString); - if (hash.equals(resultString)) { - Long tgUser = Long.valueOf(params.get("id")); - int uid = telegramService.getUser(tgUser); - if (uid > 0) { - Cookie c = new Cookie("hash", userService.getHashByUID(uid)); - c.setMaxAge(50 * 24 * 60 * 60); - response.addCookie(c); - return Utils.getPreviousPageByRequest(request).orElse("redirect:/"); - } else { - String username = StringUtils.defaultString(params.get("username"), params.get("first_name")); - telegramService.createTelegramUser(tgUser, username); - return "redirect:/signup?type=durov&hash=" + userService.getSignUpHashByTelegramID(tgUser, username); - } - } else { - logger.warn("invalid tg hash {} for {}", resultString, hash); - } - throw new HttpBadRequestException(); - }*/ -} diff --git a/juick-server/src/main/java/com/juick/server/api/Tags.java b/juick-server/src/main/java/com/juick/server/api/Tags.java index 8ced4ec9..38e71e3a 100644 --- a/juick-server/src/main/java/com/juick/server/api/Tags.java +++ b/juick-server/src/main/java/com/juick/server/api/Tags.java @@ -38,7 +38,7 @@ public class Tags { @Inject private TagService tagService; - @RequestMapping(value = "/tags", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @RequestMapping(value = "/api/tags", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public List tags( @RequestParam(required = false, defaultValue = "0") int user_id ) { diff --git a/juick-server/src/main/java/com/juick/server/api/Users.java b/juick-server/src/main/java/com/juick/server/api/Users.java index 237b7ed6..7f29a327 100644 --- a/juick-server/src/main/java/com/juick/server/api/Users.java +++ b/juick-server/src/main/java/com/juick/server/api/Users.java @@ -52,12 +52,12 @@ public class Users { private EmailService emailService; @ApiOperation(value = "This returns user token", notes = "Pass login and password using HTTP Basic") - @RequestMapping(value = "/auth", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @RequestMapping(value = "/api/auth", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public String getAuthToken() { return userService.getHashByUID(UserUtils.getCurrentUser().getUid()); } - @RequestMapping(value = "/users", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @RequestMapping(value = "/api/users", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public List doGetUsers( @RequestParam(value = "uname", required = false) List unames) { List users = new ArrayList<>(); @@ -78,7 +78,7 @@ public class Users { throw new HttpNotFoundException(); } - @GetMapping("/me") + @GetMapping("/api/me") public SecureUser getMe() { User visitor = UserUtils.getCurrentUser(); SecureUser me = new SecureUser(); @@ -93,7 +93,7 @@ public class Users { return me; } - @RequestMapping(value = "/users/read", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @RequestMapping(value = "/api/users/read", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public List doGetUserRead( @RequestParam String uname) { User visitor = UserUtils.getCurrentUser(); @@ -118,7 +118,7 @@ public class Users { throw new HttpNotFoundException(); } - @RequestMapping(value = "/users/readers", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @RequestMapping(value = "/api/users/readers", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public List doGetUserReaders( @RequestParam String uname) { User visitor = UserUtils.getCurrentUser(); @@ -144,7 +144,7 @@ public class Users { } @ApiOperation(value = "This returns detailed user info") - @GetMapping("/info/{uname}") + @GetMapping("/api/info/{uname}") public UserInfo getUserInfo(@PathVariable String uname) { User user = userService.getUserByName(uname); if (!user.isBanned()) { diff --git a/juick-server/src/main/java/com/juick/server/api/activity/Profile.java b/juick-server/src/main/java/com/juick/server/api/activity/Profile.java index 0d987b58..89236f03 100644 --- a/juick-server/src/main/java/com/juick/server/api/activity/Profile.java +++ b/juick-server/src/main/java/com/juick/server/api/activity/Profile.java @@ -38,7 +38,7 @@ public class Profile { @Value("${img_url:http://localhost:8080/i/}") private String baseImagesUri; - @GetMapping(value = "/u/{userName}", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_MEDIA_TYPE }) + @GetMapping(value = "/api/u/{userName}", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_MEDIA_TYPE }) public Person getUser(@PathVariable String userName) { User user = userService.getUserByName(userName); if (!user.isAnonymous()) { @@ -67,7 +67,7 @@ public class Profile { } throw new HttpNotFoundException(); } - @GetMapping(value = "/u/{userName}/blog/toc", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_MEDIA_TYPE }) + @GetMapping(value = "/api/u/{userName}/blog/toc", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_MEDIA_TYPE }) public OrderedCollection getOutbox(@PathVariable String userName) { User user = userService.getUserByName(userName); if (!user.isAnonymous()) { @@ -80,7 +80,7 @@ public class Profile { } throw new HttpNotFoundException(); } - @GetMapping(value = "/u/{userName}/blog", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_MEDIA_TYPE }) + @GetMapping(value = "/api/u/{userName}/blog", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_MEDIA_TYPE }) public OrderedCollectionPage getOutboxPage(@PathVariable String userName, @RequestParam(required = false, defaultValue = "0") int before) { User visitor = UserUtils.getCurrentUser(); @@ -128,7 +128,7 @@ public class Profile { } throw new HttpNotFoundException(); } - @GetMapping(value = "/u/{userName}/followers/toc", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_MEDIA_TYPE }) + @GetMapping(value = "/api/u/{userName}/followers/toc", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_MEDIA_TYPE }) public OrderedCollection getFollowers(@PathVariable String userName) { User user = userService.getUserByName(userName); if (!user.isAnonymous()) { @@ -141,7 +141,7 @@ public class Profile { } throw new HttpNotFoundException(); } - @GetMapping(value = "/u/{userName}/followers", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_MEDIA_TYPE }) + @GetMapping(value = "/api/u/{userName}/followers", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_MEDIA_TYPE }) public OrderedCollectionPage getFollowersPage(@PathVariable String userName, @RequestParam(required = false, defaultValue = "0") int page) { User user = userService.getUserByName(userName); @@ -171,7 +171,7 @@ public class Profile { } throw new HttpNotFoundException(); } - @GetMapping(value = "/u/{userName}/following/toc", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_MEDIA_TYPE }) + @GetMapping(value = "/api/u/{userName}/following/toc", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_MEDIA_TYPE }) public OrderedCollection getFollowing(@PathVariable String userName) { User user = userService.getUserByName(userName); if (!user.isAnonymous()) { @@ -184,7 +184,7 @@ public class Profile { } throw new HttpNotFoundException(); } - @GetMapping(value = "/u/{userName}/following", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_MEDIA_TYPE }) + @GetMapping(value = "/api/u/{userName}/following", produces = { ActivityObject.LD_JSON_MEDIA_TYPE, ActivityObject.ACTIVITY_JSON_MEDIA_TYPE }) public OrderedCollectionPage getFollowingPage(@PathVariable String userName, @RequestParam(required = false, defaultValue = "0") int page) { User user = userService.getUserByName(userName); -- cgit v1.2.3