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);