1extern crate minidom;
2extern crate sha2;
3extern crate sha3;
4extern crate blake2;
5extern crate base64;
6
7use minidom::Element;
8
9use error::Error;
10
11use disco::{Feature, Identity, Disco, parse_disco};
12use data_forms::DataForm;
13
14use self::sha2::{Sha256, Sha512, Digest};
15use self::sha3::{Sha3_256, Sha3_512};
16use self::blake2::Blake2b;
17
18fn compute_item(field: &String) -> Vec<u8> {
19 let mut bytes = field.as_bytes().to_vec();
20 bytes.push(0x1f);
21 bytes
22}
23
24fn compute_items<T, F: Fn(&T) -> Vec<u8>>(things: &Vec<T>, separator: u8, encode: F) -> Vec<u8> {
25 let mut string: Vec<u8> = vec!();
26 let mut accumulator: Vec<Vec<u8>> = vec!();
27 for thing in things {
28 let bytes = encode(thing);
29 accumulator.push(bytes);
30 }
31 // This works using the expected i;octet collation.
32 accumulator.sort();
33 for mut bytes in accumulator {
34 string.append(&mut bytes);
35 }
36 string.push(separator);
37 string
38}
39
40fn compute_features(features: &Vec<Feature>) -> Vec<u8> {
41 compute_items(features, 0x1c, |feature| compute_item(&feature.var))
42}
43
44fn compute_identities(identities: &Vec<Identity>) -> Vec<u8> {
45 compute_items(identities, 0x1c, |identity| {
46 let mut bytes = compute_item(&identity.category);
47 bytes.append(&mut compute_item(&identity.type_));
48 bytes.append(&mut compute_item(&identity.xml_lang));
49 bytes.append(&mut compute_item(&identity.name.clone().unwrap_or(String::new())));
50 bytes.push(0x1e);
51 bytes
52 })
53}
54
55fn compute_extensions(extensions: &Vec<DataForm>) -> Vec<u8> {
56 compute_items(extensions, 0x1c, |extension| {
57 compute_items(&extension.fields, 0x1d, |field| {
58 let mut bytes = compute_item(&field.var);
59 bytes.append(&mut compute_items(&field.values, 0x1e,
60 |value| compute_item(value)));
61 bytes
62 })
63 })
64}
65
66pub fn compute_disco(disco: &Disco) -> Vec<u8> {
67 let features_string = compute_features(&disco.features);
68 let identities_string = compute_identities(&disco.identities);
69 let extensions_string = compute_extensions(&disco.extensions);
70
71 let mut final_string = vec!();
72 final_string.extend(features_string);
73 final_string.extend(identities_string);
74 final_string.extend(extensions_string);
75 final_string
76}
77
78pub fn convert_element(root: &Element) -> Result<Vec<u8>, Error> {
79 let disco = parse_disco(root)?;
80 let final_string = compute_disco(&disco);
81 Ok(final_string)
82}
83
84pub fn hash_ecaps2(data: &Vec<u8>, algo: String) -> String {
85 match algo.as_ref() {
86 "sha-256" => {
87 let mut hasher = Sha256::default();
88 hasher.input(data);
89 let hash = hasher.result();
90 base64::encode(&hash)
91 },
92 "sha-512" => {
93 let mut hasher = Sha512::default();
94 hasher.input(data);
95 let hash = hasher.result();
96 base64::encode(&hash)
97 },
98 "sha3-256" => {
99 let mut hasher = Sha3_256::default();
100 hasher.input(data);
101 let hash = hasher.result();
102 base64::encode(&hash)
103 },
104 "sha3-512" => {
105 let mut hasher = Sha3_512::default();
106 hasher.input(data);
107 let hash = hasher.result();
108 base64::encode(&hash)
109 },
110 /*
111 "blake2b-256" => {
112 // TODO: bit length is most likely wrong here!
113 let mut hasher = Blake2b::default();
114 hasher.input(data);
115 let hash = hasher.result();
116 base64::encode(&hash)
117 },
118 "blake2b-512" => {
119 // TODO: bit length is most likely wrong here!
120 let mut hasher = Blake2b::default();
121 hasher.input(data);
122 let hash = hasher.result();
123 base64::encode(&hash)
124 },
125 */
126 _ => panic!(),
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use minidom::Element;
133 use ecaps2;
134
135 #[test]
136 fn test_simple() {
137 let elem: Element = "<query xmlns='http://jabber.org/protocol/disco#info'><identity category='client' type='pc'/><feature var='http://jabber.org/protocol/disco#info'/></query>".parse().unwrap();
138 let ecaps2 = ecaps2::convert_element(&elem).unwrap();
139 assert_eq!(ecaps2.len(), 54);
140 }
141
142 #[test]
143 fn test_xep_ex1() {
144 let elem: Element = r#"
145<query xmlns="http://jabber.org/protocol/disco#info">
146 <identity category="client" name="BombusMod" type="mobile"/>
147 <feature var="http://jabber.org/protocol/si"/>
148 <feature var="http://jabber.org/protocol/bytestreams"/>
149 <feature var="http://jabber.org/protocol/chatstates"/>
150 <feature var="http://jabber.org/protocol/disco#info"/>
151 <feature var="http://jabber.org/protocol/disco#items"/>
152 <feature var="urn:xmpp:ping"/>
153 <feature var="jabber:iq:time"/>
154 <feature var="jabber:iq:privacy"/>
155 <feature var="jabber:iq:version"/>
156 <feature var="http://jabber.org/protocol/rosterx"/>
157 <feature var="urn:xmpp:time"/>
158 <feature var="jabber:x:oob"/>
159 <feature var="http://jabber.org/protocol/ibb"/>
160 <feature var="http://jabber.org/protocol/si/profile/file-transfer"/>
161 <feature var="urn:xmpp:receipts"/>
162 <feature var="jabber:iq:roster"/>
163 <feature var="jabber:iq:last"/>
164</query>
165"#.parse().unwrap();
166 let expected = vec![104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98,
167 101, 114, 46, 111, 114, 103, 47, 112, 114, 111, 116, 111, 99, 111,
168 108, 47, 98, 121, 116, 101, 115, 116, 114, 101, 97, 109, 115, 31,
169 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111,
170 114, 103, 47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 99, 104,
171 97, 116, 115, 116, 97, 116, 101, 115, 31, 104, 116, 116, 112, 58,
172 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114,
173 111, 116, 111, 99, 111, 108, 47, 100, 105, 115, 99, 111, 35, 105,
174 110, 102, 111, 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98,
175 101, 114, 46, 111, 114, 103, 47, 112, 114, 111, 116, 111, 99, 111,
176 108, 47, 100, 105, 115, 99, 111, 35, 105, 116, 101, 109, 115, 31,
177 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111,
178 114, 103, 47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 105, 98,
179 98, 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114,
180 46, 111, 114, 103, 47, 112, 114, 111, 116, 111, 99, 111, 108, 47,
181 114, 111, 115, 116, 101, 114, 120, 31, 104, 116, 116, 112, 58, 47,
182 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114,
183 111, 116, 111, 99, 111, 108, 47, 115, 105, 31, 104, 116, 116, 112,
184 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112,
185 114, 111, 116, 111, 99, 111, 108, 47, 115, 105, 47, 112, 114, 111,
186 102, 105, 108, 101, 47, 102, 105, 108, 101, 45, 116, 114, 97, 110,
187 115, 102, 101, 114, 31, 106, 97, 98, 98, 101, 114, 58, 105, 113,
188 58, 108, 97, 115, 116, 31, 106, 97, 98, 98, 101, 114, 58, 105, 113,
189 58, 112, 114, 105, 118, 97, 99, 121, 31, 106, 97, 98, 98, 101, 114,
190 58, 105, 113, 58, 114, 111, 115, 116, 101, 114, 31, 106, 97, 98,
191 98, 101, 114, 58, 105, 113, 58, 116, 105, 109, 101, 31, 106, 97,
192 98, 98, 101, 114, 58, 105, 113, 58, 118, 101, 114, 115, 105, 111,
193 110, 31, 106, 97, 98, 98, 101, 114, 58, 120, 58, 111, 111, 98, 31,
194 117, 114, 110, 58, 120, 109, 112, 112, 58, 112, 105, 110, 103, 31,
195 117, 114, 110, 58, 120, 109, 112, 112, 58, 114, 101, 99, 101, 105,
196 112, 116, 115, 31, 117, 114, 110, 58, 120, 109, 112, 112, 58, 116,
197 105, 109, 101, 31, 28, 99, 108, 105, 101, 110, 116, 31, 109, 111,
198 98, 105, 108, 101, 31, 31, 66, 111, 109, 98, 117, 115, 77, 111,
199 100, 31, 30, 28, 28];
200 let ecaps2 = ecaps2::convert_element(&elem).unwrap();
201 assert_eq!(ecaps2.len(), 0x1d9);
202 assert_eq!(ecaps2, expected);
203
204 let sha_256 = ecaps2::hash_ecaps2(&ecaps2, String::from("sha-256"));
205 assert_eq!(sha_256, "kzBZbkqJ3ADrj7v08reD1qcWUwNGHaidNUgD7nHpiw8=");
206 let sha3_256 = ecaps2::hash_ecaps2(&ecaps2, String::from("sha3-256"));
207 assert_eq!(sha3_256, "79mdYAfU9rEdTOcWDO7UEAt6E56SUzk/g6TnqUeuD9Q=");
208 }
209
210 #[test]
211 fn test_xep_ex2() {
212 let elem: Element = r#"
213<query xmlns="http://jabber.org/protocol/disco#info">
214 <identity category="client" name="Tkabber" type="pc" xml:lang="en"/>
215 <identity category="client" name="Ткаббер" type="pc" xml:lang="ru"/>
216 <feature var="games:board"/>
217 <feature var="http://jabber.org/protocol/activity"/>
218 <feature var="http://jabber.org/protocol/activity+notify"/>
219 <feature var="http://jabber.org/protocol/bytestreams"/>
220 <feature var="http://jabber.org/protocol/chatstates"/>
221 <feature var="http://jabber.org/protocol/commands"/>
222 <feature var="http://jabber.org/protocol/disco#info"/>
223 <feature var="http://jabber.org/protocol/disco#items"/>
224 <feature var="http://jabber.org/protocol/evil"/>
225 <feature var="http://jabber.org/protocol/feature-neg"/>
226 <feature var="http://jabber.org/protocol/geoloc"/>
227 <feature var="http://jabber.org/protocol/geoloc+notify"/>
228 <feature var="http://jabber.org/protocol/ibb"/>
229 <feature var="http://jabber.org/protocol/iqibb"/>
230 <feature var="http://jabber.org/protocol/mood"/>
231 <feature var="http://jabber.org/protocol/mood+notify"/>
232 <feature var="http://jabber.org/protocol/rosterx"/>
233 <feature var="http://jabber.org/protocol/si"/>
234 <feature var="http://jabber.org/protocol/si/profile/file-transfer"/>
235 <feature var="http://jabber.org/protocol/tune"/>
236 <feature var="http://www.facebook.com/xmpp/messages"/>
237 <feature var="http://www.xmpp.org/extensions/xep-0084.html#ns-metadata+notify"/>
238 <feature var="jabber:iq:avatar"/>
239 <feature var="jabber:iq:browse"/>
240 <feature var="jabber:iq:dtcp"/>
241 <feature var="jabber:iq:filexfer"/>
242 <feature var="jabber:iq:ibb"/>
243 <feature var="jabber:iq:inband"/>
244 <feature var="jabber:iq:jidlink"/>
245 <feature var="jabber:iq:last"/>
246 <feature var="jabber:iq:oob"/>
247 <feature var="jabber:iq:privacy"/>
248 <feature var="jabber:iq:roster"/>
249 <feature var="jabber:iq:time"/>
250 <feature var="jabber:iq:version"/>
251 <feature var="jabber:x:data"/>
252 <feature var="jabber:x:event"/>
253 <feature var="jabber:x:oob"/>
254 <feature var="urn:xmpp:avatar:metadata+notify"/>
255 <feature var="urn:xmpp:ping"/>
256 <feature var="urn:xmpp:receipts"/>
257 <feature var="urn:xmpp:time"/>
258 <x xmlns="jabber:x:data" type="result">
259 <field type="hidden" var="FORM_TYPE">
260 <value>urn:xmpp:dataforms:softwareinfo</value>
261 </field>
262 <field var="software">
263 <value>Tkabber</value>
264 </field>
265 <field var="software_version">
266 <value>0.11.1-svn-20111216-mod (Tcl/Tk 8.6b2)</value>
267 </field>
268 <field var="os">
269 <value>Windows</value>
270 </field>
271 <field var="os_version">
272 <value>XP</value>
273 </field>
274 </x>
275</query>
276"#.parse().unwrap();
277 let expected = vec![103, 97, 109, 101, 115, 58, 98, 111, 97, 114, 100,
278 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46,
279 111, 114, 103, 47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 97,
280 99, 116, 105, 118, 105, 116, 121, 31, 104, 116, 116, 112, 58, 47,
281 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114,
282 111, 116, 111, 99, 111, 108, 47, 97, 99, 116, 105, 118, 105, 116,
283 121, 43, 110, 111, 116, 105, 102, 121, 31, 104, 116, 116, 112, 58,
284 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114,
285 111, 116, 111, 99, 111, 108, 47, 98, 121, 116, 101, 115, 116, 114,
286 101, 97, 109, 115, 31, 104, 116, 116, 112, 58,47, 47, 106, 97, 98,
287 98, 101, 114, 46, 111, 114, 103, 47, 112, 114, 111, 116, 111, 99,
288 111, 108, 47, 99, 104, 97, 116, 115, 116, 97, 116, 101, 115, 31,
289 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111,
290 114, 103, 47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 99, 111,
291 109, 109, 97, 110, 100, 115, 31,104,116, 116, 112, 58, 47, 47, 106,
292 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114, 111, 116,
293 111, 99, 111, 108, 47, 100, 105, 115, 99, 111, 35, 105, 110, 102,
294 111, 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114,
295 46, 111, 114, 103, 47, 112, 114, 111, 116, 111, 99, 111, 108, 47,
296 100, 105, 115, 99, 111, 35, 105, 116, 101, 109, 115, 31, 104, 116,
297 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103,
298 47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 101, 118, 105, 108,
299 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46,
300 111, 114, 103, 47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 102,
301 101, 97, 116, 117, 114, 101, 45, 110, 101, 103, 31, 104, 116, 116,
302 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47,
303 112, 114, 111, 116, 111, 99, 111, 108, 47, 103, 101, 111, 108, 111,
304 99, 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114,
305 46, 111, 114, 103, 47, 112, 114, 111, 116, 111, 99,111, 108, 47,
306 103, 101, 111, 108, 111, 99, 43, 110, 111, 116, 105, 102, 121, 31,
307 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111,
308 114, 103,47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 105, 98,
309 98, 31, 104, 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114,
310 46, 111, 114, 103, 47, 112, 114, 111,116, 111, 99, 111, 108, 47,
311 105, 113, 105, 98, 98, 31, 104, 116, 116, 112, 58, 47, 47, 106, 97,
312 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114, 111, 116,111,
313 99, 111, 108, 47, 109, 111, 111, 100, 31, 104, 116, 116, 112, 58,
314 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114,
315 111, 116, 111, 99, 111,108, 47, 109, 111, 111, 100, 43, 110, 111,
316 116, 105, 102, 121, 31, 104, 116, 116, 112, 58, 47, 47, 106, 97,
317 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114, 111, 116, 111,
318 99, 111, 108, 47, 114, 111, 115, 116, 101, 114, 120, 31, 104, 116,
319 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103,
320 47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 115, 105, 31, 104,
321 116, 116, 112, 58, 47, 47, 106, 97, 98, 98, 101, 114, 46, 111, 114,
322 103, 47, 112, 114, 111, 116, 111, 99, 111, 108, 47, 115, 105, 47,
323 112, 114, 111, 102, 105, 108, 101, 47, 102, 105, 108, 101, 45, 116,
324 114, 97, 110, 115, 102, 101, 114, 31, 104, 116, 116, 112, 58, 47,
325 47, 106, 97, 98, 98, 101, 114, 46, 111, 114, 103, 47, 112, 114,
326 111, 116, 111, 99, 111, 108, 47, 116, 117, 110, 101, 31, 104, 116,
327 116, 112, 58, 47, 47, 119, 119, 119, 46, 102, 97, 99, 101, 98, 111,
328 111, 107, 46, 99, 111, 109, 47, 120, 109, 112, 112, 47, 109, 101,
329 115, 115, 97, 103, 101, 115, 31, 104, 116, 116, 112, 58, 47, 47,
330 119, 119, 119, 46, 120, 109, 112, 112, 46, 111, 114, 103, 47, 101,
331 120, 116, 101, 110, 115, 105, 111, 110, 115, 47, 120, 101, 112, 45,
332 48, 48, 56, 52, 46, 104, 116, 109, 108, 35, 110, 115, 45, 109, 101,
333 116, 97, 100, 97, 116, 97, 43, 110, 111, 116, 105, 102, 121, 31,
334 106, 97, 98, 98, 101, 114,58, 105,113, 58, 97, 118, 97, 116, 97,
335 114, 31, 106, 97, 98, 98, 101, 114, 58, 105, 113, 58, 98, 114, 111,
336 119, 115, 101, 31, 106, 97, 98, 98, 101, 114, 58, 105, 113, 58,
337 100, 116, 99, 112, 31, 106, 97, 98, 98, 101, 114, 58, 105, 113, 58,
338 102, 105, 108, 101, 120, 102, 101, 114, 31, 106, 97, 98, 98, 101,
339 114, 58, 105, 113, 58, 105, 98, 98, 31, 106, 97, 98, 98, 101, 114,
340 58, 105, 113, 58, 105, 110, 98, 97, 110, 100, 31, 106, 97, 98, 98,
341 101, 114, 58, 105, 113, 58, 106, 105, 100, 108, 105, 110, 107, 31,
342 106, 97, 98, 98, 101, 114, 58, 105, 113, 58, 108, 97, 115, 116, 31,
343 106, 97, 98, 98, 101, 114, 58, 105, 113, 58, 111, 111, 98, 31, 106,
344 97,98, 98, 101, 114, 58, 105, 113, 58, 112, 114, 105, 118, 97, 99,
345 121, 31, 106, 97, 98, 98, 101, 114, 58, 105, 113, 58, 114, 111,
346 115, 116, 101, 114,31, 106, 97, 98, 98, 101, 114, 58, 105, 113, 58,
347 116, 105, 109, 101, 31, 106, 97, 98, 98, 101, 114, 58, 105, 113,
348 58, 118, 101, 114, 115, 105, 111, 110, 31, 106, 97, 98, 98, 101,
349 114, 58, 120, 58, 100, 97, 116, 97, 31, 106, 97, 98, 98, 101, 114,
350 58, 120, 58, 101, 118, 101, 110, 116, 31, 106, 97, 98, 98, 101,
351 114, 58, 120, 58, 111, 111, 98, 31, 117, 114, 110, 58, 120, 109,
352 112, 112, 58, 97, 118, 97, 116, 97, 114, 58, 109, 101, 116, 97,
353 100, 97, 116, 97, 43, 110, 111, 116, 105, 102, 121,31, 117, 114,
354 110, 58, 120, 109, 112, 112, 58, 112, 105, 110, 103, 31, 117, 114,
355 110, 58, 120, 109, 112, 112, 58, 114, 101, 99, 101, 105, 112, 116,
356 115, 31, 117, 114, 110, 58, 120, 109, 112, 112, 58, 116, 105, 109,
357 101, 31, 28, 99, 108, 105, 101, 110, 116, 31, 112, 99, 31, 101,
358 110, 31, 84, 107, 97, 98, 98, 101, 114,31, 30, 99, 108, 105, 101,
359 110, 116, 31, 112, 99, 31, 114, 117, 31, 208, 162, 208, 186, 208,
360 176, 208, 177, 208, 177, 208, 181, 209, 128, 31, 30, 28, 70, 79,
361 82, 77, 95, 84, 89, 80, 69, 31, 117, 114, 110, 58, 120, 109, 112,
362 112, 58, 100, 97, 116, 97, 102, 111, 114, 109, 115, 58, 115, 111,
363 102, 116, 119, 97, 114, 101,105, 110, 102, 111, 31, 30, 111, 115,
364 31, 87, 105, 110, 100, 111, 119, 115, 31, 30, 111, 115, 95, 118,
365 101, 114, 115, 105, 111, 110, 31, 88, 80, 31, 30, 115, 111, 102,
366 116, 119, 97, 114, 101, 31, 84, 107, 97, 98, 98, 101, 114, 31, 30,
367 115, 111, 102, 116, 119, 97, 114, 101, 95, 118, 101, 114, 115, 105,
368 111, 110, 31, 48, 46, 49, 49, 46, 49, 45, 115, 118, 110, 45, 50,
369 48, 49, 49, 49, 50, 49, 54, 45, 109, 111, 100, 32, 40, 84, 99, 108,
370 47, 84, 107, 32, 56, 46,54, 98, 50, 41, 31, 30, 29, 28];
371 let ecaps2 = ecaps2::convert_element(&elem).unwrap();
372 assert_eq!(ecaps2.len(), 0x543);
373 assert_eq!(ecaps2, expected);
374
375 let sha_256 = ecaps2::hash_ecaps2(&ecaps2, String::from("sha-256"));
376 assert_eq!(sha_256, "u79ZroNJbdSWhdSp311mddz44oHHPsEBntQ5b1jqBSY=");
377 let sha3_256 = ecaps2::hash_ecaps2(&ecaps2, String::from("sha3-256"));
378 assert_eq!(sha3_256, "XpUJzLAc93258sMECZ3FJpebkzuyNXDzRNwQog8eycg=");
379 }
380}