|
717 | 717 | };
|
718 | 718 | // TODO
|
719 | 719 | preferences.cookie = {};
|
| 720 | + |
| 721 | + // Copy feature settings from remote config to preferences object |
| 722 | + preferences.featureSettings = {}; |
| 723 | + remoteFeatureNames.forEach((featureName) => { |
| 724 | + if (!enabledFeatures.includes(featureName)) { |
| 725 | + return |
| 726 | + } |
| 727 | + |
| 728 | + preferences.featureSettings[featureName] = data.features[featureName].settings; |
| 729 | + }); |
| 730 | + |
720 | 731 | return preferences
|
721 | 732 | }
|
722 | 733 |
|
|
1596 | 1607 | })
|
1597 | 1608 | }
|
1598 | 1609 |
|
| 1610 | + // We use this method to detect M1 macs and set appropriate API values to prevent sites from detecting fingerprinting protections |
| 1611 | + function isAppleSilicon () { |
| 1612 | + const canvas = document.createElement('canvas'); |
| 1613 | + const gl = canvas.getContext('webgl'); |
| 1614 | + |
| 1615 | + // Best guess if the device is an Apple Silicon |
| 1616 | + // https://stackoverflow.com/a/65412357 |
| 1617 | + return gl.getSupportedExtensions().indexOf('WEBGL_compressed_texture_etc') !== -1 |
| 1618 | + } |
| 1619 | + |
| 1620 | + /** |
| 1621 | + * Take configSeting which should be an array of possible values. |
| 1622 | + * If a value contains a criteria that is a match for this environment then return that value. |
| 1623 | + * Otherwise return the first value that doesn't have a criteria. |
| 1624 | + * |
| 1625 | + * @param {*[]} configSetting - Config setting which should contain a list of possible values |
| 1626 | + * @returns {*|undefined} - The value from the list that best matches the criteria in the config |
| 1627 | + */ |
| 1628 | + function processAttrByCriteria (configSetting) { |
| 1629 | + let bestOption; |
| 1630 | + for (const item of configSetting) { |
| 1631 | + if (item.criteria) { |
| 1632 | + if (item.criteria.arch === 'AppleSilicon' && isAppleSilicon()) { |
| 1633 | + bestOption = item; |
| 1634 | + break |
| 1635 | + } |
| 1636 | + } else { |
| 1637 | + bestOption = item; |
| 1638 | + } |
| 1639 | + } |
| 1640 | + |
| 1641 | + return bestOption |
| 1642 | + } |
| 1643 | + |
| 1644 | + /** |
| 1645 | + * Get the value of a config setting. |
| 1646 | + * If the value is not set, return the default value. |
| 1647 | + * If the value is not an object, return the value. |
| 1648 | + * If the value is an object, check its type property. |
| 1649 | + * |
| 1650 | + * @param {string} featureName |
| 1651 | + * @param {object} args |
| 1652 | + * @param {string} prop |
| 1653 | + * @param {any} defaultValue - The default value to use if the config setting is not set |
| 1654 | + * @returns The value of the config setting or the default value |
| 1655 | + */ |
| 1656 | + function getFeatureAttr (featureName, args, prop, defaultValue) { |
| 1657 | + let configSetting = getFeatureSetting(featureName, args, prop); |
| 1658 | + |
| 1659 | + if (configSetting === undefined) { |
| 1660 | + return defaultValue |
| 1661 | + } |
| 1662 | + |
| 1663 | + const configSettingType = typeof configSetting; |
| 1664 | + switch (configSettingType) { |
| 1665 | + case 'object': |
| 1666 | + if (Array.isArray(configSetting)) { |
| 1667 | + configSetting = processAttrByCriteria(configSetting); |
| 1668 | + if (configSetting === undefined) { |
| 1669 | + return defaultValue |
| 1670 | + } |
| 1671 | + } |
| 1672 | + |
| 1673 | + if (!configSetting.type) { |
| 1674 | + return defaultValue |
| 1675 | + } |
| 1676 | + |
| 1677 | + if (configSetting.type === 'undefined') { |
| 1678 | + return undefined |
| 1679 | + } |
| 1680 | + |
| 1681 | + return configSetting.value |
| 1682 | + default: |
| 1683 | + return defaultValue |
| 1684 | + } |
| 1685 | + } |
| 1686 | + |
1599 | 1687 | /**
|
1600 | 1688 | * @param {string} featureName
|
1601 | 1689 | * @param {object} args
|
|
3610 | 3698 | init: init$9
|
3611 | 3699 | });
|
3612 | 3700 |
|
| 3701 | + const featureName$1 = 'fingerprinting-hardware'; |
| 3702 | + |
3613 | 3703 | function init$8 (args) {
|
3614 | 3704 | const Navigator = globalThis.Navigator;
|
3615 | 3705 | const navigator = globalThis.navigator;
|
3616 | 3706 |
|
3617 | 3707 | overrideProperty('keyboard', {
|
3618 | 3708 | object: Navigator.prototype,
|
3619 | 3709 | origValue: navigator.keyboard,
|
3620 |
| - targetValue: undefined |
| 3710 | + targetValue: getFeatureAttr(featureName$1, args, 'keyboard') |
3621 | 3711 | });
|
3622 | 3712 | overrideProperty('hardwareConcurrency', {
|
3623 | 3713 | object: Navigator.prototype,
|
3624 | 3714 | origValue: navigator.hardwareConcurrency,
|
3625 |
| - targetValue: 2 |
| 3715 | + targetValue: getFeatureAttr(featureName$1, args, 'hardwareConcurrency', 2) |
3626 | 3716 | });
|
3627 | 3717 | overrideProperty('deviceMemory', {
|
3628 | 3718 | object: Navigator.prototype,
|
3629 | 3719 | origValue: navigator.deviceMemory,
|
3630 |
| - targetValue: 8 |
| 3720 | + targetValue: getFeatureAttr(featureName$1, args, 'deviceMemory', 8) |
3631 | 3721 | });
|
3632 | 3722 | }
|
3633 | 3723 |
|
|
3636 | 3726 | init: init$8
|
3637 | 3727 | });
|
3638 | 3728 |
|
| 3729 | + const featureName = 'fingerprinting-screen-size'; |
| 3730 | + |
3639 | 3731 | /**
|
3640 | 3732 | * normalize window dimensions, if more than one monitor is in play.
|
3641 | 3733 | * X/Y values are set in the browser based on distance to the main monitor top or left, which
|
|
3725 | 3817 | origPropertyValues.availTop = overrideProperty('availTop', {
|
3726 | 3818 | object: Screen.prototype,
|
3727 | 3819 | origValue: screen.availTop,
|
3728 |
| - targetValue: 0 |
| 3820 | + targetValue: getFeatureSetting(featureName, args, 'availTop') |
3729 | 3821 | });
|
3730 | 3822 | origPropertyValues.availLeft = overrideProperty('availLeft', {
|
3731 | 3823 | object: Screen.prototype,
|
3732 | 3824 | origValue: screen.availLeft,
|
3733 |
| - targetValue: 0 |
| 3825 | + targetValue: getFeatureSetting(featureName, args, 'availLeft') |
3734 | 3826 | });
|
3735 | 3827 | origPropertyValues.availWidth = overrideProperty('availWidth', {
|
3736 | 3828 | object: Screen.prototype,
|
|
3745 | 3837 | overrideProperty('colorDepth', {
|
3746 | 3838 | object: Screen.prototype,
|
3747 | 3839 | origValue: screen.colorDepth,
|
3748 |
| - targetValue: 24 |
| 3840 | + targetValue: getFeatureSetting(featureName, args, 'colorDepth') |
3749 | 3841 | });
|
3750 | 3842 | overrideProperty('pixelDepth', {
|
3751 | 3843 | object: Screen.prototype,
|
3752 | 3844 | origValue: screen.pixelDepth,
|
3753 |
| - targetValue: 24 |
| 3845 | + targetValue: getFeatureSetting(featureName, args, 'pixelDepth') |
3754 | 3846 | });
|
3755 | 3847 |
|
3756 | 3848 | window.addEventListener('resize', function () {
|
|
0 commit comments