diff --git a/node_modules/@duckduckgo/content-scope-scripts/build/android/contentScope.js b/node_modules/@duckduckgo/content-scope-scripts/build/android/contentScope.js index 305bdde78e64..840630d9d47a 100644 --- a/node_modules/@duckduckgo/content-scope-scripts/build/android/contentScope.js +++ b/node_modules/@duckduckgo/content-scope-scripts/build/android/contentScope.js @@ -6275,6 +6275,7 @@ var MSG_PERMISSIONS_QUERY = "permissionsQuery"; var MSG_SCREEN_LOCK = "screenLock"; var MSG_SCREEN_UNLOCK = "screenUnlock"; + var MSG_DEVICE_ENUMERATION = "deviceEnumeration"; function canShare(data) { if (typeof data !== "object") return false; if (!("url" in data) && !("title" in data) && !("text" in data)) return false; @@ -6366,6 +6367,9 @@ if (this.getFeatureSettingEnabled("disableDeviceEnumeration") || this.getFeatureSettingEnabled("disableDeviceEnumerationFrames")) { this.preventDeviceEnumeration(); } + if (this.getFeatureSettingEnabled("enumerateDevices")) { + this.deviceEnumerationFix(); + } } /** Shim Web Share API in Android WebView */ shimWebShare() { @@ -6892,6 +6896,9 @@ this.forceViewportTag(viewportTag, newContent.join(", ")); } } + /** + * Prevents device enumeration by returning an empty array when enabled + */ preventDeviceEnumeration() { if (!window.MediaDevices) { return; @@ -6905,6 +6912,9 @@ } if (disableDeviceEnumeration) { const enumerateDevicesProxy = new DDGProxy(this, MediaDevices.prototype, "enumerateDevices", { + /** + * @returns {Promise} + */ apply() { return Promise.resolve([]); } @@ -6912,6 +6922,102 @@ enumerateDevicesProxy.overload(); } } + /** + * Creates a valid MediaDeviceInfo or InputDeviceInfo object that passes instanceof checks + * @param {'videoinput' | 'audioinput' | 'audiooutput'} kind - The device kind + * @returns {MediaDeviceInfo | InputDeviceInfo} + */ + createMediaDeviceInfo(kind) { + let deviceInfo; + if (kind === "videoinput" || kind === "audioinput") { + if (typeof InputDeviceInfo !== "undefined" && InputDeviceInfo.prototype) { + deviceInfo = Object.create(InputDeviceInfo.prototype); + } else { + deviceInfo = Object.create(MediaDeviceInfo.prototype); + } + } else { + deviceInfo = Object.create(MediaDeviceInfo.prototype); + } + Object.defineProperties(deviceInfo, { + deviceId: { + value: "default", + writable: false, + configurable: false, + enumerable: true + }, + kind: { + value: kind, + writable: false, + configurable: false, + enumerable: true + }, + label: { + value: "", + writable: false, + configurable: false, + enumerable: true + }, + groupId: { + value: "default-group", + writable: false, + configurable: false, + enumerable: true + }, + toJSON: { + value: function() { + return { + deviceId: this.deviceId, + kind: this.kind, + label: this.label, + groupId: this.groupId + }; + }, + writable: false, + configurable: false, + enumerable: true + } + }); + return deviceInfo; + } + /** + * Fixes device enumeration to handle permission prompts gracefully + */ + deviceEnumerationFix() { + if (!window.MediaDevices) { + return; + } + const enumerateDevicesProxy = new DDGProxy(this, MediaDevices.prototype, "enumerateDevices", { + /** + * @param {MediaDevices['enumerateDevices']} target + * @param {MediaDevices} thisArg + * @param {Parameters} args + * @returns {Promise} + */ + apply: async (target, thisArg, args) => { + try { + const response = await this.messaging.request(MSG_DEVICE_ENUMERATION, {}); + if (response.willPrompt) { + const devices = []; + if (response.videoInput) { + devices.push(this.createMediaDeviceInfo("videoinput")); + } + if (response.audioInput) { + devices.push(this.createMediaDeviceInfo("audioinput")); + } + if (response.audioOutput) { + devices.push(this.createMediaDeviceInfo("audiooutput")); + } + return Promise.resolve(devices); + } else { + return DDGReflect.apply(target, thisArg, args); + } + } catch (err) { + return DDGReflect.apply(target, thisArg, args); + } + } + }); + enumerateDevicesProxy.overload(); + } }; _activeShareRequest = new WeakMap(); _activeScreenLockRequest = new WeakMap(); diff --git a/package-lock.json b/package-lock.json index a56ba73a2c9e..c6db7e78c67b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "@duckduckgo/autoconsent": "^14.3.0", "@duckduckgo/autofill": "github:duckduckgo/duckduckgo-autofill#18.1.0", - "@duckduckgo/content-scope-scripts": "github:duckduckgo/content-scope-scripts#10.9.1", + "@duckduckgo/content-scope-scripts": "github:duckduckgo/content-scope-scripts#10.10.0", "@duckduckgo/privacy-dashboard": "github:duckduckgo/privacy-dashboard#9.0.0", "@duckduckgo/privacy-reference-tests": "github:duckduckgo/privacy-reference-tests#1751029573" }, @@ -63,7 +63,7 @@ "license": "Apache-2.0" }, "node_modules/@duckduckgo/content-scope-scripts": { - "resolved": "git+ssh://git@github.com/duckduckgo/content-scope-scripts.git#04b8764f27dd1a0d8e9438cfdb633153579df12b", + "resolved": "git+ssh://git@github.com/duckduckgo/content-scope-scripts.git#a5e876e1653905b6a0e6e16f8e0b8f8e52c8b6a0", "license": "Apache-2.0", "workspaces": [ "injected", @@ -89,13 +89,13 @@ "license": "Apache-2.0" }, "node_modules/@ghostery/adblocker": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@ghostery/adblocker/-/adblocker-2.11.0.tgz", - "integrity": "sha512-7FW/Hd/lYp2OLDw6JknYLIhEoFTkcGTC3PqMu9JiOYV1CgUJ/PKhcsRsmdm1lAbhmL9Rq86z1/bhn8CZXSPZ/w==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@ghostery/adblocker/-/adblocker-2.11.1.tgz", + "integrity": "sha512-bROAa2LayP0CfY6dJodMkV/DN7/0OgSEOrj/TnTWrOAkiSrH4rGpO3G1NlIAyF4uK9IZNOWDzcZt7/vv9qy0zA==", "license": "MPL-2.0", "dependencies": { - "@ghostery/adblocker-content": "^2.11.0", - "@ghostery/adblocker-extended-selectors": "^2.11.0", + "@ghostery/adblocker-content": "^2.11.1", + "@ghostery/adblocker-extended-selectors": "^2.11.1", "@ghostery/url-parser": "^1.3.0", "@remusao/guess-url-type": "^2.1.0", "@remusao/small": "^2.1.0", @@ -104,18 +104,18 @@ } }, "node_modules/@ghostery/adblocker-content": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@ghostery/adblocker-content/-/adblocker-content-2.11.0.tgz", - "integrity": "sha512-2TIxD5OC9lQpCq1SNC9mu4M37pZf1+1LDJCd4yM8gTGc927xMwNVkUBNDmi1aEH2r+PMtmJu4xtHN+YFhgns6A==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@ghostery/adblocker-content/-/adblocker-content-2.11.1.tgz", + "integrity": "sha512-KF1vjwp/YNzgjLKOMh+FjGcXbliZHIJnh2A9+dLgL8Fe+HCK1h49p7xa7FFa0c2pO45GDfI2LgsAiqhHSYZP6A==", "license": "MPL-2.0", "dependencies": { - "@ghostery/adblocker-extended-selectors": "^2.11.0" + "@ghostery/adblocker-extended-selectors": "^2.11.1" } }, "node_modules/@ghostery/adblocker-extended-selectors": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@ghostery/adblocker-extended-selectors/-/adblocker-extended-selectors-2.11.0.tgz", - "integrity": "sha512-yl7Ygs+TFrG2ZbxynUG8Tyt3mI4WPb4Gzy4VgVXV29SYwUbok0md0Hp7vHSYeURlSzEMMa/KqgjFoZr3GY49XA==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@ghostery/adblocker-extended-selectors/-/adblocker-extended-selectors-2.11.1.tgz", + "integrity": "sha512-T0UpheA3cd9T/4feJkJR+i5QaDvRt5gHcFWKh7DAstdYPqbKxqDG0U2RgY1Z8PtG2dVmIzBlQ0QPUB7gCF6nyw==", "license": "MPL-2.0" }, "node_modules/@ghostery/url-parser": { @@ -280,9 +280,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.0.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.12.tgz", - "integrity": "sha512-LtOrbvDf5ndC9Xi+4QZjVL0woFymF/xSTKZKPgrrl7H7XoeDvnD+E2IclKVDyaK9UM756W/3BXqSU+JEHopA9g==", + "version": "24.0.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.13.tgz", + "integrity": "sha512-Qm9OYVOFHFYg3wJoTSrz80hoec5Lia/dPp84do3X7dZvLikQvM1YpmvTBEdIr/e+U8HTkFjLHLnl78K/qjf+jQ==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 483841852010..9a634435e6d2 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "dependencies": { "@duckduckgo/autoconsent": "^14.3.0", "@duckduckgo/autofill": "github:duckduckgo/duckduckgo-autofill#18.1.0", - "@duckduckgo/content-scope-scripts": "github:duckduckgo/content-scope-scripts#10.9.1", + "@duckduckgo/content-scope-scripts": "github:duckduckgo/content-scope-scripts#10.10.0", "@duckduckgo/privacy-dashboard": "github:duckduckgo/privacy-dashboard#9.0.0", "@duckduckgo/privacy-reference-tests": "github:duckduckgo/privacy-reference-tests#1751029573" }