OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "remoting/signaling/signaling_address.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "remoting/base/name_value_map.h" |
| 9 #include "remoting/base/remoting_bot.h" |
| 10 #include "remoting/base/service_urls.h" |
| 11 #include "remoting/signaling/jid_util.h" |
| 12 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h" |
| 13 |
| 14 namespace remoting { |
| 15 |
| 16 namespace { |
| 17 |
| 18 const char kJingleNamespace[] = "urn:xmpp:jingle:1"; |
| 19 |
| 20 // Represents the XML attrbute names for the various address fields in the |
| 21 // iq stanza. |
| 22 enum class Field { JID, CHANNEL, ENDPOINT_ID }; |
| 23 |
| 24 const NameMapElement<SignalingAddress::Channel> kChannelTypes[] = { |
| 25 {SignalingAddress::Channel::LCS, "lcs"}, |
| 26 {SignalingAddress::Channel::XMPP, "xmpp"}, |
| 27 }; |
| 28 |
| 29 buzz::QName GetQNameByField(Field attr, SignalingAddress::Direction direction) { |
| 30 const char* attribute_name = nullptr; |
| 31 switch (attr) { |
| 32 case Field::JID: |
| 33 attribute_name = (direction == SignalingAddress::FROM) ? "from" : "to"; |
| 34 break; |
| 35 case Field::ENDPOINT_ID: |
| 36 attribute_name = (direction == SignalingAddress::FROM) |
| 37 ? "from-endpoint-id" |
| 38 : "to-endpoint-id"; |
| 39 break; |
| 40 case Field::CHANNEL: |
| 41 attribute_name = |
| 42 (direction == SignalingAddress::FROM) ? "from-channel" : "to-channel"; |
| 43 break; |
| 44 } |
| 45 return buzz::QName("", attribute_name); |
| 46 } |
| 47 |
| 48 } // namespace |
| 49 |
| 50 SignalingAddress::SignalingAddress() |
| 51 : channel_(SignalingAddress::Channel::XMPP) {} |
| 52 |
| 53 SignalingAddress::SignalingAddress(const std::string& jid) |
| 54 : jid_(NormalizeJid(jid)), channel_(SignalingAddress::Channel::XMPP) { |
| 55 DCHECK(!jid.empty()); |
| 56 } |
| 57 |
| 58 SignalingAddress::SignalingAddress(const std::string& jid, |
| 59 const std::string& endpoint_id, |
| 60 Channel channel) |
| 61 : jid_(NormalizeJid(jid)), |
| 62 endpoint_id_(NormalizeJid(endpoint_id)), |
| 63 channel_(channel) { |
| 64 DCHECK(!jid.empty()); |
| 65 } |
| 66 |
| 67 bool SignalingAddress::operator==(const SignalingAddress& other) const { |
| 68 return (other.jid_ == jid_) && (other.endpoint_id_ == endpoint_id_) && |
| 69 (other.channel_ == channel_); |
| 70 } |
| 71 |
| 72 bool SignalingAddress::operator!=(const SignalingAddress& other) const { |
| 73 return !(*this == other); |
| 74 } |
| 75 |
| 76 SignalingAddress SignalingAddress::Parse(const buzz::XmlElement* iq, |
| 77 SignalingAddress::Direction direction, |
| 78 std::string* error) { |
| 79 std::string jid(iq->Attr(GetQNameByField(Field::JID, direction))); |
| 80 if (jid.empty()) { |
| 81 return SignalingAddress(); |
| 82 } |
| 83 |
| 84 const buzz::XmlElement* jingle = |
| 85 iq->FirstNamed(buzz::QName(kJingleNamespace, "jingle")); |
| 86 |
| 87 if (!jingle) { |
| 88 return SignalingAddress(jid); |
| 89 } |
| 90 |
| 91 std::string type(iq->Attr(buzz::QName(std::string(), "type"))); |
| 92 // For error IQs, invert the direction as the jingle node represents the |
| 93 // original request. |
| 94 if (type == "error") { |
| 95 direction = (direction == FROM) ? TO : FROM; |
| 96 } |
| 97 |
| 98 std::string endpoint_id( |
| 99 jingle->Attr(GetQNameByField(Field::ENDPOINT_ID, direction))); |
| 100 std::string channel_str( |
| 101 jingle->Attr(GetQNameByField(Field::CHANNEL, direction))); |
| 102 SignalingAddress::Channel channel; |
| 103 |
| 104 if (channel_str.empty()) { |
| 105 channel = SignalingAddress::Channel::XMPP; |
| 106 } else if (!NameToValue(kChannelTypes, channel_str, &channel)) { |
| 107 *error = "Unknown channel: " + channel_str; |
| 108 return SignalingAddress(); |
| 109 } |
| 110 |
| 111 bool is_lcs = (channel == SignalingAddress::Channel::LCS); |
| 112 |
| 113 if (is_lcs == endpoint_id.empty()) { |
| 114 *error = (is_lcs ? "Missing |endpoint-id| for LCS channel" |
| 115 : "|endpoint_id| should be empty for XMPP channel"); |
| 116 return SignalingAddress(); |
| 117 } |
| 118 |
| 119 if (direction == FROM && is_lcs && !IsValidBotJid(jid)) { |
| 120 *error = "Reject LCS message from untrusted sender: " + jid; |
| 121 return SignalingAddress(); |
| 122 } |
| 123 |
| 124 return SignalingAddress(jid, endpoint_id, channel); |
| 125 } |
| 126 |
| 127 void SignalingAddress::SetInMessage(buzz::XmlElement* iq, |
| 128 Direction direction) const { |
| 129 DCHECK(!empty()); |
| 130 |
| 131 // Always set the JID. |
| 132 iq->SetAttr(GetQNameByField(Field::JID, direction), jid_); |
| 133 |
| 134 // Do not tamper the routing-info in the jingle tag for error IQ's, as |
| 135 // it corresponds to the original message. |
| 136 std::string type(iq->Attr(buzz::QName(std::string(), "type"))); |
| 137 if (type == "error") { |
| 138 return; |
| 139 } |
| 140 |
| 141 buzz::XmlElement* jingle = |
| 142 iq->FirstNamed(buzz::QName(kJingleNamespace, "jingle")); |
| 143 |
| 144 if (jingle) { |
| 145 // Start from a fresh slate regardless of the previous address format. |
| 146 jingle->ClearAttr(GetQNameByField(Field::CHANNEL, direction)); |
| 147 jingle->ClearAttr(GetQNameByField(Field::ENDPOINT_ID, direction)); |
| 148 } |
| 149 |
| 150 // Only set the channel and endpoint_id in the LCS channel. |
| 151 if (channel_ == SignalingAddress::Channel::LCS) { |
| 152 // Can't set LCS address in a non-jingle message; |
| 153 CHECK(jingle); |
| 154 |
| 155 jingle->AddAttr(GetQNameByField(Field::ENDPOINT_ID, direction), |
| 156 endpoint_id_); |
| 157 jingle->AddAttr(GetQNameByField(Field::CHANNEL, direction), |
| 158 ValueToName(kChannelTypes, channel_)); |
| 159 } |
| 160 } |
| 161 |
| 162 } // namespace remoting |
OLD | NEW |