|
673 | 673 | return Reflect.get(target, prop, receiver); |
674 | 674 | }; |
675 | 675 | } |
| 676 | + function wrapFunction(functionValue, realTarget) { |
| 677 | + return new Proxy(realTarget, { |
| 678 | + get(target, prop, receiver) { |
| 679 | + if (prop === "toString") { |
| 680 | + const method = Reflect.get(target, prop, receiver).bind(target); |
| 681 | + Object.defineProperty(method, "toString", { |
| 682 | + value: functionToString.bind(functionToString), |
| 683 | + enumerable: false |
| 684 | + }); |
| 685 | + return method; |
| 686 | + } |
| 687 | + return Reflect.get(target, prop, receiver); |
| 688 | + }, |
| 689 | + apply(_2, thisArg, argumentsList) { |
| 690 | + return Reflect.apply(functionValue, thisArg, argumentsList); |
| 691 | + } |
| 692 | + }); |
| 693 | + } |
676 | 694 | function wrapProperty(object, propertyName, descriptor, definePropertyFn) { |
677 | 695 | if (!object) { |
678 | 696 | return; |
|
4020 | 4038 | } |
4021 | 4039 | return dataToSend; |
4022 | 4040 | } |
4023 | | - var _activeShareRequest, _activeScreenLockRequest; |
| 4041 | + var _activeShareRequest, _activeScreenLockRequest, _webNotifications; |
4024 | 4042 | var WebCompat = class extends ContentFeature { |
4025 | 4043 | constructor() { |
4026 | 4044 | super(...arguments); |
4027 | 4045 | /** @type {Promise<any> | null} */ |
4028 | 4046 | __privateAdd(this, _activeShareRequest, null); |
4029 | 4047 | /** @type {Promise<any> | null} */ |
4030 | 4048 | __privateAdd(this, _activeScreenLockRequest, null); |
| 4049 | + /** @type {Map<string, object>} */ |
| 4050 | + __privateAdd(this, _webNotifications, /* @__PURE__ */ new Map()); |
4031 | 4051 | // Opt in to receive configuration updates from initial ping responses |
4032 | 4052 | __publicField(this, "listenForConfigUpdates", true); |
4033 | 4053 | } |
|
4047 | 4067 | if (this.getFeatureSettingEnabled("notification")) { |
4048 | 4068 | this.notificationFix(); |
4049 | 4069 | } |
| 4070 | + if (this.getFeatureSettingEnabled("webNotifications")) { |
| 4071 | + this.webNotificationsFix(); |
| 4072 | + } |
4050 | 4073 | if (this.getFeatureSettingEnabled("permissions")) { |
4051 | 4074 | const settings = this.getFeatureSetting("permissions"); |
4052 | 4075 | this.permissionsFix(settings); |
|
4181 | 4204 | enumerable: true |
4182 | 4205 | }); |
4183 | 4206 | } |
| 4207 | + /** |
| 4208 | + * Web Notifications polyfill that communicates with native code for permission |
| 4209 | + * management and notification display. |
| 4210 | + */ |
| 4211 | + webNotificationsFix() { |
| 4212 | + var _id; |
| 4213 | + if (!globalThis.isSecureContext) { |
| 4214 | + return; |
| 4215 | + } |
| 4216 | + const feature = this; |
| 4217 | + const settings = this.getFeatureSetting("webNotifications") || {}; |
| 4218 | + const nativeEnabled = settings.nativeEnabled !== false; |
| 4219 | + const nativeNotify = nativeEnabled ? (name, data) => feature.notify(name, data) : () => { |
| 4220 | + }; |
| 4221 | + const nativeRequest = nativeEnabled ? (name, data) => feature.request(name, data) : () => Promise.resolve({ permission: "denied" }); |
| 4222 | + const nativeSubscribe = nativeEnabled ? (name, cb) => feature.subscribe(name, cb) : () => () => { |
| 4223 | + }; |
| 4224 | + let permission = nativeEnabled ? "default" : "denied"; |
| 4225 | + class NotificationPolyfill { |
| 4226 | + /** |
| 4227 | + * @param {string} title |
| 4228 | + * @param {NotificationOptions} [options] |
| 4229 | + */ |
| 4230 | + constructor(title, options = {}) { |
| 4231 | + /** @type {string} */ |
| 4232 | + __privateAdd(this, _id); |
| 4233 | + /** @type {string} */ |
| 4234 | + __publicField(this, "title"); |
| 4235 | + /** @type {string} */ |
| 4236 | + __publicField(this, "body"); |
| 4237 | + /** @type {string} */ |
| 4238 | + __publicField(this, "icon"); |
| 4239 | + /** @type {string} */ |
| 4240 | + __publicField(this, "tag"); |
| 4241 | + /** @type {any} */ |
| 4242 | + __publicField(this, "data"); |
| 4243 | + // Event handlers |
| 4244 | + /** @type {((this: Notification, ev: Event) => any) | null} */ |
| 4245 | + __publicField(this, "onclick", null); |
| 4246 | + /** @type {((this: Notification, ev: Event) => any) | null} */ |
| 4247 | + __publicField(this, "onclose", null); |
| 4248 | + /** @type {((this: Notification, ev: Event) => any) | null} */ |
| 4249 | + __publicField(this, "onerror", null); |
| 4250 | + /** @type {((this: Notification, ev: Event) => any) | null} */ |
| 4251 | + __publicField(this, "onshow", null); |
| 4252 | + __privateSet(this, _id, crypto.randomUUID()); |
| 4253 | + this.title = String(title); |
| 4254 | + this.body = options.body ? String(options.body) : ""; |
| 4255 | + this.icon = options.icon ? String(options.icon) : ""; |
| 4256 | + this.tag = options.tag ? String(options.tag) : ""; |
| 4257 | + this.data = options.data; |
| 4258 | + __privateGet(feature, _webNotifications).set(__privateGet(this, _id), this); |
| 4259 | + nativeNotify("showNotification", { |
| 4260 | + id: __privateGet(this, _id), |
| 4261 | + title: this.title, |
| 4262 | + body: this.body, |
| 4263 | + icon: this.icon, |
| 4264 | + tag: this.tag |
| 4265 | + }); |
| 4266 | + } |
| 4267 | + /** |
| 4268 | + * @returns {'default' | 'denied' | 'granted'} |
| 4269 | + */ |
| 4270 | + static get permission() { |
| 4271 | + return permission; |
| 4272 | + } |
| 4273 | + /** |
| 4274 | + * @param {NotificationPermissionCallback} [deprecatedCallback] |
| 4275 | + * @returns {Promise<NotificationPermission>} |
| 4276 | + */ |
| 4277 | + static async requestPermission(deprecatedCallback) { |
| 4278 | + try { |
| 4279 | + const result = await nativeRequest("requestPermission", {}); |
| 4280 | + const resultPermission = ( |
| 4281 | + /** @type {NotificationPermission} */ |
| 4282 | + result?.permission || "denied" |
| 4283 | + ); |
| 4284 | + permission = resultPermission; |
| 4285 | + if (deprecatedCallback) { |
| 4286 | + deprecatedCallback(resultPermission); |
| 4287 | + } |
| 4288 | + return resultPermission; |
| 4289 | + } catch (e) { |
| 4290 | + permission = "denied"; |
| 4291 | + if (deprecatedCallback) { |
| 4292 | + deprecatedCallback("denied"); |
| 4293 | + } |
| 4294 | + return "denied"; |
| 4295 | + } |
| 4296 | + } |
| 4297 | + /** |
| 4298 | + * @returns {number} |
| 4299 | + */ |
| 4300 | + static get maxActions() { |
| 4301 | + return 2; |
| 4302 | + } |
| 4303 | + close() { |
| 4304 | + if (!__privateGet(feature, _webNotifications).has(__privateGet(this, _id))) { |
| 4305 | + return; |
| 4306 | + } |
| 4307 | + nativeNotify("closeNotification", { id: __privateGet(this, _id) }); |
| 4308 | + __privateGet(feature, _webNotifications).delete(__privateGet(this, _id)); |
| 4309 | + if (typeof this.onclose === "function") { |
| 4310 | + try { |
| 4311 | + this.onclose(new Event("close")); |
| 4312 | + } catch (e) { |
| 4313 | + } |
| 4314 | + } |
| 4315 | + } |
| 4316 | + } |
| 4317 | + _id = new WeakMap(); |
| 4318 | + const wrappedNotification = wrapFunction(NotificationPolyfill, NotificationPolyfill); |
| 4319 | + const wrappedRequestPermission = wrapToString( |
| 4320 | + NotificationPolyfill.requestPermission.bind(NotificationPolyfill), |
| 4321 | + NotificationPolyfill.requestPermission, |
| 4322 | + "function requestPermission() { [native code] }" |
| 4323 | + ); |
| 4324 | + nativeSubscribe("notificationEvent", (data) => { |
| 4325 | + const notification = __privateGet(this, _webNotifications).get(data.id); |
| 4326 | + if (!notification) return; |
| 4327 | + const eventName = `on${data.event}`; |
| 4328 | + if (typeof notification[eventName] === "function") { |
| 4329 | + try { |
| 4330 | + notification[eventName](new Event(data.event)); |
| 4331 | + } catch (e) { |
| 4332 | + } |
| 4333 | + } |
| 4334 | + if (data.event === "close") { |
| 4335 | + __privateGet(this, _webNotifications).delete(data.id); |
| 4336 | + } |
| 4337 | + }); |
| 4338 | + this.defineProperty(globalThis, "Notification", { |
| 4339 | + value: wrappedNotification, |
| 4340 | + writable: true, |
| 4341 | + configurable: true, |
| 4342 | + enumerable: false |
| 4343 | + }); |
| 4344 | + this.defineProperty(globalThis.Notification, "permission", { |
| 4345 | + get: () => permission, |
| 4346 | + configurable: true, |
| 4347 | + enumerable: true |
| 4348 | + }); |
| 4349 | + this.defineProperty(globalThis.Notification, "maxActions", { |
| 4350 | + get: () => 2, |
| 4351 | + configurable: true, |
| 4352 | + enumerable: true |
| 4353 | + }); |
| 4354 | + this.defineProperty(globalThis.Notification, "requestPermission", { |
| 4355 | + value: wrappedRequestPermission, |
| 4356 | + writable: true, |
| 4357 | + configurable: true, |
| 4358 | + enumerable: true |
| 4359 | + }); |
| 4360 | + } |
4184 | 4361 | cleanIframeValue() { |
4185 | 4362 | function cleanValueData(val) { |
4186 | 4363 | const clone = Object.assign({}, val); |
|
4746 | 4923 | }; |
4747 | 4924 | _activeShareRequest = new WeakMap(); |
4748 | 4925 | _activeScreenLockRequest = new WeakMap(); |
| 4926 | + _webNotifications = new WeakMap(); |
4749 | 4927 | var web_compat_default = WebCompat; |
4750 | 4928 |
|
4751 | 4929 | // src/features/fingerprinting-hardware.js |
|
0 commit comments