--- a/browser/extensions/screenshots/webextension/build/raven.js
+++ b/browser/extensions/screenshots/webextension/build/raven.js
@@ -1,9 +1,9 @@
-/*! Raven.js 3.24.1 (f3b3500) | github.com/getsentry/raven-js */
+/*! Raven.js 3.25.2 (30b6d4e) | github.com/getsentry/raven-js */
/*
* Includes TraceKit
* https://github.com/getsentry/TraceKit
*
* Copyright 2018 Matt Robenolt and other contributors
* Released under the BSD license
* https://github.com/getsentry/raven-js/blob/master/LICENSE
@@ -69,20 +69,22 @@ module.exports = {
/*global XDomainRequest:false */
var TraceKit = _dereq_(6);
var stringify = _dereq_(7);
var md5 = _dereq_(8);
var RavenConfigError = _dereq_(1);
var utils = _dereq_(5);
+var isErrorEvent = utils.isErrorEvent;
+var isDOMError = utils.isDOMError;
+var isDOMException = utils.isDOMException;
var isError = utils.isError;
var isObject = utils.isObject;
var isPlainObject = utils.isPlainObject;
-var isErrorEvent = utils.isErrorEvent;
var isUndefined = utils.isUndefined;
var isFunction = utils.isFunction;
var isString = utils.isString;
var isArray = utils.isArray;
var isEmptyObject = utils.isEmptyObject;
var each = utils.each;
var objectMerge = utils.objectMerge;
var truncate = utils.truncate;
@@ -110,17 +112,21 @@ var dsnKeys = 'source protocol user pass
function now() {
return +new Date();
}
// This is to be defensive in environments where window does not exist (see https://github.com/getsentry/raven-js/pull/785)
var _window =
typeof window !== 'undefined'
? window
- : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
+ : typeof global !== 'undefined'
+ ? global
+ : typeof self !== 'undefined'
+ ? self
+ : {};
var _document = _window.document;
var _navigator = _window.navigator;
function keepOriginalCallback(original, callback) {
return isFunction(callback)
? function(data) {
return callback(data, original);
}
@@ -200,17 +206,17 @@ function Raven() {
* @this {Raven}
*/
Raven.prototype = {
// Hardcode version string so that raven source can be loaded directly via
// webpack (using a build step causes webpack #1617). Grunt verifies that
// this value matches package.json during build.
// See: https://github.com/getsentry/raven-js/issues/465
- VERSION: '3.24.1',
+ VERSION: '3.25.2',
debug: false,
TraceKit: TraceKit, // alias to TraceKit
/*
* Configure Raven with a DSN and extra options
*
@@ -532,27 +538,45 @@ Raven.prototype = {
* @return {Raven}
*/
captureException: function(ex, options) {
options = objectMerge({trimHeadFrames: 0}, options ? options : {});
if (isErrorEvent(ex) && ex.error) {
// If it is an ErrorEvent with `error` property, extract it to get actual Error
ex = ex.error;
+ } else if (isDOMError(ex) || isDOMException(ex)) {
+ // If it is a DOMError or DOMException (which are legacy APIs, but still supported in some browsers)
+ // then we just extract the name and message, as they don't provide anything else
+ // https://developer.mozilla.org/en-US/docs/Web/API/DOMError
+ // https://developer.mozilla.org/en-US/docs/Web/API/DOMException
+ var name = ex.name || (isDOMError(ex) ? 'DOMError' : 'DOMException');
+ var message = ex.message ? name + ': ' + ex.message : name;
+
+ return this.captureMessage(
+ message,
+ objectMerge(options, {
+ // neither DOMError or DOMException provide stack trace and we most likely wont get it this way as well
+ // but it's barely any overhead so we may at least try
+ stacktrace: true,
+ trimHeadFrames: options.trimHeadFrames + 1
+ })
+ );
} else if (isError(ex)) {
// we have a real Error object
ex = ex;
} else if (isPlainObject(ex)) {
// If it is plain Object, serialize it manually and extract options
// This will allow us to group events based on top-level keys
// which is much better than creating new group when any key/value change
options = this._getCaptureExceptionOptionsFromPlainObject(options, ex);
ex = new Error(options.message);
} else {
// If none of previous checks were valid, then it means that
+ // it's not a DOMError/DOMException
// it's not a plain Object
// it's not a valid ErrorEvent (one with an error property)
// it's not an Error
// So bail out and capture it as a simple message:
return this.captureMessage(
ex,
objectMerge(options, {
stacktrace: true, // if we fall back to captureMessage, default to attempting a new trace
@@ -634,16 +658,24 @@ Raven.prototype = {
}
// null exception name so `Error` isn't prefixed to msg
ex.name = null;
var stack = TraceKit.computeStackTrace(ex);
// stack[0] is `throw new Error(msg)` call itself, we are interested in the frame that was just before that, stack[1]
var initialCall = isArray(stack.stack) && stack.stack[1];
+
+ // if stack[1] is `Raven.captureException`, it means that someone passed a string to it and we redirected that call
+ // to be handled by `captureMessage`, thus `initialCall` is the 3rd one, not 2nd
+ // initialCall => captureException(string) => captureMessage(string)
+ if (initialCall && initialCall.func === 'Raven.captureException') {
+ initialCall = stack.stack[2];
+ }
+
var fileurl = (initialCall && initialCall.url) || '';
if (
!!this._globalOptions.ignoreUrls.test &&
this._globalOptions.ignoreUrls.test(fileurl)
) {
return;
}
@@ -1431,57 +1463,70 @@ Raven.prototype = {
}
var fetchData = {
method: method,
url: url,
status_code: null
};
- return origFetch.apply(this, args).then(function(response) {
- fetchData.status_code = response.status;
-
- self.captureBreadcrumb({
- type: 'http',
- category: 'fetch',
- data: fetchData
+ return origFetch
+ .apply(this, args)
+ .then(function(response) {
+ fetchData.status_code = response.status;
+
+ self.captureBreadcrumb({
+ type: 'http',
+ category: 'fetch',
+ data: fetchData
+ });
+
+ return response;
+ })
+ ['catch'](function(err) {
+ // if there is an error performing the request
+ self.captureBreadcrumb({
+ type: 'http',
+ category: 'fetch',
+ data: fetchData,
+ level: 'error'
+ });
+
+ throw err;
});
-
- return response;
- });
};
},
wrappedBuiltIns
);
}
// Capture breadcrumbs from any click that is unhandled / bubbled up all the way
// to the document. Do this before we instrument addEventListener.
if (autoBreadcrumbs.dom && this._hasDocument) {
if (_document.addEventListener) {
_document.addEventListener('click', self._breadcrumbEventHandler('click'), false);
_document.addEventListener('keypress', self._keypressEventHandler(), false);
- } else if(_document.attachEvent){
+ } else if (_document.attachEvent) {
// IE8 Compatibility
_document.attachEvent('onclick', self._breadcrumbEventHandler('click'));
_document.attachEvent('onkeypress', self._keypressEventHandler());
}
}
// record navigation (URL) changes
// NOTE: in Chrome App environment, touching history.pushState, *even inside
// a try/catch block*, will cause Chrome to output an error to console.error
// borrowed from: https://github.com/angular/angular.js/pull/13945/files
var chrome = _window.chrome;
var isChromePackagedApp = chrome && chrome.app && chrome.app.runtime;
var hasPushAndReplaceState =
!isChromePackagedApp &&
_window.history &&
- history.pushState &&
- history.replaceState;
+ _window.history.pushState &&
+ _window.history.replaceState;
if (autoBreadcrumbs.location && hasPushAndReplaceState) {
// TODO: remove onpopstate handler on uninstall()
var oldOnPopState = _window.onpopstate;
_window.onpopstate = function() {
var currentHref = self._location.href;
self._captureUrlChange(self._lastHref, currentHref);
if (oldOnPopState) {
@@ -1500,18 +1545,18 @@ Raven.prototype = {
// coerce to string (this is what pushState does)
self._captureUrlChange(self._lastHref, url + '');
}
return origHistFunction.apply(this, arguments);
};
};
- fill(history, 'pushState', historyReplacementFunction, wrappedBuiltIns);
- fill(history, 'replaceState', historyReplacementFunction, wrappedBuiltIns);
+ fill(_window.history, 'pushState', historyReplacementFunction, wrappedBuiltIns);
+ fill(_window.history, 'replaceState', historyReplacementFunction, wrappedBuiltIns);
}
if (autoBreadcrumbs.console && 'console' in _window && console.log) {
// console
var consoleMethodCallback = function(msg, data) {
self.captureBreadcrumb({
message: msg,
level: data.level,
@@ -1717,17 +1762,17 @@ Raven.prototype = {
values: [
{
type: type,
value: message,
stacktrace: stacktrace
}
]
},
- culprit: fileurl
+ transaction: fileurl
},
options
);
// Fire away!
this._send(data);
},
@@ -1791,17 +1836,17 @@ Raven.prototype = {
},
_getHttpData: function() {
if (!this._hasNavigator && !this._hasDocument) return;
var httpData = {};
if (this._hasNavigator && _navigator.userAgent) {
httpData.headers = {
- 'User-Agent': navigator.userAgent
+ 'User-Agent': _navigator.userAgent
};
}
// Check in `window` instead of `document`, as we may be in ServiceWorker environment
if (_window.location && _window.location.href) {
httpData.url = _window.location.href;
}
@@ -1832,17 +1877,17 @@ Raven.prototype = {
* data object with a single frame (derived from the onerror args).
*/
_isRepeatData: function(current) {
var last = this._lastData;
if (
!last ||
current.message !== last.message || // defined for captureMessage
- current.culprit !== last.culprit // defined for captureException/onerror
+ current.transaction !== last.transaction // defined for captureException/onerror
)
return false;
// Stacktrace interface (i.e. from captureMessage)
if (current.stacktrace || last.stacktrace) {
return isSameStacktrace(current.stacktrace, last.stacktrace);
} else if (current.exception || last.exception) {
// Exception interface (i.e. from captureException/onerror)
@@ -2177,17 +2222,21 @@ Raven.prototype = {
evaluated[key] = typeof value === 'function' ? value() : value;
}
}
return evaluated;
},
_logDebug: function(level) {
- if (this._originalConsoleMethods[level] && this.debug) {
+ // We allow `Raven.debug` and `Raven.config(DSN, { debug: true })` to not make backward incompatible API change
+ if (
+ this._originalConsoleMethods[level] &&
+ (this.debug || this._globalOptions.debug)
+ ) {
// In IE<10 console methods do not have their own 'apply' method
Function.prototype.apply.call(
this._originalConsoleMethods[level],
this._originalConsole,
[].slice.call(arguments, 1)
);
}
},
@@ -2290,30 +2339,38 @@ var _window =
function isObject(what) {
return typeof what === 'object' && what !== null;
}
// Yanked from https://git.io/vS8DV re-used under CC0
// with some tiny modifications
function isError(value) {
- switch ({}.toString.call(value)) {
+ switch (Object.prototype.toString.call(value)) {
case '[object Error]':
return true;
case '[object Exception]':
return true;
case '[object DOMException]':
return true;
default:
return value instanceof Error;
}
}
function isErrorEvent(value) {
- return supportsErrorEvent() && {}.toString.call(value) === '[object ErrorEvent]';
+ return Object.prototype.toString.call(value) === '[object ErrorEvent]';
+}
+
+function isDOMError(value) {
+ return Object.prototype.toString.call(value) === '[object DOMError]';
+}
+
+function isDOMException(value) {
+ return Object.prototype.toString.call(value) === '[object DOMException]';
}
function isUndefined(what) {
return what === void 0;
}
function isFunction(what) {
return typeof what === 'function';
@@ -2346,16 +2403,34 @@ function supportsErrorEvent() {
try {
new ErrorEvent(''); // eslint-disable-line no-new
return true;
} catch (e) {
return false;
}
}
+function supportsDOMError() {
+ try {
+ new DOMError(''); // eslint-disable-line no-new
+ return true;
+ } catch (e) {
+ return false;
+ }
+}
+
+function supportsDOMException() {
+ try {
+ new DOMException(''); // eslint-disable-line no-new
+ return true;
+ } catch (e) {
+ return false;
+ }
+}
+
function supportsFetch() {
if (!('fetch' in _window)) return false;
try {
new Headers(); // eslint-disable-line no-new
new Request(''); // eslint-disable-line no-new
new Response(); // eslint-disable-line no-new
return true;
@@ -2438,17 +2513,23 @@ function objectMerge(obj1, obj2) {
function objectFrozen(obj) {
if (!Object.isFrozen) {
return false;
}
return Object.isFrozen(obj);
}
function truncate(str, max) {
- return !max || str.length <= max ? str : str.substr(0, max) + '\u2026';
+ if (typeof max !== 'number') {
+ throw new Error('2nd argument to `truncate` function should be a number');
+ }
+ if (typeof str !== 'string' || max === 0) {
+ return str;
+ }
+ return str.length <= max ? str : str.substr(0, max) + '\u2026';
}
/**
* hasKey, a better form of hasOwnProperty
* Example: hasKey(MainHostObject, property) === true/false
*
* @param {Object} host object to check property
* @param {string} key to check
@@ -2737,20 +2818,19 @@ function utf8Length(value) {
return ~-encodeURI(value).split(/%..|./).length;
}
function jsonSize(value) {
return utf8Length(JSON.stringify(value));
}
function serializeValue(value) {
- var maxLength = 40;
-
if (typeof value === 'string') {
- return value.length <= maxLength ? value : value.substr(0, maxLength - 1) + '\u2026';
+ var maxLength = 40;
+ return truncate(value, maxLength);
} else if (
typeof value === 'number' ||
typeof value === 'boolean' ||
typeof value === 'undefined'
) {
return value;
}
@@ -2856,23 +2936,27 @@ function sanitize(input, sanitizeKeys) {
return sanitizeWorker(safeInput);
}
module.exports = {
isObject: isObject,
isError: isError,
isErrorEvent: isErrorEvent,
+ isDOMError: isDOMError,
+ isDOMException: isDOMException,
isUndefined: isUndefined,
isFunction: isFunction,
isPlainObject: isPlainObject,
isString: isString,
isArray: isArray,
isEmptyObject: isEmptyObject,
supportsErrorEvent: supportsErrorEvent,
+ supportsDOMError: supportsDOMError,
+ supportsDOMException: supportsDOMException,
supportsFetch: supportsFetch,
supportsReferrerPolicy: supportsReferrerPolicy,
supportsPromiseRejectionEvent: supportsPromiseRejectionEvent,
wrappedCallback: wrappedCallback,
each: each,
objectMerge: objectMerge,
truncate: truncate,
objectFrozen: objectFrozen,
@@ -2922,20 +3006,34 @@ var _window =
var _slice = [].slice;
var UNKNOWN_FUNCTION = '?';
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Error_types
var ERROR_TYPES_RE = /^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$/;
function getLocationHref() {
if (typeof document === 'undefined' || document.location == null) return '';
-
return document.location.href;
}
+function getLocationOrigin() {
+ if (typeof document === 'undefined' || document.location == null) return '';
+
+ // Oh dear IE10...
+ if (!document.location.origin) {
+ document.location.origin =
+ document.location.protocol +
+ '//' +
+ document.location.hostname +
+ (document.location.port ? ':' + document.location.port : '');
+ }
+
+ return document.location.origin;
+}
+
/**
* TraceKit.report: cross-browser processing of unhandled exceptions
*
* Syntax:
* TraceKit.report.subscribe(function(stackInfo) { ... })
* TraceKit.report.unsubscribe(function(stackInfo) { ... })
* TraceKit.report(exception)
* try { ...code... } catch(ex) { TraceKit.report(ex); }
@@ -3333,16 +3431,54 @@ TraceKit.computeStackTrace = (function c
} else {
continue;
}
if (!element.func && element.line) {
element.func = UNKNOWN_FUNCTION;
}
+ if (element.url && element.url.substr(0, 5) === 'blob:') {
+ // Special case for handling JavaScript loaded into a blob.
+ // We use a synchronous AJAX request here as a blob is already in
+ // memory - it's not making a network request. This will generate a warning
+ // in the browser console, but there has already been an error so that's not
+ // that much of an issue.
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', element.url, false);
+ xhr.send(null);
+
+ // If we failed to download the source, skip this patch
+ if (xhr.status === 200) {
+ var source = xhr.responseText || '';
+
+ // We trim the source down to the last 300 characters as sourceMappingURL is always at the end of the file.
+ // Why 300? To be in line with: https://github.com/getsentry/sentry/blob/4af29e8f2350e20c28a6933354e4f42437b4ba42/src/sentry/lang/javascript/processor.py#L164-L175
+ source = source.slice(-300);
+
+ // Now we dig out the source map URL
+ var sourceMaps = source.match(/\/\/# sourceMappingURL=(.*)$/);
+
+ // If we don't find a source map comment or we find more than one, continue on to the next element.
+ if (sourceMaps) {
+ var sourceMapAddress = sourceMaps[1];
+
+ // Now we check to see if it's a relative URL.
+ // If it is, convert it to an absolute one.
+ if (sourceMapAddress.charAt(0) === '~') {
+ sourceMapAddress = getLocationOrigin() + sourceMapAddress.slice(1);
+ }
+
+ // Now we strip the '.map' off of the end of the URL and update the
+ // element so that Sentry can match the map to the blob.
+ element.url = sourceMapAddress.slice(0, -4);
+ }
+ }
+ }
+
stack.push(element);
}
if (!stack.length) {
return null;
}
return {