aboutsummaryrefslogtreecommitdiff
path: root/juick-server
diff options
context:
space:
mode:
authorGravatar Vitaly Takmazov2018-04-02 16:47:02 +0300
committerGravatar Vitaly Takmazov2018-04-02 16:47:02 +0300
commit5b5ca32a22e2e8e95c9bca86ce23d19c4a69f83d (patch)
treeb65bd56a0a7fdd59ced863e4a0063ed6510840c0 /juick-server
parent22ee9166d87a9b6a853c25c5f2bb3ff95aacad35 (diff)
xmpp: move to library project
Diffstat (limited to 'juick-server')
-rw-r--r--juick-server/build.gradle1
-rw-r--r--juick-server/src/main/java/com/juick/server/CommandsManager.java489
-rw-r--r--juick-server/src/main/java/com/juick/server/MessengerManager.java4
-rw-r--r--juick-server/src/main/java/com/juick/server/NotificationListener.java18
-rw-r--r--juick-server/src/main/java/com/juick/server/ServerManager.java10
-rw-r--r--juick-server/src/main/java/com/juick/server/TelegramBotManager.java6
-rw-r--r--juick-server/src/main/java/com/juick/server/WebsocketManager.java4
-rw-r--r--juick-server/src/main/java/com/juick/server/XMPPConnection.java743
-rw-r--r--juick-server/src/main/java/com/juick/server/XMPPServer.java432
-rw-r--r--juick-server/src/main/java/com/juick/server/api/Post.java8
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/helpers/CommandResult.java28
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/helpers/XMPPStatus.java48
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/helpers/annotation/UserCommand.java50
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/router/Stream.java184
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/router/StreamComponentServer.java58
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/router/StreamError.java44
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/router/StreamHandler.java13
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/router/StreamNamespaces.java10
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/router/XMPPError.java73
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/router/XMPPRouter.java176
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/router/XmlUtils.java88
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/s2s/CacheEntry.java40
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/s2s/Connection.java139
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionIn.java213
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionListener.java15
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionOut.java167
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/s2s/DNSQueries.java65
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/s2s/StanzaListener.java28
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/s2s/util/DialbackUtils.java37
-rw-r--r--juick-server/src/main/resources/juick.pngbin2324 -> 0 bytes
30 files changed, 12 insertions, 3179 deletions
diff --git a/juick-server/build.gradle b/juick-server/build.gradle
index bb4d68ae..15e015ed 100644
--- a/juick-server/build.gradle
+++ b/juick-server/build.gradle
@@ -3,6 +3,7 @@ apply plugin: 'org.springframework.boot'
dependencies {
compile project(':juick-server-jdbc')
+ compile project(':juick-server-xmpp')
compile ('org.springframework.boot:spring-boot-starter-security')
providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")
providedRuntime 'com.h2database:h2:1.4.196'
diff --git a/juick-server/src/main/java/com/juick/server/CommandsManager.java b/juick-server/src/main/java/com/juick/server/CommandsManager.java
deleted file mode 100644
index 6458382f..00000000
--- a/juick-server/src/main/java/com/juick/server/CommandsManager.java
+++ /dev/null
@@ -1,489 +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 <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server;
-
-import com.juick.Message;
-import com.juick.Tag;
-import com.juick.User;
-import com.juick.formatters.PlainTextFormatter;
-import com.juick.server.component.LikeEvent;
-import com.juick.server.component.MessageEvent;
-import com.juick.server.component.PingEvent;
-import com.juick.server.component.SubscribeEvent;
-import com.juick.server.helpers.TagStats;
-import com.juick.server.util.HttpUtils;
-import com.juick.server.util.ImageUtils;
-import com.juick.server.xmpp.helpers.CommandResult;
-import com.juick.server.xmpp.helpers.annotation.UserCommand;
-import com.juick.service.*;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.math.NumberUtils;
-import org.apache.commons.lang3.reflect.MethodUtils;
-import org.ocpsoft.prettytime.PrettyTime;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.stereotype.Component;
-import rocks.xmpp.addr.Jid;
-
-import javax.annotation.PostConstruct;
-import javax.inject.Inject;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.nio.file.Paths;
-import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-/**
- *
- * @author ugnich
- */
-@Component
-public class CommandsManager {
- private PrettyTime pt;
- @Inject
- private MessagesService messagesService;
- @Inject
- private UserService userService;
- @Inject
- private TagService tagService;
- @Inject
- private PMQueriesService pmQueriesService;
- @Inject
- private ShowQueriesService showQueriesService;
- @Inject
- private PrivacyQueriesService privacyQueriesService;
- @Inject
- private SubscriptionService subscriptionService;
- @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
- private String tmpDir;
- @Value("${img_path:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
- private String imgDir;
- @Inject
- private ApplicationEventPublisher applicationEventPublisher;
-
- @PostConstruct
- public void init() {
- pt = new PrettyTime(new Locale("ru"));
- }
-
-
- public Optional<CommandResult> processCommand(User user, Jid from, String input, URI attachment) throws InvocationTargetException,
- IllegalAccessException, NoSuchMethodException {
- Optional<Method> cmd = MethodUtils.getMethodsListWithAnnotation(getClass(), UserCommand.class).stream()
- .filter(m -> Pattern.compile(m.getAnnotation(UserCommand.class).pattern(),
- m.getAnnotation(UserCommand.class).patternFlags()).matcher(input).matches())
- .findFirst();
- if (cmd.isPresent()) {
- Matcher matcher = Pattern.compile(cmd.get().getAnnotation(UserCommand.class).pattern(),
- cmd.get().getAnnotation(UserCommand.class).patternFlags()).matcher(input);
- List<String> groups = new ArrayList<>();
- while (matcher.find()) {
- for (int i = 1; i <= matcher.groupCount(); i++) {
- groups.add(matcher.group(i));
- }
- }
- return Optional.of((CommandResult) getClass().getMethod(cmd.get().getName(), User.class, Jid.class, URI.class, String[].class)
- .invoke(this, user, from, attachment, groups.toArray(new String[groups.size()])));
- }
- return Optional.empty();
- }
-
- @UserCommand(pattern = "^ping$", patternFlags = Pattern.CASE_INSENSITIVE,
- help = "PING - returns you a PONG")
- public CommandResult commandPing(User user, Jid from, URI attachment, String[] input) {
- applicationEventPublisher.publishEvent(new PingEvent(this, user));
- return CommandResult.fromString("PONG");
- }
-
- @UserCommand(pattern = "^help$", patternFlags = Pattern.CASE_INSENSITIVE,
- help = "HELP - returns this help message")
- public CommandResult commandHelp(User user, Jid from, URI attachment, String[] input) {
- return CommandResult.fromString(Arrays.stream(getClass().getDeclaredMethods())
- .filter(m -> m.isAnnotationPresent(UserCommand.class))
- .map(m -> m.getAnnotation(UserCommand.class).help())
- .collect(Collectors.joining("\n")));
- }
-
- @UserCommand(pattern = "^login$", patternFlags = Pattern.CASE_INSENSITIVE,
- help = "LOGIN - log in to Juick website")
- public CommandResult commandLogin(User user_from, Jid from, URI attachment, String[] input) {
- return CommandResult.fromString("http://juick.com/login?hash=" + userService.getHashByUID(user_from.getUid()));
- }
- @UserCommand(pattern = "^\\@(\\S+)\\s+([\\s\\S]+)$", help = "@username message - send PM to username")
- public CommandResult commandPM(User user_from, Jid from, URI attachment, String... arguments) {
- String body = arguments[1];
-
- User user_to = userService.getUserByName(arguments[0]);
-
- if (user_to.getUid() > 0) {
- if (!userService.isInBLAny(user_to.getUid(), user_from.getUid())) {
- if (pmQueriesService.createPM(user_from.getUid(), user_to.getUid(), body)) {
- com.juick.Message jmsg = new com.juick.Message();
- jmsg.setUser(user_from);
- jmsg.setTo(user_to);
- jmsg.setText(body);
- applicationEventPublisher.publishEvent(new MessageEvent(this, jmsg));
- return CommandResult.fromString("Private message sent");
- }
- }
- }
- return CommandResult.fromString("Error");
- }
- @UserCommand(pattern = "^bl$", patternFlags = Pattern.CASE_INSENSITIVE,
- help = "BL - Show your blacklist")
- public CommandResult commandBLShow(User user_from, Jid from, URI attachment, String... arguments) {
- List<User> blusers = userService.getUserBLUsers(user_from.getUid());
- List<String> bltags = tagService.getUserBLTags(user_from.getUid());
-
- String txt = StringUtils.EMPTY;
- if (bltags.size() > 0) {
- for (String bltag : bltags) {
- txt += "*" + bltag + "\n";
- }
-
- if (blusers.size() > 0) {
- txt += "\n";
- }
- }
- if (blusers.size() > 0) {
- for (User bluser : blusers) {
- txt += "@" + bluser.getName() + "\n";
- }
- }
- if (txt.isEmpty()) {
- txt = "You don't have any users or tags in your blacklist.";
- }
-
- return CommandResult.fromString(txt);
- }
-
- @UserCommand(pattern = "^#\\+$", help = "#+ - Show last Juick messages")
- public CommandResult commandLast(User user_from, Jid from, URI attachment, String... arguments) {
- return CommandResult.fromString("Last messages:\n"
- + printMessages(messagesService.getAll(user_from.getUid(), 0), true));
- }
-
- @UserCommand(pattern = "@", help = "@ - Show recommendations and popular personal blogs")
- public CommandResult commandUsers(User user_from, Jid from, URI attachment, String... arguments) {
- StringBuilder msg = new StringBuilder();
- msg.append("Recommended blogs");
- List<String> recommendedUsers = showQueriesService.getRecommendedUsers(user_from);
- if (recommendedUsers.size() > 0) {
- for (String user : recommendedUsers) {
- msg.append("\n@").append(user);
- }
- } else {
- msg.append("\nNo recommendations now. Subscribe to more blogs. ;)");
- }
- msg.append("\n\nTop 10 personal blogs:");
- List<String> topUsers = showQueriesService.getTopUsers();
- if (topUsers.size() > 0) {
- for (String user : topUsers) {
- msg.append("\n@").append(user);
- }
- } else {
- msg.append("\nNo top users. Empty DB? ;)");
- }
- return CommandResult.fromString(msg.toString());
- }
- @UserCommand(pattern = "^bl\\s+@([^\\s\\n\\+]+)", patternFlags = Pattern.CASE_INSENSITIVE,
- help = "BL @username - add @username to your blacklist")
- public CommandResult blacklistUser(User user_from, Jid from, URI attachment, String... arguments) {
- User blUser = userService.getUserByName(arguments[0]);
- if (blUser != null) {
- PrivacyQueriesService.PrivacyResult result = privacyQueriesService.blacklistUser(user_from, blUser);
- if (result == PrivacyQueriesService.PrivacyResult.Added) {
- return CommandResult.fromString("User added to your blacklist");
- } else {
- return CommandResult.fromString("User removed from your blacklist");
- }
- }
- return CommandResult.fromString("User not found");
- }
- @UserCommand(pattern = "^bl\\s\\*(\\S+)$", patternFlags = Pattern.CASE_INSENSITIVE,
- help = "BL *tag - add *tag to your blacklist")
- public CommandResult blacklistTag(User user_from, Jid from, URI attachment, String... arguments) {
- User blUser = userService.getUserByName(arguments[0]);
- if (blUser != null) {
- Tag tag = tagService.getTag(arguments[0], false);
- if (tag != null) {
- PrivacyQueriesService.PrivacyResult result = privacyQueriesService.blacklistTag(user_from, tag);
- if (result == PrivacyQueriesService.PrivacyResult.Added) {
- return CommandResult.fromString("Tag added to your blacklist");
- } else {
- return CommandResult.fromString("Tag removed from your blacklist");
- }
- }
- }
- return CommandResult.fromString("Tag not found");
- }
- @UserCommand(pattern = "\\*", help = "* - Show your tags")
- public CommandResult commandTags(User currentUser, Jid from, URI attachment, String... args) {
- List<TagStats> tags = tagService.getUserTagStats(currentUser.getUid());
- String msg = "Your tags: (tag - messages)\n" +
- tags.stream()
- .map(t -> String.format("\n*%s - %d", t.getTag().getName(), t.getUsageCount())).collect(Collectors.joining());
- return CommandResult.fromString(msg);
- }
- @UserCommand(pattern = "S", help = "S - Show your subscriptions")
- public CommandResult commandSubscriptions(User currentUser, Jid from, URI attachment, String... args) {
- List<User> friends = userService.getUserFriends(currentUser.getUid());
- List<String> tags = subscriptionService.getSubscribedTags(currentUser);
- String msg = friends.size() > 0 ? "You are subscribed to users:" + friends.stream().map(u -> "\n@" + u.getName())
- .collect(Collectors.joining())
- : "You are not subscribed to any user.";
- msg += tags.size() > 0 ? "\nYou are subscribed to tags:" + tags.stream().map(t -> "\n*" + t)
- .collect(Collectors.joining())
- : "\nYou are not subscribed to any tag.";
- return CommandResult.fromString(msg);
- }
- @UserCommand(pattern = "!", help = "! - Show your favorite messages")
- public CommandResult commandFavorites(User currentUser, Jid from, URI attachment, String... args) {
- List<Integer> mids = messagesService.getUserRecommendations(currentUser.getUid(), 0);
- if (mids.size() > 0) {
- return CommandResult.fromString("Favorite messages: \n" + printMessages(mids, false));
- }
- return CommandResult.fromString("No favorite messages, try to \"like\" something ;)");
- }
- @UserCommand(pattern = "^\\!\\s+#(\\d+)", help = "! #12345 - recommend message")
- public CommandResult commandRecommend(User user, Jid from, URI attachment, String... arguments) {
- int mid = NumberUtils.toInt(arguments[0], 0);
- if (mid > 0) {
- com.juick.Message msg = messagesService.getMessage(mid);
- if (msg != null) {
- if (msg.getUser() == user) {
- return CommandResult.fromString("You can't recommend your own messages.");
- }
- MessagesService.RecommendStatus status = messagesService.recommendMessage(mid, user.getUid());
- switch (status) {
- case Added:
- applicationEventPublisher.publishEvent(new LikeEvent(this, user, msg));
- return CommandResult.fromString("Message is added to your recommendations");
- case Deleted:
- return CommandResult.fromString("Message deleted from your recommendations.");
- }
- }
- return CommandResult.fromString("Message not found");
- }
- return CommandResult.fromString("Message not found");
- }
- // TODO: target notification
- @UserCommand(pattern = "^(s|u)\\s+\\@(\\S+)$", help = "S @username - subscribe to user" +
- "\nU @username - unsubscribe from user", patternFlags = Pattern.CASE_INSENSITIVE)
- public CommandResult commandSubscribeUser(User user, Jid from, URI attachment, String... args) {
- boolean subscribe = args[0].equalsIgnoreCase("s");
- User toUser = userService.getUserByName(args[1]);
- if (subscribe) {
- if (subscriptionService.subscribeUser(user, toUser)) {
- // TODO: already subscribed case
- applicationEventPublisher.publishEvent(new SubscribeEvent(this, user, toUser));
- return CommandResult.fromString("Subscribed to @" + toUser.getName());
- }
- } else {
- if (subscriptionService.unSubscribeUser(user, toUser)) {
- return CommandResult.fromString("Unsubscribed from @" + toUser.getName());
- }
- return CommandResult.fromString("You was not subscribed to @" + toUser.getName());
- }
- return CommandResult.fromString("Error");
- }
- @UserCommand(pattern = "^(s|u)\\s+\\*(\\S+)$", help = "S *tag - subscribe to tag" +
- "\nU *tag - unsubscribe from tag", patternFlags = Pattern.CASE_INSENSITIVE)
- public CommandResult commandSubscribeTag(User user, Jid from, URI attachment, String... args) {
- boolean subscribe = args[0].equalsIgnoreCase("s");
- Tag tag = tagService.getTag(args[1], true);
- if (subscribe) {
- if (subscriptionService.subscribeTag(user, tag)) {
- return CommandResult.fromString("Subscribed");
- }
- } else {
- if (subscriptionService.unSubscribeTag(user, tag)) {
- return CommandResult.fromString("Unsubscribed from " + tag.getName());
- }
- return CommandResult.fromString("You was not subscribed to " + tag.getName());
- }
- return CommandResult.fromString("Error");
- }
- @UserCommand(pattern = "^(s|u)\\s+#(\\d+)$", help = "S #1234 - subscribe to comments" +
- "\nU #1234 - unsubscribe from comments", patternFlags = Pattern.CASE_INSENSITIVE)
- public CommandResult commandSubscribeMessage(User user, Jid from, URI attachment, String... args) {
- boolean subscribe = args[0].equalsIgnoreCase("s");
- int mid = NumberUtils.toInt(args[1], 0);
- if (messagesService.getMessage(mid) != null) {
- if (subscribe) {
- if (subscriptionService.subscribeMessage(mid, user.getUid())) {
- return CommandResult.fromString("Subscribed");
- }
- } else {
- if (subscriptionService.unSubscribeMessage(mid, user.getUid())) {
- return CommandResult.fromString("Unsubscribed from #" + mid);
- }
- return CommandResult.fromString("You was not subscribed to #" + mid);
- }
- }
- return CommandResult.fromString("Error");
- }
- @UserCommand(pattern = "^(on|off)$", patternFlags = Pattern.CASE_INSENSITIVE,
- help = "ON/OFF - Enable/disable subscriptions delivery")
- public CommandResult commandOnOff(User user, Jid from, URI attachment, String[] input) {
- UserService.ActiveStatus newStatus;
- String retValUpdated;
- if (input[0].toLowerCase().equals("on")) {
- newStatus = UserService.ActiveStatus.Active;
- retValUpdated = "Notifications are activated for " + from.asBareJid().toEscapedString();
- } else {
- newStatus = UserService.ActiveStatus.Inactive;
- retValUpdated = "Notifications are disabled for " + from.asBareJid().toEscapedString();
- }
-
- if (userService.setActiveStatusForJID(from.asBareJid().toEscapedString(), newStatus)) {
- return CommandResult.fromString(retValUpdated);
- } else {
- return CommandResult.fromString(String.format("Subscriptions status for %s was not changed", from.toEscapedString()));
- }
- }
- @UserCommand(pattern = "^\\@([^\\s\\n\\+]+)(\\+?)$",
- help = "@username+ - Show user's info and last 20 messages")
- public CommandResult commandUser(User user, Jid from, URI attachment, String... arguments) {
- User blogUser = userService.getUserByName(arguments[0]);
- int page = arguments[1].length();
- if (blogUser.getUid() > 0) {
- List<Integer> mids = messagesService.getUserBlog(blogUser.getUid(), 0, 0);
- return CommandResult.fromString(String.format("Last messages from @%s:\n%s", arguments[0],
- printMessages(mids, false)));
- }
- return CommandResult.fromString("User not found");
- }
- @UserCommand(pattern = "^#(\\d+)(\\+?)$", help = "#1234 - Show message (#1234+ - message with replies)")
- public CommandResult commandShow(User user, Jid from, URI attachment, String... arguments) {
- boolean showReplies = arguments[1].length() > 0;
- int mid = NumberUtils.toInt(arguments[0], 0);
- if (mid == 0) {
- return CommandResult.fromString("Error");
- }
- com.juick.Message msg = messagesService.getMessage(mid);
- if (msg != null) {
- if (showReplies) {
- List<com.juick.Message> replies = messagesService.getReplies(mid);
- replies.add(0, msg);
- return CommandResult.fromString(String.join("\n",
- replies.stream().map(PlainTextFormatter::formatPostSummary).collect(Collectors.toList())));
- }
- return CommandResult.fromString(PlainTextFormatter.formatPost(msg));
- }
- return CommandResult.fromString("Message not found");
- }
- @UserCommand(pattern = "^#(\\d+)\\/(\\d+)$", help = "#1234/5 - Show reply")
- public CommandResult commandShowReply(User user, Jid from, URI attachment, String... arguments) {
- int mid = NumberUtils.toInt(arguments[0], 0);
- int rid = NumberUtils.toInt(arguments[1], 0);
- com.juick.Message reply = messagesService.getReply(mid, rid);
- if (reply != null) {
- return CommandResult.fromString(PlainTextFormatter.formatPost(reply));
- }
- return CommandResult.fromString("Reply not found");
- }
- @UserCommand(pattern = "^\\*(\\S+)(\\+?)$", help = "*tag - Show last messages with tag")
- public CommandResult commandShowTag(User user, Jid from, URI attachment, String... arguments) {
- Tag tag = tagService.getTag(arguments[0], false);
- if (tag != null) {
- // TODO: synonims
- List<Integer> mids = messagesService.getTag(tag.TID, user.getUid(), 0, 10);
- return CommandResult.fromString("Last messages with *" + tag.getName() + ":\n" + printMessages(mids, true));
- }
- return CommandResult.fromString("Tag not found");
- }
- @UserCommand(pattern = "^D #(\\d+)$", help = "D #1234 - Delete post", patternFlags = Pattern.CASE_INSENSITIVE)
- public CommandResult commandDeletePost(User user, Jid from, URI attachment, String... args) {
- int mid = Integer.valueOf(args[0]);
- if (messagesService.deleteMessage(user.getUid(), mid)) {
- return CommandResult.fromString("Message deleted");
- }
- return CommandResult.fromString("This is not your message");
- }
- @UserCommand(pattern = "^D #(\\d+)(\\.|\\-|\\/)(\\d+)$", help = "D #1234/5 - Delete comment", patternFlags = Pattern.CASE_INSENSITIVE)
- public CommandResult commandDeleteReply(User user, Jid from, URI attachment, String... args) {
- int mid = Integer.valueOf(args[0]);
- int rid = Integer.valueOf(args[2]);
- if (messagesService.deleteReply(user.getUid(), mid, rid)) {
- return CommandResult.fromString("Reply deleted");
- } else {
- return CommandResult.fromString("This is not your reply");
- }
- }
- @UserCommand(pattern = "^(D L|DL|D LAST)$", help = "D L - Delete last message", patternFlags = Pattern.CASE_INSENSITIVE)
- public CommandResult commandDeleteLast(User user, Jid from, URI attachment, String... args) {
- return CommandResult.fromString("Temporarily unavailable");
- }
- @UserCommand(pattern = "^\\?\\s+\\@([a-zA-Z0-9\\-\\.\\@]+)\\s+([\\s\\S]+)$", help = "? @user string - search in user messages")
- public CommandResult commandSearch(User user, Jid from, URI attachment, String... args) {
- return CommandResult.fromString("Temporarily unavailable");
- }
- @UserCommand(pattern = "^\\?\\s+([\\s\\S]+)$", help = "? string - search in all messages")
- public CommandResult commandSearchAll(User user, Jid from, URI attachment, String... args) {
- return CommandResult.fromString("Temporarily unavailable");
- }
- @UserCommand(pattern = "^(#+)$", help = "# - Show last messages from your feed (## - second page, ...)")
- public CommandResult commandMyFeed(User user, Jid from, URI attachment, String... arguments) {
- // number of # is the page count
- int page = arguments[0].length() - 1;
- List<Integer> mids = messagesService.getMyFeed(user.getUid(), page, false);
- if (mids.size() > 0) {
- return CommandResult.fromString("Your feed: \n" + printMessages(mids, true));
- }
- return CommandResult.fromString("Your feed is empty");
- }
- @UserCommand(pattern = "^(#|\\.)(\\d+)((\\.|\\-|\\/)(\\d+))?\\s([\\s\\S]+)",
- help = "#1234 *tag *tag2 - edit tags\n#1234 text - reply to message")
- public CommandResult EditOrReply(User user, Jid from, URI attachment, String... args) throws Exception {
- int mid = NumberUtils.toInt(args[1]);
- int rid = NumberUtils.toInt(args[4], 0);
- String txt = args[5];
- List<Tag> messageTags = tagService.fromString(txt, true);
- if (messageTags.size() > 0) {
- if (user.getUid() != messagesService.getMessageAuthor(mid).getUid()) {
- return CommandResult.fromString("It is not your message");
- }
- tagService.updateTags(mid, messageTags);
- return CommandResult.fromString("Tags are updated");
- } else {
- String attachmentType = attachment != null && StringUtils.isNotEmpty(attachment.toString()) ? attachment.toString().substring(attachment.toString().length() - 3) : null;
- int newrid = messagesService.createReply(mid, rid, user.getUid(), txt, attachmentType);
- if (StringUtils.isNotEmpty(attachmentType)) {
- String attachmentFName = attachment.getScheme().equals("juick") ? attachment.getHost()
- : HttpUtils.downloadImage(attachment.toURL(), tmpDir);
- String fname = String.format("%d-%d.%s", mid, newrid, attachmentType);
- ImageUtils.saveImageWithPreviews(attachmentFName, fname, tmpDir, imgDir);
- }
- Message reply = messagesService.getReply(mid, newrid);
- applicationEventPublisher.publishEvent(new MessageEvent(this, reply));
- return CommandResult.fromMessage(reply,"Reply posted.\n#" + mid + "/" + newrid + " "
- + "https://juick.com/" + mid + "#" + newrid);
- }
- }
-
- String printMessages(List<Integer> mids, boolean crop) {
- return messagesService.getMessages(mids).stream()
- .sorted(Collections.reverseOrder())
- .map(PlainTextFormatter::formatPostSummary).collect(Collectors.joining("\n\n"));
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/MessengerManager.java b/juick-server/src/main/java/com/juick/server/MessengerManager.java
index adef1e22..ca206bd4 100644
--- a/juick-server/src/main/java/com/juick/server/MessengerManager.java
+++ b/juick-server/src/main/java/com/juick/server/MessengerManager.java
@@ -50,7 +50,7 @@ public class MessengerManager implements ApplicationListener<MessageEvent> {
@Inject
private MessengerService messengerService;
@Inject
- private ServerManager serverManager;
+ private XMPPConnection xmppConnection;
@Value("${fb_page_access_token:12345678}")
private String facebookPageAccessToken;
@@ -97,7 +97,7 @@ public class MessengerManager implements ApplicationListener<MessageEvent> {
logger.info("Received text message from '{}' at '{}' with content: {} (mid: {})",
senderId, timestamp, text, messageId);
try {
- serverManager.processMessage(user_from, text, null);
+ xmppConnection.processMessage(user_from, text, null);
} catch (Exception e) {
logger.warn("messenger error", e);
}
diff --git a/juick-server/src/main/java/com/juick/server/NotificationListener.java b/juick-server/src/main/java/com/juick/server/NotificationListener.java
deleted file mode 100644
index f6330570..00000000
--- a/juick-server/src/main/java/com/juick/server/NotificationListener.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.juick.server;
-
-import com.juick.server.component.LikeEvent;
-import com.juick.server.component.MessageEvent;
-import com.juick.server.component.PingEvent;
-import com.juick.server.component.SubscribeEvent;
-import org.springframework.context.event.EventListener;
-
-public interface NotificationListener {
- @EventListener
- void processMessageEvent(MessageEvent messageEvent);
- @EventListener
- void processSubscribeEvent(SubscribeEvent subscribeEvent);
- @EventListener
- void processLikeEvent(LikeEvent likeEvent);
- @EventListener
- void ProcessPingEvent(PingEvent pingEvent);
-}
diff --git a/juick-server/src/main/java/com/juick/server/ServerManager.java b/juick-server/src/main/java/com/juick/server/ServerManager.java
index 6cac270c..40de9d3e 100644
--- a/juick-server/src/main/java/com/juick/server/ServerManager.java
+++ b/juick-server/src/main/java/com/juick/server/ServerManager.java
@@ -57,16 +57,6 @@ public class ServerManager implements ApplicationListener<MessageEvent> {
@Inject
private XMPPConnection router;
- public com.juick.Message processMessage(User visitor, String body, String attachmentName) throws Exception {
- if (StringUtils.isNotEmpty(attachmentName)) {
- URI httpUri = URI.create(attachmentName);
- if (!httpUri.isAbsolute()) {
- attachmentName = String.format("juick://%s", attachmentName);
- }
- }
- return router.incomingMessageJuick(visitor, Jid.of(String.valueOf(visitor.getUid()), "uid.juick.com", "perl"), body, URI.create(attachmentName));
- }
-
private void onJuickPM(final int uid_to, final com.juick.Message jmsg) {
try {
String json = jsonMapper.writeValueAsString(jmsg);
diff --git a/juick-server/src/main/java/com/juick/server/TelegramBotManager.java b/juick-server/src/main/java/com/juick/server/TelegramBotManager.java
index c1ccc8ff..020d2433 100644
--- a/juick-server/src/main/java/com/juick/server/TelegramBotManager.java
+++ b/juick-server/src/main/java/com/juick/server/TelegramBotManager.java
@@ -79,7 +79,7 @@ public class TelegramBotManager implements NotificationListener {
@Inject
private UserService userService;
@Inject
- private ServerManager serverManager;
+ private XMPPConnection xmppConnection;
@Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
private String tmpDir;
@@ -183,7 +183,7 @@ public class TelegramBotManager implements NotificationListener {
int rid = Integer.valueOf(uriComponents.getFragment());
prefix = String.format("#%d/%d ", mid, rid);
}
- serverManager.processMessage(user_from, prefix + text, attachment);
+ xmppConnection.processMessage(user_from, prefix + text, attachment);
telegramNotify(message.from().id().longValue(), "Reply sent", StringUtils.EMPTY);
} else {
logger.warn("invalid path: {}", path);
@@ -200,7 +200,7 @@ public class TelegramBotManager implements NotificationListener {
"Can not reply to this message", replyMessage.messageId(), StringUtils.EMPTY);
}
} else {
- serverManager.processMessage(user_from, text, attachment);
+ xmppConnection.processMessage(user_from, text, attachment);
telegramNotify(message.from().id().longValue(), "Message sent", StringUtils.EMPTY);
}
}
diff --git a/juick-server/src/main/java/com/juick/server/WebsocketManager.java b/juick-server/src/main/java/com/juick/server/WebsocketManager.java
index 309f605c..498bf064 100644
--- a/juick-server/src/main/java/com/juick/server/WebsocketManager.java
+++ b/juick-server/src/main/java/com/juick/server/WebsocketManager.java
@@ -70,7 +70,7 @@ public class WebsocketManager extends TextWebSocketHandler {
@Inject
private ObjectMapper jsonMapper;
@Inject
- private ServerManager serverManager;
+ private XMPPConnection xmppConnection;
@Override
@@ -151,7 +151,7 @@ public class WebsocketManager extends TextWebSocketHandler {
Message draft = jsonMapper.readValue(message.asBytes(), Message.class);
if (draft.getUser() != null && (draft.getText() != null || draft.getAttachment() != null)) {
String attachmentFileName = draft.getAttachment() == null ? "" : draft.getAttachment().getUrl();
- serverManager.processMessage(draft.getUser(), draft.getText(), attachmentFileName);
+ xmppConnection.processMessage(draft.getUser(), draft.getText(), attachmentFileName);
}
} catch (Exception e) {
throw new HttpBadRequestException();
diff --git a/juick-server/src/main/java/com/juick/server/XMPPConnection.java b/juick-server/src/main/java/com/juick/server/XMPPConnection.java
deleted file mode 100644
index 4be4a5ba..00000000
--- a/juick-server/src/main/java/com/juick/server/XMPPConnection.java
+++ /dev/null
@@ -1,743 +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 <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server;
-
-import com.juick.Tag;
-import com.juick.User;
-import com.juick.server.component.LikeEvent;
-import com.juick.server.component.MessageEvent;
-import com.juick.server.component.PingEvent;
-import com.juick.server.component.SubscribeEvent;
-import com.juick.server.helpers.UserInfo;
-import com.juick.server.util.HttpUtils;
-import com.juick.server.util.ImageUtils;
-import com.juick.server.util.TagUtils;
-import com.juick.server.xmpp.helpers.CommandResult;
-import com.juick.server.xmpp.s2s.BasicXmppSession;
-import com.juick.server.xmpp.s2s.StanzaListener;
-import com.juick.service.*;
-import com.juick.util.MessageUtils;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.io.IOUtils;
-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.context.ApplicationEventPublisher;
-import org.springframework.context.annotation.DependsOn;
-import org.springframework.stereotype.Component;
-import rocks.xmpp.addr.Jid;
-import rocks.xmpp.core.XmppException;
-import rocks.xmpp.core.stanza.AbstractIQHandler;
-import rocks.xmpp.core.stanza.model.*;
-import rocks.xmpp.core.stanza.model.client.ClientMessage;
-import rocks.xmpp.core.stanza.model.client.ClientPresence;
-import rocks.xmpp.core.stanza.model.errors.Condition;
-import rocks.xmpp.extensions.caps.model.EntityCapabilities;
-import rocks.xmpp.extensions.component.accept.ExternalComponent;
-import rocks.xmpp.extensions.filetransfer.FileTransfer;
-import rocks.xmpp.extensions.filetransfer.FileTransferManager;
-import rocks.xmpp.extensions.nick.model.Nickname;
-import rocks.xmpp.extensions.oob.model.x.OobX;
-import rocks.xmpp.extensions.ping.PingManager;
-import rocks.xmpp.extensions.vcard.temp.model.VCard;
-import rocks.xmpp.extensions.version.SoftwareVersionManager;
-import rocks.xmpp.extensions.version.model.SoftwareVersion;
-import rocks.xmpp.util.XmppUtils;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.inject.Inject;
-import javax.xml.bind.JAXBException;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-
-/**
- * @author ugnich
- */
-@Component
-@DependsOn("XMPPRouter")
-public class XMPPConnection implements StanzaListener, NotificationListener {
-
- private static final Logger logger = LoggerFactory.getLogger(XMPPConnection.class);
-
- private ExternalComponent router;
- @Inject
- private XMPPServer xmpp;
- @Inject
- private CommandsManager commandsManager;
- @Value("${xmppbot_jid:juick@localhost}")
- private Jid jid;
- @Value("${componentname:localhost}")
- private String componentName;
- @Value("${component_port:5347}")
- private int componentPort;
- @Value("${xmpp_password:secret}")
- private String password;
- @Value("${xmpp_disabled:false}")
- private boolean isXmppDisabled;
- @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
- private String tmpDir;
- @Value("${img_path:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
- private String imgDir;
-
- @Inject
- private MessagesService messagesService;
- @Inject
- private UserService userService;
- @Inject
- private SubscriptionService subscriptionService;
- @Inject
- private PMQueriesService pmQueriesService;
- @Inject
- private TagService tagService;
- @Inject
- private BasicXmppSession session;
- @Inject
- private ExecutorService service;
- @Inject
- private ServerManager serverManager;
- @Inject
- private ApplicationEventPublisher applicationEventPublisher;
-
- @PostConstruct
- public void init() {
- logger.info("stream router start connecting to {}", componentPort);
- xmpp.addStanzaListener(this);
- router = ExternalComponent.create(componentName, password, session.getConfiguration(), "localhost",
- componentPort);
- PingManager pingManager = router.getManager(PingManager.class);
- pingManager.setEnabled(true);
- router.disableFeature(EntityCapabilities.NAMESPACE);
- SoftwareVersionManager softwareVersionManager = router.getManager(SoftwareVersionManager.class);
- softwareVersionManager.setSoftwareVersion(new SoftwareVersion("Juick", "2.x",
- System.getProperty("os.name", "generic")));
- VCard vCard = new VCard();
- vCard.setFormattedName("Juick");
- try {
- vCard.setUrl(new URL("http://juick.com/"));
- vCard.setPhoto(new VCard.Image("image/png", IOUtils.toByteArray(
- getClass().getClassLoader().getResource("juick.png"))));
- } catch (MalformedURLException e) {
- logger.error("invalid url", e);
- } catch (IOException e) {
- logger.warn("invalid resource", e);
- }
- router.addIQHandler(VCard.class, new AbstractIQHandler(IQ.Type.GET) {
- @Override
- protected IQ processRequest(IQ iq) {
- if (iq.getTo().equals(jid) || iq.getTo().asBareJid().equals(jid.asBareJid())
- || iq.getTo().asBareJid().toEscapedString().equals(jid.getDomain())) {
- return iq.createResult(vCard);
- }
- User user = userService.getUserByName(iq.getTo().getLocal());
- if (user.getUid() > 0) {
- UserInfo info = userService.getUserInfo(user);
- VCard userVCard = new VCard();
- userVCard.setFormattedName(info.getFullName());
- userVCard.setNickname(user.getName());
- try {
- userVCard.setPhoto(new VCard.Image(new URI("http://i.juick.com/a/" + user.getUid() + ".png")));
- if (info.getUrl() != null) {
- userVCard.setUrl(new URL(info.getUrl()));
- }
- } catch (MalformedURLException | URISyntaxException e) {
- logger.warn("url exception", e);
- }
- return iq.createResult(userVCard);
- }
- return iq.createError(Condition.BAD_REQUEST);
- }
- });
- router.addInboundMessageListener(e -> {
- Message message = e.getMessage();
- Jid jid = message.getTo();
- if (jid.getDomain().equals(router.getDomain().toEscapedString()) || jid.equals(jid)) {
- com.juick.Message jmsg = message.getExtension(com.juick.Message.class);
- if (jmsg != null) {
- if (jid.getLocal().equals("recomm")) {
- User fromUser = jmsg.getUser();
- com.juick.Message msg = messagesService.getMessage(jmsg.getMid());
- applicationEventPublisher.publishEvent(new LikeEvent(this, fromUser, msg));
- } else if (jid.getLocal().equals("pm")) {
- applicationEventPublisher.publishEvent(new MessageEvent(this, jmsg));
- } else {
- if (jmsg.getRid() > 0) {
- // to get quote and attachment
- com.juick.Message reply = messagesService.getReply(jmsg.getMid(), jmsg.getRid());
- sendJuickComment(reply);
- applicationEventPublisher.publishEvent(new MessageEvent(this, reply));
- } else if (jmsg.getMid() > 0) {
- sendJuickMessage(jmsg);
- applicationEventPublisher.publishEvent(new MessageEvent(this,
- messagesService.getMessage(jmsg.getMid())));
- }
- }
- } else {
- String attachment = StringUtils.EMPTY;
- OobX oobX = message.getExtension(OobX.class);
- if (oobX != null) {
- attachment = oobX.getUri().toString();
- }
- try {
- serverManager.processMessage(userService.getUserByUID(NumberUtils.toInt(message.getFrom().getLocal(), 0)).orElse(new User()), message.getBody(), attachment);
- } catch (Exception e1) {
- logger.warn("message exception", e1);
- }
- }
- } else if (jid.getDomain().endsWith(jid.getDomain()) && (jid.getDomain().equals(this.jid.getDomain())
- || jid.getDomain().endsWith("." + jid.getDomain()))) {
- if (logger.isInfoEnabled()) {
- try {
- logger.info("unhandled message: {}", stanzaToString(message));
- } catch (JAXBException | XMLStreamException ex) {
- logger.error("JAXB exception", ex);
- }
- }
- } else {
- s2s(ClientMessage.from(message));
- }
- });
- router.addInboundIQListener(e -> {
- IQ iq = e.getIQ();
- Jid jid = iq.getTo();
- if (!jid.getDomain().equals(this.jid.getDomain())) {
- s2s(iq);
- }
- });
- FileTransferManager fileTransferManager = router.getManager(FileTransferManager.class);
- fileTransferManager.addFileTransferOfferListener(e -> {
- try {
- List<String> allowedTypes = new ArrayList<String>() {{
- add("png");
- add("jpg");
- }};
- String attachmentExtension = FilenameUtils.getExtension(e.getName()).toLowerCase();
- String targetFilename = String.format("%s.%s",
- DigestUtils.md5Hex(String.format("%s-%s",
- e.getInitiator().toString(), e.getSessionId()).getBytes()), attachmentExtension);
- if (allowedTypes.contains(attachmentExtension)) {
- Path filePath = Paths.get(tmpDir, targetFilename);
- FileTransfer ft = e.accept(filePath).get();
- ft.addFileTransferStatusListener(st -> {
- logger.debug("{}: received {} of {}", e.getName(), st.getBytesTransferred(), e.getSize());
- if (st.getStatus().equals(FileTransfer.Status.COMPLETED)) {
- logger.info("transfer completed");
- try {
- serverManager.processMessage(userService.getUserByJID(e.getInitiator().toEscapedString()), e.getDescription(), targetFilename);
- } catch (Exception e1) {
- logger.error("ft error", e1);
- }
-
- } else if (st.getStatus().equals(FileTransfer.Status.FAILED)) {
- logger.info("transfer failed", ft.getException());
- Message msg = new Message();
- msg.setType(Message.Type.CHAT);
- msg.setFrom(jid);
- msg.setTo(e.getInitiator());
- msg.setBody("File transfer failed, please report to us");
- router.sendMessage(msg);
- } else if (st.getStatus().equals(FileTransfer.Status.CANCELED)) {
- logger.info("transfer cancelled");
- }
- });
- ft.transfer();
- logger.info("transfer started");
- } else {
- e.reject();
- logger.info("transfer rejected");
- }
- } catch (IOException | InterruptedException | ExecutionException e1) {
- logger.error("ft error", e1);
- }
- });
- router.addConnectionListener(event -> {
- if (event.getType().equals(rocks.xmpp.core.session.ConnectionEvent.Type.RECONNECTION_SUCCEEDED)) {
- logger.info("component connected");
- }
- });
- if (!isXmppDisabled) {
- service.submit(() -> {
- try {
- Thread.sleep(3000);
- router.connect();
- broadcastPresence(null);
- } catch (InterruptedException | XmppException e) {
- logger.warn("xmpp exception", e);
- }
- });
- }
- }
-
- private String stanzaToString(Stanza stanza) throws XMLStreamException, JAXBException {
- StringWriter stanzaWriter = new StringWriter();
- XMLStreamWriter xmppStreamWriter = XmppUtils.createXmppStreamWriter(
- router.getConfiguration().getXmlOutputFactory().createXMLStreamWriter(stanzaWriter));
- router.createMarshaller().marshal(stanza, xmppStreamWriter);
- xmppStreamWriter.flush();
- xmppStreamWriter.close();
- return stanzaWriter.toString();
- }
-
- private void s2s(Stanza stanza) {
- try {
- String xml = stanzaToString(stanza);
- logger.info("stream router (out): {}", xml);
- xmpp.sendOut(stanza);
- } catch (XMLStreamException | JAXBException e) {
- logger.error("JAXB exception", e);
- }
-
- }
-
-
-
- private void sendJuickMessage(com.juick.Message jmsg) {
- List<String> jids = new ArrayList<>();
-
- if (jmsg.FriendsOnly) {
- jids = subscriptionService.getJIDSubscribedToUser(jmsg.getUser().getUid(), jmsg.FriendsOnly);
- } else {
- List<User> users = subscriptionService.getSubscribedUsers(jmsg.getUser().getUid(), jmsg.getMid());
- for (User user : users) {
- jids.addAll(userService.getJIDsbyUID(user.getUid()));
- }
- }
- com.juick.Message fullMsg = messagesService.getMessage(jmsg.getMid());
- String txt = "@" + jmsg.getUser().getName() + ":" + MessageUtils.getTagsString(fullMsg) + "\n";
- String attachmentUrl = MessageUtils.attachmentUrl(fullMsg);
- if (StringUtils.isNotEmpty(attachmentUrl)) {
- txt += attachmentUrl + "\n";
- }
- txt += StringUtils.defaultString(jmsg.getText()) + "\n\n";
- txt += "#" + jmsg.getMid() + " http://juick.com/" + jmsg.getMid();
-
- Nickname nick = new Nickname("@" + jmsg.getUser().getName());
-
- Message msg = new Message();
- msg.setFrom(jid);
- msg.setBody(txt);
- msg.setType(Message.Type.CHAT);
- msg.setThread("juick-" + jmsg.getMid());
- msg.addExtension(jmsg);
- msg.addExtension(nick);
- if (StringUtils.isNotEmpty(attachmentUrl)) {
- try {
- OobX oob = new OobX(new URI(attachmentUrl));
- msg.addExtension(oob);
- } catch (URISyntaxException e) {
- logger.warn("uri exception", e);
- }
- }
- for (String jid : jids) {
- msg.setTo(Jid.of(jid));
- s2s(ClientMessage.from(msg));
- }
- }
-
- public void sendJuickComment(com.juick.Message jmsg) {
- List<User> users;
- String replyQuote;
- String replyTo;
-
- com.juick.Message op = messagesService.getMessage(jmsg.getMid());
- users = subscriptionService.getUsersSubscribedToComments(op, jmsg);
- com.juick.Message replyMessage = jmsg.getReplyto() > 0 ? messagesService.getReply(jmsg.getMid(), jmsg.getReplyto())
- : messagesService.getMessage(jmsg.getMid());
- replyTo = replyMessage.getUser().getName();
- com.juick.Message fullReply = messagesService.getReply(jmsg.getMid(), jmsg.getRid());
- replyQuote = fullReply.getReplyQuote();
-
- String txt = "Reply by @" + jmsg.getUser().getName() + ":\n" + replyQuote + "\n@" + replyTo + " ";
- String attachmentUrl = MessageUtils.attachmentUrl(fullReply);
- if (StringUtils.isNotEmpty(attachmentUrl)) {
- txt += attachmentUrl + "\n";
- }
- txt += StringUtils.defaultString(jmsg.getText()) + "\n\n" + "#" + jmsg.getMid() + "/" + jmsg.getRid() + " http://juick.com/" + jmsg.getMid() + "#" + jmsg.getRid();
-
- Message msg = new Message();
- msg.setFrom(jid);
- msg.setBody(txt);
- msg.setType(Message.Type.CHAT);
- msg.addExtension(jmsg);
- for (User user : users) {
- for (String jid : userService.getJIDsbyUID(user.getUid())) {
- msg.setTo(Jid.of(jid));
- s2s(ClientMessage.from(msg));
- }
- }
- }
-
- @Override
- public void processMessageEvent(MessageEvent event) {
- com.juick.Message msg = event.getMessage();
- boolean isPM = msg.getMid() == 0;
- boolean isReply = msg.getRid() > 0;
- if (isPM) {
- userService.getJIDsbyUID(msg.getTo().getUid())
- .forEach(userJid -> {
- Message mm = new Message();
- mm.setTo(Jid.of(userJid));
- mm.setType(Message.Type.CHAT);
- boolean inroster = pmQueriesService.havePMinRoster(msg.getUser().getUid(), userJid);
- if (inroster) {
- mm.setFrom(Jid.of(msg.getUser().getName(), "juick.com", "Juick"));
- mm.setBody(msg.getText());
- } else {
- mm.setFrom(jid);
- mm.setBody("Private message from @" + msg.getUser().getName() + ":\n" + msg.getText());
- }
- s2s(ClientMessage.from(mm));
- });
- } else if (!isReply) {
- String notify = "New message posted.\n#" + msg.getMid() + " https://juick.com/" + msg.getMid();
- userService.getJIDsbyUID(msg.getUser().getUid())
- .forEach(jid -> sendReply(Jid.of(jid), notify));
- }
- }
-
- private void sendReply(Jid jidTo, String txt) {
- Message reply = new Message();
- reply.setFrom(jid);
- reply.setTo(jidTo);
- reply.setType(Message.Type.CHAT);
- reply.setBody(txt);
- s2s(ClientMessage.from(reply));
- }
-
- @Override
- public void processSubscribeEvent(SubscribeEvent subscribeEvent) {
-
- }
-
- @Override
- public void processLikeEvent(LikeEvent likeEvent) {
- List<User> users;
- com.juick.Message jmsg = likeEvent.getMessage();
- User liker = likeEvent.getUser();
- users = subscriptionService.getUsersSubscribedToUserRecommendations(liker.getUid(),
- jmsg.getMid(), jmsg.getUser().getUid());
-
- String txt = "Recommended by @" + liker.getName() + ":\n";
- txt += "@" + jmsg.getUser().getName() + ":" + MessageUtils.getTagsString(jmsg) + "\n";
- String attachmentUrl = MessageUtils.attachmentUrl(jmsg);
- if (StringUtils.isNotEmpty(attachmentUrl)) {
- txt += attachmentUrl + "\n";
- }
- txt += StringUtils.defaultString(jmsg.getText()) + "\n\n";
- txt += "#" + jmsg.getMid();
- if (jmsg.getReplies() > 0) {
- if (jmsg.getReplies() % 10 == 1 && jmsg.getReplies() % 100 != 11) {
- txt += " (" + jmsg.getReplies() + " reply)";
- } else {
- txt += " (" + jmsg.getReplies() + " replies)";
- }
- }
- txt += " http://juick.com/" + jmsg.getMid();
-
- Nickname nick = new Nickname("@" + jmsg.getUser().getName());
-
- Message msg = new Message();
- msg.setFrom(jid);
- msg.setBody(txt);
- msg.setType(Message.Type.CHAT);
- msg.setThread("juick-" + jmsg.getMid());
- msg.addExtension(jmsg);
- msg.addExtension(nick);
- if (StringUtils.isNotEmpty(attachmentUrl)) {
- try {
- OobX oob = new OobX(new URI(attachmentUrl));
- msg.addExtension(oob);
- } catch (URISyntaxException e) {
- logger.warn("uri exception", e);
- }
- }
-
- for (User user : users) {
- for (String jid : userService.getJIDsbyUID(user.getUid())) {
- msg.setTo(Jid.of(jid));
- s2s(ClientMessage.from(msg));
- }
- }
- }
-
- @Override
- public void ProcessPingEvent(PingEvent pingEvent) {
- userService.getJIDsbyUID(pingEvent.getPinger().getUid())
- .forEach(userJid -> {
- Presence p = new Presence(Jid.of(userJid));
- p.setFrom(jid);
- p.setPriority((byte) 10);
- s2s(ClientPresence.from(p));
- });
- }
-
- private void incomingPresence(Presence p) {
- final String username = p.getTo().getLocal();
- final boolean toJuick = username.equals(jid.getLocal());
-
- if (p.getType() == null) {
- Presence reply = new Presence();
- reply.setFrom(p.getTo().asBareJid());
- reply.setTo(p.getFrom().asBareJid());
- reply.setType(Presence.Type.UNSUBSCRIBE);
- s2s(ClientPresence.from(reply));
- } else if (p.getType().equals(Presence.Type.PROBE)) {
- int uid_to = 0;
- if (!toJuick) {
- uid_to = userService.getUIDbyName(username);
- }
-
- if (toJuick || uid_to > 0) {
- Presence reply = new Presence();
- reply.setFrom(p.getTo().withResource(jid.getResource()));
- reply.setTo(p.getFrom());
- reply.setPriority((byte)10);
- if (!userService.getActiveJIDs().contains(p.getFrom().asBareJid().toEscapedString())) {
- reply.setStatus("Send ON to enable notifications");
- }
- s2s(ClientPresence.from(reply));
- } else {
- Presence reply = new Presence();
- reply.setFrom(p.getTo());
- reply.setTo(p.getFrom());
- reply.setType(Presence.Type.ERROR);
- reply.setId(p.getId());
- reply.setError(new StanzaError(StanzaError.Type.CANCEL, Condition.ITEM_NOT_FOUND));
- s2s(ClientPresence.from(reply));
- }
- } else if (p.getType().equals(Presence.Type.SUBSCRIBE)) {
- boolean canSubscribe = false;
- if (toJuick) {
- canSubscribe = true;
- } else {
- int uid_to = userService.getUIDbyName(username);
- if (uid_to > 0) {
- pmQueriesService.addPMinRoster(uid_to, p.getFrom().asBareJid().toEscapedString());
- canSubscribe = true;
- }
- }
- if (canSubscribe) {
- Presence reply = new Presence();
- reply.setFrom(p.getTo());
- reply.setTo(p.getFrom());
- reply.setType(Presence.Type.SUBSCRIBED);
- s2s(ClientPresence.from(reply));
-
- reply.setFrom(reply.getFrom().withResource(jid.getResource()));
- reply.setPriority((byte) 10);
- reply.setType(null);
- s2s(ClientPresence.from(reply));
- } else {
- Presence reply = new Presence();
- reply.setFrom(p.getTo());
- reply.setTo(p.getFrom());
- reply.setType(Presence.Type.ERROR);
- reply.setId(p.getId());
- reply.setError(new StanzaError(StanzaError.Type.CANCEL, Condition.ITEM_NOT_FOUND));
- s2s(ClientPresence.from(reply));
- }
- } else if (p.getType().equals(Presence.Type.UNSUBSCRIBE)) {
- if (!toJuick) {
- int uid_to = userService.getUIDbyName(username);
- if (uid_to > 0) {
- pmQueriesService.removePMinRoster(uid_to, p.getFrom().asBareJid().toEscapedString());
- }
- }
-
- Presence reply = new Presence();
- reply.setFrom(p.getTo());
- reply.setTo(p.getFrom());
- reply.setType(Presence.Type.UNSUBSCRIBED);
- s2s(ClientPresence.from(reply));
- }
- }
-
- public void incomingMessage(Message msg) {
- if (msg.getType() != null && msg.getType().equals(Message.Type.ERROR)) {
- StanzaError error = msg.getError();
- if (error != null && error.getCondition().equals(Condition.RESOURCE_CONSTRAINT)) {
- // offline query is full, deactivating this jid
- if (userService.setActiveStatusForJID(msg.getFrom().toEscapedString(), UserService.ActiveStatus.Inactive)) {
- logger.info("{} is inactive now", msg.getFrom());
- return;
- }
- }
- return;
- }
- if (StringUtils.isBlank(msg.getBody())) {
- return;
- }
- String username = msg.getTo().getLocal();
-
- User user_from;
- String signuphash = StringUtils.EMPTY;
- user_from = userService.getUserByJID(msg.getFrom().asBareJid().toEscapedString());
- if (user_from == null) {
- signuphash = userService.getSignUpHashByJID(msg.getFrom().asBareJid().toEscapedString());
- }
-
- if (user_from == null) {
- Message reply = new Message();
- reply.setFrom(msg.getTo());
- reply.setTo(msg.getFrom());
- reply.setType(Message.Type.CHAT);
- reply.setBody("Для того, чтобы начать пользоваться сервисом, пожалуйста пройдите быструю регистрацию: http://juick.com/signup?type=xmpp&hash=" + signuphash + "\nЕсли у вас уже есть учетная запись на Juick, вы сможете присоединить этот JabberID к ней.\n\nTo start using Juick, please sign up: http://juick.com/signup?type=xmpp&hash=" + signuphash + "\nIf you already have an account on Juick, you will be proposed to attach this JabberID to your existing account.");
- s2s(ClientMessage.from(reply));
- return;
- }
-
- if (username.equals(jid.getLocal())) {
- try {
- OobX oobX = msg.getExtension(OobX.class);
- if (oobX != null) {
- incomingMessageJuick(user_from, msg.getFrom(), msg.getBody().trim(), oobX.getUri());
- } else {
- incomingMessageJuick(user_from, msg.getFrom(), msg.getBody().trim(), null);
- }
- } catch (Exception e) {
- return;
- }
- }
-
- int uid_to = userService.getUIDbyName(username);
-
- if (uid_to == 0) {
- Message reply = new Message();
- reply.setFrom(msg.getTo());
- reply.setTo(msg.getFrom());
- reply.setType(Message.Type.ERROR);
- reply.setId(msg.getId());
- reply.setError(new StanzaError(StanzaError.Type.CANCEL, Condition.ITEM_NOT_FOUND));
- s2s(ClientMessage.from(reply));
- return;
- }
-
- boolean success = false;
- if (!userService.isInBLAny(uid_to, user_from.getUid())) {
- success = pmQueriesService.createPM(user_from.getUid(), uid_to, msg.getBody());
- }
-
- if (success) {
- com.juick.Message jmsg = new com.juick.Message();
- jmsg.setUser(user_from);
- jmsg.setTo(userService.getUserByUID(uid_to).get());
- jmsg.setText(msg.getBody());
- applicationEventPublisher.publishEvent(new MessageEvent(this, jmsg));
- } else {
- Message reply = new Message();
- reply.setFrom(msg.getTo());
- reply.setTo(msg.getFrom());
- reply.setType(Message.Type.ERROR);
- reply.setId(msg.getId());
- reply.setError(new StanzaError(StanzaError.Type.CANCEL, Condition.NOT_ALLOWED));
- s2s(ClientMessage.from(reply));
- }
-
- return;
- }
- public com.juick.Message incomingMessageJuick(User user_from, Jid from, String command, URI attachment) throws Exception {
- int commandlen = command.length();
-
- // COMPATIBILITY
- if (commandlen > 7 && command.substring(0, 3).equalsIgnoreCase("PM ")) {
- command = command.substring(3).trim();
- }
-
- Optional<CommandResult> result = commandsManager.processCommand(user_from, from, command, attachment);
- if (result.isPresent()) {
- sendReply(from, result.get().getText());
- return result.get().getNewMessage();
- } else {
- // new message
- List<Tag> tags = tagService.fromString(command, false);
- String body = command.substring(TagUtils.toString(tags).length());
- String attachmentType = StringUtils.isNotEmpty(attachment.toString()) ? attachment.toString().substring(attachment.toString().length() - 3) : null;
- int mid = messagesService.createMessage(user_from.getUid(), body, attachmentType, tags);
- subscriptionService.subscribeMessage(mid, user_from.getUid());
- if (StringUtils.isNotEmpty(attachmentType)) {
- String attachmentFName = attachment.getScheme().equals("juick") ? attachment.getHost()
- : HttpUtils.downloadImage(attachment.toURL(), tmpDir);
- String fname = String.format("%d.%s", mid, attachmentType);
- ImageUtils.saveImageWithPreviews(attachmentFName, fname, tmpDir, imgDir);
- }
- com.juick.Message msg = messagesService.getMessage(mid);
- applicationEventPublisher.publishEvent(new MessageEvent(this, msg));
- return msg;
- }
- }
-
- @Override
- public void stanzaReceived(Stanza xmlValue) {
- if (xmlValue instanceof Presence) {
- Presence p = (Presence) xmlValue;
- if (p.getType() == null || !p.getType().equals(Presence.Type.ERROR)) {
- incomingPresence(p);
- }
- } else if (xmlValue instanceof Message) {
- Message msg = (Message) xmlValue;
- incomingMessage(msg);
- } else if (xmlValue instanceof IQ) {
- IQ iq = (IQ) xmlValue;
- router.send(iq);
- }
- }
-
- private void broadcastPresence(Presence.Type type) {
- Presence presence = new Presence();
- presence.setFrom(jid);
- if (type != null) {
- presence.setType(type);
- }
- userService.getActiveJIDs().forEach(j -> {
- try {
- presence.setTo(Jid.of(j));
- s2s(ClientPresence.from(presence));
- } catch (IllegalArgumentException ex) {
- logger.warn("Invalid jid: {}", j, ex);
- }
- });
- }
-
- @PreDestroy
- public void close() throws Exception {
- broadcastPresence(Presence.Type.UNAVAILABLE);
- if (router != null) {
- router.close();
- }
- }
-
- ExternalComponent getRouter() {
- return router;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/XMPPServer.java b/juick-server/src/main/java/com/juick/server/XMPPServer.java
deleted file mode 100644
index c291202d..00000000
--- a/juick-server/src/main/java/com/juick/server/XMPPServer.java
+++ /dev/null
@@ -1,432 +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 <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server;
-
-import com.juick.server.xmpp.s2s.*;
-import com.juick.service.UserService;
-import com.juick.server.xmpp.extensions.JuickMessage;
-import com.juick.xmpp.extensions.StreamError;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-import org.xmlpull.v1.XmlPullParserException;
-import rocks.xmpp.addr.Jid;
-import rocks.xmpp.core.stanza.model.Stanza;
-import rocks.xmpp.util.XmppUtils;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.inject.Inject;
-import javax.net.ssl.*;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Unmarshaller;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
-import java.io.*;
-import java.net.*;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.SecureRandom;
-import java.time.Duration;
-import java.time.Instant;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * @author ugnich
- */
-@Component
-public class XMPPServer implements ConnectionListener, AutoCloseable {
- private static final Logger logger = LoggerFactory.getLogger(XMPPServer.class);
-
- private static final int TIMEOUT_MINUTES = 15;
-
- @Inject
- public ExecutorService service;
- @Value("${hostname:localhost}")
- private Jid jid;
- @Value("${s2s_port:5269}")
- private int s2sPort;
- @Value("${keystore:juick.p12}")
- public String keystore;
- @Value("${keystore_password:secret}")
- public String keystorePassword;
- @Value("${broken_ssl_hosts:}")
- public String[] brokenSSLhosts;
- @Value("${banned_hosts:}")
- public String[] bannedHosts;
-
- private final List<ConnectionIn> inConnections = new CopyOnWriteArrayList<>();
- private final Map<ConnectionOut, Optional<Socket>> outConnections = new ConcurrentHashMap<>();
- private final List<CacheEntry> outCache = new CopyOnWriteArrayList<>();
- private final List<StanzaListener> stanzaListeners = new CopyOnWriteArrayList<>();
- private final AtomicBoolean closeFlag = new AtomicBoolean(false);
-
- SSLContext sc;
- private TrustManager[] trustAllCerts = new TrustManager[]{
- new X509TrustManager() {
- public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
- }
-
- public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
- }
- public java.security.cert.X509Certificate[] getAcceptedIssuers() {
- return null;
- }
- }
- };
- private boolean tlsConfigured = false;
-
-
- private ServerSocket listener;
-
- @Inject
- private BasicXmppSession session;
- @Inject
- private UserService userService;
-
- @PostConstruct
- public void init() throws KeyStoreException {
- closeFlag.set(false);
- KeyStore ks = KeyStore.getInstance("PKCS12");
- try (InputStream ksIs = new FileInputStream(keystore)) {
- ks.load(ksIs, keystorePassword.toCharArray());
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
- .getDefaultAlgorithm());
- kmf.init(ks, keystorePassword.toCharArray());
- sc = SSLContext.getInstance("TLSv1.2");
- sc.init(kmf.getKeyManagers(), trustAllCerts, new SecureRandom());
- tlsConfigured = true;
- } catch (Exception e) {
- logger.warn("tls unavailable");
- }
- service.submit(() -> {
- try {
- listener = new ServerSocket(s2sPort);
- logger.info("s2s listener ready");
- while (!listener.isClosed()) {
- if (Thread.currentThread().isInterrupted()) break;
- Socket socket = listener.accept();
- ConnectionIn client = new ConnectionIn(this, socket);
- addConnectionIn(client);
- service.submit(client);
- }
- } catch (SocketException e) {
- // shutdown
- } catch (IOException | XmlPullParserException e) {
- logger.warn("xmpp exception", e);
- }
- });
- }
-
- @Override
- public void close() throws Exception {
- if (listener != null && !listener.isClosed()) {
- listener.close();
- }
- outConnections.forEach((c, s) -> {
- c.logoff();
- outConnections.remove(c);
- });
- inConnections.forEach(c -> {
- c.closeConnection();
- inConnections.remove(c);
- });
- service.shutdown();
- logger.info("XMPP server destroyed");
- }
-
- public void addConnectionIn(ConnectionIn c) {
- c.setListener(this);
- inConnections.add(c);
- }
-
- public void addConnectionOut(ConnectionOut c, Optional<Socket> socket) {
- c.setListener(this);
- outConnections.put(c, socket);
- }
-
- public void removeConnectionIn(ConnectionIn c) {
- inConnections.remove(c);
- }
-
- public void removeConnectionOut(ConnectionOut c) {
- outConnections.remove(c);
- }
-
- public String getFromCache(Jid to) {
- final String[] cache = new String[1];
- outCache.stream().filter(c -> c.hostname != null && c.hostname.equals(to)).findFirst().ifPresent(c -> {
- cache[0] = c.xml;
- outCache.remove(c);
- });
- return cache[0];
- }
-
- public Optional<ConnectionOut> getConnectionOut(Jid hostname, boolean needReady) {
- return outConnections.keySet().stream().filter(c -> c.to != null &&
- c.to.equals(hostname) && (!needReady || c.streamReady)).findFirst();
- }
-
- public Optional<ConnectionIn> getConnectionIn(String streamID) {
- return inConnections.stream().filter(c -> c.streamID != null && c.streamID.equals(streamID)).findFirst();
- }
-
- public void sendOut(Stanza s) {
- try {
- StringWriter stanzaWriter = new StringWriter();
- XMLStreamWriter xmppStreamWriter = XmppUtils.createXmppStreamWriter(
- session.getConfiguration().getXmlOutputFactory().createXMLStreamWriter(stanzaWriter));
- session.createMarshaller().marshal(s, xmppStreamWriter);
- xmppStreamWriter.flush();
- xmppStreamWriter.close();
- String xml = stanzaWriter.toString();
- logger.debug("s2s (out): {}", xml);
- sendOut(Jid.of(s.getTo().getDomain()), xml);
- } catch (XMLStreamException | JAXBException e1) {
- logger.info("jaxb exception", e1);
- }
- }
-
- public void sendOut(Jid hostname, String xml) {
- boolean haveAnyConn = false;
-
- ConnectionOut connOut = null;
- for (ConnectionOut c : outConnections.keySet()) {
- if (c.to != null && c.to.equals(hostname)) {
- if (c.streamReady) {
- connOut = c;
- break;
- } else {
- haveAnyConn = true;
- break;
- }
- }
- }
- if (connOut != null) {
- connOut.send(xml);
- return;
- }
-
- boolean haveCache = false;
- for (CacheEntry c : outCache) {
- if (c.hostname != null && c.hostname.equals(hostname)) {
- c.xml += xml;
- c.updated = Instant.now();
- haveCache = true;
- break;
- }
- }
- if (!haveCache) {
- outCache.add(new CacheEntry(hostname, xml));
- }
-
- if (!haveAnyConn && !closeFlag.get()) {
- try {
- createDialbackConnection(hostname.toEscapedString(), null, null);
- } catch (Exception e) {
- logger.warn("dialback error", e);
- }
- }
- }
-
- void createDialbackConnection(String to, String checkSID, String dbKey) throws Exception {
- ConnectionOut connectionOut = new ConnectionOut(getJid(), Jid.of(to), null, null, checkSID, dbKey);
- addConnectionOut(connectionOut, Optional.empty());
- service.submit(() -> {
- try {
- Socket socket = new Socket();
- socket.connect(DNSQueries.getServerAddress(to));
- connectionOut.setInputStream(socket.getInputStream());
- connectionOut.setOutputStream(socket.getOutputStream());
- addConnectionOut(connectionOut, Optional.of(socket));
- connectionOut.addChildParser(new JuickMessage());
- connectionOut.connect();
- } catch (IOException e) {
- userService.getActiveJIDs().stream().filter(j -> Jid.of(j).getDomain().equals(to))
- .forEach(j -> {
- userService.setActiveStatusForJID(j, UserService.ActiveStatus.Inactive);
- logger.info("{} is inactive now", j);
- });
- }
- });
- }
-
- public void startDialback(Jid from, String streamId, String dbKey) throws Exception {
- Optional<ConnectionOut> c = getConnectionOut(from, false);
- if (c.isPresent()) {
- c.get().sendDialbackVerify(streamId, dbKey);
- } else {
- createDialbackConnection(from.toEscapedString(), streamId, dbKey);
- }
- }
-
- public void addStanzaListener(StanzaListener listener) {
- stanzaListeners.add(listener);
- }
-
- public void onStanzaReceived(String xmlValue) {
- Stanza stanza = parse(xmlValue);
- stanzaListeners.forEach(l -> l.stanzaReceived(stanza));
- }
-
- public BasicXmppSession getSession() {
- return session;
- }
-
- public List<ConnectionIn> getInConnections() {
- return inConnections;
- }
-
- public Map<ConnectionOut, Optional<Socket>> getOutConnections() {
- return outConnections;
- }
-
- @Override
- public boolean isTlsAvailable() {
- return tlsConfigured;
- }
-
- @Override
- public void starttls(ConnectionIn connection) {
- logger.debug("stream {} securing", connection.streamID);
- connection.sendStanza("<proceed xmlns=\"" + Connection.NS_TLS + "\" />");
- try {
- connection.setSocket(sc.getSocketFactory().createSocket(connection.getSocket(), connection.getSocket().getInetAddress().getHostAddress(),
- connection.getSocket().getPort(), true));
- ((SSLSocket) connection.getSocket()).setUseClientMode(false);
- ((SSLSocket) connection.getSocket()).startHandshake();
- connection.setSecured(true);
- logger.debug("stream {} secured", connection.streamID);
- connection.restartParser();
- } catch (XmlPullParserException | IOException sex) {
- logger.warn("stream {} ssl error {}", connection.streamID, sex);
- connection.sendStanza("<failed xmlns\"" + Connection.NS_TLS + "\" />");
- removeConnectionIn(connection);
- connection.closeConnection();
- }
- }
-
- @Override
- public void proceed(ConnectionOut connection) {
- try {
- Socket socket = outConnections.get(connection).get();
- socket = sc.getSocketFactory().createSocket(socket, socket.getInetAddress().getHostAddress(),
- socket.getPort(), true);
- ((SSLSocket) socket).startHandshake();
- connection.setSecured(true);
- logger.debug("stream {} secured", connection.getStreamID());
- connection.setInputStream(socket.getInputStream());
- connection.setOutputStream(socket.getOutputStream());
- connection.restartStream();
- connection.sendOpenStream();
- } catch (NoSuchElementException | XmlPullParserException | IOException sex) {
- logger.error("s2s ssl error: {} {}, error {}", connection.to, connection.getStreamID(), sex);
- connection.send("<failed xmlns\"" + Connection.NS_TLS + "\" />");
- removeConnectionOut(connection);
- connection.logoff();
- }
- }
-
- @Override
- public void verify(ConnectionOut connection, String from, String type, String sid) {
- if (from != null && from.equals(connection.to.toEscapedString()) && sid != null && !sid.isEmpty() && type != null) {
- getConnectionIn(sid).ifPresent(c -> c.sendDialbackResult(Jid.of(from), type));
- }
- }
-
- @Override
- public void dialbackError(ConnectionOut connection, StreamError error) {
- logger.warn("Stream error from {}: {}", connection.getStreamID(), error.getCondition());
- removeConnectionOut(connection);
- connection.logoff();
- }
-
- @Override
- public void finished(ConnectionOut connection, boolean dirty) {
- logger.warn("stream to {} {} finished, dirty={}", connection.to, connection.getStreamID(), dirty);
- removeConnectionOut(connection);
- connection.logoff();
- }
-
- @Override
- public void exception(ConnectionOut connection, Exception ex) {
- logger.error("s2s out exception: {} {}, exception {}", connection.to, connection.getStreamID(), ex);
- removeConnectionOut(connection);
- connection.logoff();
- }
-
- @Override
- public void ready(ConnectionOut connection) {
- logger.debug("stream to {} {} ready", connection.to, connection.getStreamID());
- String cache = getFromCache(connection.to);
- if (cache != null) {
- logger.debug("stream to {} {} sending cache", connection.to, connection.getStreamID());
- connection.send(cache);
- }
- }
-
- @Override
- public boolean securing(ConnectionOut connection) {
- return !Arrays.asList(brokenSSLhosts).contains(connection.to.toEscapedString());
- }
-
- public Stanza parse(String xml) {
- try {
- Unmarshaller unmarshaller = session.createUnmarshaller();
- return (Stanza)unmarshaller.unmarshal(new StringReader(xml));
- } catch (JAXBException e) {
- logger.error("JAXB exception", e);
- }
- return null;
- }
-
- public Jid getJid() {
- return jid;
- }
- @Scheduled(fixedDelay = 10000)
- public void cleanUp() {
- Instant now = Instant.now();
- outConnections.keySet().stream().filter(c -> Duration.between(now, c.getUpdated()).toMinutes() > TIMEOUT_MINUTES)
- .forEach(c -> {
- logger.info("closing idle outgoing connection to {}", c.to);
- c.logoff();
- outConnections.remove(c);
- });
-
- inConnections.stream().filter(c -> Duration.between(now, c.updated).toMinutes() > TIMEOUT_MINUTES)
- .forEach(c -> {
- logger.info("closing idle incoming connection from {}", c.from);
- c.closeConnection();
- inConnections.remove(c);
- });
- }
- @PreDestroy
- public void preDestroy() {
- closeFlag.set(true);
- }
-}
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 3d9703fd..312df52d 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
@@ -71,7 +71,7 @@ public class Post {
@Inject
private UserService userService;
@Inject
- private ServerManager serverManager;
+ private XMPPConnection xmppConnection;
@Inject
private MessagesService messagesService;
@Inject
@@ -112,7 +112,7 @@ public class Post {
throw new HttpBadRequestException();
}
}
- serverManager.processMessage(visitor, body, attachmentFName);
+ xmppConnection.processMessage(visitor, body, attachmentFName);
}
@PostMapping("/upload")
public String doUploadFile(@RequestParam(required = true) MultipartFile attach) {
@@ -169,7 +169,7 @@ public class Post {
}
}
- return serverManager.processMessage(visitor, body, attachmentFName);
+ return xmppConnection.processMessage(visitor, body, attachmentFName);
}
Session session = Session.getDefaultInstance(new Properties());
@@ -231,7 +231,7 @@ public class Post {
body[0] = rid > 0 ? String.format("#%d/%d %s", mid, rid, body[0])
: String.format("#%d %s", mid, body[0]);
}
- serverManager.processMessage(visitor, body[0], attachmentFName[0]);
+ xmppConnection.processMessage(visitor, body[0], attachmentFName[0]);
} else {
logger.info("not registered: {}", from);
}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/helpers/CommandResult.java b/juick-server/src/main/java/com/juick/server/xmpp/helpers/CommandResult.java
deleted file mode 100644
index f952b579..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/helpers/CommandResult.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.juick.server.xmpp.helpers;
-
-import com.juick.Message;
-
-public class CommandResult {
- private String text;
- private Message newMessage;
-
- public String getText() {
- return text;
- }
-
- public Message getNewMessage() {
- return newMessage;
- }
- public static CommandResult fromMessage(Message newMessage, String text) {
- CommandResult result = new CommandResult();
- result.newMessage = newMessage;
- result.text = text;
- return result;
- }
- public static CommandResult fromString(String text) {
- CommandResult result = new CommandResult();
- result.text = text;
- return result;
- }
-
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/helpers/XMPPStatus.java b/juick-server/src/main/java/com/juick/server/xmpp/helpers/XMPPStatus.java
deleted file mode 100644
index 7978ceb3..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/helpers/XMPPStatus.java
+++ /dev/null
@@ -1,48 +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 <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.helpers;
-
-import com.juick.server.xmpp.s2s.ConnectionIn;
-import com.juick.server.xmpp.s2s.ConnectionOut;
-
-import java.util.List;
-import java.util.Set;
-
-/**
- * Created by vitalyster on 16.02.2017.
- */
-public class XMPPStatus {
- private List<ConnectionIn> inbound;
- private Set<ConnectionOut> outbound;
-
- public List<ConnectionIn> getInbound() {
- return inbound;
- }
-
- public void setInbound(List<ConnectionIn> inbound) {
- this.inbound = inbound;
- }
-
- public Set<ConnectionOut> getOutbound() {
- return outbound;
- }
-
- public void setOutbound(Set<ConnectionOut> outbound) {
- this.outbound = outbound;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/helpers/annotation/UserCommand.java b/juick-server/src/main/java/com/juick/server/xmpp/helpers/annotation/UserCommand.java
deleted file mode 100644
index 383383c9..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/helpers/annotation/UserCommand.java
+++ /dev/null
@@ -1,50 +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 <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.helpers.annotation;
-
-import org.apache.commons.lang3.StringUtils;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Created by oxpa on 22.03.16.
- */
-@Target({ElementType.TYPE, ElementType.METHOD})
-@Retention(RetentionPolicy.RUNTIME)
-public @interface UserCommand {
- /**
- *
- * @return a command pattern
- */
- String pattern() default StringUtils.EMPTY;
-
- /**
- *
- * @return pattern flags
- */
- int patternFlags() default 0;
-
- /**
- *
- * @return a string used in HELP command output. Basically, only 1 string
- */
- String help() default StringUtils.EMPTY;
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/router/Stream.java b/juick-server/src/main/java/com/juick/server/xmpp/router/Stream.java
deleted file mode 100644
index 7532443c..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/router/Stream.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Juick
- * Copyright (C) 2008-2011, Ugnich Anton
- *
- * 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.server.xmpp.router;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-import rocks.xmpp.addr.Jid;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
-import java.time.Instant;
-import java.util.UUID;
-
-/**
- *
- * @author Ugnich Anton
- */
-public abstract class Stream {
-
- public boolean isLoggedIn() {
- return loggedIn;
- }
-
- public void setLoggedIn(boolean loggedIn) {
- this.loggedIn = loggedIn;
- }
-
- Jid from;
- public Jid to;
- private InputStream is;
- private OutputStream os;
- private XmlPullParserFactory factory;
- protected XmlPullParser parser;
- private OutputStreamWriter writer;
- StreamHandler streamHandler;
- private boolean loggedIn;
- private Instant created;
- private Instant updated;
- String streamId;
- private boolean secured;
-
- public Stream(final Jid from, final Jid to, final InputStream is, final OutputStream os) throws XmlPullParserException {
- this.from = from;
- this.to = to;
- this.is = is;
- this.os = os;
- factory = XmlPullParserFactory.newInstance();
- created = updated = Instant.now();
- streamId = UUID.randomUUID().toString();
- }
-
- void restartStream() throws XmlPullParserException {
- parser = factory.newPullParser();
- parser.setInput(new InputStreamReader(is, StandardCharsets.UTF_8));
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- writer = new OutputStreamWriter(os, StandardCharsets.UTF_8);
- }
-
- public void connect() {
- try {
- restartStream();
- handshake();
- parse();
- } catch (XmlPullParserException e) {
- StreamError invalidXmlError = new StreamError("invalid-xml");
- send(invalidXmlError.toString());
- connectionFailed(new Exception(invalidXmlError.getCondition()));
- } catch (IOException e) {
- connectionFailed(e);
- }
- }
-
- public void setHandler(final StreamHandler streamHandler) {
- this.streamHandler = streamHandler;
- }
-
- public abstract void handshake() throws XmlPullParserException, IOException;
-
- public void logoff() {
- setLoggedIn(false);
- try {
- writer.flush();
- writer.close();
- //TODO close parser
- } catch (final Exception e) {
- connectionFailed(e);
- }
- }
-
- public void send(final String str) {
- try {
- updated = Instant.now();
- writer.write(str);
- writer.flush();
- } catch (final Exception e) {
- connectionFailed(e);
- }
- }
-
- private void parse() throws IOException, XmlPullParserException {
- while (parser.next() != XmlPullParser.END_DOCUMENT) {
- if (parser.getEventType() == XmlPullParser.IGNORABLE_WHITESPACE) {
- setUpdated();
- }
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- continue;
- }
- setUpdated();
- final String tag = parser.getName();
- switch (tag) {
- case "message":
- case "presence":
- case "iq":
- streamHandler.stanzaReceived(XmlUtils.parseToString(parser, false));
- break;
- case "error":
- StreamError error = StreamError.parse(parser);
- connectionFailed(new Exception(error.getCondition()));
- return;
- default:
- XmlUtils.skip(parser);
- break;
- }
- }
- }
-
- /**
- * This method is used to be called on a parser or a connection error.
- * It tries to close the XML-Reader and XML-Writer one last time.
- */
- private void connectionFailed(final Exception ex) {
- if (isLoggedIn()) {
- try {
- writer.close();
- //TODO close parser
- } catch (Exception e) {
- }
- }
- streamHandler.fail(ex);
- }
-
- public Instant getCreated() {
- return created;
- }
-
- public Instant getUpdated() {
- return updated;
- }
- public String getStreamId() {
- return streamId;
- }
-
- public boolean isSecured() {
- return secured;
- }
-
- public void setSecured(boolean secured) {
- this.secured = secured;
- }
-
- public void setUpdated() {
- this.updated = Instant.now();
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/router/StreamComponentServer.java b/juick-server/src/main/java/com/juick/server/xmpp/router/StreamComponentServer.java
deleted file mode 100644
index 5e2f6f82..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/router/StreamComponentServer.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.juick.server.xmpp.router;
-
-import com.juick.xmpp.extensions.Handshake;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.xmlpull.v1.XmlPullParserException;
-import rocks.xmpp.addr.Jid;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.UUID;
-
-/**
- * Created by vitalyster on 30.01.2017.
- */
-public class StreamComponentServer extends Stream {
-
- private String streamId, secret;
-
- public String getStreamId() {
- return streamId;
- }
-
-
- public StreamComponentServer(InputStream is, OutputStream os, String password) throws XmlPullParserException {
- super(null, null, is, os);
- secret = password;
- streamId = UUID.randomUUID().toString();
- }
- @Override
- public void handshake() throws XmlPullParserException, IOException {
- parser.next();
- if (!parser.getName().equals("stream")
- || !parser.getNamespace(null).equals(StreamNamespaces.NS_COMPONENT_ACCEPT)
- || !parser.getNamespace("stream").equals(StreamNamespaces.NS_STREAM)) {
- throw new IOException("invalid stream");
- }
- Jid domain = Jid.of(parser.getAttributeValue(null, "to"));
- if (streamHandler.filter(null, domain)) {
- send(new XMPPError(XMPPError.Type.cancel, "forbidden").toString());
- throw new IOException("invalid domain");
- }
- from = domain;
- to = domain;
- send(String.format("<stream:stream xmlns:stream='%s' " +
- "xmlns='%s' from='%s' id='%s'>", StreamNamespaces.NS_STREAM, StreamNamespaces.NS_COMPONENT_ACCEPT, from.asBareJid().toEscapedString(), streamId));
- Handshake handshake = Handshake.parse(parser);
- boolean authenticated = handshake.getValue().equals(DigestUtils.sha1Hex(streamId + secret));
- setLoggedIn(authenticated);
- if (!authenticated) {
- send(new XMPPError(XMPPError.Type.cancel, "not-authorized").toString());
- streamHandler.fail(new IOException("stream:stream, failed authentication"));
- return;
- }
- send(new Handshake().toString());
- streamHandler.ready();
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/router/StreamError.java b/juick-server/src/main/java/com/juick/server/xmpp/router/StreamError.java
deleted file mode 100644
index 7eacfc94..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/router/StreamError.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.juick.server.xmpp.router;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-
-
-/**
- * Created by vitalyster on 03.02.2017.
- */
-public class StreamError {
-
- private String condition;
-
- public StreamError() {}
-
- public StreamError(String condition) {
- this.condition = condition;
- }
-
- public static StreamError parse(XmlPullParser parser) throws IOException, XmlPullParserException {
- StreamError streamError = new StreamError();
- while (parser.next() == XmlPullParser.START_TAG) {
- final String tag = parser.getName();
- final String xmlns = parser.getNamespace();
- if (xmlns.equals(StreamNamespaces.NS_XMPP_STREAMS)) {
- streamError.condition = tag;
- } else {
- XmlUtils.skip(parser);
- }
- }
- return streamError;
- }
-
- public String getCondition() {
- return condition;
- }
-
- @Override
- public String toString() {
- return String.format("<stream:error><%s xmlns='%s'/></stream:error>", condition, StreamNamespaces.NS_XMPP_STREAMS);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/router/StreamHandler.java b/juick-server/src/main/java/com/juick/server/xmpp/router/StreamHandler.java
deleted file mode 100644
index 43836c2d..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/router/StreamHandler.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.juick.server.xmpp.router;
-
-import rocks.xmpp.addr.Jid;
-
-/**
- * Created by vitalyster on 01.02.2017.
- */
-public interface StreamHandler {
- void ready();
- void fail(final Exception ex);
- boolean filter(Jid from, Jid to);
- void stanzaReceived(String stanza);
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/router/StreamNamespaces.java b/juick-server/src/main/java/com/juick/server/xmpp/router/StreamNamespaces.java
deleted file mode 100644
index 1b9b1965..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/router/StreamNamespaces.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.juick.server.xmpp.router;
-
-public class StreamNamespaces {
- public static final String NS_STREAM = "http://etherx.jabber.org/streams";
- public static final String NS_TLS = "urn:ietf:params:xml:ns:xmpp-tls";
- public static final String NS_DB = "jabber:server:dialback";
- public static final String NS_SERVER = "jabber:server";
- public static final String NS_COMPONENT_ACCEPT = "jabber:component:accept";
- public static final String NS_XMPP_STREAMS = "urn:ietf:params:xml:ns:xmpp-streams";
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/router/XMPPError.java b/juick-server/src/main/java/com/juick/server/xmpp/router/XMPPError.java
deleted file mode 100644
index 0cf9a3bc..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/router/XMPPError.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Juick
- * Copyright (C) 2008-2013, ugnich
- *
- * 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.server.xmpp.router;
-
-import org.apache.commons.text.StringEscapeUtils;
-
-/**
- *
- * @author ugnich
- */
-public class XMPPError {
-
- public static final class Type {
-
- public static final String auth = "auth";
- public static final String cancel = "cancel";
- public static final String continue_ = "continue";
- public static final String modify = "modify";
- public static final String wait = "wait";
- }
- private final static String TagName = "error";
- public String by = null;
- private String type;
- private String condition;
- private String text = null;
-
- public XMPPError(String type, String condition) {
- this.type = type;
- this.condition = condition;
- }
-
- @Override
- public String toString() {
- StringBuilder str = new StringBuilder("<").append(TagName).append("");
- if (by != null) {
- str.append(" by=\"").append(StringEscapeUtils.escapeXml10(by)).append("\"");
- }
- if (type != null) {
- str.append(" type=\"").append(StringEscapeUtils.escapeXml10(type)).append("\"");
- }
-
- if (condition != null) {
- str.append(">");
- str.append("<").append(StringEscapeUtils.escapeXml10(condition)).append(" xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"");
- if (text != null) {
- str.append(">").append(StringEscapeUtils.escapeXml10(text)).append("</").append(StringEscapeUtils.escapeXml10(condition))
- .append(">");
- } else {
- str.append("/>");
- }
- str.append("</").append(TagName).append(">");
- } else {
- str.append("/>");
- }
-
- return str.toString();
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/router/XMPPRouter.java b/juick-server/src/main/java/com/juick/server/xmpp/router/XMPPRouter.java
deleted file mode 100644
index a262e941..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/router/XMPPRouter.java
+++ /dev/null
@@ -1,176 +0,0 @@
-package com.juick.server.xmpp.router;
-
-import com.juick.server.XMPPServer;
-import com.juick.server.xmpp.s2s.BasicXmppSession;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-import org.xmlpull.v1.XmlPullParserException;
-import rocks.xmpp.addr.Jid;
-import rocks.xmpp.core.stanza.model.Stanza;
-import rocks.xmpp.util.XmppUtils;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.inject.Inject;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Unmarshaller;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.concurrent.ExecutorService;
-
-@Component
-public class XMPPRouter implements StreamHandler {
- private static final Logger logger = LoggerFactory.getLogger(XMPPRouter.class);
-
- @Inject
- private ExecutorService service;
-
- private final List<StreamComponentServer> connections = Collections.synchronizedList(new ArrayList<>());
-
- private ServerSocket listener;
-
- @Inject
- private BasicXmppSession session;
-
- @Value("${router_port:5347}")
- private int routerPort;
-
- @Inject
- private XMPPServer xmppServer;
-
- @PostConstruct
- public void init() {
- logger.info("component router initialized");
- service.submit(() -> {
- try {
- listener = new ServerSocket(routerPort);
- logger.info("component router listening on {}", routerPort);
- while (!listener.isClosed()) {
- if (Thread.currentThread().isInterrupted()) break;
- Socket socket = listener.accept();
- service.submit(() -> {
- try {
- StreamComponentServer client = new StreamComponentServer(socket.getInputStream(), socket.getOutputStream(), "secret");
- addConnectionIn(client);
- client.setHandler(this);
- client.connect();
- } catch (IOException e) {
- logger.error("component error", e);
- } catch (XmlPullParserException e) {
- e.printStackTrace();
- }
- });
- }
- } catch (SocketException e) {
- // shutdown
- } catch (IOException e) {
- logger.warn("io exception", e);
- }
- });
- }
-
- @PreDestroy
- public void close() throws Exception {
- if (!listener.isClosed()) {
- listener.close();
- }
- synchronized (getConnections()) {
- for (Iterator<StreamComponentServer> i = getConnections().iterator(); i.hasNext(); ) {
- StreamComponentServer c = i.next();
- c.logoff();
- i.remove();
- }
- }
- service.shutdown();
- logger.info("XMPP router destroyed");
- }
-
- private void addConnectionIn(StreamComponentServer c) {
- synchronized (getConnections()) {
- getConnections().add(c);
- }
- }
-
- private void sendOut(Stanza s) {
- try {
- StringWriter stanzaWriter = new StringWriter();
- XMLStreamWriter xmppStreamWriter = XmppUtils.createXmppStreamWriter(
- session.getConfiguration().getXmlOutputFactory().createXMLStreamWriter(stanzaWriter));
- session.createMarshaller().marshal(s, xmppStreamWriter);
- xmppStreamWriter.flush();
- xmppStreamWriter.close();
- String xml = stanzaWriter.toString();
- logger.info("XMPPRouter (out): {}", xml);
- sendOut(s.getTo().getDomain(), xml);
- } catch (XMLStreamException | JAXBException e1) {
- logger.info("jaxb exception", e1);
- }
- }
-
- private void sendOut(String hostname, String xml) {
- boolean haveAnyConn = false;
-
- StreamComponentServer connOut = null;
- synchronized (getConnections()) {
- for (StreamComponentServer c : getConnections()) {
- if (c.to != null && c.to.getDomain().equals(hostname)) {
- if (c.isLoggedIn()) {
- connOut = c;
- break;
- }
- }
- }
- }
- if (connOut != null) {
- connOut.send(xml);
- return;
- }
- xmppServer.sendOut(Jid.of(hostname), xml);
-
- }
-
- public List<StreamComponentServer> getConnections() {
- return connections;
- }
-
- private Stanza parse(String xml) {
- try {
- Unmarshaller unmarshaller = session.createUnmarshaller();
- return (Stanza)unmarshaller.unmarshal(new StringReader(xml));
- } catch (JAXBException e) {
- logger.error("JAXB exception", e);
- }
- return null;
- }
- @Override
- public void stanzaReceived(String stanza) {
- sendOut(parse(stanza));
- }
-
- @Override
- public void ready() {
-
- }
-
- @Override
- public void fail(Exception e) {
-
- }
-
- @Override
- public boolean filter(Jid jid, Jid jid1) {
- return false;
- }
-} \ No newline at end of file
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/router/XmlUtils.java b/juick-server/src/main/java/com/juick/server/xmpp/router/XmlUtils.java
deleted file mode 100644
index 7579489f..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/router/XmlUtils.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Juick
- * Copyright (C) 2008-2011, Ugnich Anton
- *
- * 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.server.xmpp.router;
-
-import java.io.IOException;
-
-import org.apache.commons.text.StringEscapeUtils;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-/**
- *
- * @author Ugnich Anton
- */
-public class XmlUtils {
-
- public static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
- String tag = parser.getName();
- while (parser.getName() != null && !(parser.next() == XmlPullParser.END_TAG && parser.getName().equals(tag))) {
- }
- }
-
- public static String getTagText(XmlPullParser parser) throws XmlPullParserException, IOException {
- String ret = "";
- String tag = parser.getName();
-
- if (parser.next() == XmlPullParser.TEXT) {
- ret = parser.getText();
- }
-
- while (!(parser.getEventType() == XmlPullParser.END_TAG && parser.getName().equals(tag))) {
- parser.next();
- }
-
- return ret;
- }
-
- public static String parseToString(XmlPullParser parser, boolean skipXMLNS) throws XmlPullParserException, IOException {
- String tag = parser.getName();
- StringBuilder ret = new StringBuilder("<").append(tag);
-
- // skipXMLNS for xmlns="jabber:client"
-
- String ns = parser.getNamespace();
- if (!skipXMLNS && ns != null && !ns.isEmpty()) {
- ret.append(" xmlns=\"").append(ns).append("\"");
- }
-
- for (int i = 0; i < parser.getAttributeCount(); i++) {
- String attr = parser.getAttributeName(i);
- if ((!skipXMLNS || !attr.equals("xmlns")) && !attr.contains(":")) {
- ret.append(" ").append(attr).append("=\"").append(StringEscapeUtils.escapeXml10(parser.getAttributeValue(i))).append("\"");
- }
- }
- ret.append(">");
-
- while (!(parser.next() == XmlPullParser.END_TAG && parser.getName().equals(tag))) {
- int event = parser.getEventType();
- if (event == XmlPullParser.START_TAG) {
- if (!parser.getName().contains(":")) {
- ret.append(parseToString(parser, false));
- } else {
- skip(parser);
- }
- } else if (event == XmlPullParser.TEXT) {
- ret.append(StringEscapeUtils.escapeXml10(parser.getText()));
- }
- }
-
- ret.append("</").append(tag).append(">");
- return ret.toString();
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/s2s/CacheEntry.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/CacheEntry.java
deleted file mode 100644
index 33e875bd..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/s2s/CacheEntry.java
+++ /dev/null
@@ -1,40 +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 <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-import rocks.xmpp.addr.Jid;
-
-import java.time.Instant;
-
-/**
- *
- * @author ugnich
- */
-public class CacheEntry {
-
- public Jid hostname;
- public Instant created;
- public Instant updated;
- public String xml;
-
- public CacheEntry(Jid hostname, String xml) {
- this.hostname = hostname;
- this.created = this.updated =Instant.now();
- this.xml = xml;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/s2s/Connection.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/Connection.java
deleted file mode 100644
index 6bf61169..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/s2s/Connection.java
+++ /dev/null
@@ -1,139 +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 <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.juick.server.XMPPServer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.net.Socket;
-import java.nio.charset.StandardCharsets;
-import java.time.Instant;
-import java.util.UUID;
-
-/**
- *
- * @author ugnich
- */
-public class Connection {
-
- protected static final Logger logger = LoggerFactory.getLogger(Connection.class);
-
- public String streamID;
- public Instant created;
- public Instant updated;
- public long bytesLocal = 0;
- public long packetsLocal = 0;
- XMPPServer xmpp;
- private Socket socket;
- public static final String NS_DB = "jabber:server:dialback";
- public static final String NS_TLS = "urn:ietf:params:xml:ns:xmpp-tls";
- public static final String NS_STREAM = "http://etherx.jabber.org/streams";
- XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
- XmlPullParser parser = factory.newPullParser();
- OutputStreamWriter writer;
- private boolean secured = false;
-
-
-
- public Connection(XMPPServer xmpp) throws XmlPullParserException {
- this.xmpp = xmpp;
- created = updated = Instant.now();
- }
-
- public void logParser() {
- if (streamID == null) {
- return;
- }
- String tag = "IN: <" + parser.getName();
- for (int i = 0; i < parser.getAttributeCount(); i++) {
- tag += " " + parser.getAttributeName(i) + "=\"" + parser.getAttributeValue(i) + "\"";
- }
- tag += ">...</" + parser.getName() + ">\n";
- logger.trace(tag);
- }
-
- public void sendStanza(String xml) {
- if (streamID != null) {
- logger.trace("OUT: {}\n", xml);
- }
- try {
- writer.write(xml);
- writer.flush();
- } catch (IOException e) {
- logger.error("send stanza failed", e);
- }
-
- updated = Instant.now();
- bytesLocal += xml.length();
- packetsLocal++;
- }
-
- public void closeConnection() {
- if (streamID != null) {
- logger.debug("closing stream {}", streamID);
- }
-
- try {
- writer.write("</stream:stream>");
- } catch (Exception e) {
- }
-
- try {
- writer.close();
- } catch (Exception e) {
- }
-
- try {
- socket.close();
- } catch (Exception e) {
- }
- }
-
- public boolean isSecured() {
- return secured;
- }
-
- public void setSecured(boolean secured) {
- this.secured = secured;
- }
-
- public void restartParser() throws XmlPullParserException, IOException {
- streamID = UUID.randomUUID().toString();
- parser = factory.newPullParser();
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- parser.setInput(new InputStreamReader(socket.getInputStream()));
- writer = new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8);
- }
-
- @JsonIgnore
- public Socket getSocket() {
- return socket;
- }
-
- public void setSocket(Socket socket) {
- this.socket = socket;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionIn.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionIn.java
deleted file mode 100644
index 9ee81d4d..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionIn.java
+++ /dev/null
@@ -1,213 +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 <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-import com.juick.server.XMPPServer;
-import com.juick.xmpp.extensions.StreamError;
-import com.juick.xmpp.utils.XmlUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import rocks.xmpp.addr.Jid;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.net.Socket;
-import java.net.SocketException;
-import java.time.Instant;
-import java.util.Arrays;
-import java.util.List;
-import java.util.UUID;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * @author ugnich
- */
-public class ConnectionIn extends Connection implements Runnable {
-
- final public List<Jid> from = new CopyOnWriteArrayList<>();
- public Instant received;
- public long packetsRemote = 0;
- ConnectionListener listener;
-
- public ConnectionIn(XMPPServer xmpp, Socket socket) throws XmlPullParserException, IOException {
- super(xmpp);
- this.setSocket(socket);
- restartParser();
- }
-
- @Override
- public void run() {
- try {
- parser.next(); // stream:stream
- updateTsRemoteData();
- if (!parser.getName().equals("stream")
- || !parser.getNamespace("stream").equals(NS_STREAM)) {
-// || !parser.getAttributeValue(null, "version").equals("1.0")
-// || !parser.getAttributeValue(null, "to").equals(Main.HOSTNAME)) {
- throw new Exception(String.format("stream from %s invalid", getSocket().getRemoteSocketAddress()));
- }
- streamID = parser.getAttributeValue(null, "id");
- if (streamID == null) {
- streamID = UUID.randomUUID().toString();
- }
- boolean xmppversionnew = parser.getAttributeValue(null, "version") != null;
- String from = parser.getAttributeValue(null, "from");
-
- if (Arrays.asList(xmpp.bannedHosts).contains(from)) {
- closeConnection();
- return;
- }
- sendOpenStream(from, xmppversionnew);
-
- while (parser.next() != XmlPullParser.END_DOCUMENT) {
- updateTsRemoteData();
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- continue;
- }
- logParser();
-
- packetsRemote++;
-
- String tag = parser.getName();
- if (tag.equals("result") && parser.getNamespace().equals(NS_DB)) {
- String dfrom = parser.getAttributeValue(null, "from");
- String to = parser.getAttributeValue(null, "to");
- logger.debug("stream from {} to {} {} asking for dialback", dfrom, to, streamID);
- if (dfrom.endsWith(xmpp.getJid().toEscapedString()) && (dfrom.equals(xmpp.getJid().toEscapedString())
- || dfrom.endsWith("." + xmpp.getJid()))) {
- logger.warn("stream from {} is invalid", dfrom);
- break;
- }
- if (to != null && to.equals(xmpp.getJid().toEscapedString())) {
- String dbKey = XmlUtils.getTagText(parser);
- updateTsRemoteData();
- xmpp.startDialback(Jid.of(dfrom), streamID, dbKey);
- } else {
- logger.warn("stream from " + dfrom + " " + streamID + " invalid to " + to);
- break;
- }
- } else if (tag.equals("verify") && parser.getNamespace().equals(NS_DB)) {
- String vfrom = parser.getAttributeValue(null, "from");
- String vto = parser.getAttributeValue(null, "to");
- String vid = parser.getAttributeValue(null, "id");
- String vkey = XmlUtils.getTagText(parser);
- updateTsRemoteData();
- final boolean[] valid = {false};
- if (vfrom != null && vto != null && vid != null && vkey != null) {
- xmpp.getConnectionOut(Jid.of(vfrom), false).ifPresent(c -> {
- String dialbackKey = c.dbKey;
- valid[0] = vkey.equals(dialbackKey);
- });
- }
- if (valid[0]) {
- sendStanza("<db:verify from='" + vto + "' to='" + vfrom + "' id='" + vid + "' type='valid'/>");
- logger.debug("stream from {} {} dialback verify valid", vfrom, streamID);
- } else {
- sendStanza("<db:verify from='" + vto + "' to='" + vfrom + "' id='" + vid + "' type='invalid'/>");
- logger.warn("stream from {} {} dialback verify invalid", vfrom, streamID);
- }
- } else if (tag.equals("presence") && checkFromTo(parser)) {
- String xml = XmlUtils.parseToString(parser, false);
- logger.debug("stream {} presence: {}", streamID, xml);
- xmpp.onStanzaReceived(xml);
- } else if (tag.equals("message") && checkFromTo(parser)) {
- updateTsRemoteData();
- String xml = XmlUtils.parseToString(parser, false);
- logger.debug("stream {} message: {}", streamID, xml);
- xmpp.onStanzaReceived(xml);
-
- } else if (tag.equals("iq") && checkFromTo(parser)) {
- updateTsRemoteData();
- String type = parser.getAttributeValue(null, "type");
- String xml = XmlUtils.parseToString(parser, false);
- if (type == null || !type.equals("error")) {
- logger.debug("stream {} iq: {}", streamID, xml);
- xmpp.onStanzaReceived(xml);
- }
- } else if (!isSecured() && tag.equals("starttls")) {
- listener.starttls(this);
- } else if (isSecured() && tag.equals("stream") && parser.getNamespace().equals(NS_STREAM)) {
- sendOpenStream(null, true);
- } else if (tag.equals("error")) {
- StreamError streamError = StreamError.parse(parser);
- logger.debug("Stream error from {}: {}", streamID, streamError.getCondition());
- xmpp.removeConnectionIn(this);
- closeConnection();
- } else {
- String unhandledStanza = XmlUtils.parseToString(parser, true);
- logger.warn("Unhandled stanza from {}: {}", streamID, unhandledStanza);
- }
- }
- logger.warn("stream {} finished", streamID);
- xmpp.removeConnectionIn(this);
- closeConnection();
- } catch (EOFException | SocketException ex) {
- logger.debug("stream {} closed (dirty)", streamID);
- xmpp.removeConnectionIn(this);
- closeConnection();
- } catch (Exception e) {
- logger.debug("stream {} error {}", streamID, e);
- xmpp.removeConnectionIn(this);
- closeConnection();
- }
- }
-
- void updateTsRemoteData() {
- received = Instant.now();
- }
-
- void sendOpenStream(String from, boolean xmppversionnew) throws IOException {
- String openStream = "<?xml version='1.0'?><stream:stream xmlns='jabber:server' " +
- "xmlns:stream='http://etherx.jabber.org/streams' xmlns:db='jabber:server:dialback' from='" +
- xmpp.getJid().toEscapedString() + "' id='" + streamID + "' version='1.0'>";
- if (xmppversionnew) {
- openStream += "<stream:features>";
- if (listener != null && listener.isTlsAvailable() && !isSecured() && !Arrays.asList(xmpp.brokenSSLhosts).contains(from)) {
- openStream += "<starttls xmlns=\"" + NS_TLS + "\"><optional/></starttls>";
- }
- openStream += "</stream:features>";
- }
- sendStanza(openStream);
- }
-
- public void sendDialbackResult(Jid sfrom, String type) {
- sendStanza("<db:result from='" + xmpp.getJid().toEscapedString() + "' to='" + sfrom + "' type='" + type + "'/>");
- if (type.equals("valid")) {
- from.add(sfrom);
- logger.debug("stream from {} {} ready", sfrom, streamID);
- }
- }
-
- boolean checkFromTo(XmlPullParser parser) throws Exception {
- String cfrom = parser.getAttributeValue(null, "from");
- String cto = parser.getAttributeValue(null, "to");
- if (StringUtils.isNotEmpty(cfrom) && StringUtils.isNotEmpty(cto)) {
- Jid jidfrom = Jid.of(cfrom);
- for (Jid aFrom : from) {
- if (aFrom.equals(Jid.of(jidfrom.getDomain()))) {
- return true;
- }
- }
- }
- return false;
- }
- public void setListener(ConnectionListener listener) {
- this.listener = listener;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionListener.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionListener.java
deleted file mode 100644
index fde7a0e7..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionListener.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.juick.server.xmpp.s2s;
-
-import com.juick.xmpp.extensions.StreamError;
-
-public interface ConnectionListener {
- boolean isTlsAvailable();
- void starttls(ConnectionIn connection);
- void proceed(ConnectionOut connection);
- void verify(ConnectionOut connection, String from, String type, String sid);
- void dialbackError(ConnectionOut connection, StreamError error);
- void finished(ConnectionOut connection, boolean dirty);
- void exception(ConnectionOut connection, Exception ex);
- void ready(ConnectionOut connection);
- boolean securing(ConnectionOut connection);
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionOut.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionOut.java
deleted file mode 100644
index e3bd53e9..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionOut.java
+++ /dev/null
@@ -1,167 +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 <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-import com.juick.server.xmpp.s2s.util.DialbackUtils;
-import com.juick.xmpp.Stream;
-import com.juick.xmpp.extensions.StreamError;
-import com.juick.xmpp.extensions.StreamFeatures;
-import com.juick.xmpp.utils.XmlUtils;
-import org.apache.commons.text.RandomStringGenerator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.xmlpull.v1.XmlPullParser;
-import rocks.xmpp.addr.Jid;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.SocketException;
-import java.util.UUID;
-
-/**
- * @author ugnich
- */
-public class ConnectionOut extends Stream {
- protected static final Logger logger = LoggerFactory.getLogger(ConnectionOut.class);
- public static final String NS_TLS = "urn:ietf:params:xml:ns:xmpp-tls";
- public static final String NS_DB = "jabber:server:dialback";
- private boolean secured = false;
-
- public boolean streamReady = false;
- String checkSID = null;
- String dbKey = null;
- private String streamID;
- ConnectionListener listener;
- RandomStringGenerator generator = new RandomStringGenerator.Builder().withinRange('a', 'z').build();
-
- public ConnectionOut(Jid from, Jid to, InputStream is, OutputStream os, String checkSID, String dbKey) throws Exception {
- super(from, to, is, os);
- this.to = to;
- this.checkSID = checkSID;
- this.dbKey = dbKey;
- if (dbKey == null) {
- this.dbKey = DialbackUtils.generateDialbackKey(generator.generate(15), to, from, streamID);
- }
- streamID = UUID.randomUUID().toString();
- }
-
- public void sendOpenStream() throws IOException {
- send("<?xml version='1.0'?><stream:stream xmlns='jabber:server' id='" + streamID +
- "' xmlns:stream='http://etherx.jabber.org/streams' xmlns:db='jabber:server:dialback' from='" +
- from.toEscapedString() + "' to='" + to.toEscapedString() + "' version='1.0'>");
- }
-
- void processDialback() throws Exception {
- if (checkSID != null) {
- sendDialbackVerify(checkSID, dbKey);
- }
- send("<db:result from='" + from.toEscapedString() + "' to='" + to.toEscapedString() + "'>" +
- dbKey + "</db:result>");
- }
-
- @Override
- public void handshake() {
- try {
- restartStream();
-
- sendOpenStream();
-
- parser.next(); // stream:stream
- streamID = parser.getAttributeValue(null, "id");
- if (streamID == null || streamID.isEmpty()) {
- throw new Exception("stream to " + to + " invalid first packet");
- }
-
- logger.debug("stream to {} {} open", to, streamID);
- boolean xmppversionnew = parser.getAttributeValue(null, "version") != null;
- if (!xmppversionnew) {
- processDialback();
- }
-
- while (parser.next() != XmlPullParser.END_DOCUMENT) {
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- continue;
- }
-
- String tag = parser.getName();
- if (tag.equals("result") && parser.getNamespace().equals(NS_DB)) {
- String type = parser.getAttributeValue(null, "type");
- if (type != null && type.equals("valid")) {
- streamReady = true;
- listener.ready(this);
- } else {
- logger.warn("stream to {} {} dialback fail", to, streamID);
- }
- XmlUtils.skip(parser);
- } else if (tag.equals("verify") && parser.getNamespace().equals(NS_DB)) {
- String from = parser.getAttributeValue(null, "from");
- String type = parser.getAttributeValue(null, "type");
- String sid = parser.getAttributeValue(null, "id");
- listener.verify(this, from, type, sid);
- XmlUtils.skip(parser);
- } else if (tag.equals("features") && parser.getNamespace().equals(NS_STREAM)) {
- StreamFeatures features = StreamFeatures.parse(parser);
- if (listener != null && !secured && features.STARTTLS >= 0
- && listener.securing(this)) {
- logger.debug("stream to {} {} securing", to.toEscapedString(), streamID);
- send("<starttls xmlns=\"" + NS_TLS + "\" />");
- } else {
- processDialback();
- }
- } else if (tag.equals("proceed") && parser.getNamespace().equals(NS_TLS)) {
- listener.proceed(this);
- } else if (secured && tag.equals("stream") && parser.getNamespace().equals(NS_STREAM)) {
- streamID = parser.getAttributeValue(null, "id");
- } else if (tag.equals("error")) {
- StreamError streamError = StreamError.parse(parser);
- listener.dialbackError(this, streamError);
- } else {
- String unhandledStanza = XmlUtils.parseToString(parser, true);
- logger.warn("Unhandled stanza from {} {} : {}", to, streamID, unhandledStanza);
- }
- }
- listener.finished(this, false);
- } catch (EOFException | SocketException eofex) {
- listener.finished(this, true);
- } catch (Exception e) {
- listener.exception(this, e);
- }
- }
-
- public void sendDialbackVerify(String sid, String key) {
- send("<db:verify from='" + from.toEscapedString() + "' to='" + to + "' id='" + sid + "'>" +
- key + "</db:verify>");
- }
- public void setListener(ConnectionListener listener) {
- this.listener = listener;
- }
-
- public String getStreamID() {
- return streamID;
- }
-
- public boolean isSecured() {
- return secured;
- }
-
- public void setSecured(boolean secured) {
- this.secured = secured;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/s2s/DNSQueries.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/DNSQueries.java
deleted file mode 100644
index 1367d333..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/s2s/DNSQueries.java
+++ /dev/null
@@ -1,65 +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 <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-import org.apache.commons.lang3.math.NumberUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.net.InetSocketAddress;
-import java.util.Hashtable;
-import java.util.Random;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.InitialDirContext;
-
-/**
- *
- * @author ugnich
- */
-public class DNSQueries {
-
- private static final Logger logger = LoggerFactory.getLogger(DNSQueries.class);
-
- private static Random rand = new Random();
-
- public static InetSocketAddress getServerAddress(String hostname) {
-
- String host = hostname;
- int port = 5269;
-
- Hashtable<String, String> env = new Hashtable<>(5);
- env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
- try {
- DirContext ctx = new InitialDirContext(env);
- Attribute att = ctx.getAttributes("_xmpp-server._tcp." + hostname, new String[]{"SRV"}).get("SRV");
-
- if (att != null && att.size() > 0) {
- int i = rand.nextInt(att.size());
- String srv[] = att.get(i).toString().split(" ");
- port = NumberUtils.toInt(srv[2], 5269);
- host = srv[3];
- }
- ctx.close();
- } catch (NamingException e) {
- logger.debug("SRV record for {} is not resolved, falling back to A record", hostname);
- }
- return new InetSocketAddress(host, port);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/s2s/StanzaListener.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/StanzaListener.java
deleted file mode 100644
index 6932298f..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/s2s/StanzaListener.java
+++ /dev/null
@@ -1,28 +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 <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-
-import rocks.xmpp.core.stanza.model.Stanza;
-
-/**
- * Created by vitalyster on 07.12.2016.
- */
-public interface StanzaListener {
- void stanzaReceived(Stanza xmlValue);
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/s2s/util/DialbackUtils.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/util/DialbackUtils.java
deleted file mode 100644
index d25dbad8..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/s2s/util/DialbackUtils.java
+++ /dev/null
@@ -1,37 +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 <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s.util;
-
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.codec.digest.HmacAlgorithms;
-import org.apache.commons.codec.digest.HmacUtils;
-import rocks.xmpp.addr.Jid;
-
-/**
- * Created by vitalyster on 05.12.2016.
- */
-public class DialbackUtils {
- private DialbackUtils() {
- throw new IllegalStateException();
- }
-
- public static String generateDialbackKey(String secret, Jid to, Jid from, String id) {
- return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, DigestUtils.sha256(secret))
- .hmacHex(to.toEscapedString() + " " + from.toEscapedString() + " " + id);
- }
-}
diff --git a/juick-server/src/main/resources/juick.png b/juick-server/src/main/resources/juick.png
deleted file mode 100644
index c85ef2c4..00000000
--- a/juick-server/src/main/resources/juick.png
+++ /dev/null
Binary files differ