From b8a19617ef2c257e1233ad215836b788fa019afb Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Sun, 18 Feb 2018 00:35:39 +0300 Subject: server: cleanup layout --- .../src/main/java/com/juick/server/XMPPBot.java | 2 +- .../main/java/com/juick/server/XMPPConnection.java | 2 +- .../src/main/java/com/juick/server/XMPPServer.java | 4 +- .../src/main/java/com/juick/server/api/Index.java | 2 +- .../server/configuration/ApiAppConfiguration.java | 5 +- .../juick/server/configuration/JsonpAdvice.java | 31 +++ .../java/com/juick/server/util/JsonpAdvice.java | 31 --- .../juick/server/xmpp/extensions/JuickMessage.java | 162 ++++++++++++++++ .../juick/server/xmpp/extensions/JuickUser.java | 65 +++++++ .../juick/server/xmpp/helpers/JidConverter.java | 13 ++ .../com/juick/server/xmpp/helpers/XMPPStatus.java | 48 +++++ .../juick/server/xmpp/s2s/BasicXmppSession.java | 69 +++++++ .../java/com/juick/server/xmpp/s2s/CacheEntry.java | 40 ++++ .../java/com/juick/server/xmpp/s2s/Connection.java | 139 +++++++++++++ .../com/juick/server/xmpp/s2s/ConnectionIn.java | 216 +++++++++++++++++++++ .../juick/server/xmpp/s2s/ConnectionListener.java | 14 ++ .../com/juick/server/xmpp/s2s/ConnectionOut.java | 167 ++++++++++++++++ .../java/com/juick/server/xmpp/s2s/DNSQueries.java | 65 +++++++ .../com/juick/server/xmpp/s2s/StanzaListener.java | 28 +++ .../juick/server/xmpp/s2s/util/DialbackUtils.java | 36 ++++ .../com/juick/xmpp/extensions/JuickMessage.java | 162 ---------------- .../java/com/juick/xmpp/extensions/JuickUser.java | 65 ------- .../java/com/juick/xmpp/helpers/JidConverter.java | 13 -- .../java/com/juick/xmpp/helpers/XMPPStatus.java | 48 ----- .../java/com/juick/xmpp/s2s/BasicXmppSession.java | 69 ------- .../main/java/com/juick/xmpp/s2s/CacheEntry.java | 40 ---- .../main/java/com/juick/xmpp/s2s/Connection.java | 139 ------------- .../main/java/com/juick/xmpp/s2s/ConnectionIn.java | 216 --------------------- .../com/juick/xmpp/s2s/ConnectionListener.java | 14 -- .../java/com/juick/xmpp/s2s/ConnectionOut.java | 167 ---------------- .../main/java/com/juick/xmpp/s2s/DNSQueries.java | 65 ------- .../java/com/juick/xmpp/s2s/StanzaListener.java | 28 --- .../com/juick/xmpp/s2s/util/DialbackUtils.java | 36 ---- 33 files changed, 1100 insertions(+), 1101 deletions(-) create mode 100644 juick-server/src/main/java/com/juick/server/configuration/JsonpAdvice.java delete mode 100644 juick-server/src/main/java/com/juick/server/util/JsonpAdvice.java create mode 100644 juick-server/src/main/java/com/juick/server/xmpp/extensions/JuickMessage.java create mode 100644 juick-server/src/main/java/com/juick/server/xmpp/extensions/JuickUser.java create mode 100644 juick-server/src/main/java/com/juick/server/xmpp/helpers/JidConverter.java create mode 100644 juick-server/src/main/java/com/juick/server/xmpp/helpers/XMPPStatus.java create mode 100644 juick-server/src/main/java/com/juick/server/xmpp/s2s/BasicXmppSession.java create mode 100644 juick-server/src/main/java/com/juick/server/xmpp/s2s/CacheEntry.java create mode 100644 juick-server/src/main/java/com/juick/server/xmpp/s2s/Connection.java create mode 100644 juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionIn.java create mode 100644 juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionListener.java create mode 100644 juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionOut.java create mode 100644 juick-server/src/main/java/com/juick/server/xmpp/s2s/DNSQueries.java create mode 100644 juick-server/src/main/java/com/juick/server/xmpp/s2s/StanzaListener.java create mode 100644 juick-server/src/main/java/com/juick/server/xmpp/s2s/util/DialbackUtils.java delete mode 100644 juick-server/src/main/java/com/juick/xmpp/extensions/JuickMessage.java delete mode 100644 juick-server/src/main/java/com/juick/xmpp/extensions/JuickUser.java delete mode 100644 juick-server/src/main/java/com/juick/xmpp/helpers/JidConverter.java delete mode 100644 juick-server/src/main/java/com/juick/xmpp/helpers/XMPPStatus.java delete mode 100644 juick-server/src/main/java/com/juick/xmpp/s2s/BasicXmppSession.java delete mode 100644 juick-server/src/main/java/com/juick/xmpp/s2s/CacheEntry.java delete mode 100644 juick-server/src/main/java/com/juick/xmpp/s2s/Connection.java delete mode 100644 juick-server/src/main/java/com/juick/xmpp/s2s/ConnectionIn.java delete mode 100644 juick-server/src/main/java/com/juick/xmpp/s2s/ConnectionListener.java delete mode 100644 juick-server/src/main/java/com/juick/xmpp/s2s/ConnectionOut.java delete mode 100644 juick-server/src/main/java/com/juick/xmpp/s2s/DNSQueries.java delete mode 100644 juick-server/src/main/java/com/juick/xmpp/s2s/StanzaListener.java delete mode 100644 juick-server/src/main/java/com/juick/xmpp/s2s/util/DialbackUtils.java (limited to 'juick-server/src/main') diff --git a/juick-server/src/main/java/com/juick/server/XMPPBot.java b/juick-server/src/main/java/com/juick/server/XMPPBot.java index 21138607..a515d066 100644 --- a/juick-server/src/main/java/com/juick/server/XMPPBot.java +++ b/juick-server/src/main/java/com/juick/server/XMPPBot.java @@ -19,7 +19,7 @@ package com.juick.server; import com.juick.Tag; import com.juick.User; -import com.juick.xmpp.s2s.StanzaListener; +import com.juick.server.xmpp.s2s.StanzaListener; import com.juick.formatters.PlainTextFormatter; import com.juick.server.helpers.TagStats; import com.juick.server.protocol.annotation.UserCommand; diff --git a/juick-server/src/main/java/com/juick/server/XMPPConnection.java b/juick-server/src/main/java/com/juick/server/XMPPConnection.java index f5448880..09c30899 100644 --- a/juick-server/src/main/java/com/juick/server/XMPPConnection.java +++ b/juick-server/src/main/java/com/juick/server/XMPPConnection.java @@ -19,7 +19,7 @@ package com.juick.server; import com.juick.Attachment; import com.juick.User; -import com.juick.xmpp.s2s.BasicXmppSession; +import com.juick.server.xmpp.s2s.BasicXmppSession; import com.juick.server.helpers.UserInfo; import com.juick.service.MessagesService; import com.juick.service.SubscriptionService; diff --git a/juick-server/src/main/java/com/juick/server/XMPPServer.java b/juick-server/src/main/java/com/juick/server/XMPPServer.java index 01437232..86a855a7 100644 --- a/juick-server/src/main/java/com/juick/server/XMPPServer.java +++ b/juick-server/src/main/java/com/juick/server/XMPPServer.java @@ -17,9 +17,9 @@ package com.juick.server; -import com.juick.xmpp.s2s.*; +import com.juick.server.xmpp.s2s.*; import com.juick.service.UserService; -import com.juick.xmpp.extensions.JuickMessage; +import com.juick.server.xmpp.extensions.JuickMessage; import com.juick.xmpp.extensions.StreamError; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/juick-server/src/main/java/com/juick/server/api/Index.java b/juick-server/src/main/java/com/juick/server/api/Index.java index b1d87f67..be79bf98 100644 --- a/juick-server/src/main/java/com/juick/server/api/Index.java +++ b/juick-server/src/main/java/com/juick/server/api/Index.java @@ -20,7 +20,7 @@ package com.juick.server.api; import com.juick.Status; import com.juick.server.WebsocketManager; import com.juick.server.XMPPServer; -import com.juick.xmpp.helpers.XMPPStatus; +import com.juick.server.xmpp.helpers.XMPPStatus; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; diff --git a/juick-server/src/main/java/com/juick/server/configuration/ApiAppConfiguration.java b/juick-server/src/main/java/com/juick/server/configuration/ApiAppConfiguration.java index 21c1238b..55050f7e 100644 --- a/juick-server/src/main/java/com/juick/server/configuration/ApiAppConfiguration.java +++ b/juick-server/src/main/java/com/juick/server/configuration/ApiAppConfiguration.java @@ -17,13 +17,12 @@ package com.juick.server.configuration; -import com.juick.server.ServerManager; import com.juick.server.WebsocketManager; import com.juick.server.component.JuickServerComponent; import com.juick.server.component.JuickServerReconnectManager; import com.juick.service.UserService; -import com.juick.xmpp.helpers.JidConverter; -import com.juick.xmpp.s2s.BasicXmppSession; +import com.juick.server.xmpp.helpers.JidConverter; +import com.juick.server.xmpp.s2s.BasicXmppSession; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.*; import org.springframework.core.convert.ConversionService; diff --git a/juick-server/src/main/java/com/juick/server/configuration/JsonpAdvice.java b/juick-server/src/main/java/com/juick/server/configuration/JsonpAdvice.java new file mode 100644 index 00000000..5cee2974 --- /dev/null +++ b/juick-server/src/main/java/com/juick/server/configuration/JsonpAdvice.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2008-2017, Juick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.juick.server.configuration; + +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice; + +/** + * Created by vitalyster on 25.11.2016. + */ +@ControllerAdvice +public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice { + public JsonpAdvice() { + super("callback"); + } +} diff --git a/juick-server/src/main/java/com/juick/server/util/JsonpAdvice.java b/juick-server/src/main/java/com/juick/server/util/JsonpAdvice.java deleted file mode 100644 index 457a7df7..00000000 --- a/juick-server/src/main/java/com/juick/server/util/JsonpAdvice.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2008-2017, Juick - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package com.juick.server.util; - -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice; - -/** - * Created by vitalyster on 25.11.2016. - */ -@ControllerAdvice -public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice { - public JsonpAdvice() { - super("callback"); - } -} diff --git a/juick-server/src/main/java/com/juick/server/xmpp/extensions/JuickMessage.java b/juick-server/src/main/java/com/juick/server/xmpp/extensions/JuickMessage.java new file mode 100644 index 00000000..6956a99a --- /dev/null +++ b/juick-server/src/main/java/com/juick/server/xmpp/extensions/JuickMessage.java @@ -0,0 +1,162 @@ +/* + * 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 . + */ +package com.juick.server.xmpp.extensions; + +import com.juick.Tag; +import com.juick.xmpp.StanzaChild; +import com.juick.xmpp.utils.XmlUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.StringEscapeUtils; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; +/** + * + * @author Ugnich Anton + */ +public class JuickMessage extends com.juick.Message implements StanzaChild { + public final static String XMLNS = "http://juick.com/message"; + public final static String TagName = "juick"; + private SimpleDateFormat df; + public JuickMessage() { + df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + df.setTimeZone(TimeZone.getTimeZone("UTC")); + } + + @Override + public String getXMLNS() { + return XMLNS; + } + @Override + public JuickMessage parse(XmlPullParser parser) throws XmlPullParserException, IOException, ParseException { + JuickMessage jmsg = new JuickMessage(); + final String sMID = parser.getAttributeValue(null, "mid"); + if (sMID != null) { + jmsg.setMid(Integer.parseInt(sMID)); + } + final String sRID = parser.getAttributeValue(null, "rid"); + if (sRID != null) { + jmsg.setRid(Integer.parseInt(sRID)); + } + final String sReplyTo = parser.getAttributeValue(null, "replyto"); + if (sReplyTo != null) { + jmsg.setReplyto(Integer.parseInt(sReplyTo)); + } + final String sPrivacy = parser.getAttributeValue(null, "privacy"); + if (sPrivacy != null) { + jmsg.setPrivacy(Integer.parseInt(sPrivacy)); + } + final String sFriendsOnly = parser.getAttributeValue(null, "friendsonly"); + if (sFriendsOnly != null) { + jmsg.FriendsOnly = true; + } + final String sReadOnly = parser.getAttributeValue(null, "readonly"); + if (sReadOnly != null) { + jmsg.ReadOnly = true; + } + jmsg.setTimestamp(df.parse(parser.getAttributeValue(null, "ts")).toInstant()); + jmsg.setAttachmentType(parser.getAttributeValue(null, "attach")); + while (parser.next() == XmlPullParser.START_TAG) { + final String tag = parser.getName(); + final String xmlns = parser.getNamespace(); + if (tag.equals("body")) { + jmsg.setText(XmlUtils.getTagText(parser)); + } else if (tag.equals(JuickUser.TagName) && xmlns != null && xmlns.equals(JuickUser.XMLNS)) { + jmsg.setUser(new JuickUser().parse(parser)); + } else if (tag.equals("tag")) { + jmsg.getTags().add(new Tag(XmlUtils.getTagText(parser))); + } else { + XmlUtils.skip(parser); + } + } + return jmsg; + } + @Override + public String toString() { + StringBuilder ret = new StringBuilder("<").append(TagName).append(" xmlns=\"").append(XMLNS).append("\""); + if (getMid() > 0) { + ret.append(" mid=\"").append(getMid()).append("\""); + } + if (getRid() > 0) { + ret.append(" rid=\"").append(getRid()).append("\""); + } + if (getReplyto() > 0) { + ret.append(" replyto=\"").append(getReplyto()).append("\""); + } + ret.append(" privacy=\"").append(getPrivacy()).append("\""); + if (FriendsOnly) { + ret.append(" friendsonly=\"1\""); + } + if (ReadOnly) { + ret.append(" readonly=\"1\""); + } + if (getTimestamp() != null) { + ret.append(" ts=\"").append(df.format(Date.from(getTimestamp()))).append("\""); + } + if (getAttachmentType() != null) { + ret.append(" attach=\"").append(getAttachmentType()).append("\""); + } + ret.append(">"); + if (getUser() != null) { + ret.append(JuickUser.toString(getUser())); + } + if (getText() != null) { + ret.append("").append(StringEscapeUtils.escapeXml10(StringUtils.defaultString(getText()))).append(""); + } + for (Tag Tag : getTags()) { + ret.append("").append(StringEscapeUtils.escapeXml10(Tag.getName())).append(""); + } + ret.append(""); + return ret.toString(); + } + @Override + public boolean equals(Object obj) { + if (!(obj instanceof JuickMessage)) { + return false; + } + JuickMessage jmsg = (JuickMessage) obj; + return (this.getMid() == jmsg.getMid() && this.getRid() == jmsg.getRid()); + } + @Override + public int compareTo(Object obj) throws ClassCastException { + if (!(obj instanceof JuickMessage)) { + throw new ClassCastException(); + } + JuickMessage jmsg = (JuickMessage) obj; + if (this.getMid() != jmsg.getMid()) { + if (this.getMid() > jmsg.getMid()) { + return -1; + } else { + return 1; + } + } + if (this.getRid() != jmsg.getRid()) { + if (this.getRid() < jmsg.getRid()) { + return -1; + } else { + return 1; + } + } + return 0; + } +} \ No newline at end of file diff --git a/juick-server/src/main/java/com/juick/server/xmpp/extensions/JuickUser.java b/juick-server/src/main/java/com/juick/server/xmpp/extensions/JuickUser.java new file mode 100644 index 00000000..534efcc9 --- /dev/null +++ b/juick-server/src/main/java/com/juick/server/xmpp/extensions/JuickUser.java @@ -0,0 +1,65 @@ +/* + * 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 . + */ +package com.juick.server.xmpp.extensions; +import com.juick.xmpp.StanzaChild; +import com.juick.xmpp.utils.XmlUtils; +import org.apache.commons.text.StringEscapeUtils; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +/** + * + * @author Ugnich Anton + */ +public class JuickUser extends com.juick.User implements StanzaChild { + public final static String XMLNS = "http://juick.com/user"; + public final static String TagName = "user"; + public JuickUser() { + } + @Override + public String getXMLNS() { + return XMLNS; + } + @Override + public JuickUser parse(final XmlPullParser parser) throws XmlPullParserException, IOException { + JuickUser juser = new JuickUser(); + String strUID = parser.getAttributeValue(null, "uid"); + if (strUID != null) { + juser.setUid(Integer.parseInt(strUID)); + } + juser.setName(parser.getAttributeValue(null, "uname")); + XmlUtils.skip(parser); + return juser; + } + public static String toString(com.juick.User user) { + String str = "<" + TagName + " xmlns='" + XMLNS + "'"; + if (user.getUid() > 0) { + str += " uid='" + user.getUid() + "'"; + } + if (user.getName() != null && user.getName().length() > 0) { + str += " uname='" + StringEscapeUtils.escapeXml10(user.getName()) + "'"; + } + str += "/>"; + return str; + } + @Override + public String toString() { + return toString(this); + } +} \ No newline at end of file diff --git a/juick-server/src/main/java/com/juick/server/xmpp/helpers/JidConverter.java b/juick-server/src/main/java/com/juick/server/xmpp/helpers/JidConverter.java new file mode 100644 index 00000000..ca25c4b8 --- /dev/null +++ b/juick-server/src/main/java/com/juick/server/xmpp/helpers/JidConverter.java @@ -0,0 +1,13 @@ +package com.juick.server.xmpp.helpers; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.Nullable; +import rocks.xmpp.addr.Jid; + +public class JidConverter implements Converter { + @Nullable + @Override + public Jid convert(String jidStr) { + return Jid.of(jidStr); + } +} 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 new file mode 100644 index 00000000..7978ceb3 --- /dev/null +++ b/juick-server/src/main/java/com/juick/server/xmpp/helpers/XMPPStatus.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008-2017, Juick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.juick.server.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 inbound; + private Set outbound; + + public List getInbound() { + return inbound; + } + + public void setInbound(List inbound) { + this.inbound = inbound; + } + + public Set getOutbound() { + return outbound; + } + + public void setOutbound(Set outbound) { + this.outbound = outbound; + } +} diff --git a/juick-server/src/main/java/com/juick/server/xmpp/s2s/BasicXmppSession.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/BasicXmppSession.java new file mode 100644 index 00000000..647f2717 --- /dev/null +++ b/juick-server/src/main/java/com/juick/server/xmpp/s2s/BasicXmppSession.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2008-2017, Juick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.juick.server.xmpp.s2s; + +import rocks.xmpp.addr.Jid; +import rocks.xmpp.core.XmppException; +import rocks.xmpp.core.session.ConnectionConfiguration; +import rocks.xmpp.core.session.XmppSession; +import rocks.xmpp.core.session.XmppSessionConfiguration; +import rocks.xmpp.core.stanza.model.IQ; +import rocks.xmpp.core.stanza.model.Message; +import rocks.xmpp.core.stanza.model.Presence; +import rocks.xmpp.core.stanza.model.server.ServerIQ; +import rocks.xmpp.core.stanza.model.server.ServerMessage; +import rocks.xmpp.core.stanza.model.server.ServerPresence; +import rocks.xmpp.core.stream.model.StreamElement; + +/** + * Created by vitalyster on 06.02.2017. + */ +public class BasicXmppSession extends XmppSession { + protected BasicXmppSession(String xmppServiceDomain, XmppSessionConfiguration configuration, ConnectionConfiguration... connectionConfigurations) { + super(xmppServiceDomain, configuration, connectionConfigurations); + } + + public static BasicXmppSession create(String xmppServiceDomain, XmppSessionConfiguration configuration) { + BasicXmppSession session = new BasicXmppSession(xmppServiceDomain, configuration); + notifyCreationListeners(session); + return session; + } + + @Override + public void connect(Jid from) throws XmppException { + + } + + @Override + public Jid getConnectedResource() { + return null; + } + + @Override + protected StreamElement prepareElement(StreamElement element) { + if (element instanceof Message) { + element = ServerMessage.from((Message) element); + } else if (element instanceof Presence) { + element = ServerPresence.from((Presence) element); + } else if (element instanceof IQ) { + element = ServerIQ.from((IQ) element); + } + + return element; + } +} 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 new file mode 100644 index 00000000..33e875bd --- /dev/null +++ b/juick-server/src/main/java/com/juick/server/xmpp/s2s/CacheEntry.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2008-2017, Juick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.juick.server.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 new file mode 100644 index 00000000..d745a406 --- /dev/null +++ b/juick-server/src/main/java/com/juick/server/xmpp/s2s/Connection.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2008-2017, Juick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.juick.server.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 += ">...\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.info("closing stream {}", streamID); + } + + try { + writer.write(""); + } 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 new file mode 100644 index 00000000..a658dbde --- /dev/null +++ b/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionIn.java @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2008-2017, Juick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.juick.server.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 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.info("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(""); + logger.info("stream from {} {} dialback verify valid", vfrom, streamID); + } else { + sendStanza(""); + logger.warn("stream from {} {} dialback verify invalid", vfrom, streamID); + } + } else if (tag.equals("presence") && checkFromTo(parser)) { + String xml = XmlUtils.parseToString(parser, false); + logger.info("stream {} presence: {}", streamID, xml); + xmpp.onStanzaReceived(xml); + } else if (tag.equals("message") && checkFromTo(parser)) { + updateTsRemoteData(); + String xml = XmlUtils.parseToString(parser, false); + logger.info("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.info("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.warn("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.info("stream {} closed (dirty)", streamID); + xmpp.removeConnectionIn(this); + closeConnection(); + } catch (Exception e) { + logger.warn("stream {} error {}", streamID, e); + xmpp.removeConnectionIn(this); + closeConnection(); + } + } + + void updateTsRemoteData() { + received = Instant.now(); + } + + void sendOpenStream(String from, boolean xmppversionnew) throws IOException { + String openStream = ""; + if (xmppversionnew) { + openStream += ""; + if (listener != null && !isSecured() && !Arrays.asList(xmpp.brokenSSLhosts).contains(from)) { + openStream += ""; + } + openStream += ""; + } + sendStanza(openStream); + } + + public void sendDialbackResult(Jid sfrom, String type) { + sendStanza(""); + if (type.equals("valid")) { + from.add(sfrom); + logger.info("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 jidto = Jid.of(cto); + if (jidto.getDomain().equals(xmpp.getJid().toEscapedString())) { + 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 new file mode 100644 index 00000000..efac8732 --- /dev/null +++ b/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionListener.java @@ -0,0 +1,14 @@ +package com.juick.server.xmpp.s2s; + +import com.juick.xmpp.extensions.StreamError; + +public interface ConnectionListener { + 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 new file mode 100644 index 00000000..fb95f0e4 --- /dev/null +++ b/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionOut.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2008-2017, Juick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.juick.server.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(""); + } + + void processDialback() throws Exception { + if (checkSID != null) { + sendDialbackVerify(checkSID, dbKey); + } + send("" + + dbKey + ""); + } + + @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.info("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.info("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.info("stream to {} {} securing", to.toEscapedString(), streamID); + send(""); + } 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("" + + key + ""); + } + 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 new file mode 100644 index 00000000..3d12ed35 --- /dev/null +++ b/juick-server/src/main/java/com/juick/server/xmpp/s2s/DNSQueries.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2008-2017, Juick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.juick.server.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 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.info("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 new file mode 100644 index 00000000..6932298f --- /dev/null +++ b/juick-server/src/main/java/com/juick/server/xmpp/s2s/StanzaListener.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2008-2017, Juick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.juick.server.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 new file mode 100644 index 00000000..71405f34 --- /dev/null +++ b/juick-server/src/main/java/com/juick/server/xmpp/s2s/util/DialbackUtils.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2008-2017, Juick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.juick.server.xmpp.s2s.util; + +import org.apache.commons.codec.digest.DigestUtils; +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 HmacUtils.hmacSha256Hex(DigestUtils.sha256(secret), + (to.toEscapedString() + " " + from.toEscapedString() + " " + id).getBytes()); + } +} diff --git a/juick-server/src/main/java/com/juick/xmpp/extensions/JuickMessage.java b/juick-server/src/main/java/com/juick/xmpp/extensions/JuickMessage.java deleted file mode 100644 index c28eee14..00000000 --- a/juick-server/src/main/java/com/juick/xmpp/extensions/JuickMessage.java +++ /dev/null @@ -1,162 +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 . - */ -package com.juick.xmpp.extensions; - -import com.juick.Tag; -import com.juick.xmpp.StanzaChild; -import com.juick.xmpp.utils.XmlUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.text.StringEscapeUtils; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; -/** - * - * @author Ugnich Anton - */ -public class JuickMessage extends com.juick.Message implements StanzaChild { - public final static String XMLNS = "http://juick.com/message"; - public final static String TagName = "juick"; - private SimpleDateFormat df; - public JuickMessage() { - df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - df.setTimeZone(TimeZone.getTimeZone("UTC")); - } - - @Override - public String getXMLNS() { - return XMLNS; - } - @Override - public JuickMessage parse(XmlPullParser parser) throws XmlPullParserException, IOException, ParseException { - JuickMessage jmsg = new JuickMessage(); - final String sMID = parser.getAttributeValue(null, "mid"); - if (sMID != null) { - jmsg.setMid(Integer.parseInt(sMID)); - } - final String sRID = parser.getAttributeValue(null, "rid"); - if (sRID != null) { - jmsg.setRid(Integer.parseInt(sRID)); - } - final String sReplyTo = parser.getAttributeValue(null, "replyto"); - if (sReplyTo != null) { - jmsg.setReplyto(Integer.parseInt(sReplyTo)); - } - final String sPrivacy = parser.getAttributeValue(null, "privacy"); - if (sPrivacy != null) { - jmsg.setPrivacy(Integer.parseInt(sPrivacy)); - } - final String sFriendsOnly = parser.getAttributeValue(null, "friendsonly"); - if (sFriendsOnly != null) { - jmsg.FriendsOnly = true; - } - final String sReadOnly = parser.getAttributeValue(null, "readonly"); - if (sReadOnly != null) { - jmsg.ReadOnly = true; - } - jmsg.setTimestamp(df.parse(parser.getAttributeValue(null, "ts")).toInstant()); - jmsg.setAttachmentType(parser.getAttributeValue(null, "attach")); - while (parser.next() == XmlPullParser.START_TAG) { - final String tag = parser.getName(); - final String xmlns = parser.getNamespace(); - if (tag.equals("body")) { - jmsg.setText(XmlUtils.getTagText(parser)); - } else if (tag.equals(JuickUser.TagName) && xmlns != null && xmlns.equals(JuickUser.XMLNS)) { - jmsg.setUser(new JuickUser().parse(parser)); - } else if (tag.equals("tag")) { - jmsg.getTags().add(new Tag(XmlUtils.getTagText(parser))); - } else { - XmlUtils.skip(parser); - } - } - return jmsg; - } - @Override - public String toString() { - StringBuilder ret = new StringBuilder("<").append(TagName).append(" xmlns=\"").append(XMLNS).append("\""); - if (getMid() > 0) { - ret.append(" mid=\"").append(getMid()).append("\""); - } - if (getRid() > 0) { - ret.append(" rid=\"").append(getRid()).append("\""); - } - if (getReplyto() > 0) { - ret.append(" replyto=\"").append(getReplyto()).append("\""); - } - ret.append(" privacy=\"").append(getPrivacy()).append("\""); - if (FriendsOnly) { - ret.append(" friendsonly=\"1\""); - } - if (ReadOnly) { - ret.append(" readonly=\"1\""); - } - if (getTimestamp() != null) { - ret.append(" ts=\"").append(df.format(Date.from(getTimestamp()))).append("\""); - } - if (getAttachmentType() != null) { - ret.append(" attach=\"").append(getAttachmentType()).append("\""); - } - ret.append(">"); - if (getUser() != null) { - ret.append(JuickUser.toString(getUser())); - } - if (getText() != null) { - ret.append("").append(StringEscapeUtils.escapeXml10(StringUtils.defaultString(getText()))).append(""); - } - for (Tag Tag : getTags()) { - ret.append("").append(StringEscapeUtils.escapeXml10(Tag.getName())).append(""); - } - ret.append(""); - return ret.toString(); - } - @Override - public boolean equals(Object obj) { - if (!(obj instanceof JuickMessage)) { - return false; - } - JuickMessage jmsg = (JuickMessage) obj; - return (this.getMid() == jmsg.getMid() && this.getRid() == jmsg.getRid()); - } - @Override - public int compareTo(Object obj) throws ClassCastException { - if (!(obj instanceof JuickMessage)) { - throw new ClassCastException(); - } - JuickMessage jmsg = (JuickMessage) obj; - if (this.getMid() != jmsg.getMid()) { - if (this.getMid() > jmsg.getMid()) { - return -1; - } else { - return 1; - } - } - if (this.getRid() != jmsg.getRid()) { - if (this.getRid() < jmsg.getRid()) { - return -1; - } else { - return 1; - } - } - return 0; - } -} \ No newline at end of file diff --git a/juick-server/src/main/java/com/juick/xmpp/extensions/JuickUser.java b/juick-server/src/main/java/com/juick/xmpp/extensions/JuickUser.java deleted file mode 100644 index 10d2b564..00000000 --- a/juick-server/src/main/java/com/juick/xmpp/extensions/JuickUser.java +++ /dev/null @@ -1,65 +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 . - */ -package com.juick.xmpp.extensions; -import com.juick.xmpp.StanzaChild; -import com.juick.xmpp.utils.XmlUtils; -import org.apache.commons.text.StringEscapeUtils; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -/** - * - * @author Ugnich Anton - */ -public class JuickUser extends com.juick.User implements StanzaChild { - public final static String XMLNS = "http://juick.com/user"; - public final static String TagName = "user"; - public JuickUser() { - } - @Override - public String getXMLNS() { - return XMLNS; - } - @Override - public JuickUser parse(final XmlPullParser parser) throws XmlPullParserException, IOException { - JuickUser juser = new JuickUser(); - String strUID = parser.getAttributeValue(null, "uid"); - if (strUID != null) { - juser.setUid(Integer.parseInt(strUID)); - } - juser.setName(parser.getAttributeValue(null, "uname")); - XmlUtils.skip(parser); - return juser; - } - public static String toString(com.juick.User user) { - String str = "<" + TagName + " xmlns='" + XMLNS + "'"; - if (user.getUid() > 0) { - str += " uid='" + user.getUid() + "'"; - } - if (user.getName() != null && user.getName().length() > 0) { - str += " uname='" + StringEscapeUtils.escapeXml10(user.getName()) + "'"; - } - str += "/>"; - return str; - } - @Override - public String toString() { - return toString(this); - } -} \ No newline at end of file diff --git a/juick-server/src/main/java/com/juick/xmpp/helpers/JidConverter.java b/juick-server/src/main/java/com/juick/xmpp/helpers/JidConverter.java deleted file mode 100644 index 253c50f8..00000000 --- a/juick-server/src/main/java/com/juick/xmpp/helpers/JidConverter.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.juick.xmpp.helpers; - -import org.springframework.core.convert.converter.Converter; -import org.springframework.lang.Nullable; -import rocks.xmpp.addr.Jid; - -public class JidConverter implements Converter { - @Nullable - @Override - public Jid convert(String jidStr) { - return Jid.of(jidStr); - } -} diff --git a/juick-server/src/main/java/com/juick/xmpp/helpers/XMPPStatus.java b/juick-server/src/main/java/com/juick/xmpp/helpers/XMPPStatus.java deleted file mode 100644 index a7fa1bce..00000000 --- a/juick-server/src/main/java/com/juick/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 . - */ - -package com.juick.xmpp.helpers; - -import com.juick.xmpp.s2s.ConnectionIn; -import com.juick.xmpp.s2s.ConnectionOut; - -import java.util.List; -import java.util.Set; - -/** - * Created by vitalyster on 16.02.2017. - */ -public class XMPPStatus { - private List inbound; - private Set outbound; - - public List getInbound() { - return inbound; - } - - public void setInbound(List inbound) { - this.inbound = inbound; - } - - public Set getOutbound() { - return outbound; - } - - public void setOutbound(Set outbound) { - this.outbound = outbound; - } -} diff --git a/juick-server/src/main/java/com/juick/xmpp/s2s/BasicXmppSession.java b/juick-server/src/main/java/com/juick/xmpp/s2s/BasicXmppSession.java deleted file mode 100644 index 856d757b..00000000 --- a/juick-server/src/main/java/com/juick/xmpp/s2s/BasicXmppSession.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2008-2017, Juick - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package com.juick.xmpp.s2s; - -import rocks.xmpp.addr.Jid; -import rocks.xmpp.core.XmppException; -import rocks.xmpp.core.session.ConnectionConfiguration; -import rocks.xmpp.core.session.XmppSession; -import rocks.xmpp.core.session.XmppSessionConfiguration; -import rocks.xmpp.core.stanza.model.IQ; -import rocks.xmpp.core.stanza.model.Message; -import rocks.xmpp.core.stanza.model.Presence; -import rocks.xmpp.core.stanza.model.server.ServerIQ; -import rocks.xmpp.core.stanza.model.server.ServerMessage; -import rocks.xmpp.core.stanza.model.server.ServerPresence; -import rocks.xmpp.core.stream.model.StreamElement; - -/** - * Created by vitalyster on 06.02.2017. - */ -public class BasicXmppSession extends XmppSession { - protected BasicXmppSession(String xmppServiceDomain, XmppSessionConfiguration configuration, ConnectionConfiguration... connectionConfigurations) { - super(xmppServiceDomain, configuration, connectionConfigurations); - } - - public static BasicXmppSession create(String xmppServiceDomain, XmppSessionConfiguration configuration) { - BasicXmppSession session = new BasicXmppSession(xmppServiceDomain, configuration); - notifyCreationListeners(session); - return session; - } - - @Override - public void connect(Jid from) throws XmppException { - - } - - @Override - public Jid getConnectedResource() { - return null; - } - - @Override - protected StreamElement prepareElement(StreamElement element) { - if (element instanceof Message) { - element = ServerMessage.from((Message) element); - } else if (element instanceof Presence) { - element = ServerPresence.from((Presence) element); - } else if (element instanceof IQ) { - element = ServerIQ.from((IQ) element); - } - - return element; - } -} diff --git a/juick-server/src/main/java/com/juick/xmpp/s2s/CacheEntry.java b/juick-server/src/main/java/com/juick/xmpp/s2s/CacheEntry.java deleted file mode 100644 index 580682cb..00000000 --- a/juick-server/src/main/java/com/juick/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 . - */ - -package com.juick.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/xmpp/s2s/Connection.java b/juick-server/src/main/java/com/juick/xmpp/s2s/Connection.java deleted file mode 100644 index 638e3b58..00000000 --- a/juick-server/src/main/java/com/juick/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 . - */ - -package com.juick.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 += ">...\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.info("closing stream {}", streamID); - } - - try { - writer.write(""); - } 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/xmpp/s2s/ConnectionIn.java b/juick-server/src/main/java/com/juick/xmpp/s2s/ConnectionIn.java deleted file mode 100644 index 94da89d2..00000000 --- a/juick-server/src/main/java/com/juick/xmpp/s2s/ConnectionIn.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (C) 2008-2017, Juick - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package com.juick.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 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.info("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(""); - logger.info("stream from {} {} dialback verify valid", vfrom, streamID); - } else { - sendStanza(""); - logger.warn("stream from {} {} dialback verify invalid", vfrom, streamID); - } - } else if (tag.equals("presence") && checkFromTo(parser)) { - String xml = XmlUtils.parseToString(parser, false); - logger.info("stream {} presence: {}", streamID, xml); - xmpp.onStanzaReceived(xml); - } else if (tag.equals("message") && checkFromTo(parser)) { - updateTsRemoteData(); - String xml = XmlUtils.parseToString(parser, false); - logger.info("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.info("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.warn("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.info("stream {} closed (dirty)", streamID); - xmpp.removeConnectionIn(this); - closeConnection(); - } catch (Exception e) { - logger.warn("stream {} error {}", streamID, e); - xmpp.removeConnectionIn(this); - closeConnection(); - } - } - - void updateTsRemoteData() { - received = Instant.now(); - } - - void sendOpenStream(String from, boolean xmppversionnew) throws IOException { - String openStream = ""; - if (xmppversionnew) { - openStream += ""; - if (listener != null && !isSecured() && !Arrays.asList(xmpp.brokenSSLhosts).contains(from)) { - openStream += ""; - } - openStream += ""; - } - sendStanza(openStream); - } - - public void sendDialbackResult(Jid sfrom, String type) { - sendStanza(""); - if (type.equals("valid")) { - from.add(sfrom); - logger.info("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 jidto = Jid.of(cto); - if (jidto.getDomain().equals(xmpp.getJid().toEscapedString())) { - 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/xmpp/s2s/ConnectionListener.java b/juick-server/src/main/java/com/juick/xmpp/s2s/ConnectionListener.java deleted file mode 100644 index 76bc8bdc..00000000 --- a/juick-server/src/main/java/com/juick/xmpp/s2s/ConnectionListener.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.juick.xmpp.s2s; - -import com.juick.xmpp.extensions.StreamError; - -public interface ConnectionListener { - 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/xmpp/s2s/ConnectionOut.java b/juick-server/src/main/java/com/juick/xmpp/s2s/ConnectionOut.java deleted file mode 100644 index 6c8c9782..00000000 --- a/juick-server/src/main/java/com/juick/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 . - */ - -package com.juick.xmpp.s2s; - -import com.juick.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(""); - } - - void processDialback() throws Exception { - if (checkSID != null) { - sendDialbackVerify(checkSID, dbKey); - } - send("" + - dbKey + ""); - } - - @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.info("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.info("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.info("stream to {} {} securing", to.toEscapedString(), streamID); - send(""); - } 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("" + - key + ""); - } - 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/xmpp/s2s/DNSQueries.java b/juick-server/src/main/java/com/juick/xmpp/s2s/DNSQueries.java deleted file mode 100644 index 47b01d7e..00000000 --- a/juick-server/src/main/java/com/juick/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 . - */ - -package com.juick.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 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.info("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/xmpp/s2s/StanzaListener.java b/juick-server/src/main/java/com/juick/xmpp/s2s/StanzaListener.java deleted file mode 100644 index 324a0aa8..00000000 --- a/juick-server/src/main/java/com/juick/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 . - */ - -package com.juick.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/xmpp/s2s/util/DialbackUtils.java b/juick-server/src/main/java/com/juick/xmpp/s2s/util/DialbackUtils.java deleted file mode 100644 index a7646deb..00000000 --- a/juick-server/src/main/java/com/juick/xmpp/s2s/util/DialbackUtils.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2008-2017, Juick - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package com.juick.xmpp.s2s.util; - -import org.apache.commons.codec.digest.DigestUtils; -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 HmacUtils.hmacSha256Hex(DigestUtils.sha256(secret), - (to.toEscapedString() + " " + from.toEscapedString() + " " + id).getBytes()); - } -} -- cgit v1.2.3