|
356 | 356 | };
|
357 | 357 |
|
358 | 358 | /**
|
359 |
| - * Handles the processing of a config setting. |
| 359 | + * Processes a structured config setting and returns the value according to its type |
360 | 360 | * @param {*} configSetting
|
361 | 361 | * @param {*} [defaultValue]
|
362 | 362 | * @returns
|
|
807 | 807 | 'clickToLoad',
|
808 | 808 | 'windowsPermissionUsage',
|
809 | 809 | 'webCompat',
|
810 |
| - 'duckPlayer' |
| 810 | + 'duckPlayer', |
| 811 | + 'harmfulApis' |
811 | 812 | ]);
|
812 | 813 |
|
813 | 814 | /** @typedef {baseFeatures[number]|otherFeatures[number]} FeatureName */
|
814 | 815 | /** @type {Record<string, FeatureName[]>} */
|
815 | 816 | const platformSupport = {
|
816 | 817 | apple: [
|
817 |
| - ...baseFeatures, |
818 |
| - 'webCompat' |
| 818 | + 'webCompat', |
| 819 | + ...baseFeatures |
819 | 820 | ],
|
820 | 821 | 'apple-isolated': [
|
821 | 822 | 'duckPlayer'
|
|
827 | 828 | windows: [
|
828 | 829 | ...baseFeatures,
|
829 | 830 | 'windowsPermissionUsage',
|
830 |
| - 'duckPlayer' |
| 831 | + 'duckPlayer', |
| 832 | + 'harmfulApis' |
831 | 833 | ],
|
832 | 834 | firefox: [
|
833 | 835 | ...baseFeatures,
|
|
1507 | 1509 | }
|
1508 | 1510 |
|
1509 | 1511 | /**
|
| 1512 | + * Return a specific setting from the feature settings |
1510 | 1513 | * @param {string} featureKeyName
|
1511 | 1514 | * @param {string} [featureName]
|
1512 | 1515 | * @returns {any}
|
1513 | 1516 | */
|
1514 | 1517 | getFeatureSetting (featureKeyName, featureName) {
|
1515 |
| - let result = this._getFeatureSetting(featureName); |
| 1518 | + let result = this._getFeatureSettings(featureName); |
1516 | 1519 | if (featureKeyName === 'domains') {
|
1517 | 1520 | throw new Error('domains is a reserved feature setting key name')
|
1518 | 1521 | }
|
|
1533 | 1536 | }
|
1534 | 1537 |
|
1535 | 1538 | /**
|
| 1539 | + * Return the settings object for a feature |
1536 | 1540 | * @param {string} [featureName] - The name of the feature to get the settings for; defaults to the name of the feature
|
1537 | 1541 | * @returns {any}
|
1538 | 1542 | */
|
1539 |
| - _getFeatureSetting (featureName) { |
| 1543 | + _getFeatureSettings (featureName) { |
1540 | 1544 | const camelFeatureName = featureName || camelcase(this.name);
|
1541 | 1545 | return this.#args?.featureSettings?.[camelFeatureName]
|
1542 | 1546 | }
|
1543 | 1547 |
|
1544 | 1548 | /**
|
| 1549 | + * For simple boolean settings, return true if the setting is 'enabled' |
1545 | 1550 | * @param {string} featureKeyName
|
1546 | 1551 | * @param {string} [featureName]
|
1547 | 1552 | * @returns {boolean}
|
|
1552 | 1557 | }
|
1553 | 1558 |
|
1554 | 1559 | /**
|
| 1560 | + * Given a config key, interpret the value as a list of domain overrides, and return the elements that match the current page |
1555 | 1561 | * @param {string} featureKeyName
|
1556 | 1562 | * @return {any[]}
|
1557 | 1563 | */
|
1558 | 1564 | matchDomainFeatureSetting (featureKeyName) {
|
1559 | 1565 | const domain = this.#args?.site.domain;
|
1560 | 1566 | if (!domain) return []
|
1561 |
| - const domains = this._getFeatureSetting()?.[featureKeyName] || []; |
| 1567 | + const domains = this._getFeatureSettings()?.[featureKeyName] || []; |
1562 | 1568 | return domains.filter((rule) => {
|
1563 | 1569 | if (Array.isArray(rule.domain)) {
|
1564 | 1570 | return rule.domain.some((domainRule) => {
|
|
1617 | 1623 | }
|
1618 | 1624 | }
|
1619 | 1625 |
|
| 1626 | + /** |
| 1627 | + * Fixes incorrect sizing value for outerHeight and outerWidth |
| 1628 | + */ |
| 1629 | + function windowSizingFix () { |
| 1630 | + if (window.outerHeight !== 0 && window.outerWidth !== 0) { |
| 1631 | + return |
| 1632 | + } |
| 1633 | + window.outerHeight = window.innerHeight; |
| 1634 | + window.outerWidth = window.innerWidth; |
| 1635 | + } |
| 1636 | + |
| 1637 | + /** |
| 1638 | + * Add missing navigator.credentials API |
| 1639 | + */ |
| 1640 | + function navigatorCredentialsFix () { |
| 1641 | + try { |
| 1642 | + if ('credentials' in navigator && 'get' in navigator.credentials) { |
| 1643 | + return |
| 1644 | + } |
| 1645 | + const value = { |
| 1646 | + get () { |
| 1647 | + return Promise.reject(new Error()) |
| 1648 | + } |
| 1649 | + }; |
| 1650 | + defineProperty(Navigator.prototype, 'credentials', { |
| 1651 | + value, |
| 1652 | + configurable: true, |
| 1653 | + enumerable: true |
| 1654 | + }); |
| 1655 | + } catch { |
| 1656 | + // Ignore exceptions that could be caused by conflicting with other extensions |
| 1657 | + } |
| 1658 | + } |
| 1659 | + |
| 1660 | + function safariObjectFix () { |
| 1661 | + try { |
| 1662 | + // @ts-expect-error https://app.asana.com/0/1201614831475344/1203979574128023/f |
| 1663 | + if (window.safari) { |
| 1664 | + return |
| 1665 | + } |
| 1666 | + defineProperty(window, 'safari', { |
| 1667 | + value: { |
| 1668 | + }, |
| 1669 | + configurable: true, |
| 1670 | + enumerable: true |
| 1671 | + }); |
| 1672 | + // @ts-expect-error https://app.asana.com/0/1201614831475344/1203979574128023/f |
| 1673 | + defineProperty(window.safari, 'pushNotification', { |
| 1674 | + value: { |
| 1675 | + }, |
| 1676 | + configurable: true, |
| 1677 | + enumerable: true |
| 1678 | + }); |
| 1679 | + // @ts-expect-error https://app.asana.com/0/1201614831475344/1203979574128023/f |
| 1680 | + defineProperty(window.safari.pushNotification, 'toString', { |
| 1681 | + value: () => { return '[object SafariRemoteNotification]' }, |
| 1682 | + configurable: true, |
| 1683 | + enumerable: true |
| 1684 | + }); |
| 1685 | + class SafariRemoteNotificationPermission { |
| 1686 | + constructor () { |
| 1687 | + this.deviceToken = null; |
| 1688 | + this.permission = 'denied'; |
| 1689 | + } |
| 1690 | + } |
| 1691 | + // @ts-expect-error https://app.asana.com/0/1201614831475344/1203979574128023/f |
| 1692 | + defineProperty(window.safari.pushNotification, 'permission', { |
| 1693 | + value: () => { |
| 1694 | + return new SafariRemoteNotificationPermission() |
| 1695 | + }, |
| 1696 | + configurable: true, |
| 1697 | + enumerable: true |
| 1698 | + }); |
| 1699 | + // @ts-expect-error https://app.asana.com/0/1201614831475344/1203979574128023/f |
| 1700 | + defineProperty(window.safari.pushNotification, 'requestPermission', { |
| 1701 | + value: (name, domain, options, callback) => { |
| 1702 | + if (typeof callback === 'function') { |
| 1703 | + callback(new SafariRemoteNotificationPermission()); |
| 1704 | + return |
| 1705 | + } |
| 1706 | + const reason = "Invalid 'callback' value passed to safari.pushNotification.requestPermission(). Expected a function."; |
| 1707 | + throw new Error(reason) |
| 1708 | + }, |
| 1709 | + configurable: true, |
| 1710 | + enumerable: true |
| 1711 | + }); |
| 1712 | + } catch { |
| 1713 | + // Ignore exceptions that could be caused by conflicting with other extensions |
| 1714 | + } |
| 1715 | + } |
| 1716 | + |
| 1717 | + class WebCompat extends ContentFeature { |
| 1718 | + init () { |
| 1719 | + if (this.getFeatureSettingEnabled('windowSizing')) { |
| 1720 | + windowSizingFix(); |
| 1721 | + } |
| 1722 | + if (this.getFeatureSettingEnabled('navigatorCredentials')) { |
| 1723 | + navigatorCredentialsFix(); |
| 1724 | + } |
| 1725 | + if (this.getFeatureSettingEnabled('safariObject')) { |
| 1726 | + safariObjectFix(); |
| 1727 | + } |
| 1728 | + } |
| 1729 | + } |
| 1730 | + |
1620 | 1731 | function generateUniqueID () {
|
1621 | 1732 | return Symbol(undefined)
|
1622 | 1733 | }
|
|
5951 | 6062 | }
|
5952 | 6063 | }
|
5953 | 6064 |
|
5954 |
| - /** |
5955 |
| - * Fixes incorrect sizing value for outerHeight and outerWidth |
5956 |
| - */ |
5957 |
| - function windowSizingFix () { |
5958 |
| - if (window.outerHeight !== 0 && window.outerWidth !== 0) { |
5959 |
| - return |
5960 |
| - } |
5961 |
| - window.outerHeight = window.innerHeight; |
5962 |
| - window.outerWidth = window.innerWidth; |
5963 |
| - } |
5964 |
| - |
5965 |
| - /** |
5966 |
| - * Add missing navigator.credentials API |
5967 |
| - */ |
5968 |
| - function navigatorCredentialsFix () { |
5969 |
| - try { |
5970 |
| - if ('credentials' in navigator && 'get' in navigator.credentials) { |
5971 |
| - return |
5972 |
| - } |
5973 |
| - const value = { |
5974 |
| - get () { |
5975 |
| - return Promise.reject(new Error()) |
5976 |
| - } |
5977 |
| - }; |
5978 |
| - defineProperty(Navigator.prototype, 'credentials', { |
5979 |
| - value, |
5980 |
| - configurable: true, |
5981 |
| - enumerable: true |
5982 |
| - }); |
5983 |
| - } catch { |
5984 |
| - // Ignore exceptions that could be caused by conflicting with other extensions |
5985 |
| - } |
5986 |
| - } |
5987 |
| - |
5988 |
| - function safariObjectFix () { |
5989 |
| - try { |
5990 |
| - // @ts-expect-error https://app.asana.com/0/1201614831475344/1203979574128023/f |
5991 |
| - if (window.safari) { |
5992 |
| - return |
5993 |
| - } |
5994 |
| - defineProperty(window, 'safari', { |
5995 |
| - value: { |
5996 |
| - }, |
5997 |
| - configurable: true, |
5998 |
| - enumerable: true |
5999 |
| - }); |
6000 |
| - // @ts-expect-error https://app.asana.com/0/1201614831475344/1203979574128023/f |
6001 |
| - defineProperty(window.safari, 'pushNotification', { |
6002 |
| - value: { |
6003 |
| - }, |
6004 |
| - configurable: true, |
6005 |
| - enumerable: true |
6006 |
| - }); |
6007 |
| - // @ts-expect-error https://app.asana.com/0/1201614831475344/1203979574128023/f |
6008 |
| - defineProperty(window.safari.pushNotification, 'toString', { |
6009 |
| - value: () => { return '[object SafariRemoteNotification]' }, |
6010 |
| - configurable: true, |
6011 |
| - enumerable: true |
6012 |
| - }); |
6013 |
| - class SafariRemoteNotificationPermission { |
6014 |
| - constructor () { |
6015 |
| - this.deviceToken = null; |
6016 |
| - this.permission = 'denied'; |
6017 |
| - } |
6018 |
| - } |
6019 |
| - // @ts-expect-error https://app.asana.com/0/1201614831475344/1203979574128023/f |
6020 |
| - defineProperty(window.safari.pushNotification, 'permission', { |
6021 |
| - value: () => { |
6022 |
| - return new SafariRemoteNotificationPermission() |
6023 |
| - }, |
6024 |
| - configurable: true, |
6025 |
| - enumerable: true |
6026 |
| - }); |
6027 |
| - // @ts-expect-error https://app.asana.com/0/1201614831475344/1203979574128023/f |
6028 |
| - defineProperty(window.safari.pushNotification, 'requestPermission', { |
6029 |
| - value: (name, domain, options, callback) => { |
6030 |
| - if (typeof callback === 'function') { |
6031 |
| - callback(new SafariRemoteNotificationPermission()); |
6032 |
| - return |
6033 |
| - } |
6034 |
| - const reason = "Invalid 'callback' value passed to safari.pushNotification.requestPermission(). Expected a function."; |
6035 |
| - throw new Error(reason) |
6036 |
| - }, |
6037 |
| - configurable: true, |
6038 |
| - enumerable: true |
6039 |
| - }); |
6040 |
| - } catch { |
6041 |
| - // Ignore exceptions that could be caused by conflicting with other extensions |
6042 |
| - } |
6043 |
| - } |
6044 |
| - |
6045 |
| - class WebCompat extends ContentFeature { |
6046 |
| - init () { |
6047 |
| - if (this.getFeatureSettingEnabled('windowSizing')) { |
6048 |
| - windowSizingFix(); |
6049 |
| - } |
6050 |
| - if (this.getFeatureSettingEnabled('navigatorCredentials')) { |
6051 |
| - navigatorCredentialsFix(); |
6052 |
| - } |
6053 |
| - if (this.getFeatureSettingEnabled('safariObject')) { |
6054 |
| - safariObjectFix(); |
6055 |
| - } |
6056 |
| - } |
6057 |
| - } |
6058 |
| - |
6059 | 6065 | var platformFeatures = {
|
| 6066 | + ddg_feature_webCompat: WebCompat, |
6060 | 6067 | ddg_feature_runtimeChecks: RuntimeChecks,
|
6061 | 6068 | ddg_feature_fingerprintingAudio: FingerprintingAudio,
|
6062 | 6069 | ddg_feature_fingerprintingBattery: FingerprintingBattery,
|
|
6070 | 6077 | ddg_feature_fingerprintingTemporaryStorage: FingerprintingTemporaryStorage,
|
6071 | 6078 | ddg_feature_navigatorInterface: NavigatorInterface,
|
6072 | 6079 | ddg_feature_elementHiding: ElementHiding,
|
6073 |
| - ddg_feature_exceptionHandler: ExceptionHandler, |
6074 |
| - ddg_feature_webCompat: WebCompat |
| 6080 | + ddg_feature_exceptionHandler: ExceptionHandler |
6075 | 6081 | };
|
6076 | 6082 |
|
6077 | 6083 | /* global false */
|
|
0 commit comments