1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
import AbstractService from './AbstractService';
import { IJID } from '../../JID.interface';
import * as NS from '../xmpp/namespace';
import { $iq } from '../../vendor/Strophe';
NS.register('VCARD', 'vcard-temp');
type vCardData = {
[tagName: string]: string | vCardData | vCardData[];
};
export default class Vcard extends AbstractService {
public loadVcard(jid: IJID): Promise<vCardData> {
return this.getVcard(jid).then(this.parseVcard);
}
public getVcard(jid: IJID): Promise<JQuery<XMLDocument>> {
let iq = $iq({
type: 'get',
to: jid.bare,
}).c('vCard', {
xmlns: NS.get('VCARD'),
});
return this.sendIQ(iq).then(stanza => {
(window as any).stanza = stanza;
let vCard = $(stanza).find('vCard');
if (vCard.length === 0) {
//XML BECAUSE OF CASE SENSIVITY
return $($.parseXML('<vCard ' + NS.get('VCARD') + '/>'));
}
let vCardXML: JQuery<XMLDocument> = $($.parseXML(vCard.get(0).outerHTML)).find('>vCard') as any;
return vCardXML;
});
}
public async setAvatar(jid: IJID, avatar: string, mimetype: string) {
//first get the actual vcard to merge image into
const vCard = await this.getVcard(jid);
let photo = vCard.children('PHOTO');
if (avatar && mimetype) {
if (photo.length === 0) {
//XML BECAUSE OF CASE SENSIVITY
vCard.append('<PHOTO><TYPE/><BINVAL/></PHOTO>');
}
photo.find('TYPE').text(mimetype);
photo.find('BINVAL').text(avatar.replace(/^.+;base64,/, ''));
} else {
photo.remove();
}
return this.sendVCard(jid, vCard);
}
private async sendVCard(jid: IJID, newVCard: JQuery<XMLDocument>): Promise<any> {
let setVcardIQStanza = $iq({
type: 'set',
to: jid.bare,
}).cnode(newVCard.get(0));
return this.sendIQ(setVcardIQStanza);
}
private parseVcard = (vCardElement: JQuery<XMLDocument>): vCardData => {
let data: vCardData = {};
if (!vCardElement.length) {
return data;
}
data = this.parseVcardChildren(vCardElement);
return data;
};
private parseVcardChildren = (stanza: JQuery<XMLDocument>): vCardData => {
let self = this;
let data: vCardData = {};
let children: JQuery<XMLDocument> = stanza.children() as any;
children.each(function () {
let item = $(this);
let children = item.children();
let itemName = item.prop('tagName');
let value = null;
if (itemName === 'PHOTO') {
let img = item.find('BINVAL').text();
let type = item.find('TYPE').text();
let src = 'data:' + type + ';base64,' + img; //@REVIEW XSS
//@REVIEW privacy
if (item.find('EXTVAL').length > 0) {
src = item.find('EXTVAL').text();
}
// concat chunks
src = src.replace(/[\t\r\n\f ]/gi, '');
value = {
type,
src,
};
} else if (itemName === 'EMAIL') {
value = item.find('USERID').text();
} else if (children.length > 0) {
value = self.parseVcardChildren(item);
} else {
value = item.text().trim();
}
if (Array.isArray(data[itemName])) {
(data[itemName] as vCardData[]).push(value);
} else if (data[itemName]) {
data[itemName] = [data[itemName], value];
} else {
data[itemName] = value;
}
});
return data;
};
}
|