https://github.com/getsentry/sentry-javascript/blob/d5e44e2cf87ccecefc9a07bc460f403b3a0f46fd/dist/raven.js Reformatted using Prettier.io
Unified · Split
| @@ -1,10 +1,10 @@ | ||
| 1 | −/*! Raven.js 3.20.1 (42adaf5) | github.com/getsentry/raven-js */ | |
| 1 | +/*! Raven.js 3.25.2 (30b6d4e) | github.com/getsentry/raven-js */ | |
| 2 | 2 | |
| 3 | 3 | /* |
| 4 | 4 | * Includes TraceKit |
| 5 | 5 | * https://github.com/getsentry/TraceKit |
| 6 | 6 | * |
| 7 | − * Copyright 2017 Matt Robenolt and other contributors | |
| 7 | + * Copyright 2018 Matt Robenolt and other contributors | |
| 8 | 8 | * Released under the BSD license |
| 9 | 9 | * https://github.com/getsentry/raven-js/blob/master/LICENSE |
| 10 | 10 | * |
| @@ -77,6 +77,8 @@ · 66 unmodified lines | ||
| 77 | 77 | ], |
| 78 | 78 | 2: [ |
| 79 | 79 | function (_dereq_, module, exports) { |
| 80 | + var utils = _dereq_(5); | |
| 81 | + | |
| 80 | 82 | var wrapMethod = function (console, level, callback) { |
| 81 | 83 | var originalConsoleLevel = console[level]; |
| 82 | 84 | var originalConsole = console; |
| @@ -90,7 +92,7 @@ · 7 unmodified lines | ||
| 90 | 92 | console[level] = function () { |
| 91 | 93 | var args = [].slice.call(arguments); |
| 92 | 94 | |
| 93 | − var msg = "" + args.join(" "); | |
| 95 | + var msg = utils.safeJoin(args, " "); | |
| 94 | 96 | var data = { |
| 95 | 97 | level: sentryLevel, |
| 96 | 98 | logger: "console", |
| @@ -102,7 +104,7 @@ · 5 unmodified lines | ||
| 102 | 104 | // Default browsers message |
| 103 | 105 | msg = |
| 104 | 106 | "Assertion failed: " + |
| 105 | − (args.slice(1).join(" ") || "console.assert"); | |
| 107 | + (utils.safeJoin(args.slice(1), " ") || "console.assert"); | |
| 106 | 108 | data.extra.arguments = args.slice(1); |
| 107 | 109 | callback && callback(msg, data); |
| 108 | 110 | } |
| @@ -127,7 +129,7 @@ · 18 unmodified lines | ||
| 127 | 129 | wrapMethod: wrapMethod, |
| 128 | 130 | }; |
| 129 | 131 | }, |
| 130 | − {}, | |
| 132 | + { 5: 5 }, | |
| 131 | 133 | ], |
| 132 | 134 | 3: [ |
| 133 | 135 | function (_dereq_, module, exports) { |
| @@ -136,12 +138,16 @@ · 2 unmodified lines | ||
| 136 | 138 | |
| 137 | 139 | var TraceKit = _dereq_(6); |
| 138 | 140 | var stringify = _dereq_(7); |
| 141 | + var md5 = _dereq_(8); | |
| 139 | 142 | var RavenConfigError = _dereq_(1); |
| 140 | 143 | |
| 141 | 144 | var utils = _dereq_(5); |
| 145 | + var isErrorEvent = utils.isErrorEvent; | |
| 146 | + var isDOMError = utils.isDOMError; | |
| 147 | + var isDOMException = utils.isDOMException; | |
| 142 | 148 | var isError = utils.isError; |
| 143 | 149 | var isObject = utils.isObject; |
| 144 | − var isErrorEvent = utils.isErrorEvent; | |
| 150 | + var isPlainObject = utils.isPlainObject; | |
| 145 | 151 | var isUndefined = utils.isUndefined; |
| 146 | 152 | var isFunction = utils.isFunction; |
| 147 | 153 | var isString = utils.isString; |
| @@ -160,6 +166,11 @@ · 12 unmodified lines | ||
| 160 | 166 | var isSameStacktrace = utils.isSameStacktrace; |
| 161 | 167 | var parseUrl = utils.parseUrl; |
| 162 | 168 | var fill = utils.fill; |
| 169 | + var supportsFetch = utils.supportsFetch; | |
| 170 | + var supportsReferrerPolicy = utils.supportsReferrerPolicy; | |
| 171 | + var serializeKeysForMessage = utils.serializeKeysForMessage; | |
| 172 | + var serializeException = utils.serializeException; | |
| 173 | + var sanitize = utils.sanitize; | |
| 163 | 174 | |
| 164 | 175 | var wrapConsoleMethod = _dereq_(2).wrapMethod; |
| 165 | 176 | |
| @@ -207,20 +218,33 @@ · 41 unmodified lines | ||
| 207 | 218 | this._globalProject = null; |
| 208 | 219 | this._globalContext = {}; |
| 209 | 220 | this._globalOptions = { |
| 221 | + // SENTRY_RELEASE can be injected by https://github.com/getsentry/sentry-webpack-plugin | |
| 222 | + release: _window.SENTRY_RELEASE && _window.SENTRY_RELEASE.id, | |
| 210 | 223 | logger: "javascript", |
| 211 | 224 | ignoreErrors: [], |
| 212 | 225 | ignoreUrls: [], |
| 213 | 226 | whitelistUrls: [], |
| 214 | 227 | includePaths: [], |
| 228 | + headers: null, | |
| 215 | 229 | collectWindowErrors: true, |
| 230 | + captureUnhandledRejections: true, | |
| 216 | 231 | maxMessageLength: 0, |
| 217 | − | |
| 218 | 232 | // By default, truncates URL values to 250 chars |
| 219 | 233 | maxUrlLength: 250, |
| 220 | 234 | stackTraceLimit: 50, |
| 221 | 235 | autoBreadcrumbs: true, |
| 222 | 236 | instrument: true, |
| 223 | 237 | sampleRate: 1, |
| 238 | + sanitizeKeys: [], | |
| 239 | + }; | |
| 240 | + this._fetchDefaults = { | |
| 241 | + method: "POST", | |
| 242 | + keepalive: true, | |
| 243 | + // Despite all stars in the sky saying that Edge supports old draft syntax, aka 'never', 'always', 'origin' and 'default | |
| 244 | + // https://caniuse.com/#feat=referrer-policy | |
| 245 | + // It doesn't. And it throw exception instead of ignoring this parameter... | |
| 246 | + // REF: https://github.com/getsentry/raven-js/issues/1233 | |
| 247 | + referrerPolicy: supportsReferrerPolicy() ? "origin" : "", | |
| 224 | 248 | }; |
| 225 | 249 | this._ignoreOnError = 0; |
| 226 | 250 | this._isRavenInstalled = false; |
| @@ -257,7 +281,7 @@ · 30 unmodified lines | ||
| 257 | 281 | // webpack (using a build step causes webpack #1617). Grunt verifies that |
| 258 | 282 | // this value matches package.json during build. |
| 259 | 283 | // See: https://github.com/getsentry/raven-js/issues/465 |
| 260 | − VERSION: "3.20.1", | |
| 284 | + VERSION: "3.25.2", | |
| 261 | 285 | |
| 262 | 286 | debug: false, |
| 263 | 287 | |
| @@ -376,6 +400,10 @@ · 112 unmodified lines | ||
| 376 | 400 | self._handleOnErrorStackInfo.apply(self, arguments); |
| 377 | 401 | }); |
| 378 | 402 | |
| 403 | + if (self._globalOptions.captureUnhandledRejections) { | |
| 404 | + self._attachPromiseRejectionHandler(); | |
| 405 | + } | |
| 406 | + | |
| 379 | 407 | self._patchFunctionToString(); |
| 380 | 408 | |
| 381 | 409 | if ( |
| @@ -538,7 +566,7 @@ · 156 unmodified lines | ||
| 538 | 566 | return wrapped; |
| 539 | 567 | }, |
| 540 | 568 | |
| 541 | − /* | |
| 569 | + /** | |
| 542 | 570 | * Uninstalls the global error handler. |
| 543 | 571 | * |
| 544 | 572 | * @return {Raven} |
| @@ -546,8 +574,10 @@ · 1 unmodified line | ||
| 546 | 574 | uninstall: function () { |
| 547 | 575 | TraceKit.report.uninstall(); |
| 548 | 576 | |
| 577 | + this._detachPromiseRejectionHandler(); | |
| 549 | 578 | this._unpatchFunctionToString(); |
| 550 | 579 | this._restoreBuiltIns(); |
| 580 | + this._restoreConsole(); | |
| 551 | 581 | |
| 552 | 582 | Error.stackTraceLimit = this._originalErrorStackTraceLimit; |
| 553 | 583 | this._isRavenInstalled = false; |
| @@ -555,7 +585,58 @@ · 1 unmodified line | ||
| 555 | 585 | return this; |
| 556 | 586 | }, |
| 557 | 587 | |
| 558 | − /* | |
| 588 | + /** | |
| 589 | + * Callback used for `unhandledrejection` event | |
| 590 | + * | |
| 591 | + * @param {PromiseRejectionEvent} event An object containing | |
| 592 | + * promise: the Promise that was rejected | |
| 593 | + * reason: the value with which the Promise was rejected | |
| 594 | + * @return void | |
| 595 | + */ | |
| 596 | + _promiseRejectionHandler: function (event) { | |
| 597 | + this._logDebug( | |
| 598 | + "debug", | |
| 599 | + "Raven caught unhandled promise rejection:", | |
| 600 | + event, | |
| 601 | + ); | |
| 602 | + this.captureException(event.reason, { | |
| 603 | + extra: { | |
| 604 | + unhandledPromiseRejection: true, | |
| 605 | + }, | |
| 606 | + }); | |
| 607 | + }, | |
| 608 | + | |
| 609 | + /** | |
| 610 | + * Installs the global promise rejection handler. | |
| 611 | + * | |
| 612 | + * @return {raven} | |
| 613 | + */ | |
| 614 | + _attachPromiseRejectionHandler: function () { | |
| 615 | + this._promiseRejectionHandler = | |
| 616 | + this._promiseRejectionHandler.bind(this); | |
| 617 | + _window.addEventListener && | |
| 618 | + _window.addEventListener( | |
| 619 | + "unhandledrejection", | |
| 620 | + this._promiseRejectionHandler, | |
| 621 | + ); | |
| 622 | + return this; | |
| 623 | + }, | |
| 624 | + | |
| 625 | + /** | |
| 626 | + * Uninstalls the global promise rejection handler. | |
| 627 | + * | |
| 628 | + * @return {raven} | |
| 629 | + */ | |
| 630 | + _detachPromiseRejectionHandler: function () { | |
| 631 | + _window.removeEventListener && | |
| 632 | + _window.removeEventListener( | |
| 633 | + "unhandledrejection", | |
| 634 | + this._promiseRejectionHandler, | |
| 635 | + ); | |
| 636 | + return this; | |
| 637 | + }, | |
| 638 | + | |
| 639 | + /** | |
| 559 | 640 | * Manually capture an exception and send it over to Sentry |
| 560 | 641 | * |
| 561 | 642 | * @param {error} ex An exception to be logged |
| @@ -563,30 +644,60 @@ · 1 unmodified line | ||
| 563 | 644 | * @return {Raven} |
| 564 | 645 | */ |
| 565 | 646 | captureException: function (ex, options) { |
| 566 | − // Cases for sending ex as a message, rather than an exception | |
| 567 | − var isNotError = !isError(ex); | |
| 568 | − var isNotErrorEvent = !isErrorEvent(ex); | |
| 569 | − var isErrorEventWithoutError = isErrorEvent(ex) && !ex.error; | |
| 647 | + options = objectMerge( | |
| 648 | + { trimHeadFrames: 0 }, | |
| 649 | + options ? options : {}, | |
| 650 | + ); | |
| 570 | 651 | |
| 571 | − if ( | |
| 572 | − (isNotError && isNotErrorEvent) || | |
| 573 | − isErrorEventWithoutError | |
| 574 | − ) { | |
| 652 | + if (isErrorEvent(ex) && ex.error) { | |
| 653 | + // If it is an ErrorEvent with `error` property, extract it to get actual Error | |
| 654 | + ex = ex.error; | |
| 655 | + } else if (isDOMError(ex) || isDOMException(ex)) { | |
| 656 | + // If it is a DOMError or DOMException (which are legacy APIs, but still supported in some browsers) | |
| 657 | + // then we just extract the name and message, as they don't provide anything else | |
| 658 | + // https://developer.mozilla.org/en-US/docs/Web/API/DOMError | |
| 659 | + // https://developer.mozilla.org/en-US/docs/Web/API/DOMException | |
| 660 | + var name = | |
| 661 | + ex.name || (isDOMError(ex) ? "DOMError" : "DOMException"); | |
| 662 | + var message = ex.message ? name + ": " + ex.message : name; | |
| 663 | + | |
| 664 | + return this.captureMessage( | |
| 665 | + message, | |
| 666 | + objectMerge(options, { | |
| 667 | + // neither DOMError or DOMException provide stack trace and we most likely wont get it this way as well | |
| 668 | + // but it's barely any overhead so we may at least try | |
| 669 | + stacktrace: true, | |
| 670 | + trimHeadFrames: options.trimHeadFrames + 1, | |
| 671 | + }), | |
| 672 | + ); | |
| 673 | + } else if (isError(ex)) { | |
| 674 | + // we have a real Error object | |
| 675 | + ex = ex; | |
| 676 | + } else if (isPlainObject(ex)) { | |
| 677 | + // If it is plain Object, serialize it manually and extract options | |
| 678 | + // This will allow us to group events based on top-level keys | |
| 679 | + // which is much better than creating new group when any key/value change | |
| 680 | + options = this._getCaptureExceptionOptionsFromPlainObject( | |
| 681 | + options, | |
| 682 | + ex, | |
| 683 | + ); | |
| 684 | + ex = new Error(options.message); | |
| 685 | + } else { | |
| 686 | + // If none of previous checks were valid, then it means that | |
| 687 | + // it's not a DOMError/DOMException | |
| 688 | + // it's not a plain Object | |
| 689 | + // it's not a valid ErrorEvent (one with an error property) | |
| 690 | + // it's not an Error | |
| 691 | + // So bail out and capture it as a simple message: | |
| 575 | 692 | return this.captureMessage( |
| 576 | 693 | ex, |
| 577 | − objectMerge( | |
| 578 | − { | |
| 579 | − trimHeadFrames: 1, | |
| 580 | − stacktrace: true, // if we fall back to captureMessage, default to attempting a new trace | |
| 581 | − }, | |
| 582 | − options, | |
| 583 | − ), | |
| 694 | + objectMerge(options, { | |
| 695 | + stacktrace: true, // if we fall back to captureMessage, default to attempting a new trace | |
| 696 | + trimHeadFrames: options.trimHeadFrames + 1, | |
| 697 | + }), | |
| 584 | 698 | ); |
| 585 | 699 | } |
| 586 | 700 | |
| 587 | − // Get actual Error from ErrorEvent | |
| 588 | − if (isErrorEvent(ex)) ex = ex.error; | |
| 589 | − | |
| 590 | 701 | // Store the raw exception object for potential debugging and introspection |
| 591 | 702 | this._lastCapturedException = ex; |
| 592 | 703 | |
| @@ -607,6 +718,23 @@ · 14 unmodified lines | ||
| 607 | 718 | return this; |
| 608 | 719 | }, |
| 609 | 720 | |
| 721 | + _getCaptureExceptionOptionsFromPlainObject: function ( | |
| 722 | + currentOptions, | |
| 723 | + ex, | |
| 724 | + ) { | |
| 725 | + var exKeys = Object.keys(ex).sort(); | |
| 726 | + var options = objectMerge(currentOptions, { | |
| 727 | + message: | |
| 728 | + "Non-Error exception captured with keys: " + | |
| 729 | + serializeKeysForMessage(exKeys), | |
| 730 | + fingerprint: [md5(exKeys)], | |
| 731 | + extra: currentOptions.extra || {}, | |
| 732 | + }); | |
| 733 | + options.extra.__serialized__ = serializeException(ex); | |
| 734 | + | |
| 735 | + return options; | |
| 736 | + }, | |
| 737 | + | |
| 610 | 738 | /* |
| 611 | 739 | * Manually send a message to Sentry |
| 612 | 740 | * |
| @@ -626,10 +754,11 @@ · 13 unmodified lines | ||
| 626 | 754 | } |
| 627 | 755 | |
| 628 | 756 | options = options || {}; |
| 757 | + msg = msg + ""; // Make sure it's actually a string | |
| 629 | 758 | |
| 630 | 759 | var data = objectMerge( |
| 631 | 760 | { |
| 632 | − message: msg + "", // Make sure it's actually a string | |
| 761 | + message: msg, | |
| 633 | 762 | }, |
| 634 | 763 | options, |
| 635 | 764 | ); |
| @@ -651,6 +780,17 @@ · 15 unmodified lines | ||
| 651 | 780 | |
| 652 | 781 | // stack[0] is `throw new Error(msg)` call itself, we are interested in the frame that was just before that, stack[1] |
| 653 | 782 | var initialCall = isArray(stack.stack) && stack.stack[1]; |
| 783 | + | |
| 784 | + // if stack[1] is `Raven.captureException`, it means that someone passed a string to it and we redirected that call | |
| 785 | + // to be handled by `captureMessage`, thus `initialCall` is the 3rd one, not 2nd | |
| 786 | + // initialCall => captureException(string) => captureMessage(string) | |
| 787 | + if ( | |
| 788 | + initialCall && | |
| 789 | + initialCall.func === "Raven.captureException" | |
| 790 | + ) { | |
| 791 | + initialCall = stack.stack[2]; | |
| 792 | + } | |
| 793 | + | |
| 654 | 794 | var fileurl = (initialCall && initialCall.url) || ""; |
| 655 | 795 | |
| 656 | 796 | if ( |
| @@ -671,18 +811,21 @@ · 14 unmodified lines | ||
| 671 | 811 | this._globalOptions.stacktrace || |
| 672 | 812 | (options && options.stacktrace) |
| 673 | 813 | ) { |
| 814 | + // fingerprint on msg, not stack trace (legacy behavior, could be revisited) | |
| 815 | + data.fingerprint = | |
| 816 | + data.fingerprint == null ? msg : data.fingerprint; | |
| 817 | + | |
| 674 | 818 | options = objectMerge( |
| 675 | 819 | { |
| 676 | − // fingerprint on msg, not stack trace (legacy behavior, could be | |
| 677 | − // revisited) | |
| 678 | − fingerprint: msg, | |
| 679 | − // since we know this is a synthetic trace, the top N-most frames | |
| 680 | − // MUST be from Raven.js, so mark them as in_app later by setting | |
| 681 | − // trimHeadFrames | |
| 682 | − trimHeadFrames: (options.trimHeadFrames || 0) + 1, | |
| 820 | + trimHeadFrames: 0, | |
| 683 | 821 | }, |
| 684 | 822 | options, |
| 685 | 823 | ); |
| 824 | + // Since we know this is a synthetic trace, the top frame (this function call) | |
| 825 | + // MUST be from Raven.js, so mark it for trimming | |
| 826 | + // We add to the trim counter so that callers can choose to trim extra frames, such | |
| 827 | + // as utility functions. | |
| 828 | + options.trimHeadFrames += 1; | |
| 686 | 829 | |
| 687 | 830 | var frames = this._prepareFrames(stack, options); |
| 688 | 831 | data.stacktrace = { |
| @@ -691,6 +834,13 @@ · 2 unmodified lines | ||
| 691 | 834 | }; |
| 692 | 835 | } |
| 693 | 836 | |
| 837 | + // Make sure that fingerprint is always wrapped in an array | |
| 838 | + if (data.fingerprint) { | |
| 839 | + data.fingerprint = isArray(data.fingerprint) | |
| 840 | + ? data.fingerprint | |
| 841 | + : [data.fingerprint]; | |
| 842 | + } | |
| 843 | + | |
| 694 | 844 | // Fire away! |
| 695 | 845 | this._send(data); |
| 696 | 846 | |
| @@ -976,7 +1126,7 @@ · 279 unmodified lines | ||
| 976 | 1126 | }, |
| 977 | 1127 | |
| 978 | 1128 | _triggerEvent: function (eventType, options) { |
| 979 | − // NOTE: `event` is a native browser thing, so let's avoid conflicting with it | |
| 1129 | + // NOTE: `event` is a native browser thing, so let's avoid conflicting wiht it | |
| 980 | 1130 | var evt, key; |
| 981 | 1131 | |
| 982 | 1132 | if (!this._hasDocument) return; |
| @@ -1290,7 +1440,7 @@ · 307 unmodified lines | ||
| 1290 | 1440 | |
| 1291 | 1441 | fill(_window, "setTimeout", wrapTimeFn, wrappedBuiltIns); |
| 1292 | 1442 | fill(_window, "setInterval", wrapTimeFn, wrappedBuiltIns); |
| 1293 | − if (_requestAnimationFrame) { | |
| 1443 | + if (_window.requestAnimationFrame) { | |
| 1294 | 1444 | fill( |
| 1295 | 1445 | _window, |
| 1296 | 1446 | "requestAnimationFrame", |
| @@ -1365,7 +1515,8 @@ · 68 unmodified lines | ||
| 1365 | 1515 | } |
| 1366 | 1516 | |
| 1367 | 1517 | if (autoBreadcrumbs.xhr && "XMLHttpRequest" in _window) { |
| 1368 | − var xhrproto = XMLHttpRequest.prototype; | |
| 1518 | + var xhrproto = | |
| 1519 | + _window.XMLHttpRequest && _window.XMLHttpRequest.prototype; | |
| 1369 | 1520 | fill( |
| 1370 | 1521 | xhrproto, |
| 1371 | 1522 | "open", |
| @@ -1395,7 +1546,7 @@ · 23 unmodified lines | ||
| 1395 | 1546 | xhrproto, |
| 1396 | 1547 | "send", |
| 1397 | 1548 | function (origSend) { |
| 1398 | − return function (data) { | |
| 1549 | + return function () { | |
| 1399 | 1550 | // preserve arity |
| 1400 | 1551 | var xhr = this; |
| 1401 | 1552 | |
| @@ -1450,12 +1601,12 @@ · 48 unmodified lines | ||
| 1450 | 1601 | ); |
| 1451 | 1602 | } |
| 1452 | 1603 | |
| 1453 | − if (autoBreadcrumbs.xhr && "fetch" in _window) { | |
| 1604 | + if (autoBreadcrumbs.xhr && supportsFetch()) { | |
| 1454 | 1605 | fill( |
| 1455 | 1606 | _window, |
| 1456 | 1607 | "fetch", |
| 1457 | 1608 | function (origFetch) { |
| 1458 | − return function (fn, t) { | |
| 1609 | + return function () { | |
| 1459 | 1610 | // preserve arity |
| 1460 | 1611 | // Make a copy of the arguments to prevent deoptimization |
| 1461 | 1612 | // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments |
| @@ -1482,6 +1633,11 @@ · 20 unmodified lines | ||
| 1482 | 1633 | url = "" + fetchInput; |
| 1483 | 1634 | } |
| 1484 | 1635 | |
| 1636 | + // if Sentry key appears in URL, don't capture, as it's our own request | |
| 1637 | + if (url.indexOf(self._globalKey) !== -1) { | |
| 1638 | + return origFetch.apply(this, args); | |
| 1639 | + } | |
| 1640 | + | |
| 1485 | 1641 | if (args[1] && args[1].method) { |
| 1486 | 1642 | method = args[1].method; |
| 1487 | 1643 | } |
| @@ -1492,18 +1648,29 @@ · 4 unmodified lines | ||
| 1492 | 1648 | status_code: null, |
| 1493 | 1649 | }; |
| 1494 | 1650 | |
| 1495 | − self.captureBreadcrumb({ | |
| 1496 | − type: "http", | |
| 1497 | − category: "fetch", | |
| 1498 | − data: fetchData, | |
| 1499 | − }); | |
| 1500 | − | |
| 1501 | 1651 | return origFetch |
| 1502 | 1652 | .apply(this, args) |
| 1503 | 1653 | .then(function (response) { |
| 1504 | 1654 | fetchData.status_code = response.status; |
| 1505 | 1655 | |
| 1656 | + self.captureBreadcrumb({ | |
| 1657 | + type: "http", | |
| 1658 | + category: "fetch", | |
| 1659 | + data: fetchData, | |
| 1660 | + }); | |
| 1661 | + | |
| 1506 | 1662 | return response; |
| 1663 | + }) | |
| 1664 | + ["catch"](function (err) { | |
| 1665 | + // if there is an error performing the request | |
| 1666 | + self.captureBreadcrumb({ | |
| 1667 | + type: "http", | |
| 1668 | + category: "fetch", | |
| 1669 | + data: fetchData, | |
| 1670 | + level: "error", | |
| 1671 | + }); | |
| 1672 | + | |
| 1673 | + throw err; | |
| 1507 | 1674 | }); |
| 1508 | 1675 | }; |
| 1509 | 1676 | }, |
| @@ -1525,7 +1692,7 @@ · 15 unmodified lines | ||
| 1525 | 1692 | self._keypressEventHandler(), |
| 1526 | 1693 | false, |
| 1527 | 1694 | ); |
| 1528 | − } else { | |
| 1695 | + } else if (_document.attachEvent) { | |
| 1529 | 1696 | // IE8 Compatibility |
| 1530 | 1697 | _document.attachEvent( |
| 1531 | 1698 | "onclick", |
| @@ -1548,8 +1715,8 @@ · 16 unmodified lines | ||
| 1548 | 1715 | var hasPushAndReplaceState = |
| 1549 | 1716 | !isChromePackagedApp && |
| 1550 | 1717 | _window.history && |
| 1551 | − history.pushState && | |
| 1552 | − history.replaceState; | |
| 1718 | + _window.history.pushState && | |
| 1719 | + _window.history.replaceState; | |
| 1553 | 1720 | if (autoBreadcrumbs.location && hasPushAndReplaceState) { |
| 1554 | 1721 | // TODO: remove onpopstate handler on uninstall() |
| 1555 | 1722 | var oldOnPopState = _window.onpopstate; |
| @@ -1579,13 +1746,13 @@ · 23 unmodified lines | ||
| 1579 | 1746 | }; |
| 1580 | 1747 | |
| 1581 | 1748 | fill( |
| 1582 | − history, | |
| 1749 | + _window.history, | |
| 1583 | 1750 | "pushState", |
| 1584 | 1751 | historyReplacementFunction, |
| 1585 | 1752 | wrappedBuiltIns, |
| 1586 | 1753 | ); |
| 1587 | 1754 | fill( |
| 1588 | − history, | |
| 1755 | + _window.history, | |
| 1589 | 1756 | "replaceState", |
| 1590 | 1757 | historyReplacementFunction, |
| 1591 | 1758 | wrappedBuiltIns, |
| @@ -1629,6 +1796,14 @@ · 37 unmodified lines | ||
| 1629 | 1796 | } |
| 1630 | 1797 | }, |
| 1631 | 1798 | |
| 1799 | + _restoreConsole: function () { | |
| 1800 | + // eslint-disable-next-line guard-for-in | |
| 1801 | + for (var method in this._originalConsoleMethods) { | |
| 1802 | + this._originalConsole[method] = | |
| 1803 | + this._originalConsoleMethods[method]; | |
| 1804 | + } | |
| 1805 | + }, | |
| 1806 | + | |
| 1632 | 1807 | _drainPlugins: function () { |
| 1633 | 1808 | var self = this; |
| 1634 | 1809 | |
| @@ -1822,7 +1997,7 @@ · 187 unmodified lines | ||
| 1822 | 1997 | }, |
| 1823 | 1998 | ], |
| 1824 | 1999 | }, |
| 1825 | − culprit: fileurl, | |
| 2000 | + transaction: fileurl, | |
| 1826 | 2001 | }, |
| 1827 | 2002 | options, |
| 1828 | 2003 | ); |
| @@ -1905,18 +2080,18 @@ · 76 unmodified lines | ||
| 1905 | 2080 | |
| 1906 | 2081 | if (this._hasNavigator && _navigator.userAgent) { |
| 1907 | 2082 | httpData.headers = { |
| 1908 | − "User-Agent": navigator.userAgent, | |
| 2083 | + "User-Agent": _navigator.userAgent, | |
| 1909 | 2084 | }; |
| 1910 | 2085 | } |
| 1911 | 2086 | |
| 1912 | − if (this._hasDocument) { | |
| 1913 | − if (_document.location && _document.location.href) { | |
| 1914 | − httpData.url = _document.location.href; | |
| 1915 | − } | |
| 1916 | − if (_document.referrer) { | |
| 1917 | − if (!httpData.headers) httpData.headers = {}; | |
| 1918 | − httpData.headers.Referer = _document.referrer; | |
| 1919 | − } | |
| 2087 | + // Check in `window` instead of `document`, as we may be in ServiceWorker environment | |
| 2088 | + if (_window.location && _window.location.href) { | |
| 2089 | + httpData.url = _window.location.href; | |
| 2090 | + } | |
| 2091 | + | |
| 2092 | + if (this._hasDocument && _document.referrer) { | |
| 2093 | + if (!httpData.headers) httpData.headers = {}; | |
| 2094 | + httpData.headers.Referer = _document.referrer; | |
| 1920 | 2095 | } |
| 1921 | 2096 | |
| 1922 | 2097 | return httpData; |
| @@ -1949,7 +2124,7 @@ · 26 unmodified lines | ||
| 1949 | 2124 | if ( |
| 1950 | 2125 | !last || |
| 1951 | 2126 | current.message !== last.message || // defined for captureMessage |
| 1952 | − current.culprit !== last.culprit // defined for captureException/onerror | |
| 2127 | + current.transaction !== last.transaction // defined for captureException/onerror | |
| 1953 | 2128 | ) |
| 1954 | 2129 | return false; |
| 1955 | 2130 | |
| @@ -1982,8 +2157,14 @@ · 26 unmodified lines | ||
| 1982 | 2157 | try { |
| 1983 | 2158 | // If Retry-After is not in Access-Control-Expose-Headers, most |
| 1984 | 2159 | // browsers will throw an exception trying to access it |
| 1985 | − retry = request.getResponseHeader("Retry-After"); | |
| 1986 | − retry = parseInt(retry, 10) * 1000; // Retry-After is returned in seconds | |
| 2160 | + if (supportsFetch()) { | |
| 2161 | + retry = request.headers.get("Retry-After"); | |
| 2162 | + } else { | |
| 2163 | + retry = request.getResponseHeader("Retry-After"); | |
| 2164 | + } | |
| 2165 | + | |
| 2166 | + // Retry-After is returned in seconds | |
| 2167 | + retry = parseInt(retry, 10) * 1000; | |
| 1987 | 2168 | } catch (e) { |
| 1988 | 2169 | /* eslint no-empty:0 */ |
| 1989 | 2170 | } |
| @@ -2037,9 +2218,6 @@ · 47 unmodified lines | ||
| 2037 | 2218 | }; |
| 2038 | 2219 | } |
| 2039 | 2220 | |
| 2040 | − // If there are no tags/extra, strip the key from the payload alltogther. | |
| 2041 | − if (isEmptyObject(data.tags)) delete data.tags; | |
| 2042 | − | |
| 2043 | 2221 | if (this._globalContext.user) { |
| 2044 | 2222 | // sentry.interfaces.User |
| 2045 | 2223 | data.user = this._globalContext.user; |
| @@ -2056,6 +2234,19 @@ · 10 unmodified lines | ||
| 2056 | 2234 | if (globalOptions.serverName) |
| 2057 | 2235 | data.server_name = globalOptions.serverName; |
| 2058 | 2236 | |
| 2237 | + data = this._sanitizeData(data); | |
| 2238 | + | |
| 2239 | + // Cleanup empty properties before sending them to the server | |
| 2240 | + Object.keys(data).forEach(function (key) { | |
| 2241 | + if ( | |
| 2242 | + data[key] == null || | |
| 2243 | + data[key] === "" || | |
| 2244 | + isEmptyObject(data[key]) | |
| 2245 | + ) { | |
| 2246 | + delete data[key]; | |
| 2247 | + } | |
| 2248 | + }); | |
| 2249 | + | |
| 2059 | 2250 | if (isFunction(globalOptions.dataCallback)) { |
| 2060 | 2251 | data = globalOptions.dataCallback(data) || data; |
| 2061 | 2252 | } |
| @@ -2093,6 +2284,10 @@ · 31 unmodified lines | ||
| 2093 | 2284 | } |
| 2094 | 2285 | }, |
| 2095 | 2286 | |
| 2287 | + _sanitizeData: function (data) { | |
| 2288 | + return sanitize(data, this._globalOptions.sanitizeKeys); | |
| 2289 | + }, | |
| 2290 | + | |
| 2096 | 2291 | _getUuid: function () { |
| 2097 | 2292 | return uuid4(); |
| 2098 | 2293 | }, |
| @@ -2197,6 +2392,61 @@ · 98 unmodified lines | ||
| 2197 | 2392 | }, |
| 2198 | 2393 | |
| 2199 | 2394 | _makeRequest: function (opts) { |
| 2395 | + // Auth is intentionally sent as part of query string (NOT as custom HTTP header) to avoid preflight CORS requests | |
| 2396 | + var url = opts.url + "?" + urlencode(opts.auth); | |
| 2397 | + | |
| 2398 | + var evaluatedHeaders = null; | |
| 2399 | + var evaluatedFetchParameters = {}; | |
| 2400 | + | |
| 2401 | + if (opts.options.headers) { | |
| 2402 | + evaluatedHeaders = this._evaluateHash(opts.options.headers); | |
| 2403 | + } | |
| 2404 | + | |
| 2405 | + if (opts.options.fetchParameters) { | |
| 2406 | + evaluatedFetchParameters = this._evaluateHash( | |
| 2407 | + opts.options.fetchParameters, | |
| 2408 | + ); | |
| 2409 | + } | |
| 2410 | + | |
| 2411 | + if (supportsFetch()) { | |
| 2412 | + evaluatedFetchParameters.body = stringify(opts.data); | |
| 2413 | + | |
| 2414 | + var defaultFetchOptions = objectMerge( | |
| 2415 | + {}, | |
| 2416 | + this._fetchDefaults, | |
| 2417 | + ); | |
| 2418 | + var fetchOptions = objectMerge( | |
| 2419 | + defaultFetchOptions, | |
| 2420 | + evaluatedFetchParameters, | |
| 2421 | + ); | |
| 2422 | + | |
| 2423 | + if (evaluatedHeaders) { | |
| 2424 | + fetchOptions.headers = evaluatedHeaders; | |
| 2425 | + } | |
| 2426 | + | |
| 2427 | + return _window | |
| 2428 | + .fetch(url, fetchOptions) | |
| 2429 | + .then(function (response) { | |
| 2430 | + if (response.ok) { | |
| 2431 | + opts.onSuccess && opts.onSuccess(); | |
| 2432 | + } else { | |
| 2433 | + var error = new Error( | |
| 2434 | + "Sentry error code: " + response.status, | |
| 2435 | + ); | |
| 2436 | + // It's called request only to keep compatibility with XHR interface | |
| 2437 | + // and not add more redundant checks in setBackoffState method | |
| 2438 | + error.request = response; | |
| 2439 | + opts.onError && opts.onError(error); | |
| 2440 | + } | |
| 2441 | + }) | |
| 2442 | + ["catch"](function () { | |
| 2443 | + opts.onError && | |
| 2444 | + opts.onError( | |
| 2445 | + new Error("Sentry error code: network unavailable"), | |
| 2446 | + ); | |
| 2447 | + }); | |
| 2448 | + } | |
| 2449 | + | |
| 2200 | 2450 | var request = |
| 2201 | 2451 | _window.XMLHttpRequest && new _window.XMLHttpRequest(); |
| 2202 | 2452 | if (!request) return; |
| @@ -2208,8 +2458,6 @@ · 5 unmodified lines | ||
| 2208 | 2458 | |
| 2209 | 2459 | if (!hasCORS) return; |
| 2210 | 2460 | |
| 2211 | − var url = opts.url; | |
| 2212 | − | |
| 2213 | 2461 | if ("withCredentials" in request) { |
| 2214 | 2462 | request.onreadystatechange = function () { |
| 2215 | 2463 | if (request.readyState !== 4) { |
| @@ -2243,14 +2491,37 @@ · 27 unmodified lines | ||
| 2243 | 2491 | } |
| 2244 | 2492 | } |
| 2245 | 2493 | |
| 2246 | − // NOTE: auth is intentionally sent as part of query string (NOT as custom | |
| 2247 | − // HTTP header) so as to avoid preflight CORS requests | |
| 2248 | − request.open("POST", url + "?" + urlencode(opts.auth)); | |
| 2494 | + request.open("POST", url); | |
| 2495 | + | |
| 2496 | + if (evaluatedHeaders) { | |
| 2497 | + each(evaluatedHeaders, function (key, value) { | |
| 2498 | + request.setRequestHeader(key, value); | |
| 2499 | + }); | |
| 2500 | + } | |
| 2501 | + | |
| 2249 | 2502 | request.send(stringify(opts.data)); |
| 2250 | 2503 | }, |
| 2251 | 2504 | |
| 2505 | + _evaluateHash: function (hash) { | |
| 2506 | + var evaluated = {}; | |
| 2507 | + | |
| 2508 | + for (var key in hash) { | |
| 2509 | + if (hash.hasOwnProperty(key)) { | |
| 2510 | + var value = hash[key]; | |
| 2511 | + evaluated[key] = | |
| 2512 | + typeof value === "function" ? value() : value; | |
| 2513 | + } | |
| 2514 | + } | |
| 2515 | + | |
| 2516 | + return evaluated; | |
| 2517 | + }, | |
| 2518 | + | |
| 2252 | 2519 | _logDebug: function (level) { |
| 2253 | − if (this._originalConsoleMethods[level] && this.debug) { | |
| 2520 | + // We allow `Raven.debug` and `Raven.config(DSN, { debug: true })` to not make backward incompatible API change | |
| 2521 | + if ( | |
| 2522 | + this._originalConsoleMethods[level] && | |
| 2523 | + (this.debug || this._globalOptions.debug) | |
| 2524 | + ) { | |
| 2254 | 2525 | // In IE<10 console methods do not have their own 'apply' method |
| 2255 | 2526 | Function.prototype.apply.call( |
| 2256 | 2527 | this._originalConsoleMethods[level], |
| @@ -2288,7 +2559,7 @@ · 31 unmodified lines | ||
| 2288 | 2559 | : {}, |
| 2289 | 2560 | ); |
| 2290 | 2561 | }, |
| 2291 | − { 1: 1, 2: 2, 5: 5, 6: 6, 7: 7 }, | |
| 2562 | + { 1: 1, 2: 2, 5: 5, 6: 6, 7: 7, 8: 8 }, | |
| 2292 | 2563 | ], |
| 2293 | 2564 | 4: [ |
| 2294 | 2565 | function (_dereq_, module, exports) { |
| @@ -2328,6 +2599,42 @@ · 33 unmodified lines | ||
| 2328 | 2599 | Raven.afterLoad(); |
| 2329 | 2600 | |
| 2330 | 2601 | module.exports = Raven; |
| 2602 | + | |
| 2603 | + /** | |
| 2604 | + * DISCLAIMER: | |
| 2605 | + * | |
| 2606 | + * Expose `Client` constructor for cases where user want to track multiple "sub-applications" in one larger app. | |
| 2607 | + * It's not meant to be used by a wide audience, so pleaaase make sure that you know what you're doing before using it. | |
| 2608 | + * Accidentally calling `install` multiple times, may result in an unexpected behavior that's very hard to debug. | |
| 2609 | + * | |
| 2610 | + * It's called `Client' to be in-line with Raven Node implementation. | |
| 2611 | + * | |
| 2612 | + * HOWTO: | |
| 2613 | + * | |
| 2614 | + * import Raven from 'raven-js'; | |
| 2615 | + * | |
| 2616 | + * const someAppReporter = new Raven.Client(); | |
| 2617 | + * const someOtherAppReporter = new Raven.Client(); | |
| 2618 | + * | |
| 2619 | + * someAppReporter.config('__DSN__', { | |
| 2620 | + * ...config goes here | |
| 2621 | + * }); | |
| 2622 | + * | |
| 2623 | + * someOtherAppReporter.config('__OTHER_DSN__', { | |
| 2624 | + * ...config goes here | |
| 2625 | + * }); | |
| 2626 | + * | |
| 2627 | + * someAppReporter.captureMessage(...); | |
| 2628 | + * someAppReporter.captureException(...); | |
| 2629 | + * someAppReporter.captureBreadcrumb(...); | |
| 2630 | + * | |
| 2631 | + * someOtherAppReporter.captureMessage(...); | |
| 2632 | + * someOtherAppReporter.captureException(...); | |
| 2633 | + * someOtherAppReporter.captureBreadcrumb(...); | |
| 2634 | + * | |
| 2635 | + * It should "just work". | |
| 2636 | + */ | |
| 2637 | + module.exports.Client = RavenConstructor; | |
| 2331 | 2638 | }).call( |
| 2332 | 2639 | this, |
| 2333 | 2640 | typeof global !== "undefined" |
| @@ -2344,6 +2651,8 @@ · 10 unmodified lines | ||
| 2344 | 2651 | 5: [ |
| 2345 | 2652 | function (_dereq_, module, exports) { |
| 2346 | 2653 | (function (global) { |
| 2654 | + var stringify = _dereq_(7); | |
| 2655 | + | |
| 2347 | 2656 | var _window = |
| 2348 | 2657 | typeof window !== "undefined" |
| 2349 | 2658 | ? window |
| @@ -2360,7 +2669,7 @@ · 10 unmodified lines | ||
| 2360 | 2669 | // Yanked from https://git.io/vS8DV re-used under CC0 |
| 2361 | 2670 | // with some tiny modifications |
| 2362 | 2671 | function isError(value) { |
| 2363 | − switch ({}.toString.call(value)) { | |
| 2672 | + switch (Object.prototype.toString.call(value)) { | |
| 2364 | 2673 | case "[object Error]": |
| 2365 | 2674 | return true; |
| 2366 | 2675 | case "[object Exception]": |
| @@ -2374,8 +2683,20 @@ · 7 unmodified lines | ||
| 2374 | 2683 | |
| 2375 | 2684 | function isErrorEvent(value) { |
| 2376 | 2685 | return ( |
| 2377 | − supportsErrorEvent() && | |
| 2378 | − {}.toString.call(value) === "[object ErrorEvent]" | |
| 2686 | + Object.prototype.toString.call(value) === "[object ErrorEvent]" | |
| 2687 | + ); | |
| 2688 | + } | |
| 2689 | + | |
| 2690 | + function isDOMError(value) { | |
| 2691 | + return ( | |
| 2692 | + Object.prototype.toString.call(value) === "[object DOMError]" | |
| 2693 | + ); | |
| 2694 | + } | |
| 2695 | + | |
| 2696 | + function isDOMException(value) { | |
| 2697 | + return ( | |
| 2698 | + Object.prototype.toString.call(value) === | |
| 2699 | + "[object DOMException]" | |
| 2379 | 2700 | ); |
| 2380 | 2701 | } |
| 2381 | 2702 | |
| @@ -2387,6 +2708,10 @@ · 5 unmodified lines | ||
| 2387 | 2708 | return typeof what === "function"; |
| 2388 | 2709 | } |
| 2389 | 2710 | |
| 2711 | + function isPlainObject(what) { | |
| 2712 | + return Object.prototype.toString.call(what) === "[object Object]"; | |
| 2713 | + } | |
| 2714 | + | |
| 2390 | 2715 | function isString(what) { |
| 2391 | 2716 | return Object.prototype.toString.call(what) === "[object String]"; |
| 2392 | 2717 | } |
| @@ -2396,6 +2721,8 @@ · 3 unmodified lines | ||
| 2396 | 2721 | } |
| 2397 | 2722 | |
| 2398 | 2723 | function isEmptyObject(what) { |
| 2724 | + if (!isPlainObject(what)) return false; | |
| 2725 | + | |
| 2399 | 2726 | for (var _ in what) { |
| 2400 | 2727 | if (what.hasOwnProperty(_)) { |
| 2401 | 2728 | return false; |
| @@ -2413,6 +2740,59 @@ · 11 unmodified lines | ||
| 2413 | 2740 | } |
| 2414 | 2741 | } |
| 2415 | 2742 | |
| 2743 | + function supportsDOMError() { | |
| 2744 | + try { | |
| 2745 | + new DOMError(""); // eslint-disable-line no-new | |
| 2746 | + return true; | |
| 2747 | + } catch (e) { | |
| 2748 | + return false; | |
| 2749 | + } | |
| 2750 | + } | |
| 2751 | + | |
| 2752 | + function supportsDOMException() { | |
| 2753 | + try { | |
| 2754 | + new DOMException(""); // eslint-disable-line no-new | |
| 2755 | + return true; | |
| 2756 | + } catch (e) { | |
| 2757 | + return false; | |
| 2758 | + } | |
| 2759 | + } | |
| 2760 | + | |
| 2761 | + function supportsFetch() { | |
| 2762 | + if (!("fetch" in _window)) return false; | |
| 2763 | + | |
| 2764 | + try { | |
| 2765 | + new Headers(); // eslint-disable-line no-new | |
| 2766 | + new Request(""); // eslint-disable-line no-new | |
| 2767 | + new Response(); // eslint-disable-line no-new | |
| 2768 | + return true; | |
| 2769 | + } catch (e) { | |
| 2770 | + return false; | |
| 2771 | + } | |
| 2772 | + } | |
| 2773 | + | |
| 2774 | + // Despite all stars in the sky saying that Edge supports old draft syntax, aka 'never', 'always', 'origin' and 'default | |
| 2775 | + // https://caniuse.com/#feat=referrer-policy | |
| 2776 | + // It doesn't. And it throw exception instead of ignoring this parameter... | |
| 2777 | + // REF: https://github.com/getsentry/raven-js/issues/1233 | |
| 2778 | + function supportsReferrerPolicy() { | |
| 2779 | + if (!supportsFetch()) return false; | |
| 2780 | + | |
| 2781 | + try { | |
| 2782 | + // eslint-disable-next-line no-new | |
| 2783 | + new Request("pickleRick", { | |
| 2784 | + referrerPolicy: "origin", | |
| 2785 | + }); | |
| 2786 | + return true; | |
| 2787 | + } catch (e) { | |
| 2788 | + return false; | |
| 2789 | + } | |
| 2790 | + } | |
| 2791 | + | |
| 2792 | + function supportsPromiseRejectionEvent() { | |
| 2793 | + return typeof PromiseRejectionEvent === "function"; | |
| 2794 | + } | |
| 2795 | + | |
| 2416 | 2796 | function wrappedCallback(callback) { |
| 2417 | 2797 | function dataCallback(data, original) { |
| 2418 | 2798 | var normalizedData = callback(data) || data; |
| @@ -2470,9 +2850,15 @@ · 51 unmodified lines | ||
| 2470 | 2850 | } |
| 2471 | 2851 | |
| 2472 | 2852 | function truncate(str, max) { |
| 2473 | − return !max || str.length <= max | |
| 2474 | − ? str | |
| 2475 | − : str.substr(0, max) + "\u2026"; | |
| 2853 | + if (typeof max !== "number") { | |
| 2854 | + throw new Error( | |
| 2855 | + "2nd argument to `truncate` function should be a number", | |
| 2856 | + ); | |
| 2857 | + } | |
| 2858 | + if (typeof str !== "string" || max === 0) { | |
| 2859 | + return str; | |
| 2860 | + } | |
| 2861 | + return str.length <= max ? str : str.substr(0, max) + "\u2026"; | |
| 2476 | 2862 | } |
| 2477 | 2863 | |
| 2478 | 2864 | /** |
| @@ -2521,14 +2907,14 @@ · 42 unmodified lines | ||
| 2521 | 2907 | return pairs.join("&"); |
| 2522 | 2908 | } |
| 2523 | 2909 | |
| 2524 | − // borrowed from https://datatracker.ietf.org/doc/html/rfc3986#appendix-B | |
| 2910 | + // borrowed from https://tools.ietf.org/html/rfc3986#appendix-B | |
| 2525 | 2911 | // intentionally using regex and not <a/> href parsing trick because React Native and other |
| 2526 | 2912 | // environments where DOM might not be available |
| 2527 | 2913 | function parseUrl(url) { |
| 2914 | + if (typeof url !== "string") return {}; | |
| 2528 | 2915 | var match = url.match( |
| 2529 | 2916 | /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/, |
| 2530 | 2917 | ); |
| 2531 | − if (!match) return {}; | |
| 2532 | 2918 | |
| 2533 | 2919 | // coerce to undefined values to empty string so we don't get 'undefined' |
| 2534 | 2920 | var query = match[6] || ""; |
| @@ -2675,6 +3061,13 @@ · 140 unmodified lines | ||
| 2675 | 3061 | return !!(!!a ^ !!b); |
| 2676 | 3062 | } |
| 2677 | 3063 | |
| 3064 | + /** | |
| 3065 | + * Returns true if both parameters are undefined | |
| 3066 | + */ | |
| 3067 | + function isBothUndefined(a, b) { | |
| 3068 | + return isUndefined(a) && isUndefined(b); | |
| 3069 | + } | |
| 3070 | + | |
| 2678 | 3071 | /** |
| 2679 | 3072 | * Returns true if the two input exception interfaces have the same content |
| 2680 | 3073 | */ |
| @@ -2687,6 +3080,9 @@ · 6 unmodified lines | ||
| 2687 | 3080 | if (ex1.type !== ex2.type || ex1.value !== ex2.value) |
| 2688 | 3081 | return false; |
| 2689 | 3082 | |
| 3083 | + // in case both stacktraces are undefined, we can't decide so default to false | |
| 3084 | + if (isBothUndefined(ex1.stacktrace, ex2.stacktrace)) return false; | |
| 3085 | + | |
| 2690 | 3086 | return isSameStacktrace(ex1.stacktrace, ex2.stacktrace); |
| 2691 | 3087 | } |
| 2692 | 3088 | |
| @@ -2726,6 +3122,7 @@ · 33 unmodified lines | ||
| 2726 | 3122 | * @param track {optional} record instrumentation to an array |
| 2727 | 3123 | */ |
| 2728 | 3124 | function fill(obj, name, replacement, track) { |
| 3125 | + if (obj == null) return; | |
| 2729 | 3126 | var orig = obj[name]; |
| 2730 | 3127 | obj[name] = replacement(orig); |
| 2731 | 3128 | obj[name].__raven__ = true; |
| @@ -2735,16 +3132,190 @@ · 3 unmodified lines | ||
| 2735 | 3132 | } |
| 2736 | 3133 | } |
| 2737 | 3134 | |
| 3135 | + /** | |
| 3136 | + * Join values in array | |
| 3137 | + * @param input array of values to be joined together | |
| 3138 | + * @param delimiter string to be placed in-between values | |
| 3139 | + * @returns {string} | |
| 3140 | + */ | |
| 3141 | + function safeJoin(input, delimiter) { | |
| 3142 | + if (!isArray(input)) return ""; | |
| 3143 | + | |
| 3144 | + var output = []; | |
| 3145 | + | |
| 3146 | + for (var i = 0; i < input.length; i++) { | |
| 3147 | + try { | |
| 3148 | + output.push(String(input[i])); | |
| 3149 | + } catch (e) { | |
| 3150 | + output.push("[value cannot be serialized]"); | |
| 3151 | + } | |
| 3152 | + } | |
| 3153 | + | |
| 3154 | + return output.join(delimiter); | |
| 3155 | + } | |
| 3156 | + | |
| 3157 | + // Default Node.js REPL depth | |
| 3158 | + var MAX_SERIALIZE_EXCEPTION_DEPTH = 3; | |
| 3159 | + // 50kB, as 100kB is max payload size, so half sounds reasonable | |
| 3160 | + var MAX_SERIALIZE_EXCEPTION_SIZE = 50 * 1024; | |
| 3161 | + var MAX_SERIALIZE_KEYS_LENGTH = 40; | |
| 3162 | + | |
| 3163 | + function utf8Length(value) { | |
| 3164 | + return ~-encodeURI(value).split(/%..|./).length; | |
| 3165 | + } | |
| 3166 | + | |
| 3167 | + function jsonSize(value) { | |
| 3168 | + return utf8Length(JSON.stringify(value)); | |
| 3169 | + } | |
| 3170 | + | |
| 3171 | + function serializeValue(value) { | |
| 3172 | + if (typeof value === "string") { | |
| 3173 | + var maxLength = 40; | |
| 3174 | + return truncate(value, maxLength); | |
| 3175 | + } else if ( | |
| 3176 | + typeof value === "number" || | |
| 3177 | + typeof value === "boolean" || | |
| 3178 | + typeof value === "undefined" | |
| 3179 | + ) { | |
| 3180 | + return value; | |
| 3181 | + } | |
| 3182 | + | |
| 3183 | + var type = Object.prototype.toString.call(value); | |
| 3184 | + | |
| 3185 | + // Node.js REPL notation | |
| 3186 | + if (type === "[object Object]") return "[Object]"; | |
| 3187 | + if (type === "[object Array]") return "[Array]"; | |
| 3188 | + if (type === "[object Function]") | |
| 3189 | + return value.name | |
| 3190 | + ? "[Function: " + value.name + "]" | |
| 3191 | + : "[Function]"; | |
| 3192 | + | |
| 3193 | + return value; | |
| 3194 | + } | |
| 3195 | + | |
| 3196 | + function serializeObject(value, depth) { | |
| 3197 | + if (depth === 0) return serializeValue(value); | |
| 3198 | + | |
| 3199 | + if (isPlainObject(value)) { | |
| 3200 | + return Object.keys(value).reduce(function (acc, key) { | |
| 3201 | + acc[key] = serializeObject(value[key], depth - 1); | |
| 3202 | + return acc; | |
| 3203 | + }, {}); | |
| 3204 | + } else if (Array.isArray(value)) { | |
| 3205 | + return value.map(function (val) { | |
| 3206 | + return serializeObject(val, depth - 1); | |
| 3207 | + }); | |
| 3208 | + } | |
| 3209 | + | |
| 3210 | + return serializeValue(value); | |
| 3211 | + } | |
| 3212 | + | |
| 3213 | + function serializeException(ex, depth, maxSize) { | |
| 3214 | + if (!isPlainObject(ex)) return ex; | |
| 3215 | + | |
| 3216 | + depth = | |
| 3217 | + typeof depth !== "number" | |
| 3218 | + ? MAX_SERIALIZE_EXCEPTION_DEPTH | |
| 3219 | + : depth; | |
| 3220 | + maxSize = | |
| 3221 | + typeof depth !== "number" | |
| 3222 | + ? MAX_SERIALIZE_EXCEPTION_SIZE | |
| 3223 | + : maxSize; | |
| 3224 | + | |
| 3225 | + var serialized = serializeObject(ex, depth); | |
| 3226 | + | |
| 3227 | + if (jsonSize(stringify(serialized)) > maxSize) { | |
| 3228 | + return serializeException(ex, depth - 1); | |
| 3229 | + } | |
| 3230 | + | |
| 3231 | + return serialized; | |
| 3232 | + } | |
| 3233 | + | |
| 3234 | + function serializeKeysForMessage(keys, maxLength) { | |
| 3235 | + if (typeof keys === "number" || typeof keys === "string") | |
| 3236 | + return keys.toString(); | |
| 3237 | + if (!Array.isArray(keys)) return ""; | |
| 3238 | + | |
| 3239 | + keys = keys.filter(function (key) { | |
| 3240 | + return typeof key === "string"; | |
| 3241 | + }); | |
| 3242 | + if (keys.length === 0) return "[object has no keys]"; | |
| 3243 | + | |
| 3244 | + maxLength = | |
| 3245 | + typeof maxLength !== "number" | |
| 3246 | + ? MAX_SERIALIZE_KEYS_LENGTH | |
| 3247 | + : maxLength; | |
| 3248 | + if (keys[0].length >= maxLength) return keys[0]; | |
| 3249 | + | |
| 3250 | + for (var usedKeys = keys.length; usedKeys > 0; usedKeys--) { | |
| 3251 | + var serialized = keys.slice(0, usedKeys).join(", "); | |
| 3252 | + if (serialized.length > maxLength) continue; | |
| 3253 | + if (usedKeys === keys.length) return serialized; | |
| 3254 | + return serialized + "\u2026"; | |
| 3255 | + } | |
| 3256 | + | |
| 3257 | + return ""; | |
| 3258 | + } | |
| 3259 | + | |
| 3260 | + function sanitize(input, sanitizeKeys) { | |
| 3261 | + if ( | |
| 3262 | + !isArray(sanitizeKeys) || | |
| 3263 | + (isArray(sanitizeKeys) && sanitizeKeys.length === 0) | |
| 3264 | + ) | |
| 3265 | + return input; | |
| 3266 | + | |
| 3267 | + var sanitizeRegExp = joinRegExp(sanitizeKeys); | |
| 3268 | + var sanitizeMask = "********"; | |
| 3269 | + var safeInput; | |
| 3270 | + | |
| 3271 | + try { | |
| 3272 | + safeInput = JSON.parse(stringify(input)); | |
| 3273 | + } catch (o_O) { | |
| 3274 | + return input; | |
| 3275 | + } | |
| 3276 | + | |
| 3277 | + function sanitizeWorker(workerInput) { | |
| 3278 | + if (isArray(workerInput)) { | |
| 3279 | + return workerInput.map(function (val) { | |
| 3280 | + return sanitizeWorker(val); | |
| 3281 | + }); | |
| 3282 | + } | |
| 3283 | + | |
| 3284 | + if (isPlainObject(workerInput)) { | |
| 3285 | + return Object.keys(workerInput).reduce(function (acc, k) { | |
| 3286 | + if (sanitizeRegExp.test(k)) { | |
| 3287 | + acc[k] = sanitizeMask; | |
| 3288 | + } else { | |
| 3289 | + acc[k] = sanitizeWorker(workerInput[k]); | |
| 3290 | + } | |
| 3291 | + return acc; | |
| 3292 | + }, {}); | |
| 3293 | + } | |
| 3294 | + | |
| 3295 | + return workerInput; | |
| 3296 | + } | |
| 3297 | + | |
| 3298 | + return sanitizeWorker(safeInput); | |
| 3299 | + } | |
| 3300 | + | |
| 2738 | 3301 | module.exports = { |
| 2739 | 3302 | isObject: isObject, |
| 2740 | 3303 | isError: isError, |
| 2741 | 3304 | isErrorEvent: isErrorEvent, |
| 3305 | + isDOMError: isDOMError, | |
| 3306 | + isDOMException: isDOMException, | |
| 2742 | 3307 | isUndefined: isUndefined, |
| 2743 | 3308 | isFunction: isFunction, |
| 3309 | + isPlainObject: isPlainObject, | |
| 2744 | 3310 | isString: isString, |
| 2745 | 3311 | isArray: isArray, |
| 2746 | 3312 | isEmptyObject: isEmptyObject, |
| 2747 | 3313 | supportsErrorEvent: supportsErrorEvent, |
| 3314 | + supportsDOMError: supportsDOMError, | |
| 3315 | + supportsDOMException: supportsDOMException, | |
| 3316 | + supportsFetch: supportsFetch, | |
| 3317 | + supportsReferrerPolicy: supportsReferrerPolicy, | |
| 3318 | + supportsPromiseRejectionEvent: supportsPromiseRejectionEvent, | |
| 2748 | 3319 | wrappedCallback: wrappedCallback, |
| 2749 | 3320 | each: each, |
| 2750 | 3321 | objectMerge: objectMerge, |
| @@ -2760,6 +3331,10 @@ · 9 unmodified lines | ||
| 2760 | 3331 | isSameStacktrace: isSameStacktrace, |
| 2761 | 3332 | parseUrl: parseUrl, |
| 2762 | 3333 | fill: fill, |
| 3334 | + safeJoin: safeJoin, | |
| 3335 | + serializeException: serializeException, | |
| 3336 | + serializeKeysForMessage: serializeKeysForMessage, | |
| 3337 | + sanitize: sanitize, | |
| 2763 | 3338 | }; |
| 2764 | 3339 | }).call( |
| 2765 | 3340 | this, |
| @@ -2772,7 +3347,7 @@ · 6 unmodified lines | ||
| 2772 | 3347 | : {}, |
| 2773 | 3348 | ); |
| 2774 | 3349 | }, |
| 2775 | − {}, | |
| 3350 | + { 7: 7 }, | |
| 2776 | 3351 | ], |
| 2777 | 3352 | 6: [ |
| 2778 | 3353 | function (_dereq_, module, exports) { |
| @@ -2780,14 +3355,14 @@ · 1 unmodified line | ||
| 2780 | 3355 | var utils = _dereq_(5); |
| 2781 | 3356 | |
| 2782 | 3357 | /* |
| 2783 | − TraceKit - Cross brower stack traces | |
| 2784 | − | |
| 2785 | − This was originally forked from github.com/occ/TraceKit, but has since been | |
| 2786 | − largely re-written and is now maintained as part of raven-js. Tests for | |
| 2787 | − this are in test/vendor. | |
| 2788 | − | |
| 2789 | − MIT license | |
| 2790 | −*/ | |
| 3358 | + TraceKit - Cross brower stack traces | |
| 3359 | + | |
| 3360 | + This was originally forked from github.com/occ/TraceKit, but has since been | |
| 3361 | + largely re-written and is now maintained as part of raven-js. Tests for | |
| 3362 | + this are in test/vendor. | |
| 3363 | + | |
| 3364 | + MIT license | |
| 3365 | + */ | |
| 2791 | 3366 | |
| 2792 | 3367 | var TraceKit = { |
| 2793 | 3368 | collectWindowErrors: true, |
| @@ -2815,10 +3390,25 @@ · 21 unmodified lines | ||
| 2815 | 3390 | function getLocationHref() { |
| 2816 | 3391 | if (typeof document === "undefined" || document.location == null) |
| 2817 | 3392 | return ""; |
| 2818 | − | |
| 2819 | 3393 | return document.location.href; |
| 2820 | 3394 | } |
| 2821 | 3395 | |
| 3396 | + function getLocationOrigin() { | |
| 3397 | + if (typeof document === "undefined" || document.location == null) | |
| 3398 | + return ""; | |
| 3399 | + | |
| 3400 | + // Oh dear IE10... | |
| 3401 | + if (!document.location.origin) { | |
| 3402 | + document.location.origin = | |
| 3403 | + document.location.protocol + | |
| 3404 | + "//" + | |
| 3405 | + document.location.hostname + | |
| 3406 | + (document.location.port ? ":" + document.location.port : ""); | |
| 3407 | + } | |
| 3408 | + | |
| 3409 | + return document.location.origin; | |
| 3410 | + } | |
| 3411 | + | |
| 2822 | 3412 | /** |
| 2823 | 3413 | * TraceKit.report: cross-browser processing of unhandled exceptions |
| 2824 | 3414 | * |
| @@ -2925,7 +3515,7 @@ · 100 unmodified lines | ||
| 2925 | 3515 | /** |
| 2926 | 3516 | * Ensures all global unhandled exceptions are recorded. |
| 2927 | 3517 | * Supported by Gecko and IE. |
| 2928 | − * @param {string} message Error message. | |
| 3518 | + * @param {string} msg Error message. | |
| 2929 | 3519 | * @param {string} url URL of script that generated the exception. |
| 2930 | 3520 | * @param {(number|string)} lineNo The line number at which the error |
| 2931 | 3521 | * occurred. |
| @@ -2933,8 +3523,12 @@ · 1 unmodified line | ||
| 2933 | 3523 | * occurred. |
| 2934 | 3524 | * @param {?Error} ex The actual Error object. |
| 2935 | 3525 | */ |
| 2936 | − function traceKitWindowOnError(message, url, lineNo, colNo, ex) { | |
| 3526 | + function traceKitWindowOnError(msg, url, lineNo, colNo, ex) { | |
| 2937 | 3527 | var stack = null; |
| 3528 | + // If 'ex' is ErrorEvent, get real Error from inside | |
| 3529 | + var exception = utils.isErrorEvent(ex) ? ex.error : ex; | |
| 3530 | + // If 'msg' is ErrorEvent, get real message from inside | |
| 3531 | + var message = utils.isErrorEvent(msg) ? msg.message : msg; | |
| 2938 | 3532 | |
| 2939 | 3533 | if (lastExceptionStack) { |
| 2940 | 3534 | TraceKit.computeStackTrace.augmentStackTraceWithInitialElement( |
| @@ -2944,13 +3538,13 @@ · 3 unmodified lines | ||
| 2944 | 3538 | message, |
| 2945 | 3539 | ); |
| 2946 | 3540 | processLastException(); |
| 2947 | − } else if (ex && utils.isError(ex)) { | |
| 2948 | − // non-string `ex` arg; attempt to extract stack trace | |
| 3541 | + } else if (exception && utils.isError(exception)) { | |
| 3542 | + // non-string `exception` arg; attempt to extract stack trace | |
| 2949 | 3543 | |
| 2950 | 3544 | // New chrome and blink send along a real error object |
| 2951 | 3545 | // Let's just report that like a normal error. |
| 2952 | 3546 | // See: https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror |
| 2953 | − stack = TraceKit.computeStackTrace(ex); | |
| 3547 | + stack = TraceKit.computeStackTrace(exception); | |
| 2954 | 3548 | notifyHandlers(stack, true); |
| 2955 | 3549 | } else { |
| 2956 | 3550 | var location = { |
| @@ -2960,13 +3554,13 @@ · 3 unmodified lines | ||
| 2960 | 3554 | }; |
| 2961 | 3555 | |
| 2962 | 3556 | var name = undefined; |
| 2963 | − var msg = message; // must be new var or will modify original `arguments` | |
| 2964 | 3557 | var groups; |
| 3558 | + | |
| 2965 | 3559 | if ({}.toString.call(message) === "[object String]") { |
| 2966 | 3560 | var groups = message.match(ERROR_TYPES_RE); |
| 2967 | 3561 | if (groups) { |
| 2968 | 3562 | name = groups[1]; |
| 2969 | − msg = groups[2]; | |
| 3563 | + message = groups[2]; | |
| 2970 | 3564 | } |
| 2971 | 3565 | } |
| 2972 | 3566 | |
| @@ -2974,7 +3568,7 @@ · 1 unmodified line | ||
| 2974 | 3568 | |
| 2975 | 3569 | stack = { |
| 2976 | 3570 | name: name, |
| 2977 | − message: msg, | |
| 3571 | + message: message, | |
| 2978 | 3572 | url: getLocationHref(), |
| 2979 | 3573 | stack: [location], |
| 2980 | 3574 | }; |
| @@ -3163,20 +3757,22 @@ · 182 unmodified lines | ||
| 3163 | 3757 | if (typeof ex.stack === "undefined" || !ex.stack) return; |
| 3164 | 3758 | |
| 3165 | 3759 | var chrome = |
| 3166 | − /^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|[a-z]:|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i, | |
| 3167 | − gecko = | |
| 3168 | − /^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|resource|\[native).*?|[^@]*bundle)(?::(\d+))?(?::(\d+))?\s*$/i, | |
| 3169 | − winjs = | |
| 3170 | − /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i, | |
| 3171 | − // Used to additionally parse URL/line/column from eval frames | |
| 3172 | − geckoEval = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i, | |
| 3173 | − chromeEval = /\((\S*)(?::(\d+))(?::(\d+))\)/, | |
| 3174 | − lines = ex.stack.split("\n"), | |
| 3175 | − stack = [], | |
| 3176 | − submatch, | |
| 3177 | − parts, | |
| 3178 | − element, | |
| 3179 | − reference = /^(.*) is undefined$/.exec(ex.message); | |
| 3760 | + /^\s*at (?:(.*?) ?\()?((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|[a-z]:|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i; | |
| 3761 | + var winjs = | |
| 3762 | + /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx(?:-web)|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i; | |
| 3763 | + // NOTE: blob urls are now supposed to always have an origin, therefore it's format | |
| 3764 | + // which is `blob:http://url/path/with-some-uuid`, is matched by `blob.*?:\/` as well | |
| 3765 | + var gecko = | |
| 3766 | + /^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|resource|moz-extension).*?:\/.*?|\[native code\]|[^@]*bundle)(?::(\d+))?(?::(\d+))?\s*$/i; | |
| 3767 | + // Used to additionally parse URL/line/column from eval frames | |
| 3768 | + var geckoEval = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i; | |
| 3769 | + var chromeEval = /\((\S*)(?::(\d+))(?::(\d+))\)/; | |
| 3770 | + var lines = ex.stack.split("\n"); | |
| 3771 | + var stack = []; | |
| 3772 | + var submatch; | |
| 3773 | + var parts; | |
| 3774 | + var element; | |
| 3775 | + var reference = /^(.*) is undefined$/.exec(ex.message); | |
| 3180 | 3776 | |
| 3181 | 3777 | for (var i = 0, j = lines.length; i < j; ++i) { |
| 3182 | 3778 | if ((parts = chrome.exec(lines[i]))) { |
| @@ -3236,6 +3832,47 @@ · 53 unmodified lines | ||
| 3236 | 3832 | element.func = UNKNOWN_FUNCTION; |
| 3237 | 3833 | } |
| 3238 | 3834 | |
| 3835 | + if (element.url && element.url.substr(0, 5) === "blob:") { | |
| 3836 | + // Special case for handling JavaScript loaded into a blob. | |
| 3837 | + // We use a synchronous AJAX request here as a blob is already in | |
| 3838 | + // memory - it's not making a network request. This will generate a warning | |
| 3839 | + // in the browser console, but there has already been an error so that's not | |
| 3840 | + // that much of an issue. | |
| 3841 | + var xhr = new XMLHttpRequest(); | |
| 3842 | + xhr.open("GET", element.url, false); | |
| 3843 | + xhr.send(null); | |
| 3844 | + | |
| 3845 | + // If we failed to download the source, skip this patch | |
| 3846 | + if (xhr.status === 200) { | |
| 3847 | + var source = xhr.responseText || ""; | |
| 3848 | + | |
| 3849 | + // We trim the source down to the last 300 characters as sourceMappingURL is always at the end of the file. | |
| 3850 | + // Why 300? To be in line with: https://github.com/getsentry/sentry/blob/4af29e8f2350e20c28a6933354e4f42437b4ba42/src/sentry/lang/javascript/processor.py#L164-L175 | |
| 3851 | + source = source.slice(-300); | |
| 3852 | + | |
| 3853 | + // Now we dig out the source map URL | |
| 3854 | + var sourceMaps = source.match( | |
| 3855 | + /\/\/# sourceMappingURL=(.*)$/, | |
| 3856 | + ); | |
| 3857 | + | |
| 3858 | + // If we don't find a source map comment or we find more than one, continue on to the next element. | |
| 3859 | + if (sourceMaps) { | |
| 3860 | + var sourceMapAddress = sourceMaps[1]; | |
| 3861 | + | |
| 3862 | + // Now we check to see if it's a relative URL. | |
| 3863 | + // If it is, convert it to an absolute one. | |
| 3864 | + if (sourceMapAddress.charAt(0) === "~") { | |
| 3865 | + sourceMapAddress = | |
| 3866 | + getLocationOrigin() + sourceMapAddress.slice(1); | |
| 3867 | + } | |
| 3868 | + | |
| 3869 | + // Now we strip the '.map' off of the end of the URL and update the | |
| 3870 | + // element so that Sentry can match the map to the blob. | |
| 3871 | + element.url = sourceMapAddress.slice(0, -4); | |
| 3872 | + } | |
| 3873 | + } | |
| 3874 | + } | |
| 3875 | + | |
| 3239 | 3876 | stack.push(element); |
| 3240 | 3877 | } |
| 3241 | 3878 | |
| @@ -3449,15 +4086,15 @@ · 207 unmodified lines | ||
| 3449 | 4086 | 7: [ |
| 3450 | 4087 | function (_dereq_, module, exports) { |
| 3451 | 4088 | /* |
| 3452 | − json-stringify-safe | |
| 3453 | − Like JSON.stringify, but doesn't throw on circular references. | |
| 3454 | − | |
| 3455 | − Originally forked from https://github.com/isaacs/json-stringify-safe | |
| 3456 | − version 5.0.1 on 3/8/2017 and modified to handle Errors serialization | |
| 3457 | − and IE8 compatibility. Tests for this are in test/vendor. | |
| 3458 | − | |
| 3459 | − ISC license: https://github.com/isaacs/json-stringify-safe/blob/master/LICENSE | |
| 3460 | −*/ | |
| 4089 | + json-stringify-safe | |
| 4090 | + Like JSON.stringify, but doesn't throw on circular references. | |
| 4091 | + | |
| 4092 | + Originally forked from https://github.com/isaacs/json-stringify-safe | |
| 4093 | + version 5.0.1 on 3/8/2017 and modified to handle Errors serialization | |
| 4094 | + and IE8 compatibility. Tests for this are in test/vendor. | |
| 4095 | + | |
| 4096 | + ISC license: https://github.com/isaacs/json-stringify-safe/blob/master/LICENSE | |
| 4097 | + */ | |
| 3461 | 4098 | |
| 3462 | 4099 | exports = module.exports = stringify; |
| 3463 | 4100 | exports.getSerialize = serializer; |
| @@ -3535,6 +4172,281 @@ · 71 unmodified lines | ||
| 3535 | 4172 | }, |
| 3536 | 4173 | {}, |
| 3537 | 4174 | ], |
| 4175 | + 8: [ | |
| 4176 | + function (_dereq_, module, exports) { | |
| 4177 | + /* | |
| 4178 | + * JavaScript MD5 | |
| 4179 | + * https://github.com/blueimp/JavaScript-MD5 | |
| 4180 | + * | |
| 4181 | + * Copyright 2011, Sebastian Tschan | |
| 4182 | + * https://blueimp.net | |
| 4183 | + * | |
| 4184 | + * Licensed under the MIT license: | |
| 4185 | + * https://opensource.org/licenses/MIT | |
| 4186 | + * | |
| 4187 | + * Based on | |
| 4188 | + * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message | |
| 4189 | + * Digest Algorithm, as defined in RFC 1321. | |
| 4190 | + * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 | |
| 4191 | + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet | |
| 4192 | + * Distributed under the BSD License | |
| 4193 | + * See http://pajhome.org.uk/crypt/md5 for more info. | |
| 4194 | + */ | |
| 4195 | + | |
| 4196 | + /* | |
| 4197 | + * Add integers, wrapping at 2^32. This uses 16-bit operations internally | |
| 4198 | + * to work around bugs in some JS interpreters. | |
| 4199 | + */ | |
| 4200 | + function safeAdd(x, y) { | |
| 4201 | + var lsw = (x & 0xffff) + (y & 0xffff); | |
| 4202 | + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); | |
| 4203 | + return (msw << 16) | (lsw & 0xffff); | |
| 4204 | + } | |
| 4205 | + | |
| 4206 | + /* | |
| 4207 | + * Bitwise rotate a 32-bit number to the left. | |
| 4208 | + */ | |
| 4209 | + function bitRotateLeft(num, cnt) { | |
| 4210 | + return (num << cnt) | (num >>> (32 - cnt)); | |
| 4211 | + } | |
| 4212 | + | |
| 4213 | + /* | |
| 4214 | + * These functions implement the four basic operations the algorithm uses. | |
| 4215 | + */ | |
| 4216 | + function md5cmn(q, a, b, x, s, t) { | |
| 4217 | + return safeAdd( | |
| 4218 | + bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), | |
| 4219 | + b, | |
| 4220 | + ); | |
| 4221 | + } | |
| 4222 | + function md5ff(a, b, c, d, x, s, t) { | |
| 4223 | + return md5cmn((b & c) | (~b & d), a, b, x, s, t); | |
| 4224 | + } | |
| 4225 | + function md5gg(a, b, c, d, x, s, t) { | |
| 4226 | + return md5cmn((b & d) | (c & ~d), a, b, x, s, t); | |
| 4227 | + } | |
| 4228 | + function md5hh(a, b, c, d, x, s, t) { | |
| 4229 | + return md5cmn(b ^ c ^ d, a, b, x, s, t); | |
| 4230 | + } | |
| 4231 | + function md5ii(a, b, c, d, x, s, t) { | |
| 4232 | + return md5cmn(c ^ (b | ~d), a, b, x, s, t); | |
| 4233 | + } | |
| 4234 | + | |
| 4235 | + /* | |
| 4236 | + * Calculate the MD5 of an array of little-endian words, and a bit length. | |
| 4237 | + */ | |
| 4238 | + function binlMD5(x, len) { | |
| 4239 | + /* append padding */ | |
| 4240 | + x[len >> 5] |= 0x80 << len % 32; | |
| 4241 | + x[(((len + 64) >>> 9) << 4) + 14] = len; | |
| 4242 | + | |
| 4243 | + var i; | |
| 4244 | + var olda; | |
| 4245 | + var oldb; | |
| 4246 | + var oldc; | |
| 4247 | + var oldd; | |
| 4248 | + var a = 1732584193; | |
| 4249 | + var b = -271733879; | |
| 4250 | + var c = -1732584194; | |
| 4251 | + var d = 271733878; | |
| 4252 | + | |
| 4253 | + for (i = 0; i < x.length; i += 16) { | |
| 4254 | + olda = a; | |
| 4255 | + oldb = b; | |
| 4256 | + oldc = c; | |
| 4257 | + oldd = d; | |
| 4258 | + | |
| 4259 | + a = md5ff(a, b, c, d, x[i], 7, -680876936); | |
| 4260 | + d = md5ff(d, a, b, c, x[i + 1], 12, -389564586); | |
| 4261 | + c = md5ff(c, d, a, b, x[i + 2], 17, 606105819); | |
| 4262 | + b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330); | |
| 4263 | + a = md5ff(a, b, c, d, x[i + 4], 7, -176418897); | |
| 4264 | + d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426); | |
| 4265 | + c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341); | |
| 4266 | + b = md5ff(b, c, d, a, x[i + 7], 22, -45705983); | |
| 4267 | + a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416); | |
| 4268 | + d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417); | |
| 4269 | + c = md5ff(c, d, a, b, x[i + 10], 17, -42063); | |
| 4270 | + b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162); | |
| 4271 | + a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682); | |
| 4272 | + d = md5ff(d, a, b, c, x[i + 13], 12, -40341101); | |
| 4273 | + c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290); | |
| 4274 | + b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329); | |
| 4275 | + | |
| 4276 | + a = md5gg(a, b, c, d, x[i + 1], 5, -165796510); | |
| 4277 | + d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632); | |
| 4278 | + c = md5gg(c, d, a, b, x[i + 11], 14, 643717713); | |
| 4279 | + b = md5gg(b, c, d, a, x[i], 20, -373897302); | |
| 4280 | + a = md5gg(a, b, c, d, x[i + 5], 5, -701558691); | |
| 4281 | + d = md5gg(d, a, b, c, x[i + 10], 9, 38016083); | |
| 4282 | + c = md5gg(c, d, a, b, x[i + 15], 14, -660478335); | |
| 4283 | + b = md5gg(b, c, d, a, x[i + 4], 20, -405537848); | |
| 4284 | + a = md5gg(a, b, c, d, x[i + 9], 5, 568446438); | |
| 4285 | + d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690); | |
| 4286 | + c = md5gg(c, d, a, b, x[i + 3], 14, -187363961); | |
| 4287 | + b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501); | |
| 4288 | + a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467); | |
| 4289 | + d = md5gg(d, a, b, c, x[i + 2], 9, -51403784); | |
| 4290 | + c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473); | |
| 4291 | + b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734); | |
| 4292 | + | |
| 4293 | + a = md5hh(a, b, c, d, x[i + 5], 4, -378558); | |
| 4294 | + d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463); | |
| 4295 | + c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562); | |
| 4296 | + b = md5hh(b, c, d, a, x[i + 14], 23, -35309556); | |
| 4297 | + a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060); | |
| 4298 | + d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353); | |
| 4299 | + c = md5hh(c, d, a, b, x[i + 7], 16, -155497632); | |
| 4300 | + b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640); | |
| 4301 | + a = md5hh(a, b, c, d, x[i + 13], 4, 681279174); | |
| 4302 | + d = md5hh(d, a, b, c, x[i], 11, -358537222); | |
| 4303 | + c = md5hh(c, d, a, b, x[i + 3], 16, -722521979); | |
| 4304 | + b = md5hh(b, c, d, a, x[i + 6], 23, 76029189); | |
| 4305 | + a = md5hh(a, b, c, d, x[i + 9], 4, -640364487); | |
| 4306 | + d = md5hh(d, a, b, c, x[i + 12], 11, -421815835); | |
| 4307 | + c = md5hh(c, d, a, b, x[i + 15], 16, 530742520); | |
| 4308 | + b = md5hh(b, c, d, a, x[i + 2], 23, -995338651); | |
| 4309 | + | |
| 4310 | + a = md5ii(a, b, c, d, x[i], 6, -198630844); | |
| 4311 | + d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415); | |
| 4312 | + c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905); | |
| 4313 | + b = md5ii(b, c, d, a, x[i + 5], 21, -57434055); | |
| 4314 | + a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571); | |
| 4315 | + d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606); | |
| 4316 | + c = md5ii(c, d, a, b, x[i + 10], 15, -1051523); | |
| 4317 | + b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799); | |
| 4318 | + a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359); | |
| 4319 | + d = md5ii(d, a, b, c, x[i + 15], 10, -30611744); | |
| 4320 | + c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380); | |
| 4321 | + b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649); | |
| 4322 | + a = md5ii(a, b, c, d, x[i + 4], 6, -145523070); | |
| 4323 | + d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379); | |
| 4324 | + c = md5ii(c, d, a, b, x[i + 2], 15, 718787259); | |
| 4325 | + b = md5ii(b, c, d, a, x[i + 9], 21, -343485551); | |
| 4326 | + | |
| 4327 | + a = safeAdd(a, olda); | |
| 4328 | + b = safeAdd(b, oldb); | |
| 4329 | + c = safeAdd(c, oldc); | |
| 4330 | + d = safeAdd(d, oldd); | |
| 4331 | + } | |
| 4332 | + return [a, b, c, d]; | |
| 4333 | + } | |
| 4334 | + | |
| 4335 | + /* | |
| 4336 | + * Convert an array of little-endian words to a string | |
| 4337 | + */ | |
| 4338 | + function binl2rstr(input) { | |
| 4339 | + var i; | |
| 4340 | + var output = ""; | |
| 4341 | + var length32 = input.length * 32; | |
| 4342 | + for (i = 0; i < length32; i += 8) { | |
| 4343 | + output += String.fromCharCode((input[i >> 5] >>> i % 32) & 0xff); | |
| 4344 | + } | |
| 4345 | + return output; | |
| 4346 | + } | |
| 4347 | + | |
| 4348 | + /* | |
| 4349 | + * Convert a raw string to an array of little-endian words | |
| 4350 | + * Characters >255 have their high-byte silently ignored. | |
| 4351 | + */ | |
| 4352 | + function rstr2binl(input) { | |
| 4353 | + var i; | |
| 4354 | + var output = []; | |
| 4355 | + output[(input.length >> 2) - 1] = undefined; | |
| 4356 | + for (i = 0; i < output.length; i += 1) { | |
| 4357 | + output[i] = 0; | |
| 4358 | + } | |
| 4359 | + var length8 = input.length * 8; | |
| 4360 | + for (i = 0; i < length8; i += 8) { | |
| 4361 | + output[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << i % 32; | |
| 4362 | + } | |
| 4363 | + return output; | |
| 4364 | + } | |
| 4365 | + | |
| 4366 | + /* | |
| 4367 | + * Calculate the MD5 of a raw string | |
| 4368 | + */ | |
| 4369 | + function rstrMD5(s) { | |
| 4370 | + return binl2rstr(binlMD5(rstr2binl(s), s.length * 8)); | |
| 4371 | + } | |
| 4372 | + | |
| 4373 | + /* | |
| 4374 | + * Calculate the HMAC-MD5, of a key and some data (raw strings) | |
| 4375 | + */ | |
| 4376 | + function rstrHMACMD5(key, data) { | |
| 4377 | + var i; | |
| 4378 | + var bkey = rstr2binl(key); | |
| 4379 | + var ipad = []; | |
| 4380 | + var opad = []; | |
| 4381 | + var hash; | |
| 4382 | + ipad[15] = opad[15] = undefined; | |
| 4383 | + if (bkey.length > 16) { | |
| 4384 | + bkey = binlMD5(bkey, key.length * 8); | |
| 4385 | + } | |
| 4386 | + for (i = 0; i < 16; i += 1) { | |
| 4387 | + ipad[i] = bkey[i] ^ 0x36363636; | |
| 4388 | + opad[i] = bkey[i] ^ 0x5c5c5c5c; | |
| 4389 | + } | |
| 4390 | + hash = binlMD5(ipad.concat(rstr2binl(data)), 512 + data.length * 8); | |
| 4391 | + return binl2rstr(binlMD5(opad.concat(hash), 512 + 128)); | |
| 4392 | + } | |
| 4393 | + | |
| 4394 | + /* | |
| 4395 | + * Convert a raw string to a hex string | |
| 4396 | + */ | |
| 4397 | + function rstr2hex(input) { | |
| 4398 | + var hexTab = "0123456789abcdef"; | |
| 4399 | + var output = ""; | |
| 4400 | + var x; | |
| 4401 | + var i; | |
| 4402 | + for (i = 0; i < input.length; i += 1) { | |
| 4403 | + x = input.charCodeAt(i); | |
| 4404 | + output += | |
| 4405 | + hexTab.charAt((x >>> 4) & 0x0f) + hexTab.charAt(x & 0x0f); | |
| 4406 | + } | |
| 4407 | + return output; | |
| 4408 | + } | |
| 4409 | + | |
| 4410 | + /* | |
| 4411 | + * Encode a string as utf-8 | |
| 4412 | + */ | |
| 4413 | + function str2rstrUTF8(input) { | |
| 4414 | + return unescape(encodeURIComponent(input)); | |
| 4415 | + } | |
| 4416 | + | |
| 4417 | + /* | |
| 4418 | + * Take string arguments and return either raw or hex encoded strings | |
| 4419 | + */ | |
| 4420 | + function rawMD5(s) { | |
| 4421 | + return rstrMD5(str2rstrUTF8(s)); | |
| 4422 | + } | |
| 4423 | + function hexMD5(s) { | |
| 4424 | + return rstr2hex(rawMD5(s)); | |
| 4425 | + } | |
| 4426 | + function rawHMACMD5(k, d) { | |
| 4427 | + return rstrHMACMD5(str2rstrUTF8(k), str2rstrUTF8(d)); | |
| 4428 | + } | |
| 4429 | + function hexHMACMD5(k, d) { | |
| 4430 | + return rstr2hex(rawHMACMD5(k, d)); | |
| 4431 | + } | |
| 4432 | + | |
| 4433 | + function md5(string, key, raw) { | |
| 4434 | + if (!key) { | |
| 4435 | + if (!raw) { | |
| 4436 | + return hexMD5(string); | |
| 4437 | + } | |
| 4438 | + return rawMD5(string); | |
| 4439 | + } | |
| 4440 | + if (!raw) { | |
| 4441 | + return hexHMACMD5(key, string); | |
| 4442 | + } | |
| 4443 | + return rawHMACMD5(key, string); | |
| 4444 | + } | |
| 4445 | + | |
| 4446 | + module.exports = md5; | |
| 4447 | + }, | |
| 4448 | + {}, | |
| 4449 | + ], | |
| 3538 | 4450 | }, |
| 3539 | 4451 | {}, |
| 3540 | 4452 | [4], |