UNPKG

@vlad8096/stanza

Version:

Modern XMPP in the browser, with a JSON API

1,121 lines (1,112 loc) 529 kB
import { __awaiter } from 'tslib'; import { priorityQueue } from 'async'; import { EventEmitter } from 'events'; import Punycode from 'punycode'; import { Transform, Duplex } from 'readable-stream'; import { getMediaSections, getDescription, matchPrefix, getKind, isRejected, parseMLine, getDirection, getMid, getIceParameters, getDtlsParameters, parseRtpParameters, parseRtpEncodingParameters, parseRtcpParameters, parseMsid, parseSctpDescription, parseCandidate, writeSessionBoilerplate, writeSctpDescription, writeRtpDescription, writeRtcpParameters, writeIceParameters, writeDtlsParameters, writeCandidate } from 'sdp'; const MAX_SEQ = Math.pow(2, 32); const mod = (v, n) => ((v % n) + n) % n; class StreamManagement extends EventEmitter { constructor() { super(); this.allowResume = true; this.lastAck = 0; this.handled = 0; this.unacked = []; this.inboundStarted = false; this.outboundStarted = false; this.id = undefined; this.jid = undefined; this.allowResume = true; this.started = false; this.cacheHandler = () => undefined; this._reset(); } get started() { return this.outboundStarted && this.inboundStarted; } set started(value) { if (!value) { this.outboundStarted = false; this.inboundStarted = false; } } get resumable() { return this.started && this.allowResume; } load(opts) { var _a; this.id = opts.id; this.allowResume = (_a = opts.allowResume) !== null && _a !== void 0 ? _a : true; this.handled = opts.handled; this.lastAck = opts.lastAck; this.unacked = opts.unacked; this.emit('prebound', opts.jid); } cache(handler) { this.cacheHandler = handler; } bind(jid) { return __awaiter(this, void 0, void 0, function* () { this.jid = jid; yield this._cache(); }); } enable() { return __awaiter(this, void 0, void 0, function* () { this.emit('send', { allowResumption: this.allowResume, type: 'enable' }); }); } resume() { return __awaiter(this, void 0, void 0, function* () { this.emit('send', { handled: this.handled, previousSession: this.id, type: 'resume' }); }); } enabled(resp) { return __awaiter(this, void 0, void 0, function* () { this.id = resp.id; this.handled = 0; this.inboundStarted = true; yield this._cache(); }); } resumed(resp) { return __awaiter(this, void 0, void 0, function* () { this.id = resp.previousSession; this.inboundStarted = true; yield this.process(resp, true); yield this._cache(); }); } failed(resp) { return __awaiter(this, void 0, void 0, function* () { // Resumption might fail, but the server can still tell us how far // the old session progressed. yield this.process(resp); // We alert that any remaining unacked stanzas failed to send. It has // been too long for auto-retrying these to be the right thing to do. for (const [kind, stanza] of this.unacked) { this.emit('failed', { kind, stanza }); } this._reset(); yield this._cache(); }); } ack() { this.emit('send', { handled: this.handled, type: 'ack' }); } request() { this.emit('send', { type: 'request' }); } process(ack, resend = false) { return __awaiter(this, void 0, void 0, function* () { if (ack.handled === undefined) { return; } const numAcked = mod(ack.handled - this.lastAck, MAX_SEQ); for (let i = 0; i < numAcked && this.unacked.length > 0; i++) { const [kind, stanza] = this.unacked.shift(); this.emit('acked', { kind, stanza }); } this.lastAck = ack.handled; if (resend) { const resendUnacked = this.unacked; this.unacked = []; if (resendUnacked.length) { this.emit('begin-resend'); for (const [kind, stanza] of resendUnacked) { this.emit('resend', { kind, stanza }); } this.emit('end-resend'); } } yield this._cache(); }); } track(kind, stanza) { return __awaiter(this, void 0, void 0, function* () { if (kind === 'sm' && (stanza.type === 'enable' || stanza.type === 'resume')) { if (stanza.type !== 'resume') { this.handled = 0; } this.outboundStarted = true; yield this._cache(); return false; } if (!this.outboundStarted) { return false; } if (kind !== 'message' && kind !== 'presence' && kind !== 'iq') { return false; } this.unacked.push([kind, stanza]); yield this._cache(); return true; }); } handle() { return __awaiter(this, void 0, void 0, function* () { if (this.inboundStarted) { this.handled = mod(this.handled + 1, MAX_SEQ); yield this._cache(); } }); } hibernate() { return __awaiter(this, void 0, void 0, function* () { if (!this.resumable) { return this.shutdown(); } for (const [kind, stanza] of this.unacked) { this.emit('hibernated', { kind, stanza }); } }); } shutdown() { return __awaiter(this, void 0, void 0, function* () { return this.failed({ type: 'failed' }); }); } _cache() { return __awaiter(this, void 0, void 0, function* () { try { yield this.cacheHandler({ allowResume: this.allowResume, handled: this.handled, id: this.id, jid: this.jid, lastAck: this.lastAck, unacked: this.unacked }); } catch (err) { // TODO: Is there a good way to handle this? // istanbul ignore next console.error('Failed to cache stream state', err); } }); } _reset() { this.id = ''; this.inboundStarted = false; this.outboundStarted = false; this.lastAck = 0; this.handled = 0; this.unacked = []; } } const TABLE_DATA = { 'A.1': { r: 'hk:if|le:lf|nf:nv|qg:qv|rg:rj|rm:rp|rr:rt|rv:s3|vn:vv|17m:17n|17q:17v|18g:19g|1an:1ao|1cb:1cg|1e5:1ef|1fb:1ff|1fl:1gb|1gd:1gq|1gs:1gu|1hr:1hv|1im:1iv|1ne:1nf|1pd:1pf|1qb:1rv|1ti:280|29q:29r|2ae:2af|2al:2an|2bh:2c0|2cd:2ce|2ch:2ci|2dj:2dl|2dq:2dr|2e5:2e6|2e9:2ea|2ee:2em|2eo:2er|2f4:2f5|2fr:2g1|2g3:2g4|2gb:2ge|2gh:2gi|2hq:2hr|2i3:2i6|2i9:2ia|2ie:2io|2iv:2j5|2jl:2k0|2lq:2lr|2me:2mf|2mh:2mv|2n1:2n5|2ng:2o0|2od:2oe|2oh:2oi|2pk:2pl|2pq:2pr|2q4:2q6|2q9:2qa|2qe:2ql|2qo:2qr|2r2:2r5|2rh:2s1|2sb:2sd|2sm:2so|2t0:2t2|2t5:2t7|2tb:2td|2tq:2tt|2u3:2u5|2ue:2um|2uo:2v6|2vj:300|31q:31t|32e:32k|32n:32v|332:335|33g:341|35q:35t|36e:36k|36n:36t|372:375|37g:381|39q:39t|3a4:3a5|3ae:3am|3ao:3av|3b2:3b5|3bg:3c1|3cn:3cp|3du:3dv|3e7:3e9|3eb:3ee|3f0:3fh|3fl:3g0|3hr:3hu|3is:3k0|3k5:3k6|3kb:3kc|3ke:3kj|3l8:3l9|3lu:3lv|3me:3mf|3mq:3mr|3mu:3nv|3rb:3rg|3sc:3sf|3ud:3ue|3ug:3vv|41j:41l|41q:41v|42q:44v|466:46f|47p:47q|47s:47v|4aq:4au|4d3:4d7|4fq:4fv|4ie:4if|4iu:4iv|4ke:4kf|4lm:4ln|4m6:4m7|4om:4on|4qr:4r0|4rt:4sv|4vl:500|5jn:5jv|5kt:5kv|5nh:5nv|5ol:5ov|5pn:5pv|5qk:5qv|5rk:5rv|5ut:5uv|5va:5vv|60q:60v|63o:63v|65a:7fv|7ks:7kv|7nq:7nv|7om:7on|7ou:7ov|7q6:7q7|7qe:7qf|7ru:7rv|7uk:7ul|7vg:7vh|82j:82m|82o:82u|834:839|83i:83j|84f:84v|85i:86f|87b:87v|89r:89s|8ac:8ai|8c4:8cf|8uf:8vv|917:91v|92b:92v|9gk:9gl|9ju:9jv|9ka:9o0|9oa:9ob|9qj:9ql|9qv:9r0|9sl:9sn|9tv:9uf|9vc:9vf|ao0:bjv|bnk:bnv|bum:bvf|bvs:bvv|c4n:c4o|c80:c84|c9d:c9g|cdo:cff|cgt:cgv|ci4:cig|cjs:cju|cmc:cmf|crn:crq|cuu:cuv|jdm:jfv|17t6:17vv|194d:194f|1967:1avv|1lt4:1lvv|1uhe:1uhf|1ujb:1unv|1uo7:1uoi|1uoo:1uos|1uti:1uui|1va0:1vaf|1vcg:1vch|1ve8:1vef|1vft:1vfv|1vgg:1vgv|1vh4:1vhf|1vi7:1vi8|1vjc:1vjf|1vnt:1vnu|1vtv:1vu1|1vu8:1vu9|1vug:1vuh|1vuo:1vup|1vut:1vuv|1vvf:1vvo|2000:20nv|20p4:20pf|20qb:20vv|2116:2117|212e:3jvv|3k7m:3k7v|3k97:3k99|3keu:3kvv|3l50:3l51|3l53:3l54|3l57:3l58|3l8b:3l8c|3la7:3la9|3ll4:3ll7|3lua:3lud|3m00:3vvt|59mn:5tvv|5ugu:5vvt|6000:7vvt|8000:9vvt|a000:bvvt|c000:dvvt|e000:fvvt|g000:hvvt|i000:jvvt|k000:lvvt|m000:nvvt|o000:pvvt|q000:rvvt|s002:s00v|s040:tvvt', s: '9p8|9qc|9qe|9qn|9tg|147|bkq|3l2l|3l4t|3l5d|3l5q|3l5s|3l61|3l64|3l86|3l8l|3l8t|3l9q|3l9v|3la5|3lah|16f|c20|ccf|cnv|cvv|1b0|1c8|1d2|1dq|1h0|1nv|1oe|284|2c4|2d9|2dh|2dt|2eu|2h9|2hh|2hk|2hn|2ht|2it|2k4|2kc|2ke|2ki|2l9|2lh|2lk|2m6|2ma|2o4|2p9|2ph|2qu|2s4|2sh|2sr|2st|2tm|2u9|304|30d|30h|319|31k|325|329|344|34d|34h|359|35k|365|369|36v|384|38d|38h|399|3a9|3c4|3di|3ds|3el|3en|3k3|3k9|3ko|3l0|3l4|3l6|3lc|3lq|3m5|3m7|3q8|3so|3tt|412|418|41b|4g7|4i7|4i9|4in|4ip|4k7|4k9|4lf|4lh|4lv|4m1|4mf|4mn|4nf|4of|4oh|4ov|4q7|h1|5od|5rd|5rh|60f|1upn|1upt|1upv|1uq2|1uq5|1vij|1vj7|1vjl|1vo0|1vv7|20ov|7qo|7qq|7qs|7qu|7tl|7u5|7us|7vl|7vv|sb|sd|s000|t2|97v|uf|9go|9o5' }, 'B.1': { r: '60b:60d|80b:80d|1vg0:1vgf', s: '5d|606|1vnv|830|qf' }, 'B.2': { m: '5l:ts|6v:3j;3j|9g:39;o7|a9:ls;3e|bv:3j|fg:3a;oc|q5:tp|rq:10;tp|sg:tp;o8;o1|tg:u5;o8;o1|u2:u3|ug:ti|uh:to|ui:u5|uj:ud|uk:ub|ul:u6|um:u0|vg:tq|vh:u1|vi:u3|vl:tl|1c7:1b5;1c2|7km:38;ph|7kn:3k;o8|7ko:3n;oa|7kp:3p;oa|7kq:31;lu|7kr:7j1|7qg:u5;oj|7qi:u5;oj;o0|7qk:u5;oj;o1|7qm:u5;oj;q2|7s0:7o0;tp|7s1:7o1;tp|7s2:7o2;tp|7s3:7o3;tp|7s4:7o4;tp|7s5:7o5;tp|7s6:7o6;tp|7s7:7o7;tp|7s8:7o0;tp|7s9:7o1;tp|7sa:7o2;tp|7sb:7o3;tp|7sc:7o4;tp|7sd:7o5;tp|7se:7o6;tp|7sf:7o7;tp|7sg:7p0;tp|7sh:7p1;tp|7si:7p2;tp|7sj:7p3;tp|7sk:7p4;tp|7sl:7p5;tp|7sm:7p6;tp|7sn:7p7;tp|7so:7p0;tp|7sp:7p1;tp|7sq:7p2;tp|7sr:7p3;tp|7ss:7p4;tp|7st:7p5;tp|7su:7p6;tp|7sv:7p7;tp|7t0:7r0;tp|7t1:7r1;tp|7t2:7r2;tp|7t3:7r3;tp|7t4:7r4;tp|7t5:7r5;tp|7t6:7r6;tp|7t7:7r7;tp|7t8:7r0;tp|7t9:7r1;tp|7ta:7r2;tp|7tb:7r3;tp|7tc:7r4;tp|7td:7r5;tp|7te:7r6;tp|7tf:7r7;tp|7ti:7rg;tp|7tj:th;tp|7tk:tc;tp|7tm:th;q2|7tn:th;q2;tp|7ts:th;tp|7tu:tp|7u2:7rk;tp|7u3:tn;tp|7u4:te;tp|7u6:tn;q2|7u7:tn;q2;tp|7uc:tn;tp|7ui:tp;o8;o0|7uj:tp;o8;o1|7um:tp;q2|7un:tp;o8;q2|7v2:u5;o8;o0|7v3:u5;o8;o1|7v4:u1;oj|7v6:u5;q2|7v7:u5;o8;q2|7vi:7rs;tp|7vj:u9;tp|7vk:ue;tp|7vm:u9;q2|7vn:u9;q2;tp|7vs:u9;tp|858:3i;3j|882:33|883:5g;33|887:ir|889:5g;36|88b:38|88c:38|88d:38|88g:39|88h:39|88i:3c|88l:3e|88m:3e;3f|88p:3g|88q:3h|88r:3i|88s:3i|88t:3i|890:3j;3d|891:3k;35;3c|892:3k;3d|894:3q|898:3q|89c:32|89d:33|89g:35|89h:36|89j:3d|89u:tj|89v:u0|8a5:34|crh:38;3g;31|crj:31;3l|crl:3f;3m|cs0:3g;31|cs1:3e;31|cs2:ts;31|cs3:3d;31|cs4:3b;31|cs5:3b;32|cs6:3d;32|cs7:37;32|csa:3g;36|csb:3e;36|csc:ts;36|csg:38;3q|csh:3b;38;3q|csi:3d;38;3q|csj:37;38;3q|csk:3k;38;3q|ct9:3g;31|cta:3b;3g;31|ctb:3d;3g;31|ctc:37;3g;31|ctk:3g;3m|ctl:3e;3m|ctm:ts;3m|ctn:3d;3m|cto:3b;3m|ctp:3d;3m|ctq:3g;3n|ctr:3e;3n|cts:ts;3n|ctt:3d;3n|ctu:3b;3n|ctv:3d;3n|cu0:3b;u9|cu1:3d;u9|cu3:32;3h|cu6:33;8gl;3b;37|cu7:33;3f;1e|cu8:34;32|cu9:37;3p|cub:38;3g|cud:3b;3b|cue:3b;3d|cun:3g;38|cup:3g;3g;3d|cuq:3g;3i|cus:3j;3m|cut:3n;32|1uo0:36;36|1uo1:36;39|1uo2:36;3c|1uo3:36;36;39|1uo4:36;36;3c|1uo5:3j;3k|1uo6:3j;3k|1uoj:1bk;1bm|1uok:1bk;1b5|1uol:1bk;1bb|1uom:1bu;1bm|1uon:1bk;1bd|3l00:31|3l01:32|3l02:33|3l03:34|3l04:35|3l05:36|3l06:37|3l07:38|3l08:39|3l09:3a|3l0a:3b|3l0b:3c|3l0c:3d|3l0d:3e|3l0e:3f|3l0f:3g|3l0g:3h|3l0h:3i|3l0i:3j|3l0j:3k|3l0k:3l|3l0l:3m|3l0m:3n|3l0n:3o|3l0o:3p|3l0p:3q|3l1k:31|3l1l:32|3l1m:33|3l1n:34|3l1o:35|3l1p:36|3l1q:37|3l1r:38|3l1s:39|3l1t:3a|3l1u:3b|3l1v:3c|3l20:3d|3l21:3e|3l22:3f|3l23:3g|3l24:3h|3l25:3i|3l26:3j|3l27:3k|3l28:3l|3l29:3m|3l2a:3n|3l2b:3o|3l2c:3p|3l2d:3q|3l38:31|3l39:32|3l3a:33|3l3b:34|3l3c:35|3l3d:36|3l3e:37|3l3f:38|3l3g:39|3l3h:3a|3l3i:3b|3l3j:3c|3l3k:3d|3l3l:3e|3l3m:3f|3l3n:3g|3l3o:3h|3l3p:3i|3l3q:3j|3l3r:3k|3l3s:3l|3l3t:3m|3l3u:3n|3l3v:3o|3l40:3p|3l41:3q|3l4s:31|3l4u:33|3l4v:34|3l52:37|3l55:3a|3l56:3b|3l59:3e|3l5a:3f|3l5b:3g|3l5c:3h|3l5e:3j|3l5f:3k|3l5g:3l|3l5h:3m|3l5i:3n|3l5j:3o|3l5k:3p|3l5l:3q|3l6g:31|3l6h:32|3l6i:33|3l6j:34|3l6k:35|3l6l:36|3l6m:37|3l6n:38|3l6o:39|3l6p:3a|3l6q:3b|3l6r:3c|3l6s:3d|3l6t:3e|3l6u:3f|3l6v:3g|3l70:3h|3l71:3i|3l72:3j|3l73:3k|3l74:3l|3l75:3m|3l76:3n|3l77:3o|3l78:3p|3l79:3q|3l84:31|3l85:32|3l87:34|3l88:35|3l89:36|3l8a:37|3l8d:3a|3l8e:3b|3l8f:3c|3l8g:3d|3l8h:3e|3l8i:3f|3l8j:3g|3l8k:3h|3l8m:3j|3l8n:3k|3l8o:3l|3l8p:3m|3l8q:3n|3l8r:3o|3l8s:3p|3l9o:31|3l9p:32|3l9r:34|3l9s:35|3l9t:36|3l9u:37|3la0:39|3la1:3a|3la2:3b|3la3:3c|3la4:3d|3la6:3f|3laa:3j|3lab:3k|3lac:3l|3lad:3m|3lae:3n|3laf:3o|3lag:3p|3lbc:31|3lbd:32|3lbe:33|3lbf:34|3lbg:35|3lbh:36|3lbi:37|3lbj:38|3lbk:39|3lbl:3a|3lbm:3b|3lbn:3c|3lbo:3d|3lbp:3e|3lbq:3f|3lbr:3g|3lbs:3h|3lbt:3i|3lbu:3j|3lbv:3k|3lc0:3l|3lc1:3m|3lc2:3n|3lc3:3o|3lc4:3p|3lc5:3q|3ld0:31|3ld1:32|3ld2:33|3ld3:34|3ld4:35|3ld5:36|3ld6:37|3ld7:38|3ld8:39|3ld9:3a|3lda:3b|3ldb:3c|3ldc:3d|3ldd:3e|3lde:3f|3ldf:3g|3ldg:3h|3ldh:3i|3ldi:3j|3ldj:3k|3ldk:3l|3ldl:3m|3ldm:3n|3ldn:3o|3ldo:3p|3ldp:3q|3lek:31|3lel:32|3lem:33|3len:34|3leo:35|3lep:36|3leq:37|3ler:38|3les:39|3let:3a|3leu:3b|3lev:3c|3lf0:3d|3lf1:3e|3lf2:3f|3lf3:3g|3lf4:3h|3lf5:3i|3lf6:3j|3lf7:3k|3lf8:3l|3lf9:3m|3lfa:3n|3lfb:3o|3lfc:3p|3lfd:3q|3lg8:31|3lg9:32|3lga:33|3lgb:34|3lgc:35|3lgd:36|3lge:37|3lgf:38|3lgg:39|3lgh:3a|3lgi:3b|3lgj:3c|3lgk:3d|3lgl:3e|3lgm:3f|3lgn:3g|3lgo:3h|3lgp:3i|3lgq:3j|3lgr:3k|3lgs:3l|3lgt:3m|3lgu:3n|3lgv:3o|3lh0:3p|3lh1:3q|3lhs:31|3lht:32|3lhu:33|3lhv:34|3li0:35|3li1:36|3li2:37|3li3:38|3li4:39|3li5:3a|3li6:3b|3li7:3c|3li8:3d|3li9:3e|3lia:3f|3lib:3g|3lic:3h|3lid:3i|3lie:3j|3lif:3k|3lig:3l|3lih:3m|3lii:3n|3lij:3o|3lik:3p|3lil:3q|3ljg:31|3ljh:32|3lji:33|3ljj:34|3ljk:35|3ljl:36|3ljm:37|3ljn:38|3ljo:39|3ljp:3a|3ljq:3b|3ljr:3c|3ljs:3d|3ljt:3e|3lju:3f|3ljv:3g|3lk0:3h|3lk1:3i|3lk2:3j|3lk3:3k|3lk4:3l|3lk5:3m|3lk6:3n|3lk7:3o|3lk8:3p|3lk9:3q|3ll8:th|3ll9:ti|3lla:tj|3llb:tk|3llc:tl|3lld:tm|3lle:tn|3llf:to|3llg:tp|3llh:tq|3lli:tr|3llj:ts|3llk:tt|3lll:tu|3llm:tv|3lln:u0|3llo:u1|3llp:to|3llq:u3|3llr:u4|3lls:u5|3llt:u6|3llu:u7|3llv:u8|3lm0:u9|3lmj:u3|3ln2:th|3ln3:ti|3ln4:tj|3ln5:tk|3ln6:tl|3ln7:tm|3ln8:tn|3ln9:to|3lna:tp|3lnb:tq|3lnc:tr|3lnd:ts|3lne:tt|3lnf:tu|3lng:tv|3lnh:u0|3lni:u1|3lnj:to|3lnk:u3|3lnl:u4|3lnm:u5|3lnn:u6|3lno:u7|3lnp:u8|3lnq:u9|3lod:u3|3los:th|3lot:ti|3lou:tj|3lov:tk|3lp0:tl|3lp1:tm|3lp2:tn|3lp3:to|3lp4:tp|3lp5:tq|3lp6:tr|3lp7:ts|3lp8:tt|3lp9:tu|3lpa:tv|3lpb:u0|3lpc:u1|3lpd:to|3lpe:u3|3lpf:u4|3lpg:u5|3lph:u6|3lpi:u7|3lpj:u8|3lpk:u9|3lq7:u3|3lqm:th|3lqn:ti|3lqo:tj|3lqp:tk|3lqq:tl|3lqr:tm|3lqs:tn|3lqt:to|3lqu:tp|3lqv:tq|3lr0:tr|3lr1:ts|3lr2:tt|3lr3:tu|3lr4:tv|3lr5:u0|3lr6:u1|3lr7:to|3lr8:u3|3lr9:u4|3lra:u5|3lrb:u6|3lrc:u7|3lrd:u8|3lre:u9|3ls1:u3|3lsg:th|3lsh:ti|3lsi:tj|3lsj:tk|3lsk:tl|3lsl:tm|3lsm:tn|3lsn:to|3lso:tp|3lsp:tq|3lsq:tr|3lsr:ts|3lss:tt|3lst:tu|3lsu:tv|3lsv:u0|3lt0:u1|3lt1:to|3lt2:u3|3lt3:u4|3lt4:u5|3lt5:u6|3lt6:u7|3lt7:u8|3lt8:u9|3ltr:u3', r: '23:2c|2i:2k|2m:2q|60:6m|6o:6u|bo:bp|c1:c2|c6:c7|c9:cb|ce:ch|cj:ck|cm:co|cs:ct|cv:d0|d6:d7|de:df|dh:dj|dn:do|e4:e5|e7:e8|ea:eb|fh:fi|fm:fo|s8:sa|se:sf|sh:t1|t3:tb|100:11f|19h:1am|7o8:7of|7oo:7ot|7p8:7pf|7po:7pv|7q8:7qd|7r8:7rf|7to:7tr|7u8:7ub|7uo:7ur|7v8:7vc|7vo:7vr|89a:89b|8b0:8bf|95m:96f|1vp1:1vpq|2100:2115', s: 'v8|va|vc|ve|vk|130|132|134|136|138|13a|13c|13e|13g|13i|13k|13m|13o|13q|13s|13u|140|14a|14c|14e|14g|14i|14k|14m|14o|14q|14s|14u|150|152|154|156|158|15a|15c|15e|15g|15i|15k|15m|15o|15q|15s|15u|161|163|165|167|169|16b|16d|16g|16i|16k|16m|16o|16q|16s|16u|170|172|174|176|178|17a|17c|17e|17g|17i|17k|17o|180|182|184|186|188|18a|18c|18e|80|82|84|86|88|8a|8c|8e|8g|8i|8k|8m|8o|8q|8s|8u|90|92|94|96|98|9a|9c|9e|9i|9k|9m|9p|9r|9t|9v|a1|a3|a5|a7|aa|ac|ae|ag|ai|ak|am|ao|aq|as|au|b0|b2|b4|b6|b8|ba|bc|be|bg|bi|bk|bm|br|bt|c4|d2|d4|d9|dc|dl|ds|ed|ef|eh|ej|el|en|ep|er|eu|f0|f2|f4|f6|f8|fa|fc|fe|fk|fq|fs|fu|g0|g2|g4|g6|g8|ga|gc|ge|gg|gi|gk|gm|go|gq|gs|gu|h0|h2|h4|h6|h8|ha|hc|he|hg|hi|21|22|7g0|7g2|7g4|7g6|7g8|7ga|7gc|7ge|7gg|7gi|2d|7gk|7gm|7go|7gq|7gs|7gu|7h0|7h2|7h4|7h6|7h8|7ha|7hc|7he|7hg|7hi|7hk|7hm|7ho|7hq|7hs|7hu|7i0|7i2|7i4|7i6|7i8|7ia|7ic|7ie|7ig|7ii|7ik|7im|7io|7iq|7is|7iu|7j0|7j2|7j4|7j6|7j8|7ja|7jc|7je|7jg|7ji|7jk|7jm|2e|7jo|7jq|7js|7ju|7k0|7k2|7k4|7k6|7k8|7ka|7kc|7ke|7kg|7ki|7kk|7l0|7l2|7l4|7l6|7l8|7la|7lc|7le|7lg|7li|7lk|7lm|7lo|7lq|7ls|7lu|7m0|7m2|7m4|7m6|7m8|7ma|7mc|7me|7mg|7mi|7mk|7mm|7mo|7mq|2f|7ms|7mu|7n0|7n2|7n4|7n6|7n8|7na|7nc|7ne|7ng|7ni|7nk|7nm|7no|2g|7qp|7qr|7qt|7qv|2h|896|2l|s6|sc|uo|uq|us|uu|v0|v2|v4|v6' }, 'B.3': { m: '5l:ts|6v:3j;3j|9g:39;o7|a9:ls;3e|bv:3j|fg:3a;oc|q5:tp|sg:tp;o8;o1|tg:u5;o8;o1|u2:u3|ug:ti|uh:to|ul:u6|um:u0|vg:tq|vh:u1|vi:u3|vl:tl|1c7:1b5;1c2|7km:38;ph|7kn:3k;o8|7ko:3n;oa|7kp:3p;oa|7kq:31;lu|7kr:7j1|7qg:u5;oj|7qi:u5;oj;o0|7qk:u5;oj;o1|7qm:u5;oj;q2|7s0:7o0;tp|7s1:7o1;tp|7s2:7o2;tp|7s3:7o3;tp|7s4:7o4;tp|7s5:7o5;tp|7s6:7o6;tp|7s7:7o7;tp|7s8:7o0;tp|7s9:7o1;tp|7sa:7o2;tp|7sb:7o3;tp|7sc:7o4;tp|7sd:7o5;tp|7se:7o6;tp|7sf:7o7;tp|7sg:7p0;tp|7sh:7p1;tp|7si:7p2;tp|7sj:7p3;tp|7sk:7p4;tp|7sl:7p5;tp|7sm:7p6;tp|7sn:7p7;tp|7so:7p0;tp|7sp:7p1;tp|7sq:7p2;tp|7sr:7p3;tp|7ss:7p4;tp|7st:7p5;tp|7su:7p6;tp|7sv:7p7;tp|7t0:7r0;tp|7t1:7r1;tp|7t2:7r2;tp|7t3:7r3;tp|7t4:7r4;tp|7t5:7r5;tp|7t6:7r6;tp|7t7:7r7;tp|7t8:7r0;tp|7t9:7r1;tp|7ta:7r2;tp|7tb:7r3;tp|7tc:7r4;tp|7td:7r5;tp|7te:7r6;tp|7tf:7r7;tp|7ti:7rg;tp|7tj:th;tp|7tk:tc;tp|7tm:th;q2|7tn:th;q2;tp|7ts:th;tp|7tu:tp|7u2:7rk;tp|7u3:tn;tp|7u4:te;tp|7u6:tn;q2|7u7:tn;q2;tp|7uc:tn;tp|7ui:tp;o8;o0|7uj:tp;o8;o1|7um:tp;q2|7un:tp;o8;q2|7v2:u5;o8;o0|7v3:u5;o8;o1|7v4:u1;oj|7v6:u5;q2|7v7:u5;o8;q2|7vi:7rs;tp|7vj:u9;tp|7vk:ue;tp|7vm:u9;q2|7vn:u9;q2;tp|7vs:u9;tp|1uo0:36;36|1uo1:36;39|1uo2:36;3c|1uo3:36;36;39|1uo4:36;36;3c|1uo5:3j;3k|1uo6:3j;3k|1uoj:1bk;1bm|1uok:1bk;1b5|1uol:1bk;1bb|1uom:1bu;1bm|1uon:1bk;1bd', r: '23:2c|2i:2k|2m:2q|60:6m|6o:6u|bo:bp|c1:c2|c6:c7|c9:cb|ce:ch|cj:ck|cm:co|cs:ct|cv:d0|d6:d7|de:df|dh:dj|dn:do|e4:e5|e7:e8|ea:eb|fh:fi|fm:fo|s8:sa|se:sf|sh:t1|t3:tb|100:11f|19h:1am|7o8:7of|7oo:7ot|7p8:7pf|7po:7pv|7q8:7qd|7r8:7rf|7to:7tr|7u8:7ub|7uo:7ur|7v8:7vc|7vo:7vr|89a:89b|8b0:8bf|95m:96f|1vp1:1vpq|2100:2115', s: 'v8|va|vc|ve|vk|130|132|134|136|138|13a|13c|13e|13g|13i|13k|13m|13o|13q|13s|13u|140|14a|14c|14e|14g|14i|14k|14m|14o|14q|14s|14u|150|152|154|156|158|15a|15c|15e|15g|15i|15k|15m|15o|15q|15s|15u|161|163|165|167|169|16b|16d|16g|16i|16k|16m|16o|16q|16s|16u|170|172|174|176|178|17a|17c|17e|17g|17i|17k|17o|180|182|184|186|188|18a|18c|18e|80|82|84|86|88|8a|8c|8e|8g|8i|8k|8m|8o|8q|8s|8u|90|92|94|96|98|9a|9c|9e|9i|9k|9m|9p|9r|9t|9v|a1|a3|a5|a7|aa|ac|ae|ag|ai|ak|am|ao|aq|as|au|b0|b2|b4|b6|b8|ba|bc|be|bg|bi|bk|bm|br|bt|c4|d2|d4|d9|dc|dl|ds|ed|ef|eh|ej|el|en|ep|er|eu|f0|f2|f4|f6|f8|fa|fc|fe|fk|fq|fs|fu|g0|g2|g4|g6|g8|ga|gc|ge|gg|gi|gk|gm|go|gq|gs|gu|h0|h2|h4|h6|h8|ha|hc|he|hg|hi|21|22|7g0|7g2|7g4|7g6|7g8|7ga|7gc|7ge|7gg|7gi|2d|7gk|7gm|7go|7gq|7gs|7gu|7h0|7h2|7h4|7h6|7h8|7ha|7hc|7he|7hg|7hi|7hk|7hm|7ho|7hq|7hs|7hu|7i0|7i2|7i4|7i6|7i8|7ia|7ic|7ie|7ig|7ii|7ik|7im|7io|7iq|7is|7iu|7j0|7j2|7j4|7j6|7j8|7ja|7jc|7je|7jg|7ji|7jk|7jm|2e|7jo|7jq|7js|7ju|7k0|7k2|7k4|7k6|7k8|7ka|7kc|7ke|7kg|7ki|7kk|7l0|7l2|7l4|7l6|7l8|7la|7lc|7le|7lg|7li|7lk|7lm|7lo|7lq|7ls|7lu|7m0|7m2|7m4|7m6|7m8|7ma|7mc|7me|7mg|7mi|7mk|7mm|7mo|7mq|2f|7ms|7mu|7n0|7n2|7n4|7n6|7n8|7na|7nc|7ne|7ng|7ni|7nk|7nm|7no|2g|7qp|7qr|7qt|7qv|2h|896|2l|s6|sc|uo|uq|us|uu|v0|v2|v4|v6' }, 'C.1.1': { s: '10' }, 'C.1.2': { r: '800:80b', s: 'c00|50|5k0|81f|82v' }, 'C.2.1': { r: '0:v', s: '3v' }, 'C.2.2': { r: '40:4v|80c:80d|818:819|830:833|83a:83f|1vvp:1vvs|3kbj:3kbq', s: '1mt|1of|60e|1vnv' }, 'C.3': { r: '1o00:1u7v|u000:vvvt|10000:11vvt' }, 'C.4': { r: '1veg:1vff|1vvu:1vvv|3vvu:3vvv|5vvu:5vvv|7vvu:7vvv|9vvu:9vvv|bvvu:bvvv|dvvu:dvvv|fvvu:fvvv|hvvu:hvvv|jvvu:jvvv|lvvu:lvvv|nvvu:nvvv|pvvu:pvvv|rvvu:rvvv|tvvu:tvvv|vvvu:vvvv|11vvu:11vvv' }, 'C.5': { r: '1m00:1nvv' }, 'C.6': { r: '1vvp:1vvt' }, 'C.7': { r: 'bvg:bvr' }, 'C.8': { r: 'q0:q1|80e:80f|81a:81e|83a:83f' }, 'C.9': { r: 's010:s03v', s: 's001' }, 'D.1': { r: '1eg:1fa|1fg:1fk|1h1:1hq|1i0:1ia|1jd:1jf|1jh:1ml|1n5:1n6|1nq:1nu|1o0:1od|1oi:1pc|1s0:1t5|1uov:1up8|1upa:1upm|1upo:1ups|1uq0:1uq1|1uq3:1uq4|1uq6:1uth|1uuj:1v9t|1vag:1vcf|1vci:1ve7|1vfg:1vfs|1vjg:1vjk|1vjm:1vns', s: '1du|1e0|1e3|1gr|1gv|1mt|1og|1th|1uot|1upu|80f' }, 'D.2': { r: '21:2q|31:3q|60:6m|6o:7m|7o:h0|h2:hj|ig:ld|lg:lo|lr:m1|mg:mh|n0:n4|s8:sa|se:t1|t3:ue|ug:vl|100:142|14a:16e|16g:17l|17o:17p|180:18f|19h:1am|1ap:1av|1b1:1c7|285:29p|29t:2a0|2a9:2ac|2ao:2b1|2b4:2bg|2c2:2c3|2c5:2cc|2cf:2cg|2cj:2d8|2da:2dg|2dm:2dp|2du:2e0|2e7:2e8|2eb:2ec|2es:2et|2ev:2f1|2f6:2fh|2fk:2fq|2g5:2ga|2gf:2gg|2gj:2h8|2ha:2hg|2hi:2hj|2hl:2hm|2ho:2hp|2hu:2i0|2ip:2is|2j6:2jf|2ji:2jk|2k5:2kb|2kf:2kh|2kj:2l8|2la:2lg|2li:2lj|2ll:2lp|2lt:2m0|2mb:2mc|2n6:2nf|2o2:2o3|2o5:2oc|2of:2og|2oj:2p8|2pa:2pg|2pi:2pj|2pm:2pp|2pt:2pu|2q7:2q8|2qb:2qc|2qs:2qt|2qv:2r1|2r6:2rg|2s5:2sa|2se:2sg|2si:2sl|2sp:2sq|2su:2sv|2t3:2t4|2t8:2ta|2te:2tl|2tn:2tp|2tu:2tv|2u1:2u2|2u6:2u8|2ua:2uc|2v7:2vi|301:303|305:30c|30e:30g|30i:318|31a:31j|31l:31p|321:324|330:331|336:33f|342:343|345:34c|34e:34g|34i:358|35a:35j|35l:35p|360:364|367:368|36a:36b|36l:36m|370:371|376:37f|382:383|385:38c|38e:38g|38i:398|39a:39p|39u:3a0|3a6:3a8|3aa:3ac|3b0:3b1|3b6:3bf|3c2:3c3|3c5:3cm|3cq:3dh|3dj:3dr|3e0:3e6|3ef:3eh|3eo:3ev|3fi:3fk|3g1:3hg|3hi:3hj|3i0:3i6|3if:3ir|3k1:3k2|3k7:3k8|3kk:3kn|3kp:3kv|3l1:3l3|3la:3lb|3ld:3lg|3li:3lj|3m0:3m4|3mg:3mp|3ms:3mt|3o0:3on|3oq:3pk|3pu:3q7|3q9:3ra|3s8:3sb|3tu:3u5|3u7:3uc|400:411|413:417|419:41a|420:42n|450:465|46g:47o|480:4ap|4av:4d2|4d8:4fp|4g0:4g6|4g8:4i6|4ia:4id|4ig:4im|4iq:4it|4j0:4k6|4ka:4kd|4kg:4le|4li:4ll|4lo:4lu|4m2:4m5|4m8:4me|4mg:4mm|4mo:4ne|4ng:4oe|4oi:4ol|4oo:4ou|4p0:4q6|4q8:4qq|4r1:4rs|4t0:4vk|501:5jm|5k1:5kq|5l0:5ng|5o0:5oc|5oe:5oh|5p0:5ph|5pl:5pm|5q0:5qh|5r0:5rc|5re:5rg|5s0:5tm|5tu:5u5|5u7:5u8|5uk:5uq|5v0:5v9|60g:60p|610:63n|640:658|7g0:7kr|7l0:7np|7o0:7ol|7oo:7ot|7p0:7q5|7q8:7qd|7qg:7qn|7qv:7rt|7s0:7tk|7tm:7ts|7u2:7u4|7u6:7uc|7ug:7uj|7um:7ur|7v0:7vc|7vi:7vk|7vm:7vs|88a:88j|88p:88t|89a:89d|89f:89h|89j:89p|89t:89v|8a5:8a9|8b0:8c3|8pm:8rq|94s:979|c05:c07|c11:c19|c1h:c1l|c1o:c1s|c21:c4m|c4t:c4v|c51:c7q|c7s:c7v|c85:c9c|c9h:cce|ccg:cdn|cfg:cgs|ch0:ci3|cj0:cjr|cjv:clg|cm0:cmb|cmg:cnu|co0:crm|crr:cut|cv0:cvu|d00:jdl|jg0:17t5|1800:194c|1b00:1lt3|1m00:1uhd|1uhg:1uja|1uo0:1uo6|1uoj:1uon|1vp1:1vpq|1vq1:1vqq|1vr6:1vtu|1vu2:1vu7|1vua:1vuf|1vui:1vun|1vuq:1vus|20o0:20ou|20p0:20p3|20pg:20qa|2100:2115|2118:212d|3k00:3k7l|3k80:3k96|3k9a:3kb6|3kba:3kbi|3kc3:3kc4|3kcc:3kd9|3kde:3ket|3l00:3l2k|3l2m:3l4s|3l4u:3l4v|3l55:3l56|3l59:3l5c|3l5e:3l5p|3l5t:3l60|3l62:3l63|3l65:3l85|3l87:3l8a|3l8d:3l8k|3l8m:3l8s|3l8u:3l9p|3l9r:3l9u|3la0:3la4|3laa:3lag|3lai:3ll3|3ll8:3lu9|4000:59mm|5u00:5ugt|u000:vvvt|10000:11vvt', s: '3l52|3l5r|3la6|1c9|5a|5l|5q|283|2ag|2di|2en|2iu|2k3|2kd|2m9|2mg|2n0|2q0|2qn|2s3|2ss|2un|35u|36u|3an|3dt|3k4|3ka|3kd|3l5|3l7|3lt|3m6|3pm|3po|3rv|3s5|3uf|41c|41h|41o|47r|4i8|4io|4k8|4lg|4m0|4og|5us|ne|7qp|7qr|7qt|7tu|80e|83h|83v|882|887|88l|894|896|898|rq|s6|sc|8sl' } }; class Table { constructor(name, points) { this.singles = new Set(); this.ranges = []; this.mappings = new Map(); const data = TABLE_DATA[name]; this.name = name; if (data) { if (data.s) { this.singles = new Set(data.s.split('|').map(s => parseInt(s, 32))); } if (data.r) { this.ranges = data.r.split('|').map(r => { const [start, end] = r.split(':'); return [parseInt(start, 32), parseInt(end, 32)]; }); } if (data.m) { this.mappings = new Map(data.m.split('|').map(m => { const [point, mapping] = m.split(':'); const mappedPoints = mapping.split(';').map(p => parseInt(p, 32)); return [parseInt(point, 32), mappedPoints]; })); } } else if (points) { this.singles = new Set(points); } } contains(codePoint) { if (this.singles.has(codePoint)) { return true; } let left = 0; let right = this.ranges.length - 1; while (left <= right) { const pivot = Math.floor((left + right) / 2); const range = this.ranges[pivot]; if (codePoint < range[0]) { right = pivot - 1; continue; } if (codePoint > range[1]) { left = pivot + 1; continue; } return true; } return false; } hasMapping(codePoint) { return this.mappings.has(codePoint) || this.contains(codePoint); } map(codePoint) { if (this.contains(codePoint) && !this.mappings.has(codePoint)) { return String.fromCodePoint(codePoint).toLowerCase().codePointAt(0); } return this.mappings.get(codePoint) || null; } } const A1 = new Table('A.1'); const B1 = new Table('B.1'); const B2 = new Table('B.2'); const B3 = new Table('B.3'); const C11 = new Table('C.1.1'); const C12 = new Table('C.1.2'); const C21 = new Table('C.2.1'); const C22 = new Table('C.2.2'); const C3 = new Table('C.3'); const C4 = new Table('C.4'); const C5 = new Table('C.5'); const C6 = new Table('C.6'); const C7 = new Table('C.7'); const C8 = new Table('C.8'); const C9 = new Table('C.9'); const D1 = new Table('D.1'); const D2 = new Table('D.2'); // Shortcut some of the simpler table operations B1.map = () => { return null; }; C11.contains = (codePoint) => codePoint === 32; C12.map = (codePoint) => { return C12.contains(codePoint) ? 32 : null; }; function prepare(profile, allowUnassigned, input = '') { const inputCodePoints = Punycode.ucs2.decode(input); let mappedCodePoints = []; for (const codePoint of inputCodePoints) { if (!allowUnassigned && profile.unassigned.contains(codePoint)) { throw new Error('Unassigned code point: x' + codePoint.toString(16)); } let hasMapping = false; for (const mappingTable of profile.mappings) { if (!mappingTable.hasMapping(codePoint)) { continue; } hasMapping = true; const mappedPoint = mappingTable.map(codePoint); if (!mappedPoint) { continue; } if (Array.isArray(mappedPoint)) { mappedCodePoints = mappedCodePoints.concat(mappedPoint); } else { mappedCodePoints.push(mappedPoint); } } if (!hasMapping) { mappedCodePoints.push(codePoint); } } let normalizedCodePoints = mappedCodePoints; if (profile.normalize) { const mappedString = Punycode.ucs2.encode(mappedCodePoints); const normalizedString = mappedString.normalize('NFKC'); normalizedCodePoints = Punycode.ucs2.decode(normalizedString); } let hasRandALCat = false; let hasLCat = false; for (const codePoint of normalizedCodePoints) { for (const prohibited of profile.prohibited) { if (prohibited.contains(codePoint)) { throw new Error('Prohibited code point: x' + codePoint.toString(16)); } } if (!allowUnassigned && profile.unassigned.contains(codePoint)) { // istanbul ignore next throw new Error('Prohibited code point: x' + codePoint.toString(16)); } if (profile.bidirectional) { hasRandALCat = hasRandALCat || D1.contains(codePoint); hasLCat = hasLCat || D2.contains(codePoint); } } if (profile.bidirectional) { if (hasRandALCat && hasLCat) { throw new Error('String contained both LCat and RandALCat code points'); } if (hasRandALCat && (!D1.contains(normalizedCodePoints[0]) || !D1.contains(normalizedCodePoints[normalizedCodePoints.length - 1]))) { throw new Error('String containing RandALCat code points must start and end with RandALCat code points'); } } return Punycode.ucs2.encode(normalizedCodePoints); } const NamePrepProfile = { bidirectional: true, mappings: [B1, B2], normalize: true, prohibited: [C12, C22, C3, C4, C5, C6, C7, C8, C9], unassigned: A1 }; function nameprep(str, allowUnassigned = true) { return prepare(NamePrepProfile, allowUnassigned, str); } const NodePrepProhibited = new Table('NodePrepProhibited', [ 0x22, 0x26, 0x27, 0x2f, 0x3a, 0x3c, 0x3e, 0x40 ]); const NodePrepProfile = { bidirectional: true, mappings: [B1, B2], normalize: true, prohibited: [C11, C12, C21, C22, C3, C4, C5, C6, C7, C8, C9, NodePrepProhibited], unassigned: A1 }; function nodeprep(str, allowUnassigned = true) { return prepare(NodePrepProfile, allowUnassigned, str); } const ResourcePrepProfile = { bidirectional: true, mappings: [B1], normalize: true, prohibited: [C12, C21, C22, C3, C4, C5, C6, C7, C8, C9], unassigned: A1 }; function resourceprep(str, allowUnassigned = true) { return prepare(ResourcePrepProfile, allowUnassigned, str); } const SASLPrepProfile = { bidirectional: true, mappings: [C12, B1], normalize: true, prohibited: [C12, C21, C22, C3, C4, C5, C6, C7, C8, C9], unassigned: A1 }; function saslprep(str, allowUnassigned = false) { return prepare(SASLPrepProfile, allowUnassigned, str); } function escapeLocal(val = '') { return val .replace(/^\s+|\s+$/g, '') .replace(/\\5c/g, '\\5c5c') .replace(/\\20/g, '\\5c20') .replace(/\\22/g, '\\5c22') .replace(/\\26/g, '\\5c26') .replace(/\\27/g, '\\5c27') .replace(/\\2f/g, '\\5c2f') .replace(/\\3a/g, '\\5c3a') .replace(/\\3c/g, '\\5c3c') .replace(/\\3e/g, '\\5c3e') .replace(/\\40/g, '\\5c40') .replace(/ /g, '\\20') .replace(/"/g, '\\22') .replace(/&/g, '\\26') .replace(/'/g, '\\27') .replace(/\//g, '\\2f') .replace(/:/g, '\\3a') .replace(/</g, '\\3c') .replace(/>/g, '\\3e') .replace(/@/g, '\\40'); } function unescapeLocal(val) { return val .replace(/\\20/g, ' ') .replace(/\\22/g, '"') .replace(/\\26/g, '&') .replace(/\\27/g, `'`) .replace(/\\2f/g, '/') .replace(/\\3a/g, ':') .replace(/\\3c/g, '<') .replace(/\\3e/g, '>') .replace(/\\40/g, '@') .replace(/\\5c/g, '\\'); } function prepare$1(data) { let local = data.local || ''; let domain = data.domain; let resource = data.resource || ''; if (local) { local = nodeprep(local); } if (resource) { resource = resourceprep(resource); } if (domain[domain.length - 1] === '.') { domain = domain.slice(0, domain.length - 1); } domain = nameprep(domain.split('.').map(Punycode.toUnicode).join('.')); return { domain, local, resource }; } function create(data, opts = {}) { let localPart = data.local; if (!opts.escaped) { localPart = escapeLocal(data.local); } const prep = !opts.prepared ? prepare$1({ local: localPart, domain: data.domain, resource: data.resource }) : data; const bareJID = localPart ? `${localPart}@${prep.domain}` : prep.domain; if (prep.resource) { return `${bareJID}/${prep.resource}`; } return bareJID; } function createFull(bare, resource) { if (resource) { return `${toBare(bare)}/${resource}`; } else { return toBare(bare); } } function parse(jid = '') { let local = ''; let domain = ''; let resource = ''; const resourceStart = jid.indexOf('/'); if (resourceStart > 0) { resource = jid.slice(resourceStart + 1); jid = jid.slice(0, resourceStart); } const localEnd = jid.indexOf('@'); if (localEnd > 0) { local = jid.slice(0, localEnd); jid = jid.slice(localEnd + 1); } domain = jid; const prepped = prepare$1({ domain, local, resource }); return { bare: create({ local: prepped.local, domain: prepped.domain }, { escaped: true, prepared: true }), domain: prepped.domain, full: create(prepped, { escaped: true, prepared: true }), local: unescapeLocal(prepped.local), resource: prepped.resource }; } function allowedResponders(jid1, jid2) { const allowed = new Set(); allowed.add(undefined); allowed.add(''); if (jid1) { const split1 = parse(jid1); allowed.add(split1.full); allowed.add(split1.bare); allowed.add(split1.domain); } if (jid2) { const split2 = parse(jid2); allowed.add(split2.domain); allowed.add(split2.bare); allowed.add(split2.full); } return allowed; } function equal(jid1, jid2) { if (!jid1 || !jid2) { return false; } const parsed1 = parse(jid1); const parsed2 = parse(jid2); return (parsed1.local === parsed2.local && parsed1.domain === parsed2.domain && parsed1.resource === parsed2.resource); } function equalBare(jid1, jid2) { if (!jid1 || !jid2) { return false; } const parsed1 = parse(jid1); const parsed2 = parse(jid2); return parsed1.local === parsed2.local && parsed1.domain === parsed2.domain; } function isFull(jid) { const parsed = parse(jid); return !!parsed.resource; } function isBare(jid) { return !isFull(jid); } function getLocal(jid = '') { return parse(jid).local; } function getDomain(jid = '') { return parse(jid).domain; } function getResource(jid = '') { return parse(jid).resource; } function toBare(jid = '') { return parse(jid).bare; } function parseURI(val) { const parsed = new URL(val); if (parsed.protocol !== 'xmpp:') { throw new Error('Invalid XMPP URI, wrong protocol: ' + parsed.protocol); } const identity = parsed.hostname ? parsed.username ? create({ domain: decodeURIComponent(parsed.hostname), local: decodeURIComponent(parsed.username) }, { escaped: true }) : decodeURIComponent(parsed.hostname) : undefined; const jid = parse(decodeURIComponent(identity ? parsed.pathname.substr(1) : parsed.pathname)) .full; const hasParameters = parsed.search && parsed.search.indexOf(';') >= 1; const parameterString = hasParameters ? parsed.search.substr(parsed.search.indexOf(';') + 1) : ''; const action = parsed.search ? decodeURIComponent(parsed.search.substr(1, hasParameters ? parsed.search.indexOf(';') - 1 : undefined)) : undefined; const params = {}; for (const token of parameterString.split(';')) { const [name, value] = token.split('=').map(decodeURIComponent); if (!params[name]) { params[name] = value; } else { const existing = params[name]; if (Array.isArray(existing)) { existing.push(value); } else { params[name] = [existing, value]; } } } return { action, identity, jid, parameters: params }; } function toURI(data) { const parts = ['xmpp:']; const pushJID = (jid, allowResource) => { const res = parse(jid); if (res.local) { parts.push(encodeURIComponent(escapeLocal(res.local))); parts.push('@'); } parts.push(encodeURIComponent(res.domain)); if (allowResource && res.resource) { parts.push('/'); parts.push(encodeURIComponent(res.resource)); } }; if (data.identity) { parts.push('//'); pushJID(data.identity, false); if (data.jid) { parts.push('/'); } } if (data.jid) { pushJID(data.jid, true); } if (data.action) { parts.push('?'); parts.push(encodeURIComponent(data.action)); } for (const [name, values] of Object.entries(data.parameters || {})) { for (const val of Array.isArray(values) ? values : [values]) { parts.push(';'); parts.push(encodeURIComponent(name)); if (val !== undefined) { parts.push('='); parts.push(encodeURIComponent(val)); } } } return parts.join(''); } var JID = /*#__PURE__*/Object.freeze({ __proto__: null, escapeLocal: escapeLocal, unescapeLocal: unescapeLocal, prepare: prepare$1, create: create, createFull: createFull, parse: parse, allowedResponders: allowedResponders, equal: equal, equalBare: equalBare, isFull: isFull, isBare: isBare, getLocal: getLocal, getDomain: getDomain, getResource: getResource, toBare: toBare, parseURI: parseURI, toURI: toURI }); var JXTErrorCondition; (function (JXTErrorCondition) { JXTErrorCondition["NotWellFormed"] = "not-well-formed"; JXTErrorCondition["RestrictedXML"] = "restricted-xml"; JXTErrorCondition["AlreadyClosed"] = "already-closed"; JXTErrorCondition["UnknownRoot"] = "unknown-stream-root"; })(JXTErrorCondition || (JXTErrorCondition = {})); class JXTError extends Error { constructor(opts) { super(opts.text); this.isJXTError = true; this.condition = opts.condition; this.text = opts.text; } static notWellFormed(text) { return new JXTError({ condition: JXTErrorCondition.NotWellFormed, text }); } static restrictedXML(text) { return new JXTError({ condition: JXTErrorCondition.RestrictedXML, text }); } static alreadyClosed(text) { return new JXTError({ condition: JXTErrorCondition.AlreadyClosed, text }); } static unknownRoot(text) { return new JXTError({ condition: JXTErrorCondition.UnknownRoot, text }); } } const ESCAPE_XML_CHAR = { '"': '&quot;', '&': '&amp;', "'": '&apos;', '<': '&lt;', '>': '&gt;' }; const UNESCAPE_XML_CHAR = { '&amp;': '&', '&apos;': "'", '&gt;': '>', '&lt;': '<', '&quot;': '"' }; const ESCAPE_SEQUENCE = /&([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+);/g; const NEED_ESCAPING = /&|<|>|"|'/g; const NEED_ESCAPING_TEXT = /&|<|>/g; function escapeXMLReplaceChar(match) { return ESCAPE_XML_CHAR[match]; } function unescapeXMLReplaceChar(match) { if (UNESCAPE_XML_CHAR[match]) { return UNESCAPE_XML_CHAR[match]; } const hex = match.startsWith('&#x'); const code = parseInt(match.substring(hex ? 3 : 2, match.length - 1), hex ? 16 : 10); if (code === 0x9 || code === 0xa || code === 0xd || (0x20 <= code && code <= 0xd7ff) || (0xe000 <= code && code <= 0xfffd) || (0x10000 <= code && code <= 0x10ffff)) { return String.fromCodePoint(code); } throw JXTError.restrictedXML('Prohibited entity: ' + match); } function escapeXML(text) { return text.replace(NEED_ESCAPING, escapeXMLReplaceChar); } function unescapeXML(text) { return text.replace(ESCAPE_SEQUENCE, match => { return unescapeXMLReplaceChar(match); }); } function escapeXMLText(text) { return text.replace(NEED_ESCAPING_TEXT, escapeXMLReplaceChar); } function basicLanguageResolver(available, accept = [], current = '') { const avail = new Set(available.map(a => a.toLowerCase())); for (let acceptLang of accept.map(a => a.toLowerCase())) { if (acceptLang === '*') { continue; } while (acceptLang.length > 0) { if (avail.has(acceptLang)) { return acceptLang; } // Remove ending tag acceptLang = acceptLang.substring(0, acceptLang.lastIndexOf('-')).toLowerCase(); // Remove leftover single character tag if (acceptLang.lastIndexOf('-') === acceptLang.length - 2) { acceptLang = acceptLang.substring(0, acceptLang.lastIndexOf('-')); } } } return current; } class XMLElement { constructor(name, attrs = {}, children = []) { this.name = name; this.attributes = attrs; this.children = []; this.optionalNamespaces = {}; for (const child of children) { if (typeof child !== 'string') { const xmlChild = new XMLElement(child.name, child.attributes, child.children); xmlChild.parent = this; this.children.push(xmlChild); } else { this.children.push(child); } } } getName() { if (this.name.indexOf(':') >= 0) { return this.name.substr(this.name.indexOf(':') + 1); } else { return this.name; } } getNamespace() { if (this.name.indexOf(':') >= 0) { const prefix = this.name.substr(0, this.name.indexOf(':')); return this.findNamespaceForPrefix(prefix); } return this.findNamespaceForPrefix(); } getNamespaceContext() { let namespaces = {}; if (this.parent) { namespaces = this.parent.getNamespaceContext(); } for (const [attr, value] of Object.entries(this.attributes)) { if (attr.startsWith('xmlns:')) { const prefix = attr.substr(6); namespaces[value] = prefix; } } return namespaces; } getDefaultNamespace() { if (this.attributes.xmlns) { return this.attributes.xmlns; } if (this.parent) { return this.parent.getDefaultNamespace(); } return ''; } getNamespaceRoot(namespace) { if (this.parent) { const parentRoot = this.parent.getNamespaceRoot(namespace); if (parentRoot) { return parentRoot; } } for (const [attr, value] of Object.entries(this.attributes)) { if (attr.startsWith('xmlns:') && value === namespace) { return this; } } if (this.optionalNamespaces[namespace]) { return this; } return undefined; } getAttribute(name, xmlns) { if (!xmlns) { return this.attributes[name]; } const namespaces = this.getNamespaceContext(); if (!namespaces[xmlns]) { return undefined; } return this.attributes[[namespaces[xmlns], name].join(':')]; } getChild(name, xmlns) { return this.getChildren(name, xmlns)[0]; } getChildren(name, xmlns) { const result = []; for (const child of this.children) { if (typeof child !== 'string' && child.getName() === name && (!xmlns || child.getNamespace() === xmlns)) { result.push(child); } } return result; } getText() { let text = ''; for (const child of this.children) { if (typeof child === 'string') { text += child; } } return text; } appendChild(child) { this.children.push(child); if (typeof child !== 'string') { child.parent = this; } return child; } setAttribute(attr, val, force = false) { this.attributes[attr] = val || undefined; if (val === '' && force) { this.attributes[attr] = val; } } addOptionalNamespace(prefix, namespace) { this.optionalNamespaces[namespace] = prefix; } useNamespace(prefix, namespace) { if (this.optionalNamespaces[namespace]) { prefix = this.optionalNamespaces[namespace]; } this.setAttribute(`xmlns:${prefix}`, namespace); return prefix; } toJSON() { const children = this.children .map(child => { if (typeof child === 'string') { return child; } if (child) { return child.toJSON(); } }) .filter(child => !!child); // Strip any undefined/null attributes const attrs = {}; for (const [key, val] of Object.entries(this.attributes)) { if (val !== undefined && val !== null) { attrs[key] = val; } } return { attributes: attrs, children, name: this.name }; } toString() { let output = this.openTag(true); if (this.children.length) { for (const child of this.children) { if (typeof child === 'string') { output += escapeXMLText(child); } else if (child) { output += child.toString(); } } output += this.closeTag(); } return output; } openTag(allowSelfClose = false) { let output = ''; output += `<${this.name}`; for (const [key, value] of Object.entries(this.attributes)) { if (value !== undefined) { output += ` ${key}="${escapeXML(value.toString())}"`; } } if (allowSelfClose && this.children.length === 0) { output += '/>'; } else { output += '>'; } return output; } closeTag() { return `</${this.name}>`; } findNamespaceForPrefix(prefix) { if (!prefix) { if (this.attributes.xmlns) { return this.attributes.xmlns; } else if (this.parent) { return this.parent.findNamespaceForPrefix(); } } else { const attr = 'xmlns:' + prefix; if (this.attributes[attr]) { return this.attributes[attr]; } else if (this.parent) { return this.parent.findNamespaceForPrefix(prefix); } } return ''; } } /** * This file is derived from prior work. * * See NOTICE.md for full license text. * * Derived from: xhtml-im.js, Copyright © 2013 Waqas Hussain */ const ALLOWED_ELEMENTS = new Set([ 'a', 'blockquote', 'br', 'cite', 'em', 'img', 'li', 'ol', 'p', 'span', 'strong', 'ul' ]); const style = new Set(['style']); const ALLOWED_ATTRIBUTES = new Map([ ['a', new Set(['href', 'style'])], ['body', new Set(['style', 'xml:lang'])], ['blockquote', style], ['br', style], ['cite', style], ['em', style], ['img', new Set(['alt', 'height', 'src', 'style', 'width'])], ['li', style], ['ol', style], ['p', style], ['span', style], ['strong', style], ['ul', style] ]); const CSS_RULES = new Map([ ['font-style', /normal|italic|oblique|inherit/i], ['font-weight', /normal|bold|bolder|lighter|inherit|\d\d\d/i], ['text-decoration', /none|underline|overline|line-through|blink|inherit/i] // These properties are allowed by XHTML-IM, but really only cause UX issues: // background-color // color // font-family // font-size // margin-left // margin-right // text-align ]); const sanitizeCSS = (css) => { const declarations = `;${css}` // Declarations are ; delimited, not terminated .replace(/\/\*[^*]*\*+([^/*][^*]*\*+)*\//g, '') // Strip comments .replace(/\/\*.*/, '') // Strip