commit d9cd4709dbf57edf5659e3b3e723ea3cf38a275c Author: SwZ Date: Fri Mar 28 14:50:37 2025 +0800 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0aedf69 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.idea/ +.vscode/ +__pycache__/ +venv/ + +*.jpg +*.jpeg +*.png \ No newline at end of file diff --git a/chrome/130-0008/130.0.6723.92.manifest b/chrome/130-0008/130.0.6723.92.manifest new file mode 100644 index 0000000..c1fdbb9 --- /dev/null +++ b/chrome/130-0008/130.0.6723.92.manifest @@ -0,0 +1,8 @@ + + + + diff --git a/chrome/130-0008/Dictionaries/en-US-10-1.bdic b/chrome/130-0008/Dictionaries/en-US-10-1.bdic new file mode 100644 index 0000000..a453358 Binary files /dev/null and b/chrome/130-0008/Dictionaries/en-US-10-1.bdic differ diff --git a/chrome/130-0008/Extensions/external_extensions.json b/chrome/130-0008/Extensions/external_extensions.json new file mode 100644 index 0000000..1ef50f3 --- /dev/null +++ b/chrome/130-0008/Extensions/external_extensions.json @@ -0,0 +1,5 @@ +// This json file will contain a list of extensions that will be included +// in the installer. + +{ +} \ No newline at end of file diff --git a/chrome/130-0008/Locales/af.pak b/chrome/130-0008/Locales/af.pak new file mode 100644 index 0000000..b5e2646 Binary files /dev/null and b/chrome/130-0008/Locales/af.pak differ diff --git a/chrome/130-0008/Locales/am.pak b/chrome/130-0008/Locales/am.pak new file mode 100644 index 0000000..08a3785 Binary files /dev/null and b/chrome/130-0008/Locales/am.pak differ diff --git a/chrome/130-0008/Locales/ar.pak b/chrome/130-0008/Locales/ar.pak new file mode 100644 index 0000000..d4c8972 Binary files /dev/null and b/chrome/130-0008/Locales/ar.pak differ diff --git a/chrome/130-0008/Locales/bg.pak b/chrome/130-0008/Locales/bg.pak new file mode 100644 index 0000000..d013979 Binary files /dev/null and b/chrome/130-0008/Locales/bg.pak differ diff --git a/chrome/130-0008/Locales/bn.pak b/chrome/130-0008/Locales/bn.pak new file mode 100644 index 0000000..72265b5 Binary files /dev/null and b/chrome/130-0008/Locales/bn.pak differ diff --git a/chrome/130-0008/Locales/ca.pak b/chrome/130-0008/Locales/ca.pak new file mode 100644 index 0000000..70069ae Binary files /dev/null and b/chrome/130-0008/Locales/ca.pak differ diff --git a/chrome/130-0008/Locales/cs.pak b/chrome/130-0008/Locales/cs.pak new file mode 100644 index 0000000..df58bd0 Binary files /dev/null and b/chrome/130-0008/Locales/cs.pak differ diff --git a/chrome/130-0008/Locales/da.pak b/chrome/130-0008/Locales/da.pak new file mode 100644 index 0000000..b76b1c0 Binary files /dev/null and b/chrome/130-0008/Locales/da.pak differ diff --git a/chrome/130-0008/Locales/de.pak b/chrome/130-0008/Locales/de.pak new file mode 100644 index 0000000..26674b4 Binary files /dev/null and b/chrome/130-0008/Locales/de.pak differ diff --git a/chrome/130-0008/Locales/el.pak b/chrome/130-0008/Locales/el.pak new file mode 100644 index 0000000..3017de0 Binary files /dev/null and b/chrome/130-0008/Locales/el.pak differ diff --git a/chrome/130-0008/Locales/en-GB.pak b/chrome/130-0008/Locales/en-GB.pak new file mode 100644 index 0000000..07902b2 Binary files /dev/null and b/chrome/130-0008/Locales/en-GB.pak differ diff --git a/chrome/130-0008/Locales/en-US.pak b/chrome/130-0008/Locales/en-US.pak new file mode 100644 index 0000000..62d1af8 Binary files /dev/null and b/chrome/130-0008/Locales/en-US.pak differ diff --git a/chrome/130-0008/Locales/es-419.pak b/chrome/130-0008/Locales/es-419.pak new file mode 100644 index 0000000..abc9e22 Binary files /dev/null and b/chrome/130-0008/Locales/es-419.pak differ diff --git a/chrome/130-0008/Locales/es.pak b/chrome/130-0008/Locales/es.pak new file mode 100644 index 0000000..3735fc7 Binary files /dev/null and b/chrome/130-0008/Locales/es.pak differ diff --git a/chrome/130-0008/Locales/et.pak b/chrome/130-0008/Locales/et.pak new file mode 100644 index 0000000..4d44c38 Binary files /dev/null and b/chrome/130-0008/Locales/et.pak differ diff --git a/chrome/130-0008/Locales/fa.pak b/chrome/130-0008/Locales/fa.pak new file mode 100644 index 0000000..c333973 Binary files /dev/null and b/chrome/130-0008/Locales/fa.pak differ diff --git a/chrome/130-0008/Locales/fi.pak b/chrome/130-0008/Locales/fi.pak new file mode 100644 index 0000000..a12905d Binary files /dev/null and b/chrome/130-0008/Locales/fi.pak differ diff --git a/chrome/130-0008/Locales/fil.pak b/chrome/130-0008/Locales/fil.pak new file mode 100644 index 0000000..263ae1d Binary files /dev/null and b/chrome/130-0008/Locales/fil.pak differ diff --git a/chrome/130-0008/Locales/fr.pak b/chrome/130-0008/Locales/fr.pak new file mode 100644 index 0000000..50269c7 Binary files /dev/null and b/chrome/130-0008/Locales/fr.pak differ diff --git a/chrome/130-0008/Locales/gu.pak b/chrome/130-0008/Locales/gu.pak new file mode 100644 index 0000000..4033541 Binary files /dev/null and b/chrome/130-0008/Locales/gu.pak differ diff --git a/chrome/130-0008/Locales/he.pak b/chrome/130-0008/Locales/he.pak new file mode 100644 index 0000000..52a1933 Binary files /dev/null and b/chrome/130-0008/Locales/he.pak differ diff --git a/chrome/130-0008/Locales/hi.pak b/chrome/130-0008/Locales/hi.pak new file mode 100644 index 0000000..f821e5b Binary files /dev/null and b/chrome/130-0008/Locales/hi.pak differ diff --git a/chrome/130-0008/Locales/hr.pak b/chrome/130-0008/Locales/hr.pak new file mode 100644 index 0000000..227c816 Binary files /dev/null and b/chrome/130-0008/Locales/hr.pak differ diff --git a/chrome/130-0008/Locales/hu.pak b/chrome/130-0008/Locales/hu.pak new file mode 100644 index 0000000..57c24bf Binary files /dev/null and b/chrome/130-0008/Locales/hu.pak differ diff --git a/chrome/130-0008/Locales/id.pak b/chrome/130-0008/Locales/id.pak new file mode 100644 index 0000000..d3633a6 Binary files /dev/null and b/chrome/130-0008/Locales/id.pak differ diff --git a/chrome/130-0008/Locales/it.pak b/chrome/130-0008/Locales/it.pak new file mode 100644 index 0000000..95179db Binary files /dev/null and b/chrome/130-0008/Locales/it.pak differ diff --git a/chrome/130-0008/Locales/ja.pak b/chrome/130-0008/Locales/ja.pak new file mode 100644 index 0000000..d34e206 Binary files /dev/null and b/chrome/130-0008/Locales/ja.pak differ diff --git a/chrome/130-0008/Locales/kn.pak b/chrome/130-0008/Locales/kn.pak new file mode 100644 index 0000000..430336d Binary files /dev/null and b/chrome/130-0008/Locales/kn.pak differ diff --git a/chrome/130-0008/Locales/ko.pak b/chrome/130-0008/Locales/ko.pak new file mode 100644 index 0000000..2cc95f3 Binary files /dev/null and b/chrome/130-0008/Locales/ko.pak differ diff --git a/chrome/130-0008/Locales/lt.pak b/chrome/130-0008/Locales/lt.pak new file mode 100644 index 0000000..9472c29 Binary files /dev/null and b/chrome/130-0008/Locales/lt.pak differ diff --git a/chrome/130-0008/Locales/lv.pak b/chrome/130-0008/Locales/lv.pak new file mode 100644 index 0000000..f92d764 Binary files /dev/null and b/chrome/130-0008/Locales/lv.pak differ diff --git a/chrome/130-0008/Locales/ml.pak b/chrome/130-0008/Locales/ml.pak new file mode 100644 index 0000000..dd37e2f Binary files /dev/null and b/chrome/130-0008/Locales/ml.pak differ diff --git a/chrome/130-0008/Locales/mr.pak b/chrome/130-0008/Locales/mr.pak new file mode 100644 index 0000000..53fb418 Binary files /dev/null and b/chrome/130-0008/Locales/mr.pak differ diff --git a/chrome/130-0008/Locales/ms.pak b/chrome/130-0008/Locales/ms.pak new file mode 100644 index 0000000..1386c4a Binary files /dev/null and b/chrome/130-0008/Locales/ms.pak differ diff --git a/chrome/130-0008/Locales/nb.pak b/chrome/130-0008/Locales/nb.pak new file mode 100644 index 0000000..9fc66c6 Binary files /dev/null and b/chrome/130-0008/Locales/nb.pak differ diff --git a/chrome/130-0008/Locales/nl.pak b/chrome/130-0008/Locales/nl.pak new file mode 100644 index 0000000..98095b6 Binary files /dev/null and b/chrome/130-0008/Locales/nl.pak differ diff --git a/chrome/130-0008/Locales/pl.pak b/chrome/130-0008/Locales/pl.pak new file mode 100644 index 0000000..77460e5 Binary files /dev/null and b/chrome/130-0008/Locales/pl.pak differ diff --git a/chrome/130-0008/Locales/pt-BR.pak b/chrome/130-0008/Locales/pt-BR.pak new file mode 100644 index 0000000..8f1964f Binary files /dev/null and b/chrome/130-0008/Locales/pt-BR.pak differ diff --git a/chrome/130-0008/Locales/pt-PT.pak b/chrome/130-0008/Locales/pt-PT.pak new file mode 100644 index 0000000..eb94af7 Binary files /dev/null and b/chrome/130-0008/Locales/pt-PT.pak differ diff --git a/chrome/130-0008/Locales/ro.pak b/chrome/130-0008/Locales/ro.pak new file mode 100644 index 0000000..b31201d Binary files /dev/null and b/chrome/130-0008/Locales/ro.pak differ diff --git a/chrome/130-0008/Locales/ru.pak b/chrome/130-0008/Locales/ru.pak new file mode 100644 index 0000000..f24544b Binary files /dev/null and b/chrome/130-0008/Locales/ru.pak differ diff --git a/chrome/130-0008/Locales/sk.pak b/chrome/130-0008/Locales/sk.pak new file mode 100644 index 0000000..6be7bc3 Binary files /dev/null and b/chrome/130-0008/Locales/sk.pak differ diff --git a/chrome/130-0008/Locales/sl.pak b/chrome/130-0008/Locales/sl.pak new file mode 100644 index 0000000..c8f195f Binary files /dev/null and b/chrome/130-0008/Locales/sl.pak differ diff --git a/chrome/130-0008/Locales/sr.pak b/chrome/130-0008/Locales/sr.pak new file mode 100644 index 0000000..54c0cda Binary files /dev/null and b/chrome/130-0008/Locales/sr.pak differ diff --git a/chrome/130-0008/Locales/sv.pak b/chrome/130-0008/Locales/sv.pak new file mode 100644 index 0000000..f7f46d6 Binary files /dev/null and b/chrome/130-0008/Locales/sv.pak differ diff --git a/chrome/130-0008/Locales/sw.pak b/chrome/130-0008/Locales/sw.pak new file mode 100644 index 0000000..d5703ee Binary files /dev/null and b/chrome/130-0008/Locales/sw.pak differ diff --git a/chrome/130-0008/Locales/ta.pak b/chrome/130-0008/Locales/ta.pak new file mode 100644 index 0000000..e52d5bf Binary files /dev/null and b/chrome/130-0008/Locales/ta.pak differ diff --git a/chrome/130-0008/Locales/te.pak b/chrome/130-0008/Locales/te.pak new file mode 100644 index 0000000..a16cb50 Binary files /dev/null and b/chrome/130-0008/Locales/te.pak differ diff --git a/chrome/130-0008/Locales/th.pak b/chrome/130-0008/Locales/th.pak new file mode 100644 index 0000000..167bf4c Binary files /dev/null and b/chrome/130-0008/Locales/th.pak differ diff --git a/chrome/130-0008/Locales/tr.pak b/chrome/130-0008/Locales/tr.pak new file mode 100644 index 0000000..9d39482 Binary files /dev/null and b/chrome/130-0008/Locales/tr.pak differ diff --git a/chrome/130-0008/Locales/uk.pak b/chrome/130-0008/Locales/uk.pak new file mode 100644 index 0000000..a4dc9fb Binary files /dev/null and b/chrome/130-0008/Locales/uk.pak differ diff --git a/chrome/130-0008/Locales/ur.pak b/chrome/130-0008/Locales/ur.pak new file mode 100644 index 0000000..c574374 Binary files /dev/null and b/chrome/130-0008/Locales/ur.pak differ diff --git a/chrome/130-0008/Locales/vi.pak b/chrome/130-0008/Locales/vi.pak new file mode 100644 index 0000000..5d69837 Binary files /dev/null and b/chrome/130-0008/Locales/vi.pak differ diff --git a/chrome/130-0008/Locales/zh-CN.pak b/chrome/130-0008/Locales/zh-CN.pak new file mode 100644 index 0000000..8bbc655 Binary files /dev/null and b/chrome/130-0008/Locales/zh-CN.pak differ diff --git a/chrome/130-0008/Locales/zh-TW.pak b/chrome/130-0008/Locales/zh-TW.pak new file mode 100644 index 0000000..827639f Binary files /dev/null and b/chrome/130-0008/Locales/zh-TW.pak differ diff --git a/chrome/130-0008/MEIPreload/manifest.json b/chrome/130-0008/MEIPreload/manifest.json new file mode 100644 index 0000000..1b4fa8a --- /dev/null +++ b/chrome/130-0008/MEIPreload/manifest.json @@ -0,0 +1,8 @@ +{ + "name": "MEI Preload", + "icons": {}, + "version": "1.0.7.1652906823", + "manifest_version": 2, + "update_url": "https://clients2.google.com/service/update2/crx", + "description": "Contains preloaded data for Media Engagement" +} diff --git a/chrome/130-0008/MEIPreload/preloaded_data.pb b/chrome/130-0008/MEIPreload/preloaded_data.pb new file mode 100644 index 0000000..78f104c Binary files /dev/null and b/chrome/130-0008/MEIPreload/preloaded_data.pb differ diff --git a/chrome/130-0008/PrivacySandboxAttestationsPreloaded/manifest.json b/chrome/130-0008/PrivacySandboxAttestationsPreloaded/manifest.json new file mode 100644 index 0000000..a3eddc6 --- /dev/null +++ b/chrome/130-0008/PrivacySandboxAttestationsPreloaded/manifest.json @@ -0,0 +1,6 @@ +{ + "manifest_version": 2, + "name": "Privacy Sandbox Attestations", + "version": "2024.8.23.0", + "pre_installed": true +} \ No newline at end of file diff --git a/chrome/130-0008/PrivacySandboxAttestationsPreloaded/privacy-sandbox-attestations.dat b/chrome/130-0008/PrivacySandboxAttestationsPreloaded/privacy-sandbox-attestations.dat new file mode 100644 index 0000000..62f6371 --- /dev/null +++ b/chrome/130-0008/PrivacySandboxAttestationsPreloaded/privacy-sandbox-attestations.dat @@ -0,0 +1,258 @@ + +https://2k.comhttps://33across.comhttps://360yield.comhttps://3lift.comhttps://ad-score.com https://ad.gthttps://adentifi.comhttps://adform.nethttps://adingo.jphttps://admatrix.jphttps://admixer.nethttps://adnami.iohttps://adnxs.comhttps://adsafeprotected.comhttps://adsrvr.orghttps://adthrive.comhttps://advividnetwork.comNhttps://aggregation-service-site-dot-clz200258-datateam-italy.ew.r.appspot.comhttps://anonymised.iohttps://appier.nethttps://artistunited.comhttps://avads.nethttps://ayads.iohttps://bidswitch.nethttps://bidtheatre.nethttps://bing.comhttps://blendee.comhttps://bounceexchange.comhttps://btloader.comhttps://bypass.jphttps://casalemedia.comhttps://cdn-net.comhttps://clickonometrics.plhttps://connected-stories.comhttps://crcldu.comhttps://creativecdn.comhttps://criteo.comhttps://ctnsnet.comhttps://dabbs.nethttps://daum.nethttps://display.iohttps://dotdashmeredith.comhttps://dotomi.comhttps://doubleclick.nethttps://dynalyst.jphttps://edkt.iohttps://effinity.frhttps://ezoic.comhttps://fanbyte.comhttps://flashtalking.comhttps://fout.jphttps://funplus.comhttps://fwmrm.nethttps://gama.globohttps://ghtinc.comhttps://gmossp-sp.jphttps://google-analytics.comhttps://gsspat.jphttps://gumgum.comhttps://guoshipartners.comhttps://html-load.comhttps://im-apps.nethttps://impact-ad.jphttps://imrworldwide.comhttps://indexww.comhttps://inmobi.comhttps://innovid.comhttps://jivox.comhttps://kelkoogroup.nethttps://kidoz.nethttps://ladsp.comhttps://lucead.comhttps://mail.ruhttps://media.nethttps://mediaintelligence.dehttps://mediamath.comhttps://mediavine.comhttps://microad.jphttps://naver.comhttps://nhnace.comhttps://onetag-sys.comhttps://openx.nethttps://optable.cohttps://outbrain.com+https://privacy-sandbox-demos-ad-server.dev'https://privacy-sandbox-demos-dsp-a.dev'https://privacy-sandbox-demos-dsp-b.dev%https://privacy-sandbox-demos-dsp.dev'https://privacy-sandbox-demos-ssp-a.dev'https://privacy-sandbox-demos-ssp-b.dev%https://privacy-sandbox-demos-ssp.dev https://privacy-sandbox-test.com0https://privacy-sandcastle-dev-ad-server.web.app-https://privacy-sandcastle-dev-dsp-a1.web.app-https://privacy-sandcastle-dev-dsp-b1.web.app*https://privacy-sandcastle-dev-dsp.web.app,https://privacy-sandcastle-dev-ssp-a.web.app,https://privacy-sandcastle-dev-ssp-b.web.app*https://privacy-sandcastle-dev-ssp.web.apphttps://pub.networkhttps://pubmatic.comhttps://pubtm.comhttps://quantserve.comhttps://relevant-digital.comhttps://sascdn.comhttps://shinystat.comhttps://singular.nethttps://sportradarserving.comhttps://t13.iohttps://teads.tvhttps://theryn.iohttps://tncid.apphttps://toponad.comhttps://tpmark.nethttps://tribalfusion.comhttps://triptease.iohttps://uinterbox.comhttps://uol.com.br https://vg.nohttps://vpadn.comhttps://washingtonpost.comhttps://yahoo.co.jphttps://yahoo.comhttps://yandex.ruhttps://yelp.com +https://connatix.com + +https://open-bid.com + +https://getyourguide.com + +https://snapchat.com + +https://atomex.net + +https://grxchange.gr + +https://boost-web.com + +https://adswizz.com + +https://undertone.com +" +https://appsflyersdk.com + +https://trip.com + +https://gokwik.co +% +https://creative-serving.com + +https://pinterest.com + +https://finn.no + +https://socdm.com +! +https://ebayadservices.com + +https://adroll.com +# +https://youronlinechoices.eu + +https://eloan.co.jp + +https://ad-stir.com + +https://semafor.com + +https://bidtellect.com + +https://metro.co.uk + +https://unrulymedia.com + +https://seedtag.com +! +https://audience360.com.au + +https://torneos.gg + +https://getcapi.co + +https://r2b2.io +6 +/https://ptb-msmt-static-5jyy5ulagq-uc.a.run.app + +https://quora.com + +https://jkforum.net + +https://appconsent.io +% +https://audienceproject.com + +https://storygize.net + +https://primecaster.net + +https://yieldlab.net + +https://logly.co.jp + +https://disqus.com + +https://acxiom.com +% +https://wepowerconnections.com +$ +https://lab-dotmetrics.ninja + +https://2trk.info + +https://ebis.ne.jp + +https://presage.io + +https://aqfer.com +& +https://googleadservices.com + +https://weborama.fr + +https://onet.pl + +https://worldhistory.org + +https://iobeya.com + +https://apex-football.com + +https://nexxen.tech +" +https://rubiconproject.com + +https://aniview.com + +https://usemax.de + +https://facebook.com +( + https://smadexprivacysandbox.com +! +https://dailymotion.com + +https://shinobi.jp + +https://linkedin.com + +https://appsflyer.com +" +https://media6degrees.com + +https://cpx.to + +https://tya-dev.com +' + https://healthproductsforyou.com + +https://admission.net + +https://appscience.inc + +https://s-f.tech + +https://lwadm.com +1 +(https://paa-reporting-advertising.amazon + +https://convertunits.com + +https://bluems.com +" +https://authorizedvault.com + +https://verve.com + +https://beaconmax.com + +https://cazamba.com + +https://globo.com + +https://kargo.com + +https://atirun.com + +https://tailtarget.com + +https://dreammail.jp + +https://samplicio.us + + https://wp.pl +" +https://kompaspublishing.nl +# +https://marutishanbhag.com + +https://postrelease.com + +https://akpytela.cz + +https://paapi.ai + +https://coupang.com +% +https://googlesyndication.com + +https://adscale.de + +https://tangooserver.com + +https://taboola.com + +https://yieldmo.com + +https://gunosy.com + +https://docomo.ne.jp + +https://thesun.co.uk + +https://vidazoo.com + +https://pmdragonfly.com + +https://stackadapt.com +" +https://explorefledge.com +? +6https://protected-audience-api-advertiser.onrender.com +# +https://adsmeasurement.com + +https://deepintent.com + +https://permutive.app + +https://superfine.org + +https://fandom.com +! +https://sharethrough.com +! +https://weborama-tech.ru +" +https://amazon-adsystem.com + +https://pontiac.media + +https://dailymail.co.uk + +https://i-mobile.co.jp + +https://tiktok.com + +https://moshimo.com +7 +/https://shared-storage-demo-publisher-a.web.app + +https://retargetly.com + +https://a-mo.net + +https://demand.supply + +https://sephora.com + +https://momento.dev + +https://mobon.net +" +https://audiencemanager.de + +https://trkkn.com + +https://sitescout.com +" +https://d-edgeconnect.media + \ No newline at end of file diff --git a/chrome/130-0008/chrome.dll b/chrome/130-0008/chrome.dll new file mode 100644 index 0000000..86411b9 Binary files /dev/null and b/chrome/130-0008/chrome.dll differ diff --git a/chrome/130-0008/chrome.exe b/chrome/130-0008/chrome.exe new file mode 100644 index 0000000..066fbbb Binary files /dev/null and b/chrome/130-0008/chrome.exe differ diff --git a/chrome/130-0008/chrome_100_percent.pak b/chrome/130-0008/chrome_100_percent.pak new file mode 100644 index 0000000..78d1d71 Binary files /dev/null and b/chrome/130-0008/chrome_100_percent.pak differ diff --git a/chrome/130-0008/chrome_200_percent.pak b/chrome/130-0008/chrome_200_percent.pak new file mode 100644 index 0000000..5330b82 Binary files /dev/null and b/chrome/130-0008/chrome_200_percent.pak differ diff --git a/chrome/130-0008/chrome_elf.dll b/chrome/130-0008/chrome_elf.dll new file mode 100644 index 0000000..e006047 Binary files /dev/null and b/chrome/130-0008/chrome_elf.dll differ diff --git a/chrome/130-0008/chrome_proxy.exe b/chrome/130-0008/chrome_proxy.exe new file mode 100644 index 0000000..2d42b91 Binary files /dev/null and b/chrome/130-0008/chrome_proxy.exe differ diff --git a/chrome/130-0008/chrome_pwa_launcher.exe b/chrome/130-0008/chrome_pwa_launcher.exe new file mode 100644 index 0000000..2af3f87 Binary files /dev/null and b/chrome/130-0008/chrome_pwa_launcher.exe differ diff --git a/chrome/130-0008/chrome_wer.dll b/chrome/130-0008/chrome_wer.dll new file mode 100644 index 0000000..7797294 Binary files /dev/null and b/chrome/130-0008/chrome_wer.dll differ diff --git a/chrome/130-0008/chromedriver.exe b/chrome/130-0008/chromedriver.exe new file mode 100644 index 0000000..af96e02 Binary files /dev/null and b/chrome/130-0008/chromedriver.exe differ diff --git a/chrome/130-0008/d3dcompiler_47.dll b/chrome/130-0008/d3dcompiler_47.dll new file mode 100644 index 0000000..62b4185 Binary files /dev/null and b/chrome/130-0008/d3dcompiler_47.dll differ diff --git a/chrome/130-0008/dxcompiler.dll b/chrome/130-0008/dxcompiler.dll new file mode 100644 index 0000000..2a29129 Binary files /dev/null and b/chrome/130-0008/dxcompiler.dll differ diff --git a/chrome/130-0008/dxil.dll b/chrome/130-0008/dxil.dll new file mode 100644 index 0000000..3c30b62 Binary files /dev/null and b/chrome/130-0008/dxil.dll differ diff --git a/chrome/130-0008/eventlog_provider.dll b/chrome/130-0008/eventlog_provider.dll new file mode 100644 index 0000000..c724fff Binary files /dev/null and b/chrome/130-0008/eventlog_provider.dll differ diff --git a/chrome/130-0008/icudtl.dat b/chrome/130-0008/icudtl.dat new file mode 100644 index 0000000..331d2f3 Binary files /dev/null and b/chrome/130-0008/icudtl.dat differ diff --git a/chrome/130-0008/libEGL.dll b/chrome/130-0008/libEGL.dll new file mode 100644 index 0000000..1822715 Binary files /dev/null and b/chrome/130-0008/libEGL.dll differ diff --git a/chrome/130-0008/libGLESv2.dll b/chrome/130-0008/libGLESv2.dll new file mode 100644 index 0000000..4e9a4c1 Binary files /dev/null and b/chrome/130-0008/libGLESv2.dll differ diff --git a/chrome/130-0008/notification_helper.exe b/chrome/130-0008/notification_helper.exe new file mode 100644 index 0000000..4359659 Binary files /dev/null and b/chrome/130-0008/notification_helper.exe differ diff --git a/chrome/130-0008/resources.pak b/chrome/130-0008/resources.pak new file mode 100644 index 0000000..b423e4e Binary files /dev/null and b/chrome/130-0008/resources.pak differ diff --git a/chrome/130-0008/sig.txt b/chrome/130-0008/sig.txt new file mode 100644 index 0000000..4e9ded2 --- /dev/null +++ b/chrome/130-0008/sig.txt @@ -0,0 +1 @@ +acf29cbb6f7846fead276a05ae05a1c8 \ No newline at end of file diff --git a/chrome/130-0008/v8_context_snapshot.bin b/chrome/130-0008/v8_context_snapshot.bin new file mode 100644 index 0000000..9b01b52 Binary files /dev/null and b/chrome/130-0008/v8_context_snapshot.bin differ diff --git a/chrome/130-0008/vk_swiftshader.dll b/chrome/130-0008/vk_swiftshader.dll new file mode 100644 index 0000000..0187a77 Binary files /dev/null and b/chrome/130-0008/vk_swiftshader.dll differ diff --git a/chrome/130-0008/vk_swiftshader_icd.json b/chrome/130-0008/vk_swiftshader_icd.json new file mode 100644 index 0000000..525fbc5 --- /dev/null +++ b/chrome/130-0008/vk_swiftshader_icd.json @@ -0,0 +1 @@ +{"file_format_version": "1.0.0", "ICD": {"library_path": ".\\vk_swiftshader.dll", "api_version": "1.0.5"}} \ No newline at end of file diff --git a/chrome/130-0008/vulkan-1.dll b/chrome/130-0008/vulkan-1.dll new file mode 100644 index 0000000..c073222 Binary files /dev/null and b/chrome/130-0008/vulkan-1.dll differ diff --git a/const.py b/const.py new file mode 100644 index 0000000..a2e7566 --- /dev/null +++ b/const.py @@ -0,0 +1,27 @@ +import os +BASE_PATH = os.path.dirname(__file__) +SAFE = '!' +MIMETYPE = { + 'jpg': 'image/jpeg', + 'jpeg': 'image/jpeg', + 'png': 'image/png', + # 'gif': 'image/gif', + 'mp4': 'video/mp4', +} + +PIC_TYPE = ('image/jpeg', 'image/png') + + +ELEMENT = { +} + +# ucloud-us3 +PUBLIC_KEY = '4ZF9nrEbA93FDL29606cKFGYEb59Zu9ip' # 账户公钥 +PRIVATE_KEY = 'FD9DgHZVe4Q9GevRb8QcwBD6S8Iesv48ZBsWImwEGPZr' # 账户私钥 +BUCKET = 'fanzhixitong' # 空间名称 +UPLOAD_SUFFIX = '.jpn-tky.ufileos.com' +DOWNLOAD_SUFFIX = '.jpn-tky.ufileos.com' + +# DOVE PROXY +DOVE_USER = 'fetdog' +DOVE_PWD = 'aAa123456aAa' diff --git a/exceptions.py b/exceptions.py new file mode 100644 index 0000000..672a0b8 --- /dev/null +++ b/exceptions.py @@ -0,0 +1,6 @@ +class AuthException(Exception): + pass + + +class OperationFailed(Exception): + pass diff --git a/files/.keep b/files/.keep new file mode 100644 index 0000000..e69de29 diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 diff --git a/logger.py b/logger.py new file mode 100644 index 0000000..e87bcef --- /dev/null +++ b/logger.py @@ -0,0 +1,29 @@ +import os +import logging + +log_path = os.path.join(os.path.dirname(__file__), 'log') +simple_fmt = logging.Formatter('[%(asctime)s-%(levelname)s] %(message)s') + + +def logger_settings(name, file_log=True, level=0): + logger = logging.getLogger(name) + if file_log: + file_log = logging.FileHandler(os.path.join(log_path, f'{name}.log'), encoding='utf-8') + file_log.setFormatter(simple_fmt) + file_log.setLevel(level) + logger.addHandler(file_log) + logger.setLevel(level) + return logger + + +def record_full_log(logger, err): + trace = err.__traceback__ + while trace: + file = trace.tb_frame.f_code.co_filename + line = trace.tb_lineno + trace = trace.tb_next + logger.error(f' file:{file}, line:{line}') + logger.error(f' error: {str(err)}') + + +error_logger = logger_settings('error') diff --git a/main.py b/main.py new file mode 100644 index 0000000..ccc7f54 --- /dev/null +++ b/main.py @@ -0,0 +1,67 @@ +from concurrent.futures.thread import ThreadPoolExecutor +from spider.task import * +from logger import error_logger, record_full_log + +TASK_TYPE = { + 0: post, +} + +HOST = "http://118.193.40.152:8091" + + +def get_task(platform): + # if lock._block.locked(): + # return + response = requests.get(f'{HOST}/services/task', json={'platform': platform}) + result = response.json() + if result['code'] == 0: + return result + + +def task_callback(task_type, queue_id, data, status=1, err_msg=''): + response = requests.post( + f'{HOST}/services/task/callback', + json={ + 'task_type': task_type, + 'queue_id': queue_id, + 'status': status, + 'data': data, + 'err_msg': err_msg, + } + ) + result = response.json() + if result['code'] != 0: + raise RuntimeError(f"任务回调失败:{result['msg']}") + + +def execute_task(queue_id, task_type, **kwargs): + try: + result = TASK_TYPE.get(task_type)(**kwargs) + task_callback(task_type, queue_id, data=result) + except AuthException as e: + record_full_log(error_logger, e) + task_callback(task_type, queue_id, data={}, status=4, err_msg=str(e)) + except Exception as e: + record_full_log(error_logger, e) + task_callback(task_type, queue_id, data={}, status=0, err_msg=str(e)) + + +def main(): + with ThreadPoolExecutor(max_workers=1) as t: + while True: + try: + task = get_task(0) + if task is None: + time.sleep(10) + continue + + task['data']['queue_id'] = task['queue_id'] + task['data']['task_type'] = task['task_type'] + t.submit(execute_task, **task['data']) + except Exception as e: + error_logger.error(f'Main Error: {e}') + time.sleep(10) + + +if __name__ == '__main__': + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..167ad2e Binary files /dev/null and b/requirements.txt differ diff --git a/spider/__init__.py b/spider/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/spider/task.py b/spider/task.py new file mode 100644 index 0000000..ed4603c --- /dev/null +++ b/spider/task.py @@ -0,0 +1,1033 @@ +import io +import time +import uuid +import hashlib +import random +import requests +import json +import re +import threading +import sys +import os +from const import MIMETYPE, BUCKET, PIC_TYPE, BASE_PATH +from uclouds3 import client +from urllib.parse import quote +from exceptions import AuthException, OperationFailed +from playwright.sync_api import sync_playwright + + +def get_dtsg_token(cookies): + headers = { + 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', + 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'cache-control': 'max-age=0', + 'dpr': '2', + 'priority': 'u=0, i', + 'referer': 'https://www.facebook.com/?stype=lo&flo=1&deoia=1&jlou=AfchVgl8eRm2v_gCaPU1qqUi53hsIzJeyLP44jmPwCBLa7tUz9PYG-i0xhSc1SsyoN0UM8OfM2n4oImZKLL1OlDYm_2UMbJ2mRP3XWSR1jaRHg&smuh=27937&lh=Ac-9GdZW-IjAq1cdtk8', + 'sec-ch-prefers-color-scheme': 'light', + 'sec-ch-ua': '"Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"', + 'sec-ch-ua-full-version-list': '"Chromium";v="134.0.6998.89", "Not:A-Brand";v="24.0.0.0", "Google Chrome";v="134.0.6998.89"', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-model': '""', + 'sec-ch-ua-platform': '"macOS"', + 'sec-ch-ua-platform-version': '"15.3.2"', + 'sec-fetch-dest': 'document', + 'sec-fetch-mode': 'navigate', + 'sec-fetch-site': 'same-origin', + 'sec-fetch-user': '?1', + 'upgrade-insecure-requests': '1', + 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36', + 'viewport-width': '743', + } + + params = { + 'sk': 'welcome', + 'lsrc': 'lb', + } + response = requests.get('https://www.facebook.com/', params=params, cookies=cookies, headers=headers) + pattern = '"dtsg":{"token":"(.*?)"' + obj = re.search(pattern, response.text) + return str(obj.group(1)) + + +def _gen_waterfall_id(user_id): + a = 2147483647 + result = random.random() * a + s = f'{user_id}{int(time.time())}{result}' + md5 = hashlib.md5(s.encode('utf-8')) + return md5.hexdigest() + + +def _get_boundary(): + s = '1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM' + return ''.join(random.choices(s, k=16)) + + +def _upload_photo(cookies, filename, file, token): + user_id = cookies['c_user'] + boundary = _get_boundary() + headers = { + 'accept': '*/*', + 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'content-type': f'multipart/form-data; boundary=----WebKitFormBoundary{boundary}', + 'origin': 'https://www.facebook.com', + 'priority': 'u=1, i', + 'referer': 'https://www.facebook.com/', + 'sec-ch-ua': '"Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-platform': '"macOS"', + 'sec-fetch-dest': 'empty', + 'sec-fetch-mode': 'cors', + 'sec-fetch-site': 'same-site', + 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36', + } + + params = { + 'av': user_id, + '__aaid': '0', + '__user': user_id, + '__a': '1', + '__req': '24', + '__hs': '20160.HYP:comet_pkg.2.1...1', + 'dpr': '2', + '__ccg': 'EXCELLENT', + '__rev': '1020837445', + '__s': 'pywjy0:q8hbxy:j4h991', + '__hsi': '7481088902259545192', + '__dyn': '7xeXzWK1ixt0mUyEqxemh0noeEb8nwgUao4u5QdwSwAyUco5S3O2Saw8i2S1DwUx60GE3Qwb-q7oc81EEbbwto88422y11wBz83WwgEcEhwGxu782lwv89kbxS1Fwc61awkovwRwlE-U2exi4UaEW2au1jwUBwJK14xm3y11xfxmu3W3y261eBx_wHwdG7EbUG2-azqwaW223908O3216xi4UK2K2WEjxK2B08-269wkopg6C13xe3a3Gfw-KufxamEbbxG1fBG2-2K0E846fwk8eo', + '__csr': 'g5rddNQ9n4MIyONklsARH4iiHazhb4ijqQKDWZvW8RKrndrShiSiA9h9adctAAOf99HSBFfVDFlJ9Frkwy8AWQleqVV95QXHh8GATKmh4QVEGjh49x7zdbBi-FEyiQnJXpp6KBhXyaVkhZoLVOaijxmmfxxaibyKmmtabHXyqAAx2GhonK9AV9KdAzbxai4Z7gHAizVoOEgy98KHDBAKq2TJ2EW8DG8yaFaV8C2DDxbiyrBWAzi4GcKuGG4UK8CCizRWCyeRx6iidyVA2am9CGdzqDAKuU8rxuu4WK7UXwAK9yqzo9axefxy9opwGxSfxeE8pqzHy8tKuazpFoO2qUG5UKi3C1ex-uEowce2Om4Ua8dUy0j-0Fo5K3K0C61hxfw9S2CE4MM2pg6q2uFGBiHg-7EcUG2W18w4BwwwbC4V8aEG3-4FA0EoaEO0GayGBwqF8rz88Ai0CEvwh85m48B0lmeAwgUfoaUpxmm3yawiWxei9wOU2uHwPxCehlwcC02jC02NK04fqRwj_wfHw0Cew8txugw02Ocw6Ry82Tw4Vwmotg3awrE7G2m08fwk86204M81KU0uWP07sCw5kg0Em08lg3Hwww8K0ka086g65w37U1poy1owjU1g8a84G4Q0lG08Py8Glw13i4U0v6Dw2Jo565m4r8U1uioK2ulZ1RagOgGu0lWrpE31yU-3q0Z81m81p8Iw0tywjpo6q0ssw', + '__hsdp': '', + '__hblp': '', + '__comet_req': '15', + 'fb_dtsg': token, + 'jazoest': '25581', + 'lsd': 'EuheViRhRnOVOfgS9HBpbx', + '__spin_r': '1020837445', + '__spin_b': 'trunk', + '__spin_t': '1741826744', + } + content_type = MIMETYPE.get(filename.split('.')[-1]) + data = { + 'source': '8', + 'profile_id': user_id, + 'waterfallxapp': 'comet', + 'upload_id': 'jsc_c_5', + } + + form_data = b'' + for k, v in data.items(): + form_data += b'------WebKitFormBoundary%s\r\nContent-Disposition: form-data; name="%s"\r\n\r\n%s\r\n' % ( + boundary.encode('utf-8'), k.encode('utf-8'), v.encode('utf-8') + ) + form_data += b'------WebKitFormBoundary%s\r\nContent-Disposition: form-data; name="file"; filename="%s"\r\n' \ + b'Content-Type: %s\r\n\r\n%s\r\n------WebKitFormBoundary%s--\r\n' % \ + (boundary.encode('utf-8'), filename.encode('utf-8'), content_type.encode('utf-8'), + file.getvalue(), boundary.encode('utf-8')) + + response = requests.post( + 'https://upload.facebook.com/ajax/react_composer/attachments/photo/upload', + params=params, + cookies=cookies, + headers=headers, + data=form_data, + ) + result = response.text[9:] + photo_id = json.loads(result)['payload']['photoID'] + return photo_id + + +def _upload_video(cookies, filename, file, token): + user_id = cookies['c_user'] + content_type = MIMETYPE.get(filename.split('.')[-1]) + content = file.getvalue() + file_size = str(len(content)) + uri = f'1741828726893-{filename}-{content_type}-{file_size}-' \ + f'498AEJ73tToOXuUki2xK88hus3f+nSxTuf4/921pFh4=' + uri = f"{hashlib.md5(uri.encode('utf-8'))}-0-{file_size}" + start_headers = { + 'accept': '*/*', + 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'content-type': 'application/x-www-form-urlencoded', + 'origin': 'https://www.facebook.com', + 'priority': 'u=1, i', + 'referer': 'https://www.facebook.com', + 'sec-ch-prefers-color-scheme': 'light', + 'sec-ch-ua': '"Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"', + 'sec-ch-ua-full-version-list': '"Chromium";v="134.0.6998.46", "Not:A-Brand";v="24.0.0.0", "Google Chrome";v="134.0.6998.46"', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-model': '""', + 'sec-ch-ua-platform': '"macOS"', + 'sec-ch-ua-platform-version': '"15.3.2"', + 'sec-fetch-dest': 'empty', + 'sec-fetch-mode': 'cors', + 'sec-fetch-site': 'same-origin', + 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36', + 'x-asbd-id': file_size, + 'x-fb-lsd': 'EuheViRhRnOVOfgS9HBpbx', + 'x_fb_video_waterfall_id': '1162dcb62930e0a2f88aec53e2359276', + } + + params = { + '__a': '1', + } + file_extension = content_type.split('/')[-1] + data = f'waterfall_id=1162dcb62930e0a2f88aec53e2359276&target_id={user_id}&source=composer&composer_entry_point_ref' \ + f'=timeline&supports_chunking=true&supports_file_api=true&file_size={file_size}&' \ + f'file_extension={file_extension}&partition_start_offset=0&partition_end_offset={file_size}&' \ + f'composer_dialog_version=V2&video_publisher_action_source&__aaid=0&__user={user_id}&__a=1&__req=51' \ + f'&__hs=20160.HYP%3Acomet_pkg.2.1...1&dpr=2&__ccg=EXCELLENT&__rev=1020837445&__s=r0kci7%3Aq8hbxy%3Aj4h991&' \ + f'__hsi=7481088902259545192&__dyn=7xeXzWK1ixt0mUyEqxemh0noeEb8nwgUao4u5QdwSwAyU8EW1twYwJyE24wJwkEkwUx60GE5O0BU2_CxS320qafxOU7m2210wEwgo9oO0-E4a3a4oaEnxO0Bo7O2l2Utwqob82kwiE567Udo5qfK0zEkxe2GewyDwkUe9obrwh8lwUwgojUlDw-wUwxwjFovUaU3qxW2-awLyESE2KwwwOg2cwMwhEkxebwHwKG4UrwFg2fwxyo566k1FwgUjwOwWzUfHDzUiBG2OUqwjVqwLwHwa211zU523C&__csr=g5r6Yt2lNcbjiNklsARR4iiHazhb4ih2R8DWtvW8RKrndrOdiShk9jhcYNSijbkACIGmA_JnTnQCBJi28yjHhkVHDAAkzKJ4yGjuVp4jqCyFdbh98hUPiVkLGqFpapuTJBAqWl7KiWVkhZpFfD8F9e5po-bz4Fay8HBBDiyW-VGGii4aF5x6mUCjACUCV8Na4F94dQterAiAyFoOEgy98KHDBAKq2TJ2ECi8DG8yaFaV8C2DDxbiBKVuF8MFazbDGGxeby9FAEZuFEzJogh98SbCg8FoCqESaGFVbDK26UkGu4WK7UXwAK9yqzo9axefxy9opwGxSfxeE8pqzHy8tKuazpFoO2qUG5VF98dGwjEvDG6833wIBxe2y3u8w4_wam1rwXw9xwkojU2twFG1cc0Ck1CwDGqFkGQfxW3eawKwi819o882Vxei2G9gfUiCg2xwGzawanoCFo6Gi6UO294w9G7U4i1lx29g5lzF84e3S2K6olBwUyE4KEjAyocK0DGUcUpzAlo39w0AVw0Irw13SJo4_U3WU0A3w1QK0xS5V200b8O0rm8wt84a0jC1pxR0cG1KwuE9o0w-1gwo80j0w6Xw1XHc0tOq0lh02xo0xl0eK220yU4i0_o0wp0om0vC0im0mm8wm84-0k22y1axd05qw2cUyaBo0gQxe0s204wEyaw5KDw4aw6GwkolohIzwf20y2oK2ulZ1RagOgGu0lWrpE31yU-3q0JEfo1m81p8Iw0tywjpo6q0ssw&__hsdp=&__hblp=&__comet_req=15&fb_dtsg={quote(token)}&jazoest=25581&lsd=EuheViRhRnOVOfgS9HBpbx&__spin_r=1020837445&__spin_b=trunk&__spin_t=1741826744' + + response = requests.post( + 'https://www.facebook.com/ajax/video/upload/requests/start/', + params=params, + cookies=cookies, + headers=start_headers, + data=data, + ) + result = response.text[9:] + + video_id = json.loads(result)['payload']['video_id'] + headers = { + 'accept': '*/*', + 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'composer_session_id': '1162dcb62930e0a2f88aec53e2359276', + 'end_offset': file_size, + 'id': 'undefined', + 'offset': '0', + 'origin': 'https://www.facebook.com', + 'priority': 'u=1, i', + 'product_media_id': video_id, + 'referer': 'https://www.facebook.com/', + 'sec-ch-ua': '"Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-platform': '"macOS"', + 'sec-fetch-dest': 'empty', + 'sec-fetch-mode': 'cors', + 'sec-fetch-site': 'same-site', + 'start_offset': '0', + 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36', + 'x-entity-length': file_size, + 'x-entity-name': filename, + 'x-entity-type': content_type, + 'x-total-asset-size': file_size, + 'content-type': 'application/x-www-form-urlencoded', + } + + params = { + '__aaid': '0', + '__user': user_id, + '__a': '1', + '__req': '1a', + '__hs': '20160.HYP:comet_pkg.2.1...1', + 'dpr': '2', + '__ccg': 'EXCELLENT', + '__rev': '1020850159', + '__s': 'nc8uuq:q8hbxy:f9euk7', + '__hsi': '7481168370954579081', + '__dyn': '7xeXzWK1ixt0mUyEqxemh0noeEb8nwgUao4u5QdwSwAyUco5S3O2Saw8i2S1DwUx60GE3Qwb-q7oc81EEbbwto88422y11wBz83WwgEcEhwGxu782lwv89kbxS1Fwc61awkovwRwlE-U2exi4UaEW2au1jwUBwJK14xm3y11xfxmu3W3y261eBx_wHwdG7EbUG2-azqwaW223908O3216xi4UK2K2WEjxK2B08-269wkopg6C13xe3a3Gfw-KufxamEbbxG1fBG2-2K0E846fwk8eo', + '__csr': 'gf5M84IBlR5Et22d5N7aT69shdb8BN-zbq49b8naVaQWhcJrb8Bj-O_RjipZSD8iZcXiHTyXmJqli6DlbJ4AgSRAQAWhrJ9erWgHKt4V8KFqCmRLyRQ8jChWXhkVkqvWKUTRBVamVDCDBV9V4UKumrKpBByWK5KeHDx2iuAuKVEZGnGF44VWz8xe4VFBJ4zUy5pUhy98Cpu8xiaVUycyK49oS9WUOfyFo-VvQUOppVQcgyHzKFEjAwFqGE-qquimeGiWxOrGQ9ADz6ql3Uycz9A9xqEmyJ1y6F-E-m6oSi7-ahk2O5U-5Gx2dgoDxy68pxyu6oWbJyU-9yUS2OFF9-icwww-wVKi3u48sK2iq9wTomwhUO0QEGpwea1-Dg-4Cm4o4yHUbP0v40iN2bUhh8721JwbO3m0tKEc82WCyZ7Wz86i1hwxx13Wwu8eo2xwa3wiS0RU4m0mq44u8gKq6A4EO6Q2J7Fd0a68wiA1iwm8BwDw7BxTw9CBy80mLg0dDU0aCo022-w0U-waq0d1z8b8vw6Me1jw5Uo3Yg1Vod86G3q17w2yoeo17U2dwoUco1docoao2dxm06kU4t02fyxmp02480PO0-o4W09sw3r80DCpm0gh09q0gm19z-588o0qVg09dU24w2Moao4yQ1Tyy01p8w0n0mfwCgkx91jw5HK0TUS1OO2o7UhbK2p0FVVCbCg', + '__hsdp': '', + '__hblp': '', + '__comet_req': '15', + 'fb_dtsg': token, + 'jazoest': '25320', + 'lsd': 'kr_xMDgwgZMvLcmrnMrL6A', + '__spin_r': '1020850159', + '__spin_b': 'trunk', + '__spin_t': '1741845247', + } + + response = requests.post( + f'https://rupload-sin6-3.up.facebook.com/fb_video/{uri}', + params=params, + cookies=cookies, + headers=headers, + data=content, + ) + + video_file_chunk = response.json()['h'] + params = { + '__a': '1', + } + + data = { + 'waterfall_id': '1162dcb62930e0a2f88aec53e2359276', + 'target_id': user_id, + 'video_id': video_id, + 'source': 'composer', + 'composer_entry_point_ref': 'timeline', + 'supports_chunking': 'true', + 'supports_upload_service': 'true', + 'partition_start_offset': '0', + 'partition_end_offset': file_size, + 'start_offset': '0', + 'end_offset': file_size, + 'upload_speed': '0', + 'fbuploader_video_file_chunk': video_file_chunk, + 'composer_dialog_version': 'V2', + '__aaid': '0', + '__user': user_id, + '__a': '1', + '__req': '2w', + '__hs': '20160.HYP:comet_pkg.2.1...1', + 'dpr': '2', + '__ccg': 'EXCELLENT', + '__rev': '1020855273', + '__s': 'wgfbjc:q8hbxy:0fgg9t', + '__hsi': '7481172705613662617', + '__dyn': '7xeXzWK1ixt0mUyEqxemh0noeEb8nwgUao4u5QdwSwAyUco5S3O2Saw8i2S1DwUx60GE3Qwb-q7oc81EEbbwto88422y11wBz83WwgEcEhwGxu782lwv89kbxS1Fwc61awkovwRwlE-U2exi4UaEW2au1jwUBwJK14xm3y11xfxmu3W3y261eBx_wHwdG7EbUG2-azqwaW223908O3216xi4UK2K2WEjxK2B08-269wkopg6C13xe3a3Gfw-KufxamEbbxG1fBG2-2K0E846fwk8eo', + '__csr': 'g5fd4ONcuznkn5hsyqfONYhRYIB9R7jPTbnFuILa_SiT8HqZ99GAoyaOqnmGiEzGTkxQGKlfaBlaihkhbuh8HKaGAKHh5VfUOvkEyCV5KdQByUx9aSVAVWybhJCVpBK_UKjQm8rlenBFAgKAnCGHxmWBhUyXG8KiqRQqXo-VESWJ4BhEGQ6WiXylXLjDUGqFWyFEyQcgWJeumucK8BK8hEKuEKWgqDjVokjhpp9u8gkyWgiGbxmQdKmBxaq9z9p8GGADAUyUKi9DBBV9fzKAQubAyXy8S49pUgybgKezVEVedCDV898nCAgC2i4UkwCwxKVpFUrhpryogyElxW4UCi6lz88poB5x29DVo8EnK7EiK2OewkUvxebAwvFoy5E425-0Io57wRx-12xgF84m2u14w44ixm3C44aAxibgK3Sq18w9ady9k2q16wio4rx93URG6qwabwgQ2u5oWi37w4kxe0q6ay8xDU9UaybwbK8G0UUgAgaE2Gw40xO2OEggi-483rwp87S1x-7oF04dw6rhE1vU2Kh8C06XU1h83qG023e02Gi00wE80eiU2Lw3fQ1aw6_812wCw56glDU3QDw7tgy0DE7-0a8wj83hw4IwNw4oxO362C0zolw1Be17g0zykFA08Cw13q0J40uq0dXw2w30fOu0BU3Xwj9k3Gdw1HB00AUwrU0Ji2G3i5Q1_Ew0mcBo0m-bwsIw1r8aE7O18wrqZo22NfcE9A2NAy4', + '__hsdp': '', + '__hblp': '', + '__comet_req': '15', + 'fb_dtsg': token, + 'jazoest': '25687', + 'lsd': 'W2jWYsm50EoSzDoSO5Ue9n', + '__spin_r': '1020855273', + '__spin_b': 'trunk', + '__spin_t': '1741846256', + } + + requests.post( + 'https://www.facebook.com/ajax/video/upload/requests/receive/', + params=params, + cookies=cookies, + headers=start_headers, + data=data, + ) + return video_id + + +def _upload_comment_video(cookies, filename, file, token): + user_id = cookies['c_user'] + waterfall_id = _gen_waterfall_id(user_id) + composer_session_id = _gen_waterfall_id(user_id) + content_type = MIMETYPE.get(filename.split('.')[-1]) + content = file.getvalue() + file_size = str(len(content)) + uri = f'1741828726893-{filename}-{content_type}-{file_size}-' \ + f'498AEJ73tToOXuUki2xK88hus3f+nSxTuf4/921pFh4=' + uri = f"{hashlib.md5(uri.encode('utf-8'))}-0-{file_size}" + file_extension = content_type.split('/')[-1] + headers = { + 'accept': '*/*', + 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'content-type': 'application/x-www-form-urlencoded', + 'origin': 'https://www.facebook.com', + 'priority': 'u=1, i', + 'referer': 'https://www.facebook.com/', + 'sec-ch-ua': '"Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-platform': '"macOS"', + 'sec-fetch-dest': 'empty', + 'sec-fetch-mode': 'cors', + 'sec-fetch-site': 'same-site', + 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36', + 'x_fb_video_waterfall_id': waterfall_id, + } + + params = { + '__a': '1', + } + data = f'file_size={file_size}&file_extension={file_extension}&target_id={user_id}&source=comment&composer_dialog_version&waterfall_id={waterfall_id}&composer_session_id={composer_session_id}&composer_entry_point_ref=feed_story&composer_work_shared_draft_mode&has_file_been_replaced=false&supports_chunking=true&supports_file_api=true&partition_start_offset=0&partition_end_offset={file_size}&creator_product=2&spherical=false&video_publisher_action_source&__aaid=0&__user={user_id}&__a=1&__req=2s&__hs=20161.HYP%3Acomet_pkg.2.1...1&dpr=2&__ccg=EXCELLENT&__rev=1020896933&__s=a6lpwr%3Av72pg5%3Alvg2er&__hsi=7481534814351260330&__dyn=7xeXzWK1ixt0mUyEqxemh0noeEb8nwgUao4u5QdwSwAyUco5S3O2Saw8i2S1DwUx60GE5O0BU2_CxS320qa2OU7m2210wEwgo9oO0-E4a3a4oaEnxO0Bo7O2l2Utwqo31wiE567Udo5qfK0zEkxe2GewyDwkUe9obrwh8lwUwgojUlDw-wUwxwjFovUaU3qxW2-awLyESE2KwwwOg2cwMwhEkxebwHwKG4UrwFg2fwxyo566k1FwgUjwOwWzUfHDzUiBG2OUqwjVqwLwHwa211zU523C&__csr=geI2ex4D7NYfTfshvbN7i94jjWq6l9OqZ4EzVsQx2dqGAACCPZiqinWORrt9ajKnl5IGSiGZbJ4F4CoyWRhd5iZ95CAOtLy4jBhkjt29F8KiABJyqQ9yFIDjiZ7Lhi5HhCZrXDUCAum598gzEWuUR7ADHDqK-tUTymayF9ECjCBXG8h8iQmaQ4LzVECh1Omh1u4USjy8CmuiSFbhbCy8gyGVoSuWy94Wig-4EKmcG8yqBVoXGWZ2ECXAxmb-mFoLgGUvz9u8z9eqm7Hy9bCiHKU-3mUsyoKcxaGKaBLyqGm7-8xy2KcDAh8hxK4EiAx7xq8wGBxycxy2S79pZ29EPxy5FUd8y5E9EB1a3m8xe482qwzxC4o3ux11e1wKaJkWuqF898RwAwaxwaO3C8yEOum1LWghxy4o8m0z3o0wqU7C3DxO2R4xeShrBCUO740zoLCy4by8ct0Lwyxe0D8y68bWyE8o6608Dw9m3G2C0Fk0F8nwCx-0D8-7FUnG8wro10o0ey80zO0p3wdrl0Lye00JSE0fvE-0bWCw960k66p81X60it0oOKu0kN282wwv80D21FwbG0iC0iO1bwSwAw9i582sw1ta1izU0yOkFQ0ne04Z82Pg1Y80mSBt044g7W0hW1bgeES06Kk02dm0he08Cwm88o5h0TwiE0mry8Gu05JUhwCghG4C4aw5Kxq0Ao4y1MDDyVE6EAyy89A2CcdyHu&__hsdp=&__hblp=&__comet_req=15&fb_dtsg={quote(token)}&jazoest=25421&lsd=sBdlvZ7xyxJeCPFduGOZlc&__spin_r=1020896933&__spin_b=trunk&__spin_t=1741930566' + print(data) + response = requests.post( + 'https://vupload-edge.facebook.com/ajax/video/upload/requests/start/', + params=params, + cookies=cookies, + headers=headers, + data=data, + ) + result = response.text[9:] + video_id = json.loads(result)['payload']['video_id'] + + headers = { + 'accept': '*/*', + 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'composer_session_id': waterfall_id, + 'end_offset': file_size, + 'id': 'undefined', + 'offset': '0', + 'origin': 'https://www.facebook.com', + 'priority': 'u=1, i', + 'product_media_id': video_id, + 'referer': 'https://www.facebook.com/', + 'sec-ch-ua': '"Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-platform': '"macOS"', + 'sec-fetch-dest': 'empty', + 'sec-fetch-mode': 'cors', + 'sec-fetch-site': 'same-site', + 'start_offset': '0', + 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36', + 'x-entity-length': file_size, + 'x-entity-name': 'undefined', + 'x-entity-type': 'application/octet-stream', + 'x-total-asset-size': file_size, + 'content-type': 'application/x-www-form-urlencoded', + } + + params = { + '__aaid': '0', + '__user': user_id, + '__a': '1', + '__req': '2v', + '__hs': '20161.HYP:comet_pkg.2.1...1', + 'dpr': '2', + '__ccg': 'EXCELLENT', + '__rev': '1020896933', + '__s': 'a6lpwr:v72pg5:lvg2er', + '__hsi': '7481534814351260330', + '__dyn': '7xeXzWK1ixt0mUyEqxemh0noeEb8nwgUao4u5QdwSwAyUco5S3O2Saw8i2S1DwUx60GE5O0BU2_CxS320qa2OU7m2210wEwgo9oO0-E4a3a4oaEnxO0Bo7O2l2Utwqo31wiE567Udo5qfK0zEkxe2GewyDwkUe9obrwh8lwUwgojUlDw-wUwxwjFovUaU3qxW2-awLyESE2KwwwOg2cwMwhEkxebwHwKG4UrwFg2fwxyo566k1FwgUjwOwWzUfHDzUiBG2OUqwjVqwLwHwa211zU523C', + '__csr': 'geI2ex4D7NYfTfshvbN7i94jjWq6l9OqZ4EzVsQx2dqGAACCPZiqinWORrt9ajKnl5IGSiGZbJ4F4CoyWRhd5iZ95CAOtLy4jBhkjt29F8KiABJyqQ9yFIDjiZ7Lhi5HhCZrXDUCAum598gzEWuUR7ADHDqK-tUTymayF9ECjCBXG8h8iQmaQ4LzVECh1Omh1u4USjy8CmuiSFbhbCy8gyGVoSuWy94Wig-4EKmcG8yqBVoXGWZ2ECXAxmb-mFoLgGUvz9u8z9eqm7Hy9bCiHKU-3mUsyoKcxaGKaBLyqGm7-8xy2KcDAh8hxK4EiAx7xq8wGBxycxy2S79pZ29EPxy5FUd8y5E9EB1a3m8xe482qwzxC4o3ux11e1wKaJkWuqF898RwAwaxwaO3C8yEOum1LWghxy4o8m0z3o0wqU7C3DxO2R4xeShrBCUO740zoLCy4by8ct0Lwyxe0D8y68bWyE8o6608Dw9m3G2C0Fk0F8nwCx-0D8-7FUnG8wro10o0ey80zO0p3wdrl0Lye00JSE0fvE-0bWCw960k66p81X60it0oOKu0kN282wwv80D21FwbG0iC0iO1bwSwAw9i582sw1ta1izU0yOkFQ0ne04Z82Pg1Y80mSBt044g7W0hW1bgeES06Kk02dm0he08Cwm88o5h0TwiE0mry8Gu05JUhwCghG4C4aw5Kxq0Ao4y1MDDyVE6EAyy89A2CcdyHu', + '__hsdp': '', + '__hblp': '', + '__comet_req': '15', + 'fb_dtsg': token, + 'jazoest': '25421', + 'lsd': 'sBdlvZ7xyxJeCPFduGOZlc', + '__spin_r': '1020896933', + '__spin_b': 'trunk', + '__spin_t': '1741930566', + } + response = requests.post( + f'https://rupload-sin6-3.up.facebook.com/fb_video/{uri}', + params=params, + cookies=cookies, + headers=headers, + data=content, + ) + video_file_chunk = response.json()['h'] + + boundary = _get_boundary() + headers = { + 'accept': '*/*', + 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'content-type': f'multipart/form-data; boundary=----WebKitFormBoundary{boundary}', + 'origin': 'https://www.facebook.com', + 'priority': 'u=1, i', + 'referer': 'https://www.facebook.com/', + 'sec-ch-ua': '"Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-platform': '"macOS"', + 'sec-fetch-dest': 'empty', + 'sec-fetch-mode': 'cors', + 'sec-fetch-site': 'same-site', + 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36', + 'x_fb_video_waterfall_id': waterfall_id, + } + params = { + "composer_session_id": composer_session_id, + "video_id": video_id, + "start_offset": "0", + "end_offset": file_size, + "source": "comment", + "target_id": user_id, + "waterfall_id": waterfall_id, + "composer_entry_point_ref": "feed_story", + "has_file_been_replaced": "false", + "supports_chunking": "true", + "partition_start_offset": "0", + "partition_end_offset": file_size, + "__aaid": "0", + "__user": user_id, + "__a": "1", + "__req": "2w", + "__hs": "20161.HYP:comet_pkg.2.1...1", + "dpr": "2", + "__ccg": "EXCELLENT", + "__rev": "1020896933", + "__s": "a6lpwr:v72pg5:lvg2er", + "__hsi": "7481534814351260330", + "__dyn": "7xeXzWK1ixt0mUyEqxemh0noeEb8nwgUao4u5QdwSwAyUco5S3O2Saw8i2S1DwUx60GE5O0BU2_CxS320qa2OU7m2210wEwgo9oO0-E4a3a4oaEnxO0Bo7O2l2Utwqo31wiE567Udo5qfK0zEkxe2GewyDwkUe9obrwh8lwUwgojUlDw-wUwxwjFovUaU3qxW2-awLyESE2KwwwOg2cwMwhEkxebwHwKG4UrwFg2fwxyo566k1FwgUjwOwWzUfHDzUiBG2OUqwjVqwLwHwa211zU523C", + "__csr": "geI2ex4D7NYfTfshvbN7i94jjWq6l9OqZ4EzVsQx2dqGAACCPZiqinWORrt9ajKnl5IGSiGZbJ4F4CoyWRhd5iZ95CAOtLy4jBhkjt29F8KiABJyqQ9yFIDjiZ7Lhi5HhCZrXDUCAum598gzEWuUR7ADHDqK-tUTymayF9ECjCBXG8h8iQmaQ4LzVECh1Omh1u4USjy8CmuiSFbhbCy8gyGVoSuWy94Wig-4EKmcG8yqBVoXGWZ2ECXAxmb-mFoLgGUvz9u8z9eqm7Hy9bCiHKU-3mUsyoKcxaGKaBLyqGm7-8xy2KcDAh8hxK4EiAx7xq8wGBxycxy2S79pZ29EPxy5FUd8y5E9EB1a3m8xe482qwzxC4o3ux11e1wKaJkWuqF898RwAwaxwaO3C8yEOum1LWghxy4o8m0z3o0wqU7C3DxO2R4xeShrBCUO740zoLCy4by8ct0Lwyxe0D8y68bWyE8o6608Dw9m3G2C0Fk0F8nwCx-0D8-7FUnG8wro10o0ey80zO0p3wdrl0Lye00JSE0fvE-0bWCw960k66p81X60it0oOKu0kN282wwv80D21FwbG0iC0iO1bwSwAw9i582sw1ta1izU0yOkFQ0ne04Z82Pg1Y80mSBt044g7W0hW1bgeES06Kk02dm0he08Cwm88o5h0TwiE0mry8Gu05JUhwCghG4C4aw5Kxq0Ao4y1MDDyVE6EAyy89A2CcdyHu", + "__comet_req": "15", + "fb_dtsg": token, + "jazoest": "25421", + "lsd": "sBdlvZ7xyxJeCPFduGOZlc", + "__spin_r": "1020896933", + "__spin_b": "trunk", + "__spin_t": "1741930566" + } + form_data = b'------WebKitFormBoundary%s\r\nContent-Disposition: form-data; ' \ + b'name="fbuploader_video_file_chunk"\r\n\r\n%s\r\n' % ( + boundary.encode('utf-8'), video_file_chunk.encode('utf-8') + ) + requests.post( + 'https://vupload-edge.facebook.com/ajax/video/upload/requests/receive/', + cookies=cookies, + headers=headers, + params=params, + data=form_data, + ) + return video_id + + +def post(cookies, message, image_key=None): + user_id = cookies['c_user'] + dtsg_token = get_dtsg_token(cookies) + headers = { + 'accept': '*/*', + 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'content-type': 'application/x-www-form-urlencoded', + 'origin': 'https://www.facebook.com', + 'priority': 'u=1, i', + 'referer': f'https://www.facebook.com/', + 'sec-ch-prefers-color-scheme': 'light', + 'sec-ch-ua': '"Not(A:Brand";v="99", "Google Chrome";v="133", "Chromium";v="133"', + 'sec-ch-ua-full-version-list': '"Not(A:Brand";v="99.0.0.0", "Google Chrome";v="133.0.6943.127", "Chromium";v="133.0.6943.127"', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-model': '""', + 'sec-ch-ua-platform': '"macOS"', + 'sec-ch-ua-platform-version': '"15.3.2"', + 'sec-fetch-dest': 'empty', + 'sec-fetch-mode': 'cors', + 'sec-fetch-site': 'same-origin', + 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36', + 'x-asbd-id': '359341', + 'x-fb-friendly-name': 'ComposerStoryCreateMutation', + 'x-fb-lsd': 'aQBZ0Gh5mfQSPgCywj081r', + } + uuid4_token = str(uuid.uuid4()) + + # 处理图片或视频上传 + attachments = [] + if image_key: + # bio = client.download_bytes_file(BUCKET, image_key) + with open('../files/xmbl.mp4', 'rb') as f: + bio = io.BytesIO(f.read()) + filename = image_key.split('/')[-1] + content_type = MIMETYPE.get(filename.split('.')[-1]) + if not content_type: + raise OperationFailed('文件类型暂不支持') + if content_type in PIC_TYPE: + # 上传图片 + photo_id = _upload_photo(cookies, filename, bio, dtsg_token) + attachments = [{'photo': {'id': photo_id}}] + else: + # 上传视频 + video_id = _upload_video(cookies, filename, bio, dtsg_token) + attachments = [{'video': {'id': video_id, 'notify_when_processed': True}}] + + data = { + 'av': user_id, + '__aaid': '0', + '__user': user_id, + '__a': '1', + '__req': '42', + '__hs': '20159.HYP:comet_pkg.2.1...1', + 'dpr': '2', + '__ccg': 'EXCELLENT', + '__rev': '1020809040', + '__s': 'itr9j4:q8hbxy:4gveux', + '__hsi': '7480795543745950771', + '__dyn': '7xeXzWK1ixt0mUyEqxemh0noeEb8nwgUao4u5QdwSwAyUco5S3O2Saw8i2S1DwUx60GE5O0BU2_CxS320qa2OU7m221Fwgo9oO0-E4a3a4oaEnxO0Bo7O2l2Utwqo31wiE567Udo5qfK0zEkxe2GewyDwkUe9obrwh8lwUwgojUlDw-wSU8o4Wm7-2K1ywtUuwLyEbUGdG0HE88cA0z8c84q58jyUaUbGxe6Uak0zU8oC1hxB0qo4e4UcEeE-3WVU-4FqwIK6E4-mEbUaU2wwgo623C', + '__csr': 'g4r1p3O7ZNk4kn4gxn2lkIIp7iLlsZSQyO8yaXOEy9H8qAOsqXkGi8yGmzSXldtnhqh2nO4FkIFttVVQKmLnhZ9Jq8GJ6iybBt6QiF95iunUBF4gCqhSGrhWSuDCildrLCpVBC-VlDy-jK8n_DmlCBhJQUym-i6pahFVkVV9aCyGpKnXmfDiBBBgRaqXCAh8hnAypS4UKGKQvQWBzqAx3HVSjKip2qUi-mEgDAVkVaxai4WCCF5ypKqdKi9ypHCAGrBV_jAAxuHLV98hxCnAWV6GADy8Ci8hkFXiJ7K6omzrLh8x1a2qUjiJ38Na8znwzzXU-UkzXGdyrx50Ixei58OQ9ybxau2i4qDyku4U8ax516eLy8KcwAxi9xiufxiU8Q7EK2i14G5ocS2yHDwDwMwmEcE2LwLz9o15EN122i2GAp6hQGwIHyUZw867k18EE6Wao2_woo2lwEx61lye0x86Wi2u3ZCy9Q1tQ0F8lny8iye1kwOGcECUlwcu0Ko5m9J1by5GlU62ewYwXw9m0G846i0zEeUcVu2twuuE0n_w0wdw2cU1QEd8721iocE0OG2Dm5E081Enw08xG03HK1fw8a0nq0oeu1dw72a16wyw55wBo3jg1X48wa21-w2w85e0PoKu0hy0iy18wgEfE7uhxa5o8y3U9EK04SK9w4zDg0zygEyaw7Xw3mE3Vwbx07yw3IU1N306Ew9G0WVFmm1eBg0n9wcp0fafw17i0s60s60ju0rypo4O15w8e2a5o987S05wpQaw1eK0EkK464WzQ2C09tDxGE3qOuiA5f472dKLm', + '__hsdp': '', + '__hblp': '', + '__comet_req': '15', + 'fb_dtsg': dtsg_token, + 'jazoest': '25494', + 'lsd': 'WgZt97AQ_LCDMTfuw-sO6Y', + '__spin_r': '1020809040', + '__spin_b': 'trunk', + '__spin_t': '1741758441', + 'fb_api_caller_class': 'RelayModern', + 'fb_api_req_friendly_name': 'ComposerStoryCreateMutation', + 'variables': '{"input":{"composer_entry_point":"inline_composer","composer_source_surface":"timeline","idempotence_token":"%s_FEED","source":"WWW","attachments":%s,"audience":{"privacy":{"allow":[],"base_state":"EVERYONE","deny":[],"tag_expansion_state":"UNSPECIFIED"}},"message":{"ranges":[],"text":"%s"},"with_tags_ids":null,"inline_activities":[],"text_format_preset_id":"0","publishing_flow":{"supported_flows":["ASYNC_SILENT","ASYNC_NOTIF","FALLBACK"]},"logging":{"composer_session_id":"%s"},"navigation_data":{"attribution_id_v2":"ProfileCometTimelineListViewRoot.react,comet.profile.timeline.list,tap_bookmark,1741758458056,864702,61573941575877,,"},"tracking":[null],"event_share_metadata":{"surface":"timeline"},"actor_id":"%s","client_mutation_id":"9"},"feedLocation":"TIMELINE","feedbackSource":0,"focusCommentID":null,"gridMediaWidth":230,"groupID":null,"scale":2,"privacySelectorRenderLocation":"COMET_STREAM","checkPhotosToReelsUpsellEligibility":true,"renderLocation":"timeline","useDefaultActor":false,"inviteShortLinkKey":null,"isFeed":false,"isFundraiser":false,"isFunFactPost":false,"isGroup":false,"isEvent":false,"isTimeline":true,"isSocialLearning":false,"isPageNewsFeed":false,"isProfileReviews":false,"isWorkSharedDraft":false,"hashtag":null,"canUserManageOffers":false,"__relay_internal__pv__CometUFIShareActionMigrationrelayprovider":true,"__relay_internal__pv__GHLShouldChangeSponsoredDataFieldNamerelayprovider":false,"__relay_internal__pv__GHLShouldChangeAdIdFieldNamerelayprovider":false,"__relay_internal__pv__IsWorkUserrelayprovider":false,"__relay_internal__pv__CometUFIReactionsEnableShortNamerelayprovider":false,"__relay_internal__pv__CometFeedStoryDynamicResolutionPhotoAttachmentRenderer_experimentWidthrelayprovider":500,"__relay_internal__pv__CometImmersivePhotoCanUserDisable3DMotionrelayprovider":false,"__relay_internal__pv__WorkCometIsEmployeeGKProviderrelayprovider":false,"__relay_internal__pv__IsMergQAPollsrelayprovider":false,"__relay_internal__pv__FBReels_deprecate_short_form_video_context_gkrelayprovider":false,"__relay_internal__pv__FBReelsMediaFooter_comet_enable_reels_ads_gkrelayprovider":false,"__relay_internal__pv__StoriesArmadilloReplyEnabledrelayprovider":false,"__relay_internal__pv__FBReelsIFUTileContent_reelsIFUPlayOnHoverrelayprovider":false,"__relay_internal__pv__EventCometCardImage_prefetchEventImagerelayprovider":false,"__relay_internal__pv__GHLShouldChangeSponsoredAuctionDistanceFieldNamerelayprovider":false}' % ( + uuid4_token, json.dumps(attachments), message, uuid4_token, user_id + ), + 'server_timestamps': 'true', + 'doc_id': '9835564903120639', + } + response = requests.post('https://www.facebook.com/api/graphql/', cookies=cookies, headers=headers, data=data) + if response.status_code != 200: + raise OperationFailed(f'发帖异常 response: {response.text}') + + if response.json() and response.json().get('data'): + if not response.json()['data']['story_create'].get('timeline_feed_units_edge'): + return + post_id = response.json()['data']['story_create']['timeline_feed_units_edge']['node']['feedback']['id'] + return {'reso_id': post_id} + else: + raise OperationFailed(f'参数错误, response: {response.text}') + + +def like(cookies, post_id): + user_id = cookies['c_user'] + dtsg_token = get_dtsg_token(cookies) + headers = { + 'accept': '*/*', + 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'content-type': 'application/x-www-form-urlencoded', + 'origin': 'https://www.facebook.com', + 'priority': 'u=1, i', + 'referer': 'https://www.facebook.com/', + 'sec-ch-prefers-color-scheme': 'light', + 'sec-ch-ua': '"Not(A:Brand";v="99", "Google Chrome";v="133", "Chromium";v="133"', + 'sec-ch-ua-full-version-list': '"Not(A:Brand";v="99.0.0.0", "Google Chrome";v="133.0.6943.127", "Chromium";v="133.0.6943.127"', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-model': '""', + 'sec-ch-ua-platform': '"macOS"', + 'sec-ch-ua-platform-version': '"15.3.1"', + 'sec-fetch-dest': 'empty', + 'sec-fetch-mode': 'cors', + 'sec-fetch-site': 'same-origin', + 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36', + 'x-asbd-id': '359341', + 'x-fb-friendly-name': 'CometUFIFeedbackReactMutation', + 'x-fb-lsd': 'pSe8b3OaUeIWyqreatk6Bt', + } + + data = { + 'av': user_id, + '__aaid': '0', + '__user': user_id, + '__a': '1', + '__req': '73', + '__hs': '20159.HYP:comet_pkg.2.1...1', + 'dpr': '2', + '__ccg': 'EXCELLENT', + '__rev': '1020805083', + '__s': 'rkcs6h:q8hbxy:ud5a0g', + '__hsi': '7480739570773453695', + '__dyn': '7xeXzWK1ixt0mUyEqxemh0noeEb8nwgUao4u5QdwSwAyUco5S3O2Saw8i2S1DwUx60GE3Qwb-q7oc81EEbbwto886C11wBz83WwgEcEhwGxu782lwv89kbxS1Fwc61awkovwRwlE-U2exi4UaEW2au1jwUBwJK14xm3y11xfxmu3W3iU8o4Wm7-2K1ywtUuwLyEbUGdG0HE88cA0z8c84q58jyUaUbGxe6Uak0zU8oC1hxB0qo4e4UcEeE-3WVU-4FqwIK6E4-mEbUaU2wwgomwioeo', + '__csr': 'g4v2Qp2I8MB2sBiMP6hWT94Pi8BOh4JEAjOIAYkOkCOl8TFfXAlOEhi4QySYQQJ99Qyjh3uRIBtEDDqkREOQBWFa-leLCnfKGHflRKZpkAJQAnllFkQhrEDZ5h2pV7AFd6BA9LBFTG-nyJKAeh8yCgPKC8iBLAHKKmAayUGCQKjSF4ibCz6qhkX-V6pWBWCWLSHHmmJi2qKKQbXyp8-FqKclAgzylmiimHCdyQFQhCXWGq8jQpABnWGGGcDxbBJ6VpXFx69gygxAqmt2eiKjK-jQppoWu9JapzZknWiFf-h4y9VXBBDp5LKp3rFXimaBKihGijBLyAqAfBCxVUCuXx6EVScAx22Oezebx2UyWV9bCGrx279EqyGG5bF3e2uuFFEPDAK4UB3oHxp5UOvDAUG4ElymESeCCxLzVFAawNolgpw8i4o1hEd87u48swt81mS2C3pa1FAwcG2GeBl11240xo-2e11wzwXm598jx61xwTo9qwygBQ0Ho8EO5E36yt2Ah5UrBwJBAhe6VXjXwsy0aS7UZ1GeJ5Owxxa6U4x0OF2A4o4O8Ujg4G2K291i9Z08a4EnOel1-19wGCK7FEKK4VpU7W9y8RwDwCw0Bbw3s81DU0qfw3388Elwk_m1mo0Gm3W069UeU10ooAo7yU4K7802Nkw4YxS1fp86e0ZEaocE5iawDwuo2kwo8jwXwoo27wdu1aw9a0E8Dh411w3k8gwh8CA9w3pE7a08Swho9E1x83ww51waegB019W0G9U1hFE4e1byE6W0N87a08c4kq0F8hg3-Dw_Dw5rwroqw6wxXg6G11wgU3LmifwIwSgK0pu1jCw6yxkE1PXhE0AR0da48iw9i10wVw1wTw2FUGl0HxkwgBto3Qw80LOAwDWqQi5eAPJ4BBo2Qwax6Qu0FU4O540GUeUK2u0mK0jUw0tzwKx20EU1BO0', + '__hsdp': '', + '__hblp': '', + '__comet_req': '15', + 'fb_dtsg': dtsg_token, + 'jazoest': '25686', + 'lsd': 'pSe8b3OaUeIWyqreatk6Bt', + '__spin_r': '1020805083', + '__spin_b': 'trunk', + '__spin_t': '1741745409', + 'fb_api_caller_class': 'RelayModern', + 'fb_api_req_friendly_name': 'CometUFIFeedbackReactMutation', + 'variables': '{"input":{"attribution_id_v2":"ProfileCometTimelineListViewRoot.react,comet.profile.timeline.list,via_cold_start,1741762579222,259553,190055527696468,,","feedback_id":"%s","feedback_reaction_id":"1635855486666999","feedback_source":"NEWS_FEED","feedback_referrer":"/","is_tracking_encrypted":true,"tracking":["AZU7Uu1mm-QEQWdf13bCqxa9BLW6XkzoVE0sGm0QPL4CVtIl4WisVkoklN9Br-D0Au3gMFW4r6MvQ0nT00cAJa6iF6KyFW3HCZaxjanGT-stTURNU_RPjcB29mJ-hLkoviYK03qDPP41KJKtNwLxhWyj6z_wd3i__pyfdS8FecVlOj8qHhr2s6LJq32sUIqQ8omYEHGRnDN99kb9BW8HS_x4C8ZY8-fDY5abf-cXMixnohPQBtAqhQhwB2DxkFwqYxPHy6psbCYTCVyjbhPsFyvEfSO7bVN4_foTsx9dzcyhY820L0NB847Fzu77vWNC0wHffoD_SCOnJQTU8m-TcjVTbZu0vwoam47IPOi0DK3xSSxG_8bDXdbv86prssWEsvi7vkbERsPACyi9JcuGCiO0cIpOnJSsJkbuOU_BqYq7SrR9h254Px8T85lj5F_OmWCvOuKYJ8IAUS6cyc56dw-cGPBkQ2R5ewEDCl5uwfB0rg"],"session_id":"121da0a0-58ab-4ab0-93dd-6a7e3c42625e","actor_id":"%s","client_mutation_id":"1"},"useDefaultActor":false,"__relay_internal__pv__CometUFIReactionsEnableShortNamerelayprovider":false}' % ( + post_id, user_id + ), + 'server_timestamps': 'true', + 'doc_id': '9232085126871383', + } + + response = requests.post('https://www.facebook.com/api/graphql/', cookies=cookies, headers=headers, data=data) + if response.status_code != 200: + raise OperationFailed(f'点赞异常 response: {response.text}') + + +def comment(cookies, post_id, message, image_key=None): + user_id = cookies['c_user'] + uuid4_token = str(uuid.uuid4()) + dtsg_token = get_dtsg_token(cookies) + headers = { + 'accept': '*/*', + 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', + 'content-type': 'application/x-www-form-urlencoded', + 'origin': 'https://www.facebook.com', + 'priority': 'u=1, i', + 'referer': 'https://www.facebook.com/', + 'sec-ch-prefers-color-scheme': 'light', + 'sec-ch-ua': '"Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"', + 'sec-ch-ua-full-version-list': '"Chromium";v="134.0.6998.89", "Not:A-Brand";v="24.0.0.0", "Google Chrome";v="134.0.6998.89"', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-model': '""', + 'sec-ch-ua-platform': '"macOS"', + 'sec-ch-ua-platform-version': '"15.3.2"', + 'sec-fetch-dest': 'empty', + 'sec-fetch-mode': 'cors', + 'sec-fetch-site': 'same-origin', + 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36', + 'x-asbd-id': '359341', + 'x-fb-friendly-name': 'useCometUFICreateCommentMutation', + 'x-fb-lsd': 'sBdlvZ7xyxJeCPFduGOZlc', + } + + # 处理图片或视频上传 + attachments = 'null' + if image_key: + # bio = client.download_bytes_file(BUCKET, image_key) + with open('../xzpq.mp4', 'rb') as f: + bio = io.BytesIO(f.read()) + filename = image_key.split('/')[-1] + content_type = MIMETYPE.get(filename.split('.')[-1]) + if not content_type: + raise OperationFailed('文件类型暂不支持') + if content_type in PIC_TYPE: + # 上传图片 + photo_id = _upload_photo(cookies, filename, bio, dtsg_token) + attachments = json.dumps([{'media': {'id': photo_id}}]) + else: + # 上传视频 + video_id = _upload_comment_video(cookies, filename, bio, dtsg_token) + attachments = json.dumps([{'media': {'id': video_id}}]) + data = { + 'av': user_id, + '__aaid': '0', + '__user': user_id, + '__a': '1', + '__req': '2z', + '__hs': '20161.HYP:comet_pkg.2.1...1', + 'dpr': '2', + '__ccg': 'EXCELLENT', + '__rev': '1020896933', + '__s': 'a6lpwr:v72pg5:lvg2er', + '__hsi': '7481534814351260330', + '__dyn': '7xeXzWK1ixt0mUyEqxemh0noeEb8nwgUao4u5QdwSwAyUco5S3O2Saw8i2S1DwUx60GE5O0BU2_CxS320qa2OU7m2210wEwgo9oO0-E4a3a4oaEnxO0Bo7O2l2Utwqo31wiE567Udo5qfK0zEkxe2GewyDwkUe9obrwh8lwUwgojUlDw-wUwxwjFovUaU3qxW2-awLyESE2KwwwOg2cwMwhEkxebwHwKG4UrwFg2fwxyo566k1FwgUjwOwWzUfHDzUiBG2OUqwjVqwLwHwa211zU523C', + '__csr': 'geI2ex4D7NYfTfshvbN7i94jjWq6l9OqZ4EzVsQx2dqGAACCPZiqinWORrt9ajKnl5IGSiGZbJ4F4CoyWRhd5iZ95CAOtLy4jBhkjt29F8KiABJyqQ9yFIDjiZ7Lhi5HhCZrXDUCAum598gzEWuUR7ADHDqK-tUTymayF9ECjCBXG8h8iQmaQ4LzVECh1Omh1u4USjy8CmuiSFbhbCy8gyGVoSuWy94Wig-4EKmcG8yqBVoXGWZ2ECXAxmb-mFoLgGUvz9u8z9eqm7Hy9bCiHKU-3mUsyoKcxaGKaBLyqGm7-8xy2KcDAh8hxK4EiAx7xq8wGBxycxy2S79pZ29EPxy5FUd8y5E9EB1a3m8xe482qwzxC4o3ux11e1wKaJkWuqF898RwAwaxwaO3C8yEOum1LWghxy4o8m0z3o0wqU7C3DxO2R4xeShrBCUO740zoLCy4by8ct0Lwyxe0D8y68bWyE8o6608Dw9m3G2C0Fk0F8nwCx-0D8-7FUnG8wro10o0ey80zO0p3wdrl0Lye00JSE0fvE-0bWCw960k66p81X60it0oOKu0kN282wwv80D21FwbG0iC0iO1bwSwAw9i582sw1ta1izU0yOkFQ0ne04Z82Pg1Y80mSBt044g7W0hW1bgeES06Kk02dm0he08Cwm88o5h0TwiE0mry8Gu05JUhwCghG4C4aw5Kxq0Ao4y1MDDyVE6EAyy89A2CcdyHu', + '__hsdp': '', + '__hblp': '', + '__comet_req': '15', + 'fb_dtsg': dtsg_token, + 'jazoest': '25421', + 'lsd': 'sBdlvZ7xyxJeCPFduGOZlc', + '__spin_r': '1020896933', + '__spin_b': 'trunk', + '__spin_t': '1741930566', + 'fb_api_caller_class': 'RelayModern', + 'fb_api_req_friendly_name': 'useCometUFICreateCommentMutation', + 'variables': '{"feedLocation":"DEDICATED_COMMENTING_SURFACE","feedbackSource":110,"groupID":null,"input":{"client_mutation_id":"9","actor_id":"%s","attachments":%s,"feedback_id":"%s","formatting_style":null,"message":{"ranges":[],"text":"%s"},"reply_target_clicked":false,"attribution_id_v2":"ProfileCometTimelineListViewRoot.react,comet.profile.timeline.list,via_cold_start,1741930566987,158144,190055527696468,,","vod_video_timestamp":null,"is_tracking_encrypted":true,"tracking":["AZUnHF90UjvMroqev0xy6W_qNXEYnMdkDf2rOE-nm5QixlfrYaVfAvJUqno_2QpxLLNNH4DHVW3nOxZV7bQ8g-mFD5gsNi8pyl3TCLHIoaVbwibiTs-HdYDZiIkx1x3XW0xFcl8qgJvOjvbxKJfELSMgvIzV41LuBiCsetCc90f-Ix5k-9BspWI2AMnOMvYsWfxZ59yHxUtvL_D9lAdfopanDANfA5LeeDThbw5uaixa8GwokZpZGlwj0prU9qeQ9JWrOy6praN_WrvO2bZhFu3rhSBG_oKZ_bYZITmkN6uKs4eN4EVFhPfeVzGafPB5LoKIsY0Qs5zYTQdn8-KLvdYLHHhzcSxArKjActiRETyNQ8ZdZGThr0yyLy1weKmbRSKSoHSXC9eMJYF6ApK_zA2KFapQv_w2j9bIdnML9A9SbHYajroIofnXJ5eAHWv83TVbotU0gw-kl5zRzV25Am0tZ8-p7K8Two2ai0HxkF0MMTi60mI96lTmzLviyj8om76TLDB7-u-X5MLukgzHfqmTSnhd5KyVIrx77kLaXr4E-5mDMjPvAF5jcunXAJBjDl5rRmFze0rO1PgWwFEAvCvnjC8ftDH4VdRbW0wUMmQAMA","{\\"assistant_caller\\":\\"comet_above_composer\\",\\"conversation_guide_session_id\\":\\"d75579ed-48e4-4aac-8975-84cf698151f4\\",\\"conversation_guide_shown\\":null}"],"feedback_source":"DEDICATED_COMMENTING_SURFACE","idempotence_token":"client:%s","session_id":"cce85c8c-eb4e-4304-9e86-ac7d27d7f642"},"inviteShortLinkKey":null,"renderLocation":null,"scale":2,"useDefaultActor":false,"focusCommentID":null,"__relay_internal__pv__IsWorkUserrelayprovider":false}' % ( + user_id, attachments, post_id, message, uuid4_token + ), + 'server_timestamps': 'true', + 'doc_id': '9389802714420896', + } + response = requests.post('https://www.facebook.com/api/graphql/', cookies=cookies, headers=headers, data=data) + if response.status_code != 200: + raise OperationFailed(f'评论异常 response: {response.text}') + + if response.json() and response.json().get('data'): + return {'resp_id': response.json()['data']['comment_create']['feedback_comment_edge']['node']['id']} + else: + raise OperationFailed(f'参数错误, response: {response.text}') + + +def sleep(a, b): + return time.sleep(round(random.uniform(a, b), 1)) + + +def update_windows_distinguish(x=1920, y=1080): + """更改windows分辨率""" + if sys.platform == "win32": + import win32api + import win32con + import pywintypes + + devmode = pywintypes.DEVMODEType() + + # screenSize = [1280,800] + screenSize = [x, y] + + devmode.PelsWidth = screenSize[0] + devmode.PelsHeight = screenSize[1] + devmode.Fields = win32con.DM_PELSWIDTH | win32con.DM_PELSHEIGHT + win32api.ChangeDisplaySettings(devmode, 0) + + +def _change_language(page): + sleep(1, 2) + page.click('//*[@id="«R1ldm6l6ismipapd5aq»"]/*[2]') + sleep(1, 2) + page.click('//div[@role="listitem" and @class="x1n2onr6 x1ja2u2z x9f619 x78zum5 xdt5ytf x2lah0s x193iq5w"][1]') + sleep(1, 2) + page.click('//div[@role="menu"]/div[2]') + sleep(1, 2) + page.click('//div[@class="x1y1aw1k x4uap5 xwxc41k xkhd6sd"]/div/div[2]') + sleep(1, 2) + page.click('//span[@class="x1lliihq x6ikm8r x10wlt62 x1n2onr6 xlyipyv xuxw1ft" and text()="English (US)"][1]') + sleep(3, 5) + + +def _edit_privacy(page): + sleep(1, 2) + page.click('//div[contains(@aria-label, "Edit privacy")]') + sleep(1, 2) + page.click('//div[@aria-label="Select audience"]//span[text()="Public"]') + page.click('//div[@aria-label="Done"]') + sleep(1, 2) + + +class RLock(threading._RLock): + pass + + +lock = RLock() + + +def playwright_like(cookies, post_id): + path = os.path.join(BASE_PATH, 'chrome', '130-0008', 'chrome.exe') + with lock: + with sync_playwright() as playwright: + update_windows_distinguish() + browser = playwright.chromium.launch( + headless=False, args=['--start-maximized'], executable_path=path + # proxy=dove_proxy.get_playwright_proxy(get_storage(cookies, 'username')) + ) + context = browser.new_context(no_viewport=True) + context.add_init_script(path=os.path.join(BASE_PATH, 'stealth.min.js')) + context.add_cookies([ + {'name': k, 'value': v, 'domain': '.facebook.com', 'path': '/'} for k, v in cookies.items() + ]) + page = context.new_page() + url = 'https://facebook.com' + page.goto(url) + _change_language(page) + + if 'permalink.php?story_fbid' in post_id or '/posts/' in post_id: + # 文字或图片类型 + button_xpath = '//div[@class="__fb-light-mode x1n2onr6 x1vjfegm"]//span[@data-ad-rendering-role="like_button"]' + elif 'watch/?v' in post_id: + # 视频类型 + button_xpath = '//span[@data-ad-rendering-role="like_button"][1]' + elif '/reel/' in post_id: + # 短视频类型 + button_xpath = '//div[@class="__fb-dark-mode x1afcbsf x1uhb9sk x1swf91x"]//div[@aria-label="Like"]//div[@aria-label="Like"]' + else: + raise OperationFailed(f'不支持的帖子类型POST: {post_id}') + + page.goto(post_id) + sleep(1, 2) + page.click(button_xpath) + time.sleep(10) + + context.close() + browser.close() + + +def playwright_post(cookies, message, image_key=None): + path = os.path.join(BASE_PATH, 'chrome', '130-0008', 'chrome.exe') + with lock: + with sync_playwright() as playwright: + update_windows_distinguish() + browser = playwright.chromium.launch( + headless=False, args=['--start-maximized'], executable_path=path + # proxy=dove_proxy.get_playwright_proxy(get_storage(cookies, 'username')) + ) + context = browser.new_context(no_viewport=True) + context.add_init_script(path=os.path.join(BASE_PATH, 'stealth.min.js')) + context.add_cookies([ + {'name': k, 'value': v, 'domain': '.facebook.com', 'path': '/'} for k, v in cookies.items() + ]) + page = context.new_page() + url = 'https://facebook.com' + page.goto(url) + _change_language(page) + time.sleep(5) + + if image_key: + filename = image_key.split('/')[-1] + file_path = os.path.join(BASE_PATH, 'files', filename) + client.download_file(BUCKET, image_key, file_path) + page.click('//div[@aria-label="Photo/video"]') + sleep(1, 2) + with page.expect_file_chooser() as fc_info: + page.click('//span[text()="Add photos/videos"]') + file_chooser = fc_info.value + file_chooser.set_files(file_path) + time.sleep(5) + + page.click('''//span[contains(text(), "What's on your mind")]''') + _edit_privacy(page) + page.type('''//div[contains(@aria-label, "What's on your mind")]''', message) + + page.click('//div[@aria-label="Post"]') + context.close() + browser.close() + + +def playwright_comment(cookies, post_id, message, image_key=None): + path = os.path.join(BASE_PATH, 'chrome', '130-0008', 'chrome.exe') + with lock: + with sync_playwright() as playwright: + update_windows_distinguish() + browser = playwright.chromium.launch( + headless=False, args=['--start-maximized'], executable_path=path + # proxy=dove_proxy.get_playwright_proxy(get_storage(cookies, 'username')) + ) + context = browser.new_context(no_viewport=True) + context.add_init_script(path=os.path.join(BASE_PATH, 'stealth.min.js')) + context.add_cookies([ + {'name': k, 'value': v, 'domain': '.facebook.com', 'path': '/'} for k, v in cookies.items() + ]) + page = context.new_page() + url = 'https://facebook.com' + page.goto(url) + _change_language(page) + time.sleep(5) + + page.goto(post_id) + sleep(1, 2) + + if 'permalink.php?story_fbid' in post_id or '/posts/' in post_id: + # 文字或图片类型 + input_xpath = '//div[@aria-label="Write a comment…"]' + attach_xpath = '//div[@id="focused-state-actions-list"]//div[@aria-label="Attach a photo or video"]' + comment_xpath = '//div[@aria-label="Comment"]' + page.click(input_xpath) + sleep(1, 2) + elif 'watch/?v' in post_id: + # 视频类型 + input_xpath = '//div[@aria-label="Write a comment…"]' + attach_xpath = '//div[@aria-label="Attach a photo or video"]' + comment_xpath = '//div[@aria-label="Comment"]' + elif '/reel/' in post_id: + # 短视频类型 + input_xpath = '//div[@aria-label="Write a comment…"]' + attach_xpath = '//div[@aria-label="Attach a photo or video"]' + comment_xpath = '//div[@role="complementary"]//div[@aria-label="Comment"]' + page.click('//div[@aria-label="Comment"][1]') + sleep(1, 2) + else: + raise OperationFailed(f'不支持的帖子类型POST: {post_id}') + + if image_key: + filename = image_key.split('/')[-1] + file_path = os.path.join(BASE_PATH, 'files', filename) + client.download_file(BUCKET, image_key, file_path) + sleep(1, 2) + with page.expect_file_chooser() as fc_info: + page.click(attach_xpath) + file_chooser = fc_info.value + file_chooser.set_files(file_path) + time.sleep(5) + + page.type(input_xpath, message) + page.click(comment_xpath) + + context.close() + browser.close() + + +def playwright_get_user_profile(cookies): + path = os.path.join(BASE_PATH, 'chrome', '130-0008', 'chrome.exe') + with lock: + with sync_playwright() as playwright: + update_windows_distinguish() + browser = playwright.chromium.launch( + headless=False, args=['--start-maximized'], executable_path=path + # proxy=dove_proxy.get_playwright_proxy(get_storage(cookies, 'username')) + ) + context = browser.new_context(no_viewport=True) + context.add_init_script(path=os.path.join(BASE_PATH, 'stealth.min.js')) + context.add_cookies([ + {'name': k, 'value': v, 'domain': '.facebook.com', 'path': '/'} for k, v in cookies.items() + ]) + page = context.new_page() + url = 'https://facebook.com' + page.goto(url) + _change_language(page) + + profile_pic_url = page.locator('//div[@aria-label="Shortcuts"]//li[1]//*[@preserveAspectRatio="xMidYMid slice"]').get_attribute('xlink:href') + nickname = page.locator('//div[@aria-label="Shortcuts"]//li[1]//span').first.inner_text() + context.close() + browser.close() + + response = requests.get( + url=profile_pic_url, + headers={'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36'}, + ) + bio = io.BytesIO(response.content) + key = f"facebook/{nickname.replace(' ', '_')}.png" + client.putstream(BUCKET, key, bio) + return {'profile_pic': key, 'nickname': nickname} + + +def playwright_set_user_profile(cookies, firstname=None, lastname=None, image_key=None): + if not firstname and not lastname and not image_key: + return + + path = os.path.join(BASE_PATH, 'chrome', '130-0008', 'chrome.exe') + with lock: + with sync_playwright() as playwright: + update_windows_distinguish() + browser = playwright.chromium.launch( + headless=False, args=['--start-maximized'], executable_path=path + # proxy=dove_proxy.get_playwright_proxy(get_storage(cookies, 'username')) + ) + context = browser.new_context(no_viewport=True) + context.add_init_script(path=os.path.join(BASE_PATH, 'stealth.min.js')) + context.add_cookies([ + {'name': k, 'value': v, 'domain': '.facebook.com', 'path': '/'} for k, v in cookies.items() + ]) + page = context.new_page() + url = 'https://www.facebook.com' + page.goto(url) + _change_language(page) + + url = 'https://accountscenter.facebook.com/?entry_point=app_settings' + page.goto(url) + page.locator('//div[@role="list"]/div').first.click() + + if firstname or lastname: + if firstname and lastname: + # 修改名称 + page.click('//a[@aria-label="Name"]') + page.locator('//input').first.fill(firstname) + page.locator('//input').last.fill(lastname) + page.locator('//div[@role="button"]').last.click() + page.click('//span[text()="Done"]') + else: + raise OperationFailed('名称中必须有First name和Last name') + + if image_key: + # 修改头像 + page.click('//a[@aria-label="Profile picture"]') + filename = image_key.split('/')[-1] + file_path = os.path.join(BASE_PATH, 'files', filename) + client.download_file(BUCKET, image_key, file_path) + sleep(1, 2) + with page.expect_file_chooser() as fc_info: + page.click('//div[text()="Upload new photo"]') + file_chooser = fc_info.value + file_chooser.set_files(file_path) + page.locator('//span[text()="Save"]').last.click() + time.sleep(5) + + context.close() + browser.close() + + +if __name__ == '__main__': + # cookies = { + # 'datr': 'gUM7ZgtRENjtL34mDqlmAhD6', + # 'sb': '3-jQZxmj3sGZwWeCljieq_X6', + # 'c_user': '61573941575877', + # 'locale': 'zh_CN', + # 'presence': 'C%7B%22t3%22%3A%5B%5D%2C%22utc3%22%3A1741745415451%2C%22v%22%3A1%7D', + # 'fr': '1I4dwdZF6jROteKRg.AWUKdna6hiEq5tAR7DMwI3ln8q49Km00-iVZzQ.Bn0PRY..AAA.0.0.Bn0PRY.AWVQ4Md7YN8', + # 'xs': '47%3AHNx1689XzRyiDw%3A2%3A1741745375%3A-1%3A-1%3A%3AAcUaomjGuSJlQilSly9moQfhEB9P1mqZn-p4NQvvUA', + # 'wd': '1728x411', + # } + cookies = { + 'datr': '4MXgZ3twsUMLaR7_yYPjboTs', + 'sb': '4MXgZ5AKdd6AiVqGy_N0-cpe', + 'locale': 'zh_CN', + 'presence': 'C{"t3":[],"utc3":1742784026639,"v":1}', + 'ps_n': '1', + 'wd': '1369x475', + 'c_user': '61574433449058', + 'fr': '04xfKMRdCsbtllhPA.AWUt-rPOi-ist5ZdVHl3jiYcKYM11xLu0MN9gA.Bn4MXg..AAA.0.0.Bn4MYY.AWWmAFxhQek', + 'xs': '6:he_0XMG7YzQPKQ:2:1742784022:-1:-1', + } + + # post(cookies, 'cs2025') + # like(cookies, 'ZmVlZGJhY2s6MTIyMTA5NjE0NjU0NzkzNzc5') + # comment(cookies, 'ZmVlZGJhY2s6MTIyMTA5NjE0NjU0NzkzNzc5', 'game la', 'facebook/xzpq.mp4') + # playwright_like(cookies, 'https://www.facebook.com/watch/?v=1007800324567828') + # playwright_post(cookies, '2025-3-26~like', 'face/rg.jpg') + # playwright_comment( + # cookies, + # # 'https://www.facebook.com/watch/?v=1603348023628396', + # # 'https://www.facebook.com/permalink.php?story_fbid=635052906055594&id=100086526695858', + # 'https://www.facebook.com/reel/3578555425778137', + # '2025-3-26~like', + # # 'face/rg.jpg' + # ) + # print(playwright_get_user_profile(cookies)) + # playwright_set_user_profile( + # cookies, + # firstname='Lisa', + # lastname='Keals', + # image_key='facebook/rg.jpg' + # ) diff --git a/stealth.min.js b/stealth.min.js new file mode 100644 index 0000000..81a436e --- /dev/null +++ b/stealth.min.js @@ -0,0 +1,7 @@ +/*! + * Note: Auto-generated, do not update manually. + * Generated by: https://github.com/berstend/puppeteer-extra/tree/master/packages/extract-stealth-evasions + * Generated on: Mon, 17 Mar 2025 06:25:04 GMT + * License: MIT + */ +(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(`at `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\n `at Object.${trap} `, // e.g. Object.get or Object.apply\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in `makeNativeString`\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // `toString` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // `toString` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> `canPlayType`\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple `navigator` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:'utils => {\n if (!window.chrome) {\n // Use the exact property descriptor found in headful Chrome\n // fetch it via `Object.getOwnPropertyDescriptor(window, \'chrome\')`\n Object.defineProperty(window, \'chrome\', {\n writable: true,\n enumerable: true,\n configurable: false, // note!\n value: {} // We\'ll extend that later\n })\n }\n\n // That means we\'re running headful and don\'t need to mock anything\n if (\'app\' in window.chrome) {\n return // Nothing to do here\n }\n\n const makeError = {\n ErrorInInvocation: fn => {\n const err = new TypeError(`Error in invocation of app.${fn}()`)\n return utils.stripErrorWithAnchor(\n err,\n `at ${fn} (eval at `\n )\n }\n }\n\n // There\'s a some static data in that property which doesn\'t seem to change,\n // we should periodically check for updates: `JSON.stringify(window.app, null, 2)`\n const STATIC_DATA = JSON.parse(\n `\n{\n "isInstalled": false,\n "InstallState": {\n "DISABLED": "disabled",\n "INSTALLED": "installed",\n "NOT_INSTALLED": "not_installed"\n },\n "RunningState": {\n "CANNOT_RUN": "cannot_run",\n "READY_TO_RUN": "ready_to_run",\n "RUNNING": "running"\n }\n}\n `.trim()\n )\n\n window.chrome.app = {\n ...STATIC_DATA,\n\n get isInstalled() {\n return false\n },\n\n getDetails: function getDetails() {\n if (arguments.length) {\n throw makeError.ErrorInInvocation(`getDetails`)\n }\n return null\n },\n getIsInstalled: function getDetails() {\n if (arguments.length) {\n throw makeError.ErrorInInvocation(`getIsInstalled`)\n }\n return false\n },\n runningState: function getDetails() {\n if (arguments.length) {\n throw makeError.ErrorInInvocation(`runningState`)\n }\n return \'cannot_run\'\n }\n }\n utils.patchToStringNested(window.chrome.app)\n }',_args:[]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(`at `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\n `at Object.${trap} `, // e.g. Object.get or Object.apply\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in `makeNativeString`\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // `toString` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // `toString` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> `canPlayType`\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple `navigator` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"utils => {\n if (!window.chrome) {\n // Use the exact property descriptor found in headful Chrome\n // fetch it via `Object.getOwnPropertyDescriptor(window, 'chrome')`\n Object.defineProperty(window, 'chrome', {\n writable: true,\n enumerable: true,\n configurable: false, // note!\n value: {} // We'll extend that later\n })\n }\n\n // That means we're running headful and don't need to mock anything\n if ('csi' in window.chrome) {\n return // Nothing to do here\n }\n\n // Check that the Navigation Timing API v1 is available, we need that\n if (!window.performance || !window.performance.timing) {\n return\n }\n\n const { timing } = window.performance\n\n window.chrome.csi = function() {\n return {\n onloadT: timing.domContentLoadedEventEnd,\n startE: timing.navigationStart,\n pageT: Date.now() - timing.navigationStart,\n tran: 15 // Transition type or something\n }\n }\n utils.patchToString(window.chrome.csi)\n }",_args:[]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(`at `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\n `at Object.${trap} `, // e.g. Object.get or Object.apply\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in `makeNativeString`\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // `toString` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // `toString` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> `canPlayType`\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple `navigator` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"(utils, { opts }) => {\n if (!window.chrome) {\n // Use the exact property descriptor found in headful Chrome\n // fetch it via `Object.getOwnPropertyDescriptor(window, 'chrome')`\n Object.defineProperty(window, 'chrome', {\n writable: true,\n enumerable: true,\n configurable: false, // note!\n value: {} // We'll extend that later\n })\n }\n\n // That means we're running headful and don't need to mock anything\n if ('loadTimes' in window.chrome) {\n return // Nothing to do here\n }\n\n // Check that the Navigation Timing API v1 + v2 is available, we need that\n if (\n !window.performance ||\n !window.performance.timing ||\n !window.PerformancePaintTiming\n ) {\n return\n }\n\n const { performance } = window\n\n // Some stuff is not available on about:blank as it requires a navigation to occur,\n // let's harden the code to not fail then:\n const ntEntryFallback = {\n nextHopProtocol: 'h2',\n type: 'other'\n }\n\n // The API exposes some funky info regarding the connection\n const protocolInfo = {\n get connectionInfo() {\n const ntEntry =\n performance.getEntriesByType('navigation')[0] || ntEntryFallback\n return ntEntry.nextHopProtocol\n },\n get npnNegotiatedProtocol() {\n // NPN is deprecated in favor of ALPN, but this implementation returns the\n // HTTP/2 or HTTP2+QUIC/39 requests negotiated via ALPN.\n const ntEntry =\n performance.getEntriesByType('navigation')[0] || ntEntryFallback\n return ['h2', 'hq'].includes(ntEntry.nextHopProtocol)\n ? ntEntry.nextHopProtocol\n : 'unknown'\n },\n get navigationType() {\n const ntEntry =\n performance.getEntriesByType('navigation')[0] || ntEntryFallback\n return ntEntry.type\n },\n get wasAlternateProtocolAvailable() {\n // The Alternate-Protocol header is deprecated in favor of Alt-Svc\n // (https://www.mnot.net/blog/2016/03/09/alt-svc), so technically this\n // should always return false.\n return false\n },\n get wasFetchedViaSpdy() {\n // SPDY is deprecated in favor of HTTP/2, but this implementation returns\n // true for HTTP/2 or HTTP2+QUIC/39 as well.\n const ntEntry =\n performance.getEntriesByType('navigation')[0] || ntEntryFallback\n return ['h2', 'hq'].includes(ntEntry.nextHopProtocol)\n },\n get wasNpnNegotiated() {\n // NPN is deprecated in favor of ALPN, but this implementation returns true\n // for HTTP/2 or HTTP2+QUIC/39 requests negotiated via ALPN.\n const ntEntry =\n performance.getEntriesByType('navigation')[0] || ntEntryFallback\n return ['h2', 'hq'].includes(ntEntry.nextHopProtocol)\n }\n }\n\n const { timing } = window.performance\n\n // Truncate number to specific number of decimals, most of the `loadTimes` stuff has 3\n function toFixed(num, fixed) {\n var re = new RegExp('^-?\\\\d+(?:.\\\\d{0,' + (fixed || -1) + '})?')\n return num.toString().match(re)[0]\n }\n\n const timingInfo = {\n get firstPaintAfterLoadTime() {\n // This was never actually implemented and always returns 0.\n return 0\n },\n get requestTime() {\n return timing.navigationStart / 1000\n },\n get startLoadTime() {\n return timing.navigationStart / 1000\n },\n get commitLoadTime() {\n return timing.responseStart / 1000\n },\n get finishDocumentLoadTime() {\n return timing.domContentLoadedEventEnd / 1000\n },\n get finishLoadTime() {\n return timing.loadEventEnd / 1000\n },\n get firstPaintTime() {\n const fpEntry = performance.getEntriesByType('paint')[0] || {\n startTime: timing.loadEventEnd / 1000 // Fallback if no navigation occured (`about:blank`)\n }\n return toFixed(\n (fpEntry.startTime + performance.timeOrigin) / 1000,\n 3\n )\n }\n }\n\n window.chrome.loadTimes = function() {\n return {\n ...protocolInfo,\n ...timingInfo\n }\n }\n utils.patchToString(window.chrome.loadTimes)\n }",_args:[{opts:{}}]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(`at `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\n `at Object.${trap} `, // e.g. Object.get or Object.apply\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in `makeNativeString`\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // `toString` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // `toString` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> `canPlayType`\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple `navigator` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"(utils, { opts, STATIC_DATA }) => {\n if (!window.chrome) {\n // Use the exact property descriptor found in headful Chrome\n // fetch it via `Object.getOwnPropertyDescriptor(window, 'chrome')`\n Object.defineProperty(window, 'chrome', {\n writable: true,\n enumerable: true,\n configurable: false, // note!\n value: {} // We'll extend that later\n })\n }\n\n // That means we're running headful and don't need to mock anything\n const existsAlready = 'runtime' in window.chrome\n // `chrome.runtime` is only exposed on secure origins\n const isNotSecure = !window.location.protocol.startsWith('https')\n if (existsAlready || (isNotSecure && !opts.runOnInsecureOrigins)) {\n return // Nothing to do here\n }\n\n window.chrome.runtime = {\n // There's a bunch of static data in that property which doesn't seem to change,\n // we should periodically check for updates: `JSON.stringify(window.chrome.runtime, null, 2)`\n ...STATIC_DATA,\n // `chrome.runtime.id` is extension related and returns undefined in Chrome\n get id() {\n return undefined\n },\n // These two require more sophisticated mocks\n connect: null,\n sendMessage: null\n }\n\n const makeCustomRuntimeErrors = (preamble, method, extensionId) => ({\n NoMatchingSignature: new TypeError(\n preamble + `No matching signature.`\n ),\n MustSpecifyExtensionID: new TypeError(\n preamble +\n `${method} called from a webpage must specify an Extension ID (string) for its first argument.`\n ),\n InvalidExtensionID: new TypeError(\n preamble + `Invalid extension id: '${extensionId}'`\n )\n })\n\n // Valid Extension IDs are 32 characters in length and use the letter `a` to `p`:\n // https://source.chromium.org/chromium/chromium/src/+/master:components/crx_file/id_util.cc;drc=14a055ccb17e8c8d5d437fe080faba4c6f07beac;l=90\n const isValidExtensionID = str =>\n str.length === 32 && str.toLowerCase().match(/^[a-p]+$/)\n\n /** Mock `chrome.runtime.sendMessage` */\n const sendMessageHandler = {\n apply: function(target, ctx, args) {\n const [extensionId, options, responseCallback] = args || []\n\n // Define custom errors\n const errorPreamble = `Error in invocation of runtime.sendMessage(optional string extensionId, any message, optional object options, optional function responseCallback): `\n const Errors = makeCustomRuntimeErrors(\n errorPreamble,\n `chrome.runtime.sendMessage()`,\n extensionId\n )\n\n // Check if the call signature looks ok\n const noArguments = args.length === 0\n const tooManyArguments = args.length > 4\n const incorrectOptions = options && typeof options !== 'object'\n const incorrectResponseCallback =\n responseCallback && typeof responseCallback !== 'function'\n if (\n noArguments ||\n tooManyArguments ||\n incorrectOptions ||\n incorrectResponseCallback\n ) {\n throw Errors.NoMatchingSignature\n }\n\n // At least 2 arguments are required before we even validate the extension ID\n if (args.length < 2) {\n throw Errors.MustSpecifyExtensionID\n }\n\n // Now let's make sure we got a string as extension ID\n if (typeof extensionId !== 'string') {\n throw Errors.NoMatchingSignature\n }\n\n if (!isValidExtensionID(extensionId)) {\n throw Errors.InvalidExtensionID\n }\n\n return undefined // Normal behavior\n }\n }\n utils.mockWithProxy(\n window.chrome.runtime,\n 'sendMessage',\n function sendMessage() {},\n sendMessageHandler\n )\n\n /**\n * Mock `chrome.runtime.connect`\n *\n * @see https://developer.chrome.com/apps/runtime#method-connect\n */\n const connectHandler = {\n apply: function(target, ctx, args) {\n const [extensionId, connectInfo] = args || []\n\n // Define custom errors\n const errorPreamble = `Error in invocation of runtime.connect(optional string extensionId, optional object connectInfo): `\n const Errors = makeCustomRuntimeErrors(\n errorPreamble,\n `chrome.runtime.connect()`,\n extensionId\n )\n\n // Behavior differs a bit from sendMessage:\n const noArguments = args.length === 0\n const emptyStringArgument = args.length === 1 && extensionId === ''\n if (noArguments || emptyStringArgument) {\n throw Errors.MustSpecifyExtensionID\n }\n\n const tooManyArguments = args.length > 2\n const incorrectConnectInfoType =\n connectInfo && typeof connectInfo !== 'object'\n\n if (tooManyArguments || incorrectConnectInfoType) {\n throw Errors.NoMatchingSignature\n }\n\n const extensionIdIsString = typeof extensionId === 'string'\n if (extensionIdIsString && extensionId === '') {\n throw Errors.MustSpecifyExtensionID\n }\n if (extensionIdIsString && !isValidExtensionID(extensionId)) {\n throw Errors.InvalidExtensionID\n }\n\n // There's another edge-case here: extensionId is optional so we might find a connectInfo object as first param, which we need to validate\n const validateConnectInfo = ci => {\n // More than a first param connectInfo as been provided\n if (args.length > 1) {\n throw Errors.NoMatchingSignature\n }\n // An empty connectInfo has been provided\n if (Object.keys(ci).length === 0) {\n throw Errors.MustSpecifyExtensionID\n }\n // Loop over all connectInfo props an check them\n Object.entries(ci).forEach(([k, v]) => {\n const isExpected = ['name', 'includeTlsChannelId'].includes(k)\n if (!isExpected) {\n throw new TypeError(\n errorPreamble + `Unexpected property: '${k}'.`\n )\n }\n const MismatchError = (propName, expected, found) =>\n TypeError(\n errorPreamble +\n `Error at property '${propName}': Invalid type: expected ${expected}, found ${found}.`\n )\n if (k === 'name' && typeof v !== 'string') {\n throw MismatchError(k, 'string', typeof v)\n }\n if (k === 'includeTlsChannelId' && typeof v !== 'boolean') {\n throw MismatchError(k, 'boolean', typeof v)\n }\n })\n }\n if (typeof extensionId === 'object') {\n validateConnectInfo(extensionId)\n throw Errors.MustSpecifyExtensionID\n }\n\n // Unfortunately even when the connect fails Chrome will return an object with methods we need to mock as well\n return utils.patchToStringNested(makeConnectResponse())\n }\n }\n utils.mockWithProxy(\n window.chrome.runtime,\n 'connect',\n function connect() {},\n connectHandler\n )\n\n function makeConnectResponse() {\n const onSomething = () => ({\n addListener: function addListener() {},\n dispatch: function dispatch() {},\n hasListener: function hasListener() {},\n hasListeners: function hasListeners() {\n return false\n },\n removeListener: function removeListener() {}\n })\n\n const response = {\n name: '',\n sender: undefined,\n disconnect: function disconnect() {},\n onDisconnect: onSomething(),\n onMessage: onSomething(),\n postMessage: function postMessage() {\n if (!arguments.length) {\n throw new TypeError(`Insufficient number of arguments.`)\n }\n throw new Error(`Attempting to use a disconnected port object`)\n }\n }\n return response\n }\n }",_args:[{opts:{runOnInsecureOrigins:!1},STATIC_DATA:{OnInstalledReason:{CHROME_UPDATE:"chrome_update",INSTALL:"install",SHARED_MODULE_UPDATE:"shared_module_update",UPDATE:"update"},OnRestartRequiredReason:{APP_UPDATE:"app_update",OS_UPDATE:"os_update",PERIODIC:"periodic"},PlatformArch:{ARM:"arm",ARM64:"arm64",MIPS:"mips",MIPS64:"mips64",X86_32:"x86-32",X86_64:"x86-64"},PlatformNaclArch:{ARM:"arm",MIPS:"mips",MIPS64:"mips64",X86_32:"x86-32",X86_64:"x86-64"},PlatformOs:{ANDROID:"android",CROS:"cros",LINUX:"linux",MAC:"mac",OPENBSD:"openbsd",WIN:"win"},RequestUpdateCheckStatus:{NO_UPDATE:"no_update",THROTTLED:"throttled",UPDATE_AVAILABLE:"update_available"}}}]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(`at `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\n `at Object.${trap} `, // e.g. Object.get or Object.apply\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in `makeNativeString`\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // `toString` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // `toString` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> `canPlayType`\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple `navigator` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"utils => {\n /**\n * Input might look funky, we need to normalize it so e.g. whitespace isn't an issue for our spoofing.\n *\n * @example\n * video/webm; codecs=\"vp8, vorbis\"\n * video/mp4; codecs=\"avc1.42E01E\"\n * audio/x-m4a;\n * audio/ogg; codecs=\"vorbis\"\n * @param {String} arg\n */\n const parseInput = arg => {\n const [mime, codecStr] = arg.trim().split(';')\n let codecs = []\n if (codecStr && codecStr.includes('codecs=\"')) {\n codecs = codecStr\n .trim()\n .replace(`codecs=\"`, '')\n .replace(`\"`, '')\n .trim()\n .split(',')\n .filter(x => !!x)\n .map(x => x.trim())\n }\n return {\n mime,\n codecStr,\n codecs\n }\n }\n\n const canPlayType = {\n // Intercept certain requests\n apply: function(target, ctx, args) {\n if (!args || !args.length) {\n return target.apply(ctx, args)\n }\n const { mime, codecs } = parseInput(args[0])\n // This specific mp4 codec is missing in Chromium\n if (mime === 'video/mp4') {\n if (codecs.includes('avc1.42E01E')) {\n return 'probably'\n }\n }\n // This mimetype is only supported if no codecs are specified\n if (mime === 'audio/x-m4a' && !codecs.length) {\n return 'maybe'\n }\n\n // This mimetype is only supported if no codecs are specified\n if (mime === 'audio/aac' && !codecs.length) {\n return 'probably'\n }\n // Everything else as usual\n return target.apply(ctx, args)\n }\n }\n\n /* global HTMLMediaElement */\n utils.replaceWithProxy(\n HTMLMediaElement.prototype,\n 'canPlayType',\n canPlayType\n )\n }",_args:[]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(`at `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\n `at Object.${trap} `, // e.g. Object.get or Object.apply\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in `makeNativeString`\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // `toString` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // `toString` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> `canPlayType`\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple `navigator` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"(utils, { opts }) => {\n utils.replaceGetterWithProxy(\n Object.getPrototypeOf(navigator),\n 'hardwareConcurrency',\n utils.makeHandler().getterValue(opts.hardwareConcurrency)\n )\n }",_args:[{opts:{hardwareConcurrency:4}}]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(`at `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\n `at Object.${trap} `, // e.g. Object.get or Object.apply\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in `makeNativeString`\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // `toString` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // `toString` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> `canPlayType`\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple `navigator` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"(utils, { opts }) => {\n const languages = opts.languages.length\n ? opts.languages\n : ['en-US', 'en']\n utils.replaceGetterWithProxy(\n Object.getPrototypeOf(navigator),\n 'languages',\n utils.makeHandler().getterValue(Object.freeze([...languages]))\n )\n }",_args:[{opts:{languages:[]}}]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(`at `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\n `at Object.${trap} `, // e.g. Object.get or Object.apply\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in `makeNativeString`\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // `toString` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // `toString` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> `canPlayType`\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple `navigator` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"(utils, opts) => {\n const isSecure = document.location.protocol.startsWith('https')\n\n // In headful on secure origins the permission should be \"default\", not \"denied\"\n if (isSecure) {\n utils.replaceGetterWithProxy(Notification, 'permission', {\n apply() {\n return 'default'\n }\n })\n }\n\n // Another weird behavior:\n // On insecure origins in headful the state is \"denied\",\n // whereas in headless it's \"prompt\"\n if (!isSecure) {\n const handler = {\n apply(target, ctx, args) {\n const param = (args || [])[0]\n\n const isNotifications =\n param && param.name && param.name === 'notifications'\n if (!isNotifications) {\n return utils.cache.Reflect.apply(...arguments)\n }\n\n return Promise.resolve(\n Object.setPrototypeOf(\n {\n state: 'denied',\n onchange: null\n },\n PermissionStatus.prototype\n )\n )\n }\n }\n // Note: Don't use `Object.getPrototypeOf` here\n utils.replaceWithProxy(Permissions.prototype, 'query', handler)\n }\n }",_args:[{}]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(`at `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\n `at Object.${trap} `, // e.g. Object.get or Object.apply\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in `makeNativeString`\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // `toString` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // `toString` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> `canPlayType`\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple `navigator` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"(utils, { fns, data }) => {\n fns = utils.materializeFns(fns)\n\n // That means we're running headful\n const hasPlugins = 'plugins' in navigator && navigator.plugins.length\n if (hasPlugins) {\n return // nothing to do here\n }\n\n const mimeTypes = fns.generateMimeTypeArray(utils, fns)(data.mimeTypes)\n const plugins = fns.generatePluginArray(utils, fns)(data.plugins)\n\n // Plugin and MimeType cross-reference each other, let's do that now\n // Note: We're looping through `data.plugins` here, not the generated `plugins`\n for (const pluginData of data.plugins) {\n pluginData.__mimeTypes.forEach((type, index) => {\n plugins[pluginData.name][index] = mimeTypes[type]\n\n Object.defineProperty(plugins[pluginData.name], type, {\n value: mimeTypes[type],\n writable: false,\n enumerable: false, // Not enumerable\n configurable: true\n })\n Object.defineProperty(mimeTypes[type], 'enabledPlugin', {\n value:\n type === 'application/x-pnacl'\n ? mimeTypes['application/x-nacl'].enabledPlugin // these reference the same plugin, so we need to re-use the Proxy in order to avoid leaks\n : new Proxy(plugins[pluginData.name], {}), // Prevent circular references\n writable: false,\n enumerable: false, // Important: `JSON.stringify(navigator.plugins)`\n configurable: true\n })\n })\n }\n\n const patchNavigator = (name, value) =>\n utils.replaceProperty(Object.getPrototypeOf(navigator), name, {\n get() {\n return value\n }\n })\n\n patchNavigator('mimeTypes', mimeTypes)\n patchNavigator('plugins', plugins)\n\n // All done\n }",_args:[{fns:{generateMimeTypeArray:"(utils, fns) => mimeTypesData => {\n return fns.generateMagicArray(utils, fns)(\n mimeTypesData,\n MimeTypeArray.prototype,\n MimeType.prototype,\n 'type'\n )\n}",generatePluginArray:"(utils, fns) => pluginsData => {\n return fns.generateMagicArray(utils, fns)(\n pluginsData,\n PluginArray.prototype,\n Plugin.prototype,\n 'name'\n )\n}",generateMagicArray:"(utils, fns) =>\n function(\n dataArray = [],\n proto = MimeTypeArray.prototype,\n itemProto = MimeType.prototype,\n itemMainProp = 'type'\n ) {\n // Quick helper to set props with the same descriptors vanilla is using\n const defineProp = (obj, prop, value) =>\n Object.defineProperty(obj, prop, {\n value,\n writable: false,\n enumerable: false, // Important for mimeTypes & plugins: `JSON.stringify(navigator.mimeTypes)`\n configurable: true\n })\n\n // Loop over our fake data and construct items\n const makeItem = data => {\n const item = {}\n for (const prop of Object.keys(data)) {\n if (prop.startsWith('__')) {\n continue\n }\n defineProp(item, prop, data[prop])\n }\n return patchItem(item, data)\n }\n\n const patchItem = (item, data) => {\n let descriptor = Object.getOwnPropertyDescriptors(item)\n\n // Special case: Plugins have a magic length property which is not enumerable\n // e.g. `navigator.plugins[i].length` should always be the length of the assigned mimeTypes\n if (itemProto === Plugin.prototype) {\n descriptor = {\n ...descriptor,\n length: {\n value: data.__mimeTypes.length,\n writable: false,\n enumerable: false,\n configurable: true // Important to be able to use the ownKeys trap in a Proxy to strip `length`\n }\n }\n }\n\n // We need to spoof a specific `MimeType` or `Plugin` object\n const obj = Object.create(itemProto, descriptor)\n\n // Virtually all property keys are not enumerable in vanilla\n const blacklist = [...Object.keys(data), 'length', 'enabledPlugin']\n return new Proxy(obj, {\n ownKeys(target) {\n return Reflect.ownKeys(target).filter(k => !blacklist.includes(k))\n },\n getOwnPropertyDescriptor(target, prop) {\n if (blacklist.includes(prop)) {\n return undefined\n }\n return Reflect.getOwnPropertyDescriptor(target, prop)\n }\n })\n }\n\n const magicArray = []\n\n // Loop through our fake data and use that to create convincing entities\n dataArray.forEach(data => {\n magicArray.push(makeItem(data))\n })\n\n // Add direct property access based on types (e.g. `obj['application/pdf']`) afterwards\n magicArray.forEach(entry => {\n defineProp(magicArray, entry[itemMainProp], entry)\n })\n\n // This is the best way to fake the type to make sure this is false: `Array.isArray(navigator.mimeTypes)`\n const magicArrayObj = Object.create(proto, {\n ...Object.getOwnPropertyDescriptors(magicArray),\n\n // There's one ugly quirk we unfortunately need to take care of:\n // The `MimeTypeArray` prototype has an enumerable `length` property,\n // but headful Chrome will still skip it when running `Object.getOwnPropertyNames(navigator.mimeTypes)`.\n // To strip it we need to make it first `configurable` and can then overlay a Proxy with an `ownKeys` trap.\n length: {\n value: magicArray.length,\n writable: false,\n enumerable: false,\n configurable: true // Important to be able to use the ownKeys trap in a Proxy to strip `length`\n }\n })\n\n // Generate our functional function mocks :-)\n const functionMocks = fns.generateFunctionMocks(utils)(\n proto,\n itemMainProp,\n magicArray\n )\n\n // We need to overlay our custom object with a JS Proxy\n const magicArrayObjProxy = new Proxy(magicArrayObj, {\n get(target, key = '') {\n // Redirect function calls to our custom proxied versions mocking the vanilla behavior\n if (key === 'item') {\n return functionMocks.item\n }\n if (key === 'namedItem') {\n return functionMocks.namedItem\n }\n if (proto === PluginArray.prototype && key === 'refresh') {\n return functionMocks.refresh\n }\n // Everything else can pass through as normal\n return utils.cache.Reflect.get(...arguments)\n },\n ownKeys(target) {\n // There are a couple of quirks where the original property demonstrates \"magical\" behavior that makes no sense\n // This can be witnessed when calling `Object.getOwnPropertyNames(navigator.mimeTypes)` and the absense of `length`\n // My guess is that it has to do with the recent change of not allowing data enumeration and this being implemented weirdly\n // For that reason we just completely fake the available property names based on our data to match what regular Chrome is doing\n // Specific issues when not patching this: `length` property is available, direct `types` props (e.g. `obj['application/pdf']`) are missing\n const keys = []\n const typeProps = magicArray.map(mt => mt[itemMainProp])\n typeProps.forEach((_, i) => keys.push(`${i}`))\n typeProps.forEach(propName => keys.push(propName))\n return keys\n },\n getOwnPropertyDescriptor(target, prop) {\n if (prop === 'length') {\n return undefined\n }\n return Reflect.getOwnPropertyDescriptor(target, prop)\n }\n })\n\n return magicArrayObjProxy\n }",generateFunctionMocks:"utils => (\n proto,\n itemMainProp,\n dataArray\n) => ({\n /** Returns the MimeType object with the specified index. */\n item: utils.createProxy(proto.item, {\n apply(target, ctx, args) {\n if (!args.length) {\n throw new TypeError(\n `Failed to execute 'item' on '${\n proto[Symbol.toStringTag]\n }': 1 argument required, but only 0 present.`\n )\n }\n // Special behavior alert:\n // - Vanilla tries to cast strings to Numbers (only integers!) and use them as property index lookup\n // - If anything else than an integer (including as string) is provided it will return the first entry\n const isInteger = args[0] && Number.isInteger(Number(args[0])) // Cast potential string to number first, then check for integer\n // Note: Vanilla never returns `undefined`\n return (isInteger ? dataArray[Number(args[0])] : dataArray[0]) || null\n }\n }),\n /** Returns the MimeType object with the specified name. */\n namedItem: utils.createProxy(proto.namedItem, {\n apply(target, ctx, args) {\n if (!args.length) {\n throw new TypeError(\n `Failed to execute 'namedItem' on '${\n proto[Symbol.toStringTag]\n }': 1 argument required, but only 0 present.`\n )\n }\n return dataArray.find(mt => mt[itemMainProp] === args[0]) || null // Not `undefined`!\n }\n }),\n /** Does nothing and shall return nothing */\n refresh: proto.refresh\n ? utils.createProxy(proto.refresh, {\n apply(target, ctx, args) {\n return undefined\n }\n })\n : undefined\n})"},data:{mimeTypes:[{type:"application/pdf",suffixes:"pdf",description:"",__pluginName:"Chrome PDF Viewer"},{type:"application/x-google-chrome-pdf",suffixes:"pdf",description:"Portable Document Format",__pluginName:"Chrome PDF Plugin"},{type:"application/x-nacl",suffixes:"",description:"Native Client Executable",__pluginName:"Native Client"},{type:"application/x-pnacl",suffixes:"",description:"Portable Native Client Executable",__pluginName:"Native Client"}],plugins:[{name:"Chrome PDF Plugin",filename:"internal-pdf-viewer",description:"Portable Document Format",__mimeTypes:["application/x-google-chrome-pdf"]},{name:"Chrome PDF Viewer",filename:"mhjfbmdgcfjbbpaeojofohoefgiehjai",description:"",__mimeTypes:["application/pdf"]},{name:"Native Client",filename:"internal-nacl-plugin",description:"",__mimeTypes:["application/x-nacl","application/x-pnacl"]}]}}]}),!1===navigator.webdriver||void 0===navigator.webdriver||delete Object.getPrototypeOf(navigator).webdriver,(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(`at `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\n `at Object.${trap} `, // e.g. Object.get or Object.apply\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in `makeNativeString`\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // `toString` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // `toString` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> `canPlayType`\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple `navigator` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"(utils, opts) => {\n const getParameterProxyHandler = {\n apply: function(target, ctx, args) {\n const param = (args || [])[0]\n const result = utils.cache.Reflect.apply(target, ctx, args)\n // UNMASKED_VENDOR_WEBGL\n if (param === 37445) {\n return opts.vendor || 'Intel Inc.' // default in headless: Google Inc.\n }\n // UNMASKED_RENDERER_WEBGL\n if (param === 37446) {\n return opts.renderer || 'Intel Iris OpenGL Engine' // default in headless: Google SwiftShader\n }\n return result\n }\n }\n\n // There's more than one WebGL rendering context\n // https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext#Browser_compatibility\n // To find out the original values here: Object.getOwnPropertyDescriptors(WebGLRenderingContext.prototype.getParameter)\n const addProxy = (obj, propName) => {\n utils.replaceWithProxy(obj, propName, getParameterProxyHandler)\n }\n // For whatever weird reason loops don't play nice with Object.defineProperty, here's the next best thing:\n addProxy(WebGLRenderingContext.prototype, 'getParameter')\n addProxy(WebGL2RenderingContext.prototype, 'getParameter')\n }",_args:[{}]}),(()=>{try{if(window.outerWidth&&window.outerHeight)return;const n=85;window.outerWidth=window.innerWidth,window.outerHeight=window.innerHeight+n}catch(n){}})(),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(`at `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n `at Reflect.${trap} `, // e.g. Reflect.get or Reflect.apply\n `at Object.${trap} `, // e.g. Object.get or Object.apply\n `at Object.newHandler. [as ${trap}] ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || `at Object.newHandler. [as ${trap}] ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. `TypeError`)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in `makeNativeString`\n nativeToStringStr: Function.toString + '' // => `function toString() { [native code] }`\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // `toString` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. `HTMLMediaElement.prototype.canPlayType.toString + \"\"`\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // `toString` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> `HTMLMediaElement.prototype`\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> `canPlayType`\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(`() => ${value}`)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple `navigator` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like `navigator.__proto__.vendor` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"(utils, opts) => {\n try {\n // Adds a contentWindow proxy to the provided iframe element\n const addContentWindowProxy = iframe => {\n const contentWindowProxy = {\n get(target, key) {\n // Now to the interesting part:\n // We actually make this thing behave like a regular iframe window,\n // by intercepting calls to e.g. `.self` and redirect it to the correct thing. :)\n // That makes it possible for these assertions to be correct:\n // iframe.contentWindow.self === window.top // must be false\n if (key === 'self') {\n return this\n }\n // iframe.contentWindow.frameElement === iframe // must be true\n if (key === 'frameElement') {\n return iframe\n }\n // Intercept iframe.contentWindow[0] to hide the property 0 added by the proxy.\n if (key === '0') {\n return undefined\n }\n return Reflect.get(target, key)\n }\n }\n\n if (!iframe.contentWindow) {\n const proxy = new Proxy(window, contentWindowProxy)\n Object.defineProperty(iframe, 'contentWindow', {\n get() {\n return proxy\n },\n set(newValue) {\n return newValue // contentWindow is immutable\n },\n enumerable: true,\n configurable: false\n })\n }\n }\n\n // Handles iframe element creation, augments `srcdoc` property so we can intercept further\n const handleIframeCreation = (target, thisArg, args) => {\n const iframe = target.apply(thisArg, args)\n\n // We need to keep the originals around\n const _iframe = iframe\n const _srcdoc = _iframe.srcdoc\n\n // Add hook for the srcdoc property\n // We need to be very surgical here to not break other iframes by accident\n Object.defineProperty(iframe, 'srcdoc', {\n configurable: true, // Important, so we can reset this later\n get: function() {\n return _srcdoc\n },\n set: function(newValue) {\n addContentWindowProxy(this)\n // Reset property, the hook is only needed once\n Object.defineProperty(iframe, 'srcdoc', {\n configurable: false,\n writable: false,\n value: _srcdoc\n })\n _iframe.srcdoc = newValue\n }\n })\n return iframe\n }\n\n // Adds a hook to intercept iframe creation events\n const addIframeCreationSniffer = () => {\n /* global document */\n const createElementHandler = {\n // Make toString() native\n get(target, key) {\n return Reflect.get(target, key)\n },\n apply: function(target, thisArg, args) {\n const isIframe =\n args && args.length && `${args[0]}`.toLowerCase() === 'iframe'\n if (!isIframe) {\n // Everything as usual\n return target.apply(thisArg, args)\n } else {\n return handleIframeCreation(target, thisArg, args)\n }\n }\n }\n // All this just due to iframes with srcdoc bug\n utils.replaceWithProxy(\n document,\n 'createElement',\n createElementHandler\n )\n }\n\n // Let's go\n addIframeCreationSniffer()\n } catch (err) {\n // console.warn(err)\n }\n }",_args:[]}); \ No newline at end of file diff --git a/uclouds3.py b/uclouds3.py new file mode 100644 index 0000000..f89b235 --- /dev/null +++ b/uclouds3.py @@ -0,0 +1,55 @@ +from io import BytesIO + +from ufile import filemanager, config, httprequest +from const import PUBLIC_KEY, PRIVATE_KEY, UPLOAD_SUFFIX, DOWNLOAD_SUFFIX + + +def _download_file_save_to_bio(url, header): + try: + response = httprequest.requests.get(url, headers=header, stream=True) + except httprequest.RequestException as e: + return None, httprequest.ResponseInfo(None, e) + if response.status_code in [200, 206]: + bio = BytesIO() + for block in response.iter_content(config.BLOCKSIZE): + bio.write(block) + else: + return + return bio + + +class BioFileManager(filemanager.FileManager): + def download_bytes_file(self, bucket, key, isprivate=True, expires=None, content_range=None, header=None): + """ + :param bucket: string类型, UFile空间名称 + :param key: string类型, 下载文件在空间中的名称 + :param isprivate: boolean类型,如果为私有空间则为True + :param expires: integer类型,私有文件链接有效时间 + :param content_range: tuple类型,元素为两个整型 + :param header: dict类型,http 请求header,键值对类型分别为string,比如{'User-Agent': 'Google Chrome'} + :return: ret: 如果http状态码为[200, 204, 206]之一则返回None,否则如果服务器返回json信息则返回dict类型,键值对类型分别为string, unicode string类型,否则返回空的dict + :return: ResponseInfo: 响应的具体信息,UCloud UFile 服务器返回信息或者网络链接异常 + """ + if header is None: + header = dict() + else: + filemanager._check_dict(header) + + if expires is None: + expires = config.get_default('expires') + + if 'User-Agent' not in header: + header['User-Agent'] = config.get_default('user_agent') + + if isinstance(content_range, tuple) and len(content_range) == 2: + header['Range'] = 'bytes=' + '-'.join(map(lambda x: str(x), content_range)) + + if not isprivate: + url = self.public_download_url(bucket, key) + else: + url = self.private_download_url(bucket, key, expires, header, True) + + return _download_file_save_to_bio(url, header) + + +client = BioFileManager(PUBLIC_KEY, PRIVATE_KEY, UPLOAD_SUFFIX, DOWNLOAD_SUFFIX)