1 // Copyright 2015 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.
6 /** @suppress {duplicate} */
7 var remoting
= remoting
|| {};
14 * This class monitors incoming XMPP stanza and records the first
15 * error encountered. It also strips all PII from the error stanza,
16 * so that it can be uploaded to the cloud for error analysis.
21 remoting
.XmppErrorCache = function() {
22 /** @private {remoting.ChromotingEvent.XmppError} */
23 this.firstError_
= null;
27 * @return {remoting.ChromotingEvent.XmppError} The first XMPP error that the
28 * monitor encountered. Returns null if no errors have been encountered so
31 remoting
.XmppErrorCache
.prototype.getFirstError = function() {
32 return this.firstError_
;
36 * Monitor the incoming stanza for error.
38 * @param {Element} iqNode
40 remoting
.XmppErrorCache
.prototype.processStanza = function(iqNode
) {
41 if (this.firstError_
!= null) {
44 // The XML structure is as follows:
46 // <jingle action='session-accept'/>
47 // <error type='modify' code=''/>
49 if (iqNode
.getAttribute('type') != 'error') {
53 var strippedStanza
= this.stripPII_(iqNode
);
54 this.firstError_
= new remoting
.ChromotingEvent
.XmppError(strippedStanza
);
58 * @param {Element} iqNode
59 * @return {string} Return a string representation of |iqNode| with all PII
63 remoting
.XmppErrorCache
.prototype.stripPII_ = function(iqNode
) {
64 var parser
= new DOMParser();
65 var outDocument
= parser
.parseFromString('<iq/>', 'text/xml');
66 stripPII(iqNode
, outDocument
.firstElementChild
);
67 return new XMLSerializer().serializeToString(outDocument
.firstElementChild
);
71 * @param {Element} node
72 * @param {Element} outNode
74 function stripPII(node
, outNode
) {
75 var attributesWhiteList
= new Set([
92 var nodesWhiteList
= new Set([
102 'initial-resolution',
105 'service-unavailable'
108 // Strip PII from attributes.
109 var attributes
= node
.attributes
;
110 for (var i
= 0; i
< attributes
.length
; i
++) {
111 var attribute
= /** @type {Attr} */ (attributes
[i
]);
112 var value
= 'REDACTED';
113 if (attributesWhiteList
.has(attribute
.nodeName
)) {
114 value
= attribute
.nodeValue
;
116 outNode
.setAttribute(attribute
.nodeName
, value
);
119 // Copy the text content.
120 if (node
.childNodes
.length
== 1 &&
121 node
.firstChild
.nodeType
== Node
.TEXT_NODE
) {
122 var textValue
= 'REDACTED';
123 if (nodesWhiteList
.has(node
.tagName
)) {
124 textValue
= node
.firstChild
.nodeValue
;
126 outNode
.appendChild(outNode
.ownerDocument
.createTextNode(textValue
));
130 // Strip PII from child nodes.
131 var children
= node
.children
;
132 for (i
= 0; i
< children
.length
; i
++) {
133 var child
= /** @type{Element}*/ (children
[i
]);
134 var childCopy
= outNode
.ownerDocument
.createElement(child
.tagName
);
135 outNode
.appendChild(childCopy
);
136 stripPII(child
, childCopy
);