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