diff --git a/app/src/main/java/com/duckduckgo/app/browser/RealWebViewCapabilityChecker.kt b/app/src/main/java/com/duckduckgo/app/browser/RealWebViewCapabilityChecker.kt index 0e4e74e89521..4d2314a377fd 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/RealWebViewCapabilityChecker.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/RealWebViewCapabilityChecker.kt @@ -24,12 +24,12 @@ import com.duckduckgo.app.browser.api.WebViewCapabilityChecker.WebViewCapability import com.duckduckgo.browser.api.WebViewVersionProvider import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.common.utils.extensions.compareSemanticVersion -import com.duckduckgo.di.scopes.FragmentScope +import com.duckduckgo.di.scopes.AppScope import com.squareup.anvil.annotations.ContributesBinding import javax.inject.Inject import kotlinx.coroutines.withContext -@ContributesBinding(FragmentScope::class) +@ContributesBinding(AppScope::class) class RealWebViewCapabilityChecker @Inject constructor( private val dispatchers: DispatcherProvider, private val webViewVersionProvider: WebViewVersionProvider, diff --git a/app/src/main/java/com/duckduckgo/app/browser/WebViewSafeMessageListening.kt b/app/src/main/java/com/duckduckgo/app/browser/WebViewSafeMessageListening.kt deleted file mode 100644 index d614b3167088..000000000000 --- a/app/src/main/java/com/duckduckgo/app/browser/WebViewSafeMessageListening.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2024 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.app.browser - -import androidx.webkit.WebViewFeature -import com.duckduckgo.browser.api.WebViewMessageListening -import com.duckduckgo.browser.api.WebViewVersionProvider -import com.duckduckgo.common.utils.DispatcherProvider -import com.duckduckgo.common.utils.extensions.compareSemanticVersion -import com.duckduckgo.di.scopes.AppScope -import com.squareup.anvil.annotations.ContributesBinding -import javax.inject.Inject -import kotlinx.coroutines.withContext - -@ContributesBinding(AppScope::class) -class WebViewSafeMessageListening @Inject constructor( - private val dispatchers: DispatcherProvider, - private val webViewVersionProvider: WebViewVersionProvider, -) : WebViewMessageListening { - - override suspend fun isWebMessageListenerSupported(): Boolean { - return withContext(dispatchers.io()) { - webViewVersionProvider.getFullVersion().compareSemanticVersion(WEB_MESSAGE_LISTENER_WEBVIEW_VERSION)?.let { - it >= 0 - } ?: false - } && WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER) - } - - companion object { - private const val WEB_MESSAGE_LISTENER_WEBVIEW_VERSION = "126.0.6478.40" - } -} diff --git a/autofill/autofill-api/src/main/java/com/duckduckgo/autofill/api/AutofillScreens.kt b/autofill/autofill-api/src/main/java/com/duckduckgo/autofill/api/AutofillScreens.kt index ff119db2c586..b600554a3f76 100644 --- a/autofill/autofill-api/src/main/java/com/duckduckgo/autofill/api/AutofillScreens.kt +++ b/autofill/autofill-api/src/main/java/com/duckduckgo/autofill/api/AutofillScreens.kt @@ -16,10 +16,8 @@ package com.duckduckgo.autofill.api -import android.os.Parcelable import com.duckduckgo.autofill.api.domain.app.LoginCredentials import com.duckduckgo.navigation.api.GlobalActivityStarter.ActivityParams -import kotlinx.parcelize.Parcelize sealed interface AutofillScreens { @@ -50,29 +48,6 @@ sealed interface AutofillScreens { val loginCredentials: LoginCredentials, val source: AutofillSettingsLaunchSource, ) : ActivityParams - - object ImportGooglePassword { - data object AutofillImportViaGooglePasswordManagerScreen : ActivityParams { - private fun readResolve(): Any = AutofillImportViaGooglePasswordManagerScreen - } - - sealed interface Result : Parcelable { - - companion object { - const val RESULT_KEY = "importResult" - const val RESULT_KEY_DETAILS = "importResultDetails" - } - - @Parcelize - data class Success(val importedCount: Int) : Result - - @Parcelize - data class UserCancelled(val stage: String) : Result - - @Parcelize - data object Error : Result - } - } } enum class AutofillSettingsLaunchSource { diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/blob/WebViewBlobDownloader.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/blob/WebViewBlobDownloader.kt new file mode 100644 index 000000000000..a0a9a025c833 --- /dev/null +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/blob/WebViewBlobDownloader.kt @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2024 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.autofill.impl.importing.blob + +import android.annotation.SuppressLint +import android.net.Uri +import android.webkit.WebView +import androidx.webkit.JavaScriptReplyProxy +import androidx.webkit.WebViewCompat +import com.duckduckgo.app.browser.api.WebViewCapabilityChecker +import com.duckduckgo.app.browser.api.WebViewCapabilityChecker.WebViewCapability +import com.duckduckgo.di.scopes.AppScope +import com.squareup.anvil.annotations.ContributesBinding +import javax.inject.Inject + +/** + * This interface provides the ability to add modern blob download support to a WebView. + */ +interface WebViewBlobDownloader { + + /** + * Configures a web view to support blob downloads, including in iframes. + */ + suspend fun addBlobDownloadSupport(webView: WebView) + + /** + * Requests the WebView to convert a blob URL to a data URI. + */ + suspend fun convertBlobToDataUri(blobUrl: String) + + /** + * Stores a reply proxy for a given location. + */ + suspend fun storeReplyProxy( + originUrl: String, + replyProxy: JavaScriptReplyProxy, + locationHref: String?, + ) + + /** + * Clears any stored JavaScript reply proxies. + */ + fun clearReplyProxies() +} + +@ContributesBinding(AppScope::class) +class WebViewBlobDownloaderModernImpl @Inject constructor( + private val webViewCapabilityChecker: WebViewCapabilityChecker, +) : WebViewBlobDownloader { + + // Map>() = Map>() + private val fixedReplyProxyMap = mutableMapOf>() + + @SuppressLint("RequiresFeature") + override suspend fun addBlobDownloadSupport(webView: WebView) { + if (isBlobDownloadWebViewFeatureEnabled()) { + WebViewCompat.addDocumentStartJavaScript(webView, script, setOf("*")) + } + } + + @SuppressLint("RequiresFeature") + override suspend fun convertBlobToDataUri(blobUrl: String) { + for ((key, proxies) in fixedReplyProxyMap) { + if (sameOrigin(blobUrl.removePrefix("blob:"), key)) { + for (replyProxy in proxies.values) { + replyProxy.postMessage(blobUrl) + } + return + } + } + } + + override suspend fun storeReplyProxy( + originUrl: String, + replyProxy: JavaScriptReplyProxy, + locationHref: String?, + ) { + val frameProxies = fixedReplyProxyMap[originUrl]?.toMutableMap() ?: mutableMapOf() + // if location.href is not passed, we fall back to origin + val safeLocationHref = locationHref ?: originUrl + frameProxies[safeLocationHref] = replyProxy + fixedReplyProxyMap[originUrl] = frameProxies + } + + private fun sameOrigin( + firstUrl: String, + secondUrl: String, + ): Boolean { + return kotlin.runCatching { + val firstUri = Uri.parse(firstUrl) + val secondUri = Uri.parse(secondUrl) + + firstUri.host == secondUri.host && firstUri.scheme == secondUri.scheme && firstUri.port == secondUri.port + }.getOrNull() ?: return false + } + + override fun clearReplyProxies() { + fixedReplyProxyMap.clear() + } + + private suspend fun isBlobDownloadWebViewFeatureEnabled(): Boolean { + return webViewCapabilityChecker.isSupported(WebViewCapability.WebMessageListener) && + webViewCapabilityChecker.isSupported(WebViewCapability.DocumentStartJavaScript) + } + + companion object { + private val script = """ + window.__url_to_blob_collection = {}; + + const original_createObjectURL = URL.createObjectURL; + + URL.createObjectURL = function () { + const blob = arguments[0]; + const url = original_createObjectURL.call(this, ...arguments); + if (blob instanceof Blob) { + __url_to_blob_collection[url] = blob; + } + return url; + } + + function blobToBase64DataUrl(blob) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onloadend = function() { + resolve(reader.result); + } + reader.onerror = function() { + reject(new Error('Failed to read Blob object')); + } + reader.readAsDataURL(blob); + }); + } + + const pingMessage = 'Ping:' + window.location.href + ddgBlobDownloadObj.postMessage(pingMessage) + + ddgBlobDownloadObj.onmessage = function(event) { + if (event.data.startsWith('blob:')) { + const blob = window.__url_to_blob_collection[event.data]; + if (blob) { + blobToBase64DataUrl(blob).then((dataUrl) => { + ddgBlobDownloadObj.postMessage(dataUrl); + }); + } + } + } + """.trimIndent() + } +} diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordBlobConsumer.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordBlobConsumer.kt index 0dd3a250ae6d..089dfbdc13c8 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordBlobConsumer.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordBlobConsumer.kt @@ -23,8 +23,8 @@ import androidx.webkit.JavaScriptReplyProxy import androidx.webkit.WebMessageCompat import androidx.webkit.WebViewCompat import com.duckduckgo.app.di.AppCoroutineScope +import com.duckduckgo.autofill.impl.importing.blob.WebViewBlobDownloader import com.duckduckgo.autofill.impl.importing.gpm.webflow.GooglePasswordBlobConsumer.Callback -import com.duckduckgo.browser.api.WebViewMessageListening import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.di.scopes.FragmentScope import com.squareup.anvil.annotations.ContributesBinding @@ -50,23 +50,19 @@ interface GooglePasswordBlobConsumer { @ContributesBinding(FragmentScope::class) class ImportGooglePasswordBlobConsumer @Inject constructor( + private val webViewBlobDownloader: WebViewBlobDownloader, private val dispatchers: DispatcherProvider, - private val webViewMessageListening: WebViewMessageListening, @AppCoroutineScope private val appCoroutineScope: CoroutineScope, ) : GooglePasswordBlobConsumer { - private val replyProxyMap = mutableMapOf() - - // Map>() = Map>() - private val fixedReplyProxyMap = mutableMapOf>() - @SuppressLint("RequiresFeature") override suspend fun configureWebViewForBlobDownload( webView: WebView, callback: Callback, ) { withContext(dispatchers.main()) { - WebViewCompat.addDocumentStartJavaScript(webView, blobDownloadScript(), setOf("*")) + webViewBlobDownloader.addBlobDownloadSupport(webView) + WebViewCompat.addWebMessageListener( webView, "ddgBlobDownloadObj", @@ -93,108 +89,11 @@ class ImportGooglePasswordBlobConsumer @Inject constructor( }.onFailure { callback.onCsvError() } } else if (message.data?.startsWith("Ping:") == true) { val locationRef = message.data.toString().encode().md5().toString() - saveReplyProxyForBlobDownload(sourceOrigin.toString(), replyProxy, locationRef) - } - } - - private suspend fun saveReplyProxyForBlobDownload( - originUrl: String, - replyProxy: JavaScriptReplyProxy, - locationHref: String? = null, - ) { - withContext(dispatchers.io()) { // FF check has disk IO - if (true) { - // if (webViewBlobDownloadFeature.fixBlobDownloadWithIframes().isEnabled()) { - val frameProxies = fixedReplyProxyMap[originUrl]?.toMutableMap() ?: mutableMapOf() - // if location.href is not passed, we fall back to origin - val safeLocationHref = locationHref ?: originUrl - frameProxies[safeLocationHref] = replyProxy - fixedReplyProxyMap[originUrl] = frameProxies - } else { - replyProxyMap[originUrl] = replyProxy - } + webViewBlobDownloader.storeReplyProxy(sourceOrigin.toString(), replyProxy, locationRef) } } - @SuppressLint("RequiresFeature") // it's already checked in isBlobDownloadWebViewFeatureEnabled override suspend fun postMessageToConvertBlobToDataUri(url: String) { - withContext(dispatchers.main()) { // main because postMessage is not always safe in another thread - if (true) { - // if (withContext(dispatchers.io()) { webViewBlobDownloadFeature.fixBlobDownloadWithIframes().isEnabled() }) { - for ((key, proxies) in fixedReplyProxyMap) { - if (sameOrigin(url.removePrefix("blob:"), key)) { - for (replyProxy in proxies.values) { - replyProxy.postMessage(url) - } - return@withContext - } - } - } else { - for ((key, value) in replyProxyMap) { - if (sameOrigin(url.removePrefix("blob:"), key)) { - value.postMessage(url) - return@withContext - } - } - } - } - } - - private fun sameOrigin( - firstUrl: String, - secondUrl: String, - ): Boolean { - return kotlin.runCatching { - val firstUri = Uri.parse(firstUrl) - val secondUri = Uri.parse(secondUrl) - - firstUri.host == secondUri.host && firstUri.scheme == secondUri.scheme && firstUri.port == secondUri.port - }.getOrNull() ?: return false - } - - private fun blobDownloadScript(): String { - val script = """ - window.__url_to_blob_collection = {}; - - const original_createObjectURL = URL.createObjectURL; - - URL.createObjectURL = function () { - const blob = arguments[0]; - const url = original_createObjectURL.call(this, ...arguments); - if (blob instanceof Blob) { - __url_to_blob_collection[url] = blob; - } - return url; - } - - function blobToBase64DataUrl(blob) { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onloadend = function() { - resolve(reader.result); - } - reader.onerror = function() { - reject(new Error('Failed to read Blob object')); - } - reader.readAsDataURL(blob); - }); - } - - const pingMessage = 'Ping:' + window.location.href - ddgBlobDownloadObj.postMessage(pingMessage) - - ddgBlobDownloadObj.onmessage = function(event) { - if (event.data.startsWith('blob:')) { - const blob = window.__url_to_blob_collection[event.data]; - if (blob) { - blobToBase64DataUrl(blob).then((dataUrl) => { - ddgBlobDownloadObj.postMessage(dataUrl); - }); - } - } - } - """.trimIndent() - - return script + webViewBlobDownloader.convertBlobToDataUri(url) } } diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordResult.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordResult.kt new file mode 100644 index 000000000000..eaed74028443 --- /dev/null +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordResult.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.autofill.impl.importing.gpm.webflow + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +sealed interface ImportGooglePasswordResult : Parcelable { + + @Parcelize + data class Success(val importedCount: Int, val foundInImport: Int, val importJobId: String) : ImportGooglePasswordResult + + @Parcelize + data class UserCancelled(val stage: String) : ImportGooglePasswordResult + + @Parcelize + data object Error : ImportGooglePasswordResult + + companion object { + const val RESULT_KEY = "importResult" + const val RESULT_KEY_DETAILS = "importResultDetails" + } +} diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordsWebFlowActivity.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordsWebFlowActivity.kt index a5ca8ee8a6cb..97838bcddec1 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordsWebFlowActivity.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordsWebFlowActivity.kt @@ -21,15 +21,16 @@ import android.os.Bundle import androidx.fragment.app.commit import com.duckduckgo.anvil.annotations.ContributeToActivityStarter import com.duckduckgo.anvil.annotations.InjectWith -import com.duckduckgo.autofill.api.AutofillScreens.ImportGooglePassword.AutofillImportViaGooglePasswordManagerScreen -import com.duckduckgo.autofill.api.AutofillScreens.ImportGooglePassword.Result.Companion.RESULT_KEY -import com.duckduckgo.autofill.api.AutofillScreens.ImportGooglePassword.Result.Companion.RESULT_KEY_DETAILS -import com.duckduckgo.autofill.api.AutofillScreens.ImportGooglePassword.Result.UserCancelled import com.duckduckgo.autofill.impl.R import com.duckduckgo.autofill.impl.databinding.ActivityImportGooglePasswordsWebflowBinding +import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePassword.AutofillImportViaGooglePasswordManagerScreen +import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordResult.Companion.RESULT_KEY +import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordResult.Companion.RESULT_KEY_DETAILS +import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordResult.UserCancelled import com.duckduckgo.common.ui.DuckDuckGoActivity import com.duckduckgo.common.ui.viewbinding.viewBinding import com.duckduckgo.di.scopes.ActivityScope +import com.duckduckgo.navigation.api.GlobalActivityStarter.ActivityParams @InjectWith(ActivityScope::class) @ContributeToActivityStarter(AutofillImportViaGooglePasswordManagerScreen::class) @@ -68,3 +69,9 @@ class ImportGooglePasswordsWebFlowActivity : DuckDuckGoActivity() { exitWithResult(result) } } + +object ImportGooglePassword { + data object AutofillImportViaGooglePasswordManagerScreen : ActivityParams { + private fun readResolve(): Any = AutofillImportViaGooglePasswordManagerScreen + } +} diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordsWebFlowFragment.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordsWebFlowFragment.kt index e6714f1316be..12c700d53051 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordsWebFlowFragment.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordsWebFlowFragment.kt @@ -17,9 +17,10 @@ package com.duckduckgo.autofill.impl.importing.gpm.webflow import android.annotation.SuppressLint -import android.content.Intent import android.os.Bundle +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.webkit.WebSettings import android.webkit.WebView import androidx.activity.OnBackPressedCallback @@ -35,27 +36,24 @@ import com.duckduckgo.anvil.annotations.InjectWith import com.duckduckgo.app.statistics.pixels.Pixel import com.duckduckgo.autofill.api.AutofillCapabilityChecker import com.duckduckgo.autofill.api.AutofillFragmentResultsPlugin -import com.duckduckgo.autofill.api.AutofillScreens.ImportGooglePassword.Result -import com.duckduckgo.autofill.api.AutofillScreens.ImportGooglePassword.Result.Companion.RESULT_KEY -import com.duckduckgo.autofill.api.AutofillScreens.ImportGooglePassword.Result.Companion.RESULT_KEY_DETAILS -import com.duckduckgo.autofill.api.AutofillWebMessageRequest import com.duckduckgo.autofill.api.BrowserAutofill import com.duckduckgo.autofill.api.CredentialAutofillDialogFactory import com.duckduckgo.autofill.api.domain.app.LoginCredentials import com.duckduckgo.autofill.api.domain.app.LoginTriggerType import com.duckduckgo.autofill.impl.R import com.duckduckgo.autofill.impl.databinding.FragmentImportGooglePasswordsWebflowBinding -import com.duckduckgo.autofill.impl.importing.CsvPasswordImporter -import com.duckduckgo.autofill.impl.importing.PasswordImporter +import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordResult.Companion.RESULT_KEY +import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordsWebFlowViewModel.ViewState.Initializing import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordsWebFlowViewModel.ViewState.NavigatingBack -import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordsWebFlowViewModel.ViewState.ShowingWebContent import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordsWebFlowViewModel.ViewState.UserCancelledImportFlow +import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordsWebFlowViewModel.ViewState.UserFinishedImportFlow import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordsWebFlowWebChromeClient.ProgressListener import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordsWebFlowWebViewClient.NewPageCallback -import com.duckduckgo.autofill.impl.importing.gpm.webflow.autofill.ImportGooglePasswordAutofillCallback -import com.duckduckgo.autofill.impl.importing.gpm.webflow.autofill.ImportGooglePasswordAutofillEventListener +import com.duckduckgo.autofill.impl.importing.gpm.webflow.autofill.NoOpAutofillCallback +import com.duckduckgo.autofill.impl.importing.gpm.webflow.autofill.NoOpAutofillEventListener +import com.duckduckgo.autofill.impl.importing.gpm.webflow.autofill.NoOpEmailProtectionInContextSignupFlowListener +import com.duckduckgo.autofill.impl.importing.gpm.webflow.autofill.NoOpEmailProtectionUserPromptListener import com.duckduckgo.common.ui.DuckDuckGoFragment -import com.duckduckgo.common.ui.viewbinding.viewBinding import com.duckduckgo.common.utils.ConflatedJob import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.common.utils.FragmentViewModelFactory @@ -72,8 +70,10 @@ class ImportGooglePasswordsWebFlowFragment : DuckDuckGoFragment(R.layout.fragment_import_google_passwords_webflow), ProgressListener, NewPageCallback, - ImportGooglePasswordAutofillEventListener, - ImportGooglePasswordAutofillCallback, + NoOpAutofillCallback, + NoOpEmailProtectionInContextSignupFlowListener, + NoOpEmailProtectionUserPromptListener, + NoOpAutofillEventListener, GooglePasswordBlobConsumer.Callback { @Inject @@ -107,18 +107,24 @@ class ImportGooglePasswordsWebFlowFragment : lateinit var passwordImporterScriptLoader: PasswordImporterScriptLoader @Inject - lateinit var csvPasswordImporter: CsvPasswordImporter + lateinit var browserAutofillConfigurator: BrowserAutofill.Configurator - @Inject - lateinit var passwordImporter: PasswordImporter + private val autofillConfigurationJob = ConflatedJob() - val viewModel by lazy { + private var binding: FragmentImportGooglePasswordsWebflowBinding? = null + + private val viewModel by lazy { ViewModelProvider(requireActivity(), viewModelFactory)[ImportGooglePasswordsWebFlowViewModel::class.java] } - private val autofillConfigurationJob = ConflatedJob() - - private val binding: FragmentImportGooglePasswordsWebflowBinding by viewBinding() + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View? { + binding = FragmentImportGooglePasswordsWebflowBinding.inflate(inflater, container, false) + return binding?.root + } override fun onViewCreated( view: View, @@ -129,16 +135,18 @@ class ImportGooglePasswordsWebFlowFragment : configureWebView() configureBackButtonHandler() observeViewState() - loadFirstWebpage(activity?.intent) + loadFirstWebpage() } - private fun loadFirstWebpage(intent: Intent?) { + override fun onDestroyView() { + super.onDestroyView() + binding = null + } + + private fun loadFirstWebpage() { lifecycleScope.launch(dispatchers.main()) { autofillConfigurationJob.join() - - binding.webView.loadUrl(STARTING_URL) - - viewModel.loadedStartingUrl() + binding?.webView?.loadUrl(STARTING_URL) } } @@ -147,14 +155,10 @@ class ImportGooglePasswordsWebFlowFragment : repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.viewState.collect { viewState -> when (viewState) { - // is ViewState.CancellingInContextSignUp -> cancelInContextSignUp() - // is ViewState.ConfirmingCancellationOfInContextSignUp -> confirmCancellationOfInContextSignUp() - // is ViewState.NavigatingBack -> navigateWebViewBack() - // is ViewState.ShowingWebContent -> showWebContent(viewState) - // is ViewState.ExitingAsSuccess -> closeActivityAsSuccessfulSignup() - is ShowingWebContent -> {} // TODO() + is UserFinishedImportFlow -> exitFlowAsSuccess(viewState.bundle) is UserCancelledImportFlow -> exitFlowAsCancellation(viewState.stage) - is NavigatingBack -> binding.webView.goBack() + is NavigatingBack -> binding?.webView?.goBack() + is Initializing -> {} } } } @@ -165,13 +169,17 @@ class ImportGooglePasswordsWebFlowFragment : (activity as ImportGooglePasswordsWebFlowActivity).exitUserCancelled(stage) } + private fun exitFlowAsSuccess(resultBundle: Bundle) { + setFragmentResult(RESULT_KEY, resultBundle) + } + private fun configureBackButtonHandler() { activity?.let { it.onBackPressedDispatcher.addCallback( it, object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { - viewModel.onBackButtonPressed(url = binding.webView.url, canGoBack = binding.webView.canGoBack()) + viewModel.onBackButtonPressed(url = binding?.webView?.url, canGoBack = binding?.webView?.canGoBack() ?: false) } }, ) @@ -182,7 +190,7 @@ class ImportGooglePasswordsWebFlowFragment : with(getToolbar()) { title = getString(R.string.autofillImportGooglePasswordsWebFlowTitle) setNavigationIconAsCross() - setNavigationOnClickListener { viewModel.onCloseButtonPressed(binding.webView.url) } + setNavigationOnClickListener { viewModel.onCloseButtonPressed(binding?.webView?.url) } } } @@ -190,10 +198,10 @@ class ImportGooglePasswordsWebFlowFragment : setNavigationIcon(com.duckduckgo.mobile.android.R.drawable.ic_close_24) } - @SuppressLint("SetJavaScriptEnabled", "RequiresFeature") + @SuppressLint("SetJavaScriptEnabled") private fun configureWebView() { Timber.i("cdr Configuring WebView") - binding.webView.let { webView -> + binding?.webView?.let { webView -> webView.webChromeClient = ImportGooglePasswordsWebFlowWebChromeClient(this) webView.webViewClient = ImportGooglePasswordsWebFlowWebViewClient(this) @@ -223,7 +231,13 @@ class ImportGooglePasswordsWebFlowFragment : private fun configureAutofill(it: WebView) { lifecycleScope.launch { - browserAutofill.addJsInterface(it, this@ImportGooglePasswordsWebFlowFragment, CUSTOM_FLOW_TAB_ID) + browserAutofill.addJsInterface( + it, + this@ImportGooglePasswordsWebFlowFragment, + this@ImportGooglePasswordsWebFlowFragment, + this@ImportGooglePasswordsWebFlowFragment, + CUSTOM_FLOW_TAB_ID, + ) } autofillFragmentResultListeners.getPlugins().forEach { plugin -> @@ -260,7 +274,10 @@ class ImportGooglePasswordsWebFlowFragment : private fun getToolbar() = (activity as ImportGooglePasswordsWebFlowActivity).binding.includeToolbar.toolbar override fun onPageStarted(url: String?) { - viewModel.onPageStarted(url) + binding?.let { + browserAutofillConfigurator.configureAutofillForCurrentPage(it.webView, url) + viewModel.onPageStarted(url) + } } override fun onPageFinished(url: String?) { @@ -268,20 +285,20 @@ class ImportGooglePasswordsWebFlowFragment : } override suspend fun onCredentialsAvailableToInject( - autofillWebMessageRequest: AutofillWebMessageRequest, + originalUrl: String, credentials: List, triggerType: LoginTriggerType, ) { Timber.i("cdr Credentials available to autofill (%d creds available)", credentials.size) withContext(dispatchers.main()) { - val url = binding.webView.url ?: return@withContext - if (url != autofillWebMessageRequest.originalPageUrl) { + val url = binding?.webView?.url ?: return@withContext + if (url != originalUrl) { Timber.w("WebView url has changed since autofill request; bailing") return@withContext } val dialog = credentialAutofillDialogFactory.autofillSelectCredentialsDialog( - autofillWebMessageRequest, + url, credentials, triggerType, CUSTOM_FLOW_TAB_ID, @@ -291,22 +308,30 @@ class ImportGooglePasswordsWebFlowFragment : } override suspend fun onCsvAvailable(csv: String) { - Timber.i("cdr CSV available %s", csv) - val passwords = csvPasswordImporter.readCsv(csv) - val result = passwordImporter.importPasswords(passwords) - Timber.i("cdr Imported %d passwords (# duplicates = %d", result.savedCredentialIds.size, result.duplicatedPasswords.size) - val resultBundle = Bundle().also { - it.putParcelable(RESULT_KEY_DETAILS, Result.Success(result.savedCredentialIds.size)) - } - setFragmentResult(RESULT_KEY, resultBundle) + viewModel.onCsvAvailable(csv) } override suspend fun onCsvError() { - Timber.e("cdr Error decoding CSV") - val resultBundle = Bundle().also { - it.putParcelable(RESULT_KEY_DETAILS, Result.Error) + viewModel.onCsvError() + } + + override fun onShareCredentialsForAutofill( + originalUrl: String, + selectedCredentials: LoginCredentials, + ) { + if (binding?.webView?.url != originalUrl) { + Timber.w("WebView url has changed since autofill request; bailing") + return } - setFragmentResult(RESULT_KEY, resultBundle) + browserAutofill.injectCredentials(selectedCredentials) + } + + override fun onNoCredentialsChosenForAutofill(originalUrl: String) { + if (binding?.webView?.url != originalUrl) { + Timber.w("WebView url has changed since autofill request; bailing") + return + } + browserAutofill.injectCredentials(null) } companion object { diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordsWebFlowViewModel.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordsWebFlowViewModel.kt index bd6adeb7b634..52ac13ecf514 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordsWebFlowViewModel.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/ImportGooglePasswordsWebFlowViewModel.kt @@ -16,11 +16,15 @@ package com.duckduckgo.autofill.impl.importing.gpm.webflow +import android.os.Bundle import androidx.lifecycle.ViewModel import com.duckduckgo.anvil.annotations.ContributesViewModel -import com.duckduckgo.app.statistics.pixels.Pixel -import com.duckduckgo.autofill.api.email.EmailManager -import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordsWebFlowViewModel.ViewState.ShowingWebContent +import com.duckduckgo.autofill.impl.importing.CsvPasswordConverter +import com.duckduckgo.autofill.impl.importing.CsvPasswordConverter.CsvPasswordImportResult +import com.duckduckgo.autofill.impl.importing.CsvPasswordConverter.CsvPasswordImportResult.Success +import com.duckduckgo.autofill.impl.importing.PasswordImporter +import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordResult.Companion.RESULT_KEY_DETAILS +import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordsWebFlowViewModel.ViewState.Initializing import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.di.scopes.ActivityScope import javax.inject.Inject @@ -29,17 +33,18 @@ import kotlinx.coroutines.flow.StateFlow import timber.log.Timber @ContributesViewModel(ActivityScope::class) -class ImportGooglePasswordsWebFlowViewModel @Inject constructor( - private val pixel: Pixel, -) : ViewModel() { +class ImportGooglePasswordsWebFlowViewModel @Inject constructor() : ViewModel() { @Inject - lateinit var emailManager: EmailManager + lateinit var dispatchers: DispatcherProvider @Inject - lateinit var dispatchers: DispatcherProvider + lateinit var passwordImporter: PasswordImporter + + @Inject + lateinit var csvPasswordConverter: CsvPasswordConverter - private val _viewState = MutableStateFlow(ShowingWebContent) + private val _viewState = MutableStateFlow(Initializing) val viewState: StateFlow = _viewState fun onPageStarted(url: String?) { @@ -47,16 +52,55 @@ class ImportGooglePasswordsWebFlowViewModel @Inject constructor( } fun onPageFinished(url: String?) { - _viewState.value = ShowingWebContent Timber.i("onPageFinished: $url") } + suspend fun onCsvAvailable(csv: String) { + when (val parseResult = csvPasswordConverter.readCsv(csv)) { + is CsvPasswordImportResult.Success -> onCsvParsed(parseResult) + is CsvPasswordImportResult.Error -> onCsvError() + } + } + + private suspend fun onCsvParsed(parseResult: Success) { + val jobId = + passwordImporter.importPasswords(parseResult.loginCredentialsToImport, parseResult.numberPasswordsInSource) + val resultBundle = Bundle().also { + it.putParcelable( + RESULT_KEY_DETAILS, + ImportGooglePasswordResult.Success( + importedCount = parseResult.loginCredentialsToImport.size, + foundInImport = parseResult.loginCredentialsToImport.size, + importJobId = jobId, + ), + ) + } + _viewState.value = ViewState.UserFinishedImportFlow(resultBundle) + } + + fun onCsvError() { + Timber.e("cdr Error decoding CSV") + val resultBundle = Bundle().also { + it.putParcelable(RESULT_KEY_DETAILS, ImportGooglePasswordResult.Error) + } + _viewState.value = ViewState.UserFinishedImportFlow(resultBundle) + } + + fun onCloseButtonPressed(url: String?) { + if (url?.startsWith(ENCRYPTED_PASSPHRASE_ERROR_URL) == true) { + val resultBundle = Bundle().also { + it.putParcelable(RESULT_KEY_DETAILS, ImportGooglePasswordResult.Error) + } + _viewState.value = ViewState.UserFinishedImportFlow(resultBundle) + } else { + terminateFlowAsCancellation(url ?: "unknown") + } + } + fun onBackButtonPressed( url: String?, canGoBack: Boolean, ) { - Timber.v("onBackButtonPressed: %s, canGoBack=%s", url, canGoBack) - // if WebView can't go back, then we're at the first stage or something's gone wrong. Either way, time to cancel out of the screen. if (!canGoBack) { terminateFlowAsCancellation(url ?: "unknown") @@ -70,17 +114,10 @@ class ImportGooglePasswordsWebFlowViewModel @Inject constructor( _viewState.value = ViewState.UserCancelledImportFlow(stage) } - fun loadedStartingUrl() { - // pixel.fire(EMAIL_PROTECTION_IN_CONTEXT_MODAL_DISPLAYED) - } - - fun onCloseButtonPressed(url: String?) { - terminateFlowAsCancellation(url ?: "unknown") - } - sealed interface ViewState { - data object ShowingWebContent : ViewState + data object Initializing : ViewState data class UserCancelledImportFlow(val stage: String) : ViewState + data class UserFinishedImportFlow(val bundle: Bundle) : ViewState data object NavigatingBack : ViewState } @@ -89,5 +126,6 @@ class ImportGooglePasswordsWebFlowViewModel @Inject constructor( } companion object { + private const val ENCRYPTED_PASSPHRASE_ERROR_URL = "https://passwords.google.com/error/sync-passphrase" } } diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/PasswordImporterCssScriptLoader.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/PasswordImporterCssScriptLoader.kt index 7abf2df16f66..be04d3ffa89e 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/PasswordImporterCssScriptLoader.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/PasswordImporterCssScriptLoader.kt @@ -16,6 +16,7 @@ package com.duckduckgo.autofill.impl.importing.gpm.webflow +import com.duckduckgo.autofill.impl.importing.gpm.feature.AutofillImportPasswordConfigStore import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.di.scopes.FragmentScope import com.squareup.anvil.annotations.ContributesBinding @@ -30,6 +31,7 @@ interface PasswordImporterScriptLoader { @ContributesBinding(FragmentScope::class) class PasswordImporterCssScriptLoader @Inject constructor( private val dispatchers: DispatcherProvider, + private val configStore: AutofillImportPasswordConfigStore, ) : PasswordImporterScriptLoader { private lateinit var contentScopeJS: String @@ -37,61 +39,34 @@ class PasswordImporterCssScriptLoader @Inject constructor( override suspend fun getScript(): String { return withContext(dispatchers.io()) { getContentScopeJS() - .replace(CONTENT_SCOPE_PLACEHOLDER, getContentScopeJson()) + .replace(CONTENT_SCOPE_PLACEHOLDER, getContentScopeJson(loadSettingsJson())) .replace(USER_UNPROTECTED_DOMAINS_PLACEHOLDER, getUnprotectedDomainsJson()) .replace(USER_PREFERENCES_PLACEHOLDER, getUserPreferencesJson()) } } - private fun getContentScopeJson( - showHintSignInButton: Boolean = true, - showHintSettingsButton: Boolean = true, - showHintExportButton: Boolean = true, - ): String = ( - """{ + /** + * This enables the password import hints feature in C-S-S. + * These settings are for enabling it; the check for whether it should be enabled or not is done elsewhere. + */ + private fun getContentScopeJson(settingsJson: String): String { + return """{ "features":{ - "passwordImport" : { + "autofillPasswordImport" : { "state": "enabled", "exceptions": [], - "settings": { - "settingsButton": { - "highlight": { - "enabled": $showHintSettingsButton, - "selector": "bla bla" - }, - "autotap": { - "enabled": false, - "selector": "bla bla" - } - }, - "exportButton": { - "highlight": { - "enabled": $showHintExportButton, - "selector": "bla bla" - }, - "autotap": { - "enabled": false, - "selector": "bla bla" - } - }, - "signInButton": { - "highlight":{ - "enabled": $showHintSignInButton, - "selector": "bla bla" - }, - "autotap": { - "enabled": false, - "selector": "bla bla" - } - } - } + "settings": $settingsJson } }, "unprotectedTemporary":[] } """.trimMargin() - ) + } + + private suspend fun loadSettingsJson(): String { + return configStore.getConfig().javascriptConfigGooglePasswords + } private fun getUserPreferencesJson(): String { return """ @@ -109,7 +84,7 @@ class PasswordImporterCssScriptLoader @Inject constructor( private fun getContentScopeJS(): String { if (!this::contentScopeJS.isInitialized) { - contentScopeJS = loadJs("passwordImport.js") + contentScopeJS = loadJs("autofillPasswordImport.js") } return contentScopeJS } diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/autofill/AutofillNoOpCallbacks.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/autofill/AutofillNoOpCallbacks.kt index 7339119699f2..8c9a35f141f7 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/autofill/AutofillNoOpCallbacks.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/gpm/webflow/autofill/AutofillNoOpCallbacks.kt @@ -17,28 +17,93 @@ package com.duckduckgo.autofill.impl.importing.gpm.webflow.autofill import com.duckduckgo.autofill.api.AutofillEventListener -import com.duckduckgo.autofill.api.AutofillWebMessageRequest import com.duckduckgo.autofill.api.Callback +import com.duckduckgo.autofill.api.EmailProtectionInContextSignupFlowListener +import com.duckduckgo.autofill.api.EmailProtectionUserPromptListener import com.duckduckgo.autofill.api.domain.app.LoginCredentials +import com.duckduckgo.autofill.api.domain.app.LoginTriggerType -interface ImportGooglePasswordAutofillCallback : Callback { +interface NoOpAutofillCallback : Callback { + override suspend fun onCredentialsAvailableToInject( + originalUrl: String, + credentials: List, + triggerType: LoginTriggerType, + ) { + } + + override suspend fun onCredentialsAvailableToSave( + currentUrl: String, + credentials: LoginCredentials, + ) { + } override suspend fun onGeneratedPasswordAvailableToUse( - autofillWebMessageRequest: AutofillWebMessageRequest, + originalUrl: String, username: String?, generatedPassword: String, - ) {} + ) { + } + + override fun noCredentialsAvailable(originalUrl: String) { + } + + override fun onCredentialsSaved(savedCredentials: LoginCredentials) { + } +} + +interface NoOpAutofillEventListener : AutofillEventListener { + override fun onAcceptGeneratedPassword(originalUrl: String) { + } + + override fun onRejectGeneratedPassword(originalUrl: String) { + } + + override fun onUseEmailProtectionPersonalAddress( + originalUrl: String, + duckAddress: String, + ) { + } + + override fun onUseEmailProtectionPrivateAlias( + originalUrl: String, + duckAddress: String, + ) { + } - override fun onCredentialsSaved(savedCredentials: LoginCredentials) {} + override fun onSelectedToSignUpForInContextEmailProtection() { + } - override fun showNativeChooseEmailAddressPrompt(autofillWebMessageRequest: AutofillWebMessageRequest) {} - override suspend fun onCredentialsAvailableToSave(autofillWebMessageRequest: AutofillWebMessageRequest, credentials: LoginCredentials) {} - override fun showNativeInContextEmailProtectionSignupPrompt(autofillWebMessageRequest: AutofillWebMessageRequest) {} + override fun onEndOfEmailProtectionInContextSignupFlow() { + } + + override fun onShareCredentialsForAutofill( + originalUrl: String, + selectedCredentials: LoginCredentials, + ) { + } + + override fun onNoCredentialsChosenForAutofill(originalUrl: String) { + } + + override fun onSavedCredentials(credentials: LoginCredentials) { + } + + override fun onUpdatedCredentials(credentials: LoginCredentials) { + } + + override fun onAutofillStateChange() { + } +} + +interface NoOpEmailProtectionInContextSignupFlowListener : EmailProtectionInContextSignupFlowListener { + override fun closeInContextSignup() { + } } -interface ImportGooglePasswordAutofillEventListener : AutofillEventListener { - override fun onSelectedToSignUpForInContextEmailProtection(autofillWebMessageRequest: AutofillWebMessageRequest) {} - override fun onSavedCredentials(credentials: LoginCredentials) {} - override fun onUpdatedCredentials(credentials: LoginCredentials) {} - override fun onAutofillStateChange() {} +interface NoOpEmailProtectionUserPromptListener : EmailProtectionUserPromptListener { + override fun showNativeInContextEmailProtectionSignupPrompt() { + } + + override fun showNativeChooseEmailAddressPrompt() { + } } diff --git a/autofill/autofill-internal/src/main/java/com/duckduckgo/autofill/internal/AutofillInternalSettingsActivity.kt b/autofill/autofill-internal/src/main/java/com/duckduckgo/autofill/internal/AutofillInternalSettingsActivity.kt index 998ca7a665f9..271f52f43efd 100644 --- a/autofill/autofill-internal/src/main/java/com/duckduckgo/autofill/internal/AutofillInternalSettingsActivity.kt +++ b/autofill/autofill-internal/src/main/java/com/duckduckgo/autofill/internal/AutofillInternalSettingsActivity.kt @@ -23,6 +23,7 @@ import android.content.Intent import android.os.Bundle import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.content.IntentCompat import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle.State.STARTED import androidx.lifecycle.lifecycleScope @@ -31,9 +32,6 @@ import com.duckduckgo.anvil.annotations.InjectWith import com.duckduckgo.app.tabs.BrowserNav import com.duckduckgo.autofill.api.AutofillFeature import com.duckduckgo.autofill.api.AutofillScreens.AutofillSettingsScreen -import com.duckduckgo.autofill.api.AutofillScreens.ImportGooglePassword -import com.duckduckgo.autofill.api.AutofillScreens.ImportGooglePassword.Result.Error -import com.duckduckgo.autofill.api.AutofillScreens.ImportGooglePassword.Result.Success import com.duckduckgo.autofill.api.AutofillSettingsLaunchSource.InternalDevSettings import com.duckduckgo.autofill.api.domain.app.LoginCredentials import com.duckduckgo.autofill.api.email.EmailManager @@ -45,6 +43,12 @@ import com.duckduckgo.autofill.impl.importing.CsvPasswordConverter.CsvPasswordIm import com.duckduckgo.autofill.impl.importing.PasswordImporter import com.duckduckgo.autofill.impl.importing.PasswordImporter.ImportResult.Finished import com.duckduckgo.autofill.impl.importing.PasswordImporter.ImportResult.InProgress +import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePassword.AutofillImportViaGooglePasswordManagerScreen +import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordResult +import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordResult.Companion.RESULT_KEY_DETAILS +import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordResult.Error +import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordResult.Success +import com.duckduckgo.autofill.impl.importing.gpm.webflow.ImportGooglePasswordResult.UserCancelled import com.duckduckgo.autofill.impl.reporting.AutofillSiteBreakageReportingDataStore import com.duckduckgo.autofill.impl.store.InternalAutofillStore import com.duckduckgo.autofill.impl.store.NeverSavedSiteRepository @@ -132,7 +136,7 @@ class AutofillInternalSettingsActivity : DuckDuckGoActivity() { logcat { "cdr onActivityResult for CSV file request. resultCode=${result.resultCode}. uri=$fileUrl" } if (fileUrl != null) { - lifecycleScope.launch { + lifecycleScope.launch(dispatchers.io()) { when (val parseResult = csvPasswordConverter.readCsv(fileUrl)) { is CsvPasswordImportResult.Success -> { val jobId = passwordImporter.importPasswords(parseResult.loginCredentialsToImport, parseResult.numberPasswordsInSource) @@ -151,7 +155,18 @@ class AutofillInternalSettingsActivity : DuckDuckGoActivity() { logcat { "cdr onActivityResult for Google Password Manager import flow. resultCode=${result.resultCode}" } if (result.resultCode == Activity.RESULT_OK) { - observePasswordInputUpdates() + result.data?.let { + when (val resultDetails = IntentCompat.getParcelableExtra(it, RESULT_KEY_DETAILS, ImportGooglePasswordResult::class.java)) { + is Success -> { + observePasswordInputUpdates(resultDetails.importJobId) + } + Error -> { + "Failed to import passwords due to an error".showSnackbar() + } + is UserCancelled, null -> { + } + } + } } } @@ -165,7 +180,7 @@ class AutofillInternalSettingsActivity : DuckDuckGoActivity() { } is Finished -> { - logcat { "cdr Imported ${it.savedCredentialIds.size} passwords" } + logcat { "cdr Imported ${it.savedCredentialIds.size} passwords. (${it.importListOriginalSize} were found in total)" } "Imported ${it.savedCredentialIds.size} passwords".showSnackbar() } } @@ -260,7 +275,7 @@ class AutofillInternalSettingsActivity : DuckDuckGoActivity() { startActivity(browserNav.openInNewTab(this, googlePasswordsUrl)) } binding.importPasswordsLaunchGooglePasswordCustomFlow.setClickListener { - val intent = globalActivityStarter.startIntent(this, ImportGooglePassword.AutofillImportViaGooglePasswordManagerScreen) + val intent = globalActivityStarter.startIntent(this, AutofillImportViaGooglePasswordManagerScreen) importGooglePasswordsFlowLauncher.launch(intent) } diff --git a/browser-api/src/main/java/com/duckduckgo/browser/api/WebViewMessageListening.kt b/browser-api/src/main/java/com/duckduckgo/browser/api/WebViewMessageListening.kt deleted file mode 100644 index b612dea72384..000000000000 --- a/browser-api/src/main/java/com/duckduckgo/browser/api/WebViewMessageListening.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2024 DuckDuckGo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.duckduckgo.browser.api - -interface WebViewMessageListening { - - suspend fun isWebMessageListenerSupported(): Boolean -} diff --git a/node_modules/@duckduckgo/content-scope-scripts/build/android/contentScope.js b/node_modules/@duckduckgo/content-scope-scripts/build/android/contentScope.js index 71525ddea5b0..97de912ee16b 100644 --- a/node_modules/@duckduckgo/content-scope-scripts/build/android/contentScope.js +++ b/node_modules/@duckduckgo/content-scope-scripts/build/android/contentScope.js @@ -2,6 +2,7 @@ (function () { 'use strict'; + /* eslint-disable no-redeclare */ const Set$1 = globalThis.Set; const Reflect$1 = globalThis.Reflect; const customElementsGet = globalThis.customElements?.get.bind(globalThis.customElements); @@ -14,10 +15,11 @@ const URL$1 = globalThis.URL; const Proxy$1 = globalThis.Proxy; + /* eslint-disable no-redeclare, no-global-assign */ /* global cloneInto, exportFunction, false */ // Only use globalThis for testing this breaks window.wrappedJSObject code in Firefox - // eslint-disable-next-line no-global-assign + let globalObj = typeof window === 'undefined' ? globalThis : window; let Error$1 = globalObj.Error; let messageSecret; @@ -253,7 +255,7 @@ // eslint-disable-next-line no-debugger debugger }, - // eslint-disable-next-line @typescript-eslint/no-empty-function + noop: () => { } }; @@ -770,6 +772,7 @@ /** * Tiny wrapper around performance.mark and performance.measure */ + // eslint-disable-next-line no-redeclare class PerformanceMark { /** * @param {string} name @@ -1460,55 +1463,60 @@ return sjcl.codec.hex.fromBits(hmac.encrypt(inputData)) } - function _typeof$2(obj) { "@babel/helpers - typeof"; return _typeof$2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof$2(obj); } function isJSONArray(value) { return Array.isArray(value); } function isJSONObject(value) { - return value !== null && _typeof$2(value) === 'object' && value.constructor === Object // do not match on classes or Array + return value !== null && typeof value === 'object' && (value.constructor === undefined || + // for example Object.create(null) + value.constructor.name === 'Object') // do not match on classes or Array ; } - function _typeof$1(obj) { "@babel/helpers - typeof"; return _typeof$1 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof$1(obj); } - /** - * Test deep equality of two JSON values, objects, or arrays - */ // TODO: write unit tests + /** + * Test deep equality of two JSON values, objects, or arrays + */ + // TODO: write unit tests function isEqual(a, b) { // FIXME: this function will return false for two objects with the same keys // but different order of keys return JSON.stringify(a) === JSON.stringify(b); } - /** - * Get all but the last items from an array + /** + * Get all but the last items from an array */ // TODO: write unit tests function initial(array) { return array.slice(0, array.length - 1); } - /** - * Get the last item from an array + /** + * Get the last item from an array */ // TODO: write unit tests function last(array) { return array[array.length - 1]; } - /** - * Test whether a value is an Object or an Array (and not a primitive JSON value) + /** + * Test whether a value is an Object or an Array (and not a primitive JSON value) */ // TODO: write unit tests function isObjectOrArray(value) { - return _typeof$1(value) === 'object' && value !== null; + return typeof value === 'object' && value !== null; } - function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } - function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } - function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } - function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } - function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } + /** + * Immutability helpers + * + * inspiration: + * + * https://www.npmjs.com/package/seamless-immutable + * https://www.npmjs.com/package/ih + * https://www.npmjs.com/package/mutatis + * https://github.com/mariocasciaro/object-path-immutable + */ /** * Shallow clone of an Object, Array, or value @@ -1517,10 +1525,10 @@ function shallowClone(value) { if (isJSONArray(value)) { // copy array items - var copy = value.slice(); + const copy = value.slice(); // copy all symbols - Object.getOwnPropertySymbols(value).forEach(function (symbol) { + Object.getOwnPropertySymbols(value).forEach(symbol => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore copy[symbol] = value[symbol]; @@ -1528,15 +1536,17 @@ return copy; } else if (isJSONObject(value)) { // copy object properties - var _copy = _objectSpread({}, value); + const copy = { + ...value + }; // copy all symbols - Object.getOwnPropertySymbols(value).forEach(function (symbol) { + Object.getOwnPropertySymbols(value).forEach(symbol => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - _copy[symbol] = value[symbol]; + copy[symbol] = value[symbol]; }); - return _copy; + return copy; } else { return value; } @@ -1553,7 +1563,7 @@ // return original object unchanged when the new value is identical to the old one return object; } else { - var updatedObject = shallowClone(object); + const updatedObject = shallowClone(object); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore updatedObject[key] = value; @@ -1567,8 +1577,8 @@ * @return Returns the field when found, or undefined when the path doesn't exist */ function getIn(object, path) { - var value = object; - var i = 0; + let value = object; + let i = 0; while (i < path.length) { if (isJSONObject(value)) { value = value[path[i]]; @@ -1599,19 +1609,19 @@ * @return Returns a new, updated object or array */ function setIn(object, path, value) { - var createPath = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + let createPath = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; if (path.length === 0) { return value; } - var key = path[0]; + const key = path[0]; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - var updatedValue = setIn(object ? object[key] : undefined, path.slice(1), value, createPath); + const updatedValue = setIn(object ? object[key] : undefined, path.slice(1), value, createPath); if (isJSONObject(object) || isJSONArray(object)) { return applyProp(object, key, updatedValue); } else { if (createPath) { - var newObject = IS_INTEGER_REGEX.test(key) ? [] : {}; + const newObject = IS_INTEGER_REGEX.test(key) ? [] : {}; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore newObject[key] = updatedValue; @@ -1621,7 +1631,7 @@ } } } - var IS_INTEGER_REGEX = /^\d+$/; + const IS_INTEGER_REGEX = /^\d+$/; /** * helper function to replace a nested property in an object with a new value @@ -1629,17 +1639,17 @@ * * @return Returns a new, updated object or array */ - function updateIn(object, path, callback) { + function updateIn(object, path, transform) { if (path.length === 0) { - return callback(object); + return transform(object); } if (!isObjectOrArray(object)) { throw new Error('Path doesn\'t exist'); } - var key = path[0]; + const key = path[0]; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - var updatedValue = updateIn(object[key], path.slice(1), callback); + const updatedValue = updateIn(object[key], path.slice(1), transform); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore return applyProp(object, key, updatedValue); @@ -1659,25 +1669,25 @@ throw new Error('Path does not exist'); } if (path.length === 1) { - var _key = path[0]; - if (!(_key in object)) { + const key = path[0]; + if (!(key in object)) { // key doesn't exist. return object unchanged return object; } else { - var updatedObject = shallowClone(object); + const updatedObject = shallowClone(object); if (isJSONArray(updatedObject)) { - updatedObject.splice(parseInt(_key), 1); + updatedObject.splice(parseInt(key), 1); } if (isJSONObject(updatedObject)) { - delete updatedObject[_key]; + delete updatedObject[key]; } return updatedObject; } } - var key = path[0]; + const key = path[0]; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - var updatedValue = deleteIn(object[key], path.slice(1)); + const updatedValue = deleteIn(object[key], path.slice(1)); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore return applyProp(object, key, updatedValue); @@ -1690,13 +1700,13 @@ * insertAt({arr: [1,2,3]}, ['arr', '2'], 'inserted') // [1,2,'inserted',3] */ function insertAt(document, path, value) { - var parentPath = path.slice(0, path.length - 1); - var index = path[path.length - 1]; - return updateIn(document, parentPath, function (items) { + const parentPath = path.slice(0, path.length - 1); + const index = path[path.length - 1]; + return updateIn(document, parentPath, items => { if (!Array.isArray(items)) { throw new TypeError('Array expected at path ' + JSON.stringify(parentPath)); } - var updatedItems = shallowClone(items); + const updatedItems = shallowClone(items); updatedItems.splice(parseInt(index), 0, value); return updatedItems; }); @@ -1726,12 +1736,10 @@ * Parse a JSON Pointer */ function parseJSONPointer(pointer) { - var path = pointer.split('/'); + const path = pointer.split('/'); path.shift(); // remove the first empty entry - return path.map(function (p) { - return p.replace(/~1/g, '/').replace(/~0/g, '~'); - }); + return path.map(p => p.replace(/~1/g, '/').replace(/~0/g, '~')); } /** @@ -1754,31 +1762,11 @@ * instead, the patch is applied in an immutable way */ function immutableJSONPatch(document, operations, options) { - var updatedDocument = document; - for (var i = 0; i < operations.length; i++) { + let updatedDocument = document; + for (let i = 0; i < operations.length; i++) { validateJSONPatchOperation(operations[i]); - var operation = operations[i]; - - // TODO: test before - if (options && options.before) { - var result = options.before(updatedDocument, operation); - if (result !== undefined) { - if (result.document !== undefined) { - updatedDocument = result.document; - } - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - if (result.json !== undefined) { - // TODO: deprecated since v5.0.0. Cleanup this warning some day - throw new Error('Deprecation warning: returned object property ".json" has been renamed to ".document"'); - } - if (result.operation !== undefined) { - operation = result.operation; - } - } - } - var previousDocument = updatedDocument; - var path = parsePath(updatedDocument, operation.path); + let operation = operations[i]; + const path = parsePath(updatedDocument, operation.path); if (operation.op === 'add') { updatedDocument = add(updatedDocument, path, operation.value); } else if (operation.op === 'remove') { @@ -1794,14 +1782,6 @@ } else { throw new Error('Unknown JSONPatch operation ' + JSON.stringify(operation)); } - - // TODO: test after - if (options && options.after) { - var _result = options.after(updatedDocument, operation, previousDocument); - if (_result !== undefined) { - updatedDocument = _result; - } - } } return updatedDocument; } @@ -1835,12 +1815,12 @@ * Copy a value */ function copy(document, path, from) { - var value = getIn(document, from); + const value = getIn(document, from); if (isArrayItem(document, path)) { return insertAt(document, path, value); } else { - var _value = getIn(document, from); - return setIn(document, path, _value); + const value = getIn(document, from); + return setIn(document, path, value); } } @@ -1848,10 +1828,10 @@ * Move a value */ function move(document, path, from) { - var value = getIn(document, from); + const value = getIn(document, from); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - var removedJson = deleteIn(document, from); + const removedJson = deleteIn(document, from); return isArrayItem(removedJson, path) ? insertAt(removedJson, path, value) : setIn(removedJson, path, value); } @@ -1861,21 +1841,21 @@ */ function test(document, path, value) { if (value === undefined) { - throw new Error("Test failed: no value provided (path: \"".concat(compileJSONPointer(path), "\")")); + throw new Error(`Test failed: no value provided (path: "${compileJSONPointer(path)}")`); } if (!existsIn(document, path)) { - throw new Error("Test failed: path not found (path: \"".concat(compileJSONPointer(path), "\")")); + throw new Error(`Test failed: path not found (path: "${compileJSONPointer(path)}")`); } - var actualValue = getIn(document, path); + const actualValue = getIn(document, path); if (!isEqual(actualValue, value)) { - throw new Error("Test failed, value differs (path: \"".concat(compileJSONPointer(path), "\")")); + throw new Error(`Test failed, value differs (path: "${compileJSONPointer(path)}")`); } } function isArrayItem(document, path) { if (path.length === 0) { return false; } - var parent = getIn(document, initial(path)); + const parent = getIn(document, initial(path)); return Array.isArray(parent); } @@ -1887,8 +1867,8 @@ if (last(path) !== '-') { return path; } - var parentPath = initial(path); - var parent = getIn(document, parentPath); + const parentPath = initial(path); + const parent = getIn(document, parentPath); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore @@ -1901,7 +1881,7 @@ */ function validateJSONPatchOperation(operation) { // TODO: write unit tests - var ops = ['add', 'remove', 'replace', 'copy', 'move', 'test']; + const ops = ['add', 'remove', 'replace', 'copy', 'move', 'test']; if (!ops.includes(operation.op)) { throw new Error('Unknown JSONPatch op ' + JSON.stringify(operation.op)); } @@ -2435,13 +2415,13 @@ }; // console.log('DEBUG: handler setup', { config, comparator }) - // eslint-disable-next-line no-undef + this.config.methods.addEventListener('message', idHandler); options?.signal?.addEventListener('abort', abortHandler); teardown = () => { // console.log('DEBUG: handler teardown', { config, comparator }) - // eslint-disable-next-line no-undef + this.config.methods.removeEventListener('message', idHandler); options?.signal?.removeEventListener('abort', abortHandler); }; @@ -2911,7 +2891,7 @@ * @param {any[]} args */ value: (...args) => { - // eslint-disable-next-line n/no-callback-literal + callback(...args); delete this.globals.window[randomMethodName]; } @@ -3863,8 +3843,10 @@ /** @type {boolean | undefined} */ #documentOriginIsTracker /** @type {Record | undefined} */ + // eslint-disable-next-line no-unused-private-class-members #bundledfeatureSettings /** @type {import('../../messaging').Messaging} */ + // eslint-disable-next-line no-unused-private-class-members #messaging /** @type {boolean} */ #isDebugFlagSet = false @@ -4046,7 +4028,7 @@ }) } - // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function + init (args) { } @@ -4059,7 +4041,7 @@ this.measure(); } - // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function + load (args) { } @@ -4128,7 +4110,7 @@ } } - // eslint-disable-next-line @typescript-eslint/no-empty-function + update () { } @@ -4377,683 +4359,687 @@ } } - var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } var alea$1 = {exports: {}}; - alea$1.exports; - - (function (module) { - // A port of an algorithm by Johannes Baagøe , 2010 - // http://baagoe.com/en/RandomMusings/javascript/ - // https://github.com/nquinlan/better-random-numbers-for-javascript-mirror - // Original work is under MIT license - - - // Copyright (C) 2010 by Johannes Baagøe - // - // Permission is hereby granted, free of charge, to any person obtaining a copy - // of this software and associated documentation files (the "Software"), to deal - // in the Software without restriction, including without limitation the rights - // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - // copies of the Software, and to permit persons to whom the Software is - // furnished to do so, subject to the following conditions: - // - // The above copyright notice and this permission notice shall be included in - // all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - // THE SOFTWARE. - - - - (function(global, module, define) { - - function Alea(seed) { - var me = this, mash = Mash(); - - me.next = function() { - var t = 2091639 * me.s0 + me.c * 2.3283064365386963e-10; // 2^-32 - me.s0 = me.s1; - me.s1 = me.s2; - return me.s2 = t - (me.c = t | 0); - }; - - // Apply the seeding algorithm from Baagoe. - me.c = 1; - me.s0 = mash(' '); - me.s1 = mash(' '); - me.s2 = mash(' '); - me.s0 -= mash(seed); - if (me.s0 < 0) { me.s0 += 1; } - me.s1 -= mash(seed); - if (me.s1 < 0) { me.s1 += 1; } - me.s2 -= mash(seed); - if (me.s2 < 0) { me.s2 += 1; } - mash = null; - } - - function copy(f, t) { - t.c = f.c; - t.s0 = f.s0; - t.s1 = f.s1; - t.s2 = f.s2; - return t; - } - - function impl(seed, opts) { - var xg = new Alea(seed), - state = opts && opts.state, - prng = xg.next; - prng.int32 = function() { return (xg.next() * 0x100000000) | 0; }; - prng.double = function() { - return prng() + (prng() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53 - }; - prng.quick = prng; - if (state) { - if (typeof(state) == 'object') copy(state, xg); - prng.state = function() { return copy(xg, {}); }; - } - return prng; - } - - function Mash() { - var n = 0xefc8249d; - - var mash = function(data) { - data = String(data); - for (var i = 0; i < data.length; i++) { - n += data.charCodeAt(i); - var h = 0.02519603282416938 * n; - n = h >>> 0; - h -= n; - h *= n; - n = h >>> 0; - h -= n; - n += h * 0x100000000; // 2^32 - } - return (n >>> 0) * 2.3283064365386963e-10; // 2^-32 - }; - - return mash; - } - - - if (module && module.exports) { - module.exports = impl; - } else if (define && define.amd) { - define(function() { return impl; }); - } else { - this.alea = impl; - } - - })( - commonjsGlobal, - module, // present in node.js - (typeof undefined) == 'function' // present with an AMD loader - ); - } (alea$1)); - - var aleaExports = alea$1.exports; + var alea = alea$1.exports; + + var hasRequiredAlea; + + function requireAlea () { + if (hasRequiredAlea) return alea$1.exports; + hasRequiredAlea = 1; + (function (module) { + // A port of an algorithm by Johannes Baagøe , 2010 + // http://baagoe.com/en/RandomMusings/javascript/ + // https://github.com/nquinlan/better-random-numbers-for-javascript-mirror + // Original work is under MIT license - + + // Copyright (C) 2010 by Johannes Baagøe + // + // Permission is hereby granted, free of charge, to any person obtaining a copy + // of this software and associated documentation files (the "Software"), to deal + // in the Software without restriction, including without limitation the rights + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + // copies of the Software, and to permit persons to whom the Software is + // furnished to do so, subject to the following conditions: + // + // The above copyright notice and this permission notice shall be included in + // all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + // THE SOFTWARE. + + + + (function(global, module, define) { + + function Alea(seed) { + var me = this, mash = Mash(); + + me.next = function() { + var t = 2091639 * me.s0 + me.c * 2.3283064365386963e-10; // 2^-32 + me.s0 = me.s1; + me.s1 = me.s2; + return me.s2 = t - (me.c = t | 0); + }; + + // Apply the seeding algorithm from Baagoe. + me.c = 1; + me.s0 = mash(' '); + me.s1 = mash(' '); + me.s2 = mash(' '); + me.s0 -= mash(seed); + if (me.s0 < 0) { me.s0 += 1; } + me.s1 -= mash(seed); + if (me.s1 < 0) { me.s1 += 1; } + me.s2 -= mash(seed); + if (me.s2 < 0) { me.s2 += 1; } + mash = null; + } + + function copy(f, t) { + t.c = f.c; + t.s0 = f.s0; + t.s1 = f.s1; + t.s2 = f.s2; + return t; + } + + function impl(seed, opts) { + var xg = new Alea(seed), + state = opts && opts.state, + prng = xg.next; + prng.int32 = function() { return (xg.next() * 0x100000000) | 0; }; + prng.double = function() { + return prng() + (prng() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53 + }; + prng.quick = prng; + if (state) { + if (typeof(state) == 'object') copy(state, xg); + prng.state = function() { return copy(xg, {}); }; + } + return prng; + } + + function Mash() { + var n = 0xefc8249d; + + var mash = function(data) { + data = String(data); + for (var i = 0; i < data.length; i++) { + n += data.charCodeAt(i); + var h = 0.02519603282416938 * n; + n = h >>> 0; + h -= n; + h *= n; + n = h >>> 0; + h -= n; + n += h * 0x100000000; // 2^32 + } + return (n >>> 0) * 2.3283064365386963e-10; // 2^-32 + }; + + return mash; + } + + + if (module && module.exports) { + module.exports = impl; + } else { + this.alea = impl; + } + + })( + alea, + module); + } (alea$1)); + return alea$1.exports; + } var xor128$1 = {exports: {}}; - xor128$1.exports; - - (function (module) { - // A Javascript implementaion of the "xor128" prng algorithm by - // George Marsaglia. See http://www.jstatsoft.org/v08/i14/paper - - (function(global, module, define) { - - function XorGen(seed) { - var me = this, strseed = ''; - - me.x = 0; - me.y = 0; - me.z = 0; - me.w = 0; - - // Set up generator function. - me.next = function() { - var t = me.x ^ (me.x << 11); - me.x = me.y; - me.y = me.z; - me.z = me.w; - return me.w ^= (me.w >>> 19) ^ t ^ (t >>> 8); - }; - - if (seed === (seed | 0)) { - // Integer seed. - me.x = seed; - } else { - // String seed. - strseed += seed; - } - - // Mix in string seed, then discard an initial batch of 64 values. - for (var k = 0; k < strseed.length + 64; k++) { - me.x ^= strseed.charCodeAt(k) | 0; - me.next(); - } - } - - function copy(f, t) { - t.x = f.x; - t.y = f.y; - t.z = f.z; - t.w = f.w; - return t; - } - - function impl(seed, opts) { - var xg = new XorGen(seed), - state = opts && opts.state, - prng = function() { return (xg.next() >>> 0) / 0x100000000; }; - prng.double = function() { - do { - var top = xg.next() >>> 11, - bot = (xg.next() >>> 0) / 0x100000000, - result = (top + bot) / (1 << 21); - } while (result === 0); - return result; - }; - prng.int32 = xg.next; - prng.quick = prng; - if (state) { - if (typeof(state) == 'object') copy(state, xg); - prng.state = function() { return copy(xg, {}); }; - } - return prng; - } - - if (module && module.exports) { - module.exports = impl; - } else if (define && define.amd) { - define(function() { return impl; }); - } else { - this.xor128 = impl; - } - - })( - commonjsGlobal, - module, // present in node.js - (typeof undefined) == 'function' // present with an AMD loader - ); - } (xor128$1)); - - var xor128Exports = xor128$1.exports; + var xor128 = xor128$1.exports; + + var hasRequiredXor128; + + function requireXor128 () { + if (hasRequiredXor128) return xor128$1.exports; + hasRequiredXor128 = 1; + (function (module) { + // A Javascript implementaion of the "xor128" prng algorithm by + // George Marsaglia. See http://www.jstatsoft.org/v08/i14/paper + + (function(global, module, define) { + + function XorGen(seed) { + var me = this, strseed = ''; + + me.x = 0; + me.y = 0; + me.z = 0; + me.w = 0; + + // Set up generator function. + me.next = function() { + var t = me.x ^ (me.x << 11); + me.x = me.y; + me.y = me.z; + me.z = me.w; + return me.w ^= (me.w >>> 19) ^ t ^ (t >>> 8); + }; + + if (seed === (seed | 0)) { + // Integer seed. + me.x = seed; + } else { + // String seed. + strseed += seed; + } + + // Mix in string seed, then discard an initial batch of 64 values. + for (var k = 0; k < strseed.length + 64; k++) { + me.x ^= strseed.charCodeAt(k) | 0; + me.next(); + } + } + + function copy(f, t) { + t.x = f.x; + t.y = f.y; + t.z = f.z; + t.w = f.w; + return t; + } + + function impl(seed, opts) { + var xg = new XorGen(seed), + state = opts && opts.state, + prng = function() { return (xg.next() >>> 0) / 0x100000000; }; + prng.double = function() { + do { + var top = xg.next() >>> 11, + bot = (xg.next() >>> 0) / 0x100000000, + result = (top + bot) / (1 << 21); + } while (result === 0); + return result; + }; + prng.int32 = xg.next; + prng.quick = prng; + if (state) { + if (typeof(state) == 'object') copy(state, xg); + prng.state = function() { return copy(xg, {}); }; + } + return prng; + } + + if (module && module.exports) { + module.exports = impl; + } else { + this.xor128 = impl; + } + + })( + xor128, + module); + } (xor128$1)); + return xor128$1.exports; + } var xorwow$1 = {exports: {}}; - xorwow$1.exports; - - (function (module) { - // A Javascript implementaion of the "xorwow" prng algorithm by - // George Marsaglia. See http://www.jstatsoft.org/v08/i14/paper - - (function(global, module, define) { - - function XorGen(seed) { - var me = this, strseed = ''; - - // Set up generator function. - me.next = function() { - var t = (me.x ^ (me.x >>> 2)); - me.x = me.y; me.y = me.z; me.z = me.w; me.w = me.v; - return (me.d = (me.d + 362437 | 0)) + - (me.v = (me.v ^ (me.v << 4)) ^ (t ^ (t << 1))) | 0; - }; - - me.x = 0; - me.y = 0; - me.z = 0; - me.w = 0; - me.v = 0; - - if (seed === (seed | 0)) { - // Integer seed. - me.x = seed; - } else { - // String seed. - strseed += seed; - } - - // Mix in string seed, then discard an initial batch of 64 values. - for (var k = 0; k < strseed.length + 64; k++) { - me.x ^= strseed.charCodeAt(k) | 0; - if (k == strseed.length) { - me.d = me.x << 10 ^ me.x >>> 4; - } - me.next(); - } - } - - function copy(f, t) { - t.x = f.x; - t.y = f.y; - t.z = f.z; - t.w = f.w; - t.v = f.v; - t.d = f.d; - return t; - } - - function impl(seed, opts) { - var xg = new XorGen(seed), - state = opts && opts.state, - prng = function() { return (xg.next() >>> 0) / 0x100000000; }; - prng.double = function() { - do { - var top = xg.next() >>> 11, - bot = (xg.next() >>> 0) / 0x100000000, - result = (top + bot) / (1 << 21); - } while (result === 0); - return result; - }; - prng.int32 = xg.next; - prng.quick = prng; - if (state) { - if (typeof(state) == 'object') copy(state, xg); - prng.state = function() { return copy(xg, {}); }; - } - return prng; - } - - if (module && module.exports) { - module.exports = impl; - } else if (define && define.amd) { - define(function() { return impl; }); - } else { - this.xorwow = impl; - } - - })( - commonjsGlobal, - module, // present in node.js - (typeof undefined) == 'function' // present with an AMD loader - ); - } (xorwow$1)); - - var xorwowExports = xorwow$1.exports; + var xorwow = xorwow$1.exports; + + var hasRequiredXorwow; + + function requireXorwow () { + if (hasRequiredXorwow) return xorwow$1.exports; + hasRequiredXorwow = 1; + (function (module) { + // A Javascript implementaion of the "xorwow" prng algorithm by + // George Marsaglia. See http://www.jstatsoft.org/v08/i14/paper + + (function(global, module, define) { + + function XorGen(seed) { + var me = this, strseed = ''; + + // Set up generator function. + me.next = function() { + var t = (me.x ^ (me.x >>> 2)); + me.x = me.y; me.y = me.z; me.z = me.w; me.w = me.v; + return (me.d = (me.d + 362437 | 0)) + + (me.v = (me.v ^ (me.v << 4)) ^ (t ^ (t << 1))) | 0; + }; + + me.x = 0; + me.y = 0; + me.z = 0; + me.w = 0; + me.v = 0; + + if (seed === (seed | 0)) { + // Integer seed. + me.x = seed; + } else { + // String seed. + strseed += seed; + } + + // Mix in string seed, then discard an initial batch of 64 values. + for (var k = 0; k < strseed.length + 64; k++) { + me.x ^= strseed.charCodeAt(k) | 0; + if (k == strseed.length) { + me.d = me.x << 10 ^ me.x >>> 4; + } + me.next(); + } + } + + function copy(f, t) { + t.x = f.x; + t.y = f.y; + t.z = f.z; + t.w = f.w; + t.v = f.v; + t.d = f.d; + return t; + } + + function impl(seed, opts) { + var xg = new XorGen(seed), + state = opts && opts.state, + prng = function() { return (xg.next() >>> 0) / 0x100000000; }; + prng.double = function() { + do { + var top = xg.next() >>> 11, + bot = (xg.next() >>> 0) / 0x100000000, + result = (top + bot) / (1 << 21); + } while (result === 0); + return result; + }; + prng.int32 = xg.next; + prng.quick = prng; + if (state) { + if (typeof(state) == 'object') copy(state, xg); + prng.state = function() { return copy(xg, {}); }; + } + return prng; + } + + if (module && module.exports) { + module.exports = impl; + } else { + this.xorwow = impl; + } + + })( + xorwow, + module); + } (xorwow$1)); + return xorwow$1.exports; + } var xorshift7$1 = {exports: {}}; - xorshift7$1.exports; - - (function (module) { - // A Javascript implementaion of the "xorshift7" algorithm by - // François Panneton and Pierre L'ecuyer: - // "On the Xorgshift Random Number Generators" - // http://saluc.engr.uconn.edu/refs/crypto/rng/panneton05onthexorshift.pdf - - (function(global, module, define) { - - function XorGen(seed) { - var me = this; - - // Set up generator function. - me.next = function() { - // Update xor generator. - var X = me.x, i = me.i, t, v; - t = X[i]; t ^= (t >>> 7); v = t ^ (t << 24); - t = X[(i + 1) & 7]; v ^= t ^ (t >>> 10); - t = X[(i + 3) & 7]; v ^= t ^ (t >>> 3); - t = X[(i + 4) & 7]; v ^= t ^ (t << 7); - t = X[(i + 7) & 7]; t = t ^ (t << 13); v ^= t ^ (t << 9); - X[i] = v; - me.i = (i + 1) & 7; - return v; - }; - - function init(me, seed) { - var j, X = []; - - if (seed === (seed | 0)) { - // Seed state array using a 32-bit integer. - X[0] = seed; - } else { - // Seed state using a string. - seed = '' + seed; - for (j = 0; j < seed.length; ++j) { - X[j & 7] = (X[j & 7] << 15) ^ - (seed.charCodeAt(j) + X[(j + 1) & 7] << 13); - } - } - // Enforce an array length of 8, not all zeroes. - while (X.length < 8) X.push(0); - for (j = 0; j < 8 && X[j] === 0; ++j); - if (j == 8) X[7] = -1; else X[j]; - - me.x = X; - me.i = 0; - - // Discard an initial 256 values. - for (j = 256; j > 0; --j) { - me.next(); - } - } - - init(me, seed); - } - - function copy(f, t) { - t.x = f.x.slice(); - t.i = f.i; - return t; - } - - function impl(seed, opts) { - if (seed == null) seed = +(new Date); - var xg = new XorGen(seed), - state = opts && opts.state, - prng = function() { return (xg.next() >>> 0) / 0x100000000; }; - prng.double = function() { - do { - var top = xg.next() >>> 11, - bot = (xg.next() >>> 0) / 0x100000000, - result = (top + bot) / (1 << 21); - } while (result === 0); - return result; - }; - prng.int32 = xg.next; - prng.quick = prng; - if (state) { - if (state.x) copy(state, xg); - prng.state = function() { return copy(xg, {}); }; - } - return prng; - } - - if (module && module.exports) { - module.exports = impl; - } else if (define && define.amd) { - define(function() { return impl; }); - } else { - this.xorshift7 = impl; - } - - })( - commonjsGlobal, - module, // present in node.js - (typeof undefined) == 'function' // present with an AMD loader - ); - } (xorshift7$1)); - - var xorshift7Exports = xorshift7$1.exports; + var xorshift7 = xorshift7$1.exports; + + var hasRequiredXorshift7; + + function requireXorshift7 () { + if (hasRequiredXorshift7) return xorshift7$1.exports; + hasRequiredXorshift7 = 1; + (function (module) { + // A Javascript implementaion of the "xorshift7" algorithm by + // François Panneton and Pierre L'ecuyer: + // "On the Xorgshift Random Number Generators" + // http://saluc.engr.uconn.edu/refs/crypto/rng/panneton05onthexorshift.pdf + + (function(global, module, define) { + + function XorGen(seed) { + var me = this; + + // Set up generator function. + me.next = function() { + // Update xor generator. + var X = me.x, i = me.i, t, v; + t = X[i]; t ^= (t >>> 7); v = t ^ (t << 24); + t = X[(i + 1) & 7]; v ^= t ^ (t >>> 10); + t = X[(i + 3) & 7]; v ^= t ^ (t >>> 3); + t = X[(i + 4) & 7]; v ^= t ^ (t << 7); + t = X[(i + 7) & 7]; t = t ^ (t << 13); v ^= t ^ (t << 9); + X[i] = v; + me.i = (i + 1) & 7; + return v; + }; + + function init(me, seed) { + var j, X = []; + + if (seed === (seed | 0)) { + // Seed state array using a 32-bit integer. + X[0] = seed; + } else { + // Seed state using a string. + seed = '' + seed; + for (j = 0; j < seed.length; ++j) { + X[j & 7] = (X[j & 7] << 15) ^ + (seed.charCodeAt(j) + X[(j + 1) & 7] << 13); + } + } + // Enforce an array length of 8, not all zeroes. + while (X.length < 8) X.push(0); + for (j = 0; j < 8 && X[j] === 0; ++j); + if (j == 8) X[7] = -1; else X[j]; + + me.x = X; + me.i = 0; + + // Discard an initial 256 values. + for (j = 256; j > 0; --j) { + me.next(); + } + } + + init(me, seed); + } + + function copy(f, t) { + t.x = f.x.slice(); + t.i = f.i; + return t; + } + + function impl(seed, opts) { + if (seed == null) seed = +(new Date); + var xg = new XorGen(seed), + state = opts && opts.state, + prng = function() { return (xg.next() >>> 0) / 0x100000000; }; + prng.double = function() { + do { + var top = xg.next() >>> 11, + bot = (xg.next() >>> 0) / 0x100000000, + result = (top + bot) / (1 << 21); + } while (result === 0); + return result; + }; + prng.int32 = xg.next; + prng.quick = prng; + if (state) { + if (state.x) copy(state, xg); + prng.state = function() { return copy(xg, {}); }; + } + return prng; + } + + if (module && module.exports) { + module.exports = impl; + } else { + this.xorshift7 = impl; + } + + })( + xorshift7, + module); + } (xorshift7$1)); + return xorshift7$1.exports; + } var xor4096$1 = {exports: {}}; - xor4096$1.exports; - - (function (module) { - // A Javascript implementaion of Richard Brent's Xorgens xor4096 algorithm. - // - // This fast non-cryptographic random number generator is designed for - // use in Monte-Carlo algorithms. It combines a long-period xorshift - // generator with a Weyl generator, and it passes all common batteries - // of stasticial tests for randomness while consuming only a few nanoseconds - // for each prng generated. For background on the generator, see Brent's - // paper: "Some long-period random number generators using shifts and xors." - // http://arxiv.org/pdf/1004.3115v1.pdf - // - // Usage: - // - // var xor4096 = require('xor4096'); - // random = xor4096(1); // Seed with int32 or string. - // assert.equal(random(), 0.1520436450538547); // (0, 1) range, 53 bits. - // assert.equal(random.int32(), 1806534897); // signed int32, 32 bits. - // - // For nonzero numeric keys, this impelementation provides a sequence - // identical to that by Brent's xorgens 3 implementaion in C. This - // implementation also provides for initalizing the generator with - // string seeds, or for saving and restoring the state of the generator. - // - // On Chrome, this prng benchmarks about 2.1 times slower than - // Javascript's built-in Math.random(). - - (function(global, module, define) { - - function XorGen(seed) { - var me = this; - - // Set up generator function. - me.next = function() { - var w = me.w, - X = me.X, i = me.i, t, v; - // Update Weyl generator. - me.w = w = (w + 0x61c88647) | 0; - // Update xor generator. - v = X[(i + 34) & 127]; - t = X[i = ((i + 1) & 127)]; - v ^= v << 13; - t ^= t << 17; - v ^= v >>> 15; - t ^= t >>> 12; - // Update Xor generator array state. - v = X[i] = v ^ t; - me.i = i; - // Result is the combination. - return (v + (w ^ (w >>> 16))) | 0; - }; - - function init(me, seed) { - var t, v, i, j, w, X = [], limit = 128; - if (seed === (seed | 0)) { - // Numeric seeds initialize v, which is used to generates X. - v = seed; - seed = null; - } else { - // String seeds are mixed into v and X one character at a time. - seed = seed + '\0'; - v = 0; - limit = Math.max(limit, seed.length); - } - // Initialize circular array and weyl value. - for (i = 0, j = -32; j < limit; ++j) { - // Put the unicode characters into the array, and shuffle them. - if (seed) v ^= seed.charCodeAt((j + 32) % seed.length); - // After 32 shuffles, take v as the starting w value. - if (j === 0) w = v; - v ^= v << 10; - v ^= v >>> 15; - v ^= v << 4; - v ^= v >>> 13; - if (j >= 0) { - w = (w + 0x61c88647) | 0; // Weyl. - t = (X[j & 127] ^= (v + w)); // Combine xor and weyl to init array. - i = (0 == t) ? i + 1 : 0; // Count zeroes. - } - } - // We have detected all zeroes; make the key nonzero. - if (i >= 128) { - X[(seed && seed.length || 0) & 127] = -1; - } - // Run the generator 512 times to further mix the state before using it. - // Factoring this as a function slows the main generator, so it is just - // unrolled here. The weyl generator is not advanced while warming up. - i = 127; - for (j = 4 * 128; j > 0; --j) { - v = X[(i + 34) & 127]; - t = X[i = ((i + 1) & 127)]; - v ^= v << 13; - t ^= t << 17; - v ^= v >>> 15; - t ^= t >>> 12; - X[i] = v ^ t; - } - // Storing state as object members is faster than using closure variables. - me.w = w; - me.X = X; - me.i = i; - } - - init(me, seed); - } - - function copy(f, t) { - t.i = f.i; - t.w = f.w; - t.X = f.X.slice(); - return t; - } - function impl(seed, opts) { - if (seed == null) seed = +(new Date); - var xg = new XorGen(seed), - state = opts && opts.state, - prng = function() { return (xg.next() >>> 0) / 0x100000000; }; - prng.double = function() { - do { - var top = xg.next() >>> 11, - bot = (xg.next() >>> 0) / 0x100000000, - result = (top + bot) / (1 << 21); - } while (result === 0); - return result; - }; - prng.int32 = xg.next; - prng.quick = prng; - if (state) { - if (state.X) copy(state, xg); - prng.state = function() { return copy(xg, {}); }; - } - return prng; - } - - if (module && module.exports) { - module.exports = impl; - } else if (define && define.amd) { - define(function() { return impl; }); - } else { - this.xor4096 = impl; - } - - })( - commonjsGlobal, // window object or global - module, // present in node.js - (typeof undefined) == 'function' // present with an AMD loader - ); - } (xor4096$1)); - - var xor4096Exports = xor4096$1.exports; + var xor4096 = xor4096$1.exports; + + var hasRequiredXor4096; + + function requireXor4096 () { + if (hasRequiredXor4096) return xor4096$1.exports; + hasRequiredXor4096 = 1; + (function (module) { + // A Javascript implementaion of Richard Brent's Xorgens xor4096 algorithm. + // + // This fast non-cryptographic random number generator is designed for + // use in Monte-Carlo algorithms. It combines a long-period xorshift + // generator with a Weyl generator, and it passes all common batteries + // of stasticial tests for randomness while consuming only a few nanoseconds + // for each prng generated. For background on the generator, see Brent's + // paper: "Some long-period random number generators using shifts and xors." + // http://arxiv.org/pdf/1004.3115v1.pdf + // + // Usage: + // + // var xor4096 = require('xor4096'); + // random = xor4096(1); // Seed with int32 or string. + // assert.equal(random(), 0.1520436450538547); // (0, 1) range, 53 bits. + // assert.equal(random.int32(), 1806534897); // signed int32, 32 bits. + // + // For nonzero numeric keys, this impelementation provides a sequence + // identical to that by Brent's xorgens 3 implementaion in C. This + // implementation also provides for initalizing the generator with + // string seeds, or for saving and restoring the state of the generator. + // + // On Chrome, this prng benchmarks about 2.1 times slower than + // Javascript's built-in Math.random(). + + (function(global, module, define) { + + function XorGen(seed) { + var me = this; + + // Set up generator function. + me.next = function() { + var w = me.w, + X = me.X, i = me.i, t, v; + // Update Weyl generator. + me.w = w = (w + 0x61c88647) | 0; + // Update xor generator. + v = X[(i + 34) & 127]; + t = X[i = ((i + 1) & 127)]; + v ^= v << 13; + t ^= t << 17; + v ^= v >>> 15; + t ^= t >>> 12; + // Update Xor generator array state. + v = X[i] = v ^ t; + me.i = i; + // Result is the combination. + return (v + (w ^ (w >>> 16))) | 0; + }; + + function init(me, seed) { + var t, v, i, j, w, X = [], limit = 128; + if (seed === (seed | 0)) { + // Numeric seeds initialize v, which is used to generates X. + v = seed; + seed = null; + } else { + // String seeds are mixed into v and X one character at a time. + seed = seed + '\0'; + v = 0; + limit = Math.max(limit, seed.length); + } + // Initialize circular array and weyl value. + for (i = 0, j = -32; j < limit; ++j) { + // Put the unicode characters into the array, and shuffle them. + if (seed) v ^= seed.charCodeAt((j + 32) % seed.length); + // After 32 shuffles, take v as the starting w value. + if (j === 0) w = v; + v ^= v << 10; + v ^= v >>> 15; + v ^= v << 4; + v ^= v >>> 13; + if (j >= 0) { + w = (w + 0x61c88647) | 0; // Weyl. + t = (X[j & 127] ^= (v + w)); // Combine xor and weyl to init array. + i = (0 == t) ? i + 1 : 0; // Count zeroes. + } + } + // We have detected all zeroes; make the key nonzero. + if (i >= 128) { + X[(seed && seed.length || 0) & 127] = -1; + } + // Run the generator 512 times to further mix the state before using it. + // Factoring this as a function slows the main generator, so it is just + // unrolled here. The weyl generator is not advanced while warming up. + i = 127; + for (j = 4 * 128; j > 0; --j) { + v = X[(i + 34) & 127]; + t = X[i = ((i + 1) & 127)]; + v ^= v << 13; + t ^= t << 17; + v ^= v >>> 15; + t ^= t >>> 12; + X[i] = v ^ t; + } + // Storing state as object members is faster than using closure variables. + me.w = w; + me.X = X; + me.i = i; + } + + init(me, seed); + } + + function copy(f, t) { + t.i = f.i; + t.w = f.w; + t.X = f.X.slice(); + return t; + } + function impl(seed, opts) { + if (seed == null) seed = +(new Date); + var xg = new XorGen(seed), + state = opts && opts.state, + prng = function() { return (xg.next() >>> 0) / 0x100000000; }; + prng.double = function() { + do { + var top = xg.next() >>> 11, + bot = (xg.next() >>> 0) / 0x100000000, + result = (top + bot) / (1 << 21); + } while (result === 0); + return result; + }; + prng.int32 = xg.next; + prng.quick = prng; + if (state) { + if (state.X) copy(state, xg); + prng.state = function() { return copy(xg, {}); }; + } + return prng; + } + + if (module && module.exports) { + module.exports = impl; + } else { + this.xor4096 = impl; + } + + })( + xor4096, // window object or global + module); + } (xor4096$1)); + return xor4096$1.exports; + } var tychei$1 = {exports: {}}; - tychei$1.exports; - - (function (module) { - // A Javascript implementaion of the "Tyche-i" prng algorithm by - // Samuel Neves and Filipe Araujo. - // See https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf - - (function(global, module, define) { - - function XorGen(seed) { - var me = this, strseed = ''; - - // Set up generator function. - me.next = function() { - var b = me.b, c = me.c, d = me.d, a = me.a; - b = (b << 25) ^ (b >>> 7) ^ c; - c = (c - d) | 0; - d = (d << 24) ^ (d >>> 8) ^ a; - a = (a - b) | 0; - me.b = b = (b << 20) ^ (b >>> 12) ^ c; - me.c = c = (c - d) | 0; - me.d = (d << 16) ^ (c >>> 16) ^ a; - return me.a = (a - b) | 0; - }; - - /* The following is non-inverted tyche, which has better internal - * bit diffusion, but which is about 25% slower than tyche-i in JS. - me.next = function() { - var a = me.a, b = me.b, c = me.c, d = me.d; - a = (me.a + me.b | 0) >>> 0; - d = me.d ^ a; d = d << 16 ^ d >>> 16; - c = me.c + d | 0; - b = me.b ^ c; b = b << 12 ^ d >>> 20; - me.a = a = a + b | 0; - d = d ^ a; me.d = d = d << 8 ^ d >>> 24; - me.c = c = c + d | 0; - b = b ^ c; - return me.b = (b << 7 ^ b >>> 25); - } - */ - - me.a = 0; - me.b = 0; - me.c = 2654435769 | 0; - me.d = 1367130551; - - if (seed === Math.floor(seed)) { - // Integer seed. - me.a = (seed / 0x100000000) | 0; - me.b = seed | 0; - } else { - // String seed. - strseed += seed; - } - - // Mix in string seed, then discard an initial batch of 64 values. - for (var k = 0; k < strseed.length + 20; k++) { - me.b ^= strseed.charCodeAt(k) | 0; - me.next(); - } - } - - function copy(f, t) { - t.a = f.a; - t.b = f.b; - t.c = f.c; - t.d = f.d; - return t; - } - function impl(seed, opts) { - var xg = new XorGen(seed), - state = opts && opts.state, - prng = function() { return (xg.next() >>> 0) / 0x100000000; }; - prng.double = function() { - do { - var top = xg.next() >>> 11, - bot = (xg.next() >>> 0) / 0x100000000, - result = (top + bot) / (1 << 21); - } while (result === 0); - return result; - }; - prng.int32 = xg.next; - prng.quick = prng; - if (state) { - if (typeof(state) == 'object') copy(state, xg); - prng.state = function() { return copy(xg, {}); }; - } - return prng; - } - - if (module && module.exports) { - module.exports = impl; - } else if (define && define.amd) { - define(function() { return impl; }); - } else { - this.tychei = impl; - } - - })( - commonjsGlobal, - module, // present in node.js - (typeof undefined) == 'function' // present with an AMD loader - ); - } (tychei$1)); - - var tycheiExports = tychei$1.exports; - - var seedrandom$1 = {exports: {}}; + var tychei = tychei$1.exports; + + var hasRequiredTychei; + + function requireTychei () { + if (hasRequiredTychei) return tychei$1.exports; + hasRequiredTychei = 1; + (function (module) { + // A Javascript implementaion of the "Tyche-i" prng algorithm by + // Samuel Neves and Filipe Araujo. + // See https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf + + (function(global, module, define) { + + function XorGen(seed) { + var me = this, strseed = ''; + + // Set up generator function. + me.next = function() { + var b = me.b, c = me.c, d = me.d, a = me.a; + b = (b << 25) ^ (b >>> 7) ^ c; + c = (c - d) | 0; + d = (d << 24) ^ (d >>> 8) ^ a; + a = (a - b) | 0; + me.b = b = (b << 20) ^ (b >>> 12) ^ c; + me.c = c = (c - d) | 0; + me.d = (d << 16) ^ (c >>> 16) ^ a; + return me.a = (a - b) | 0; + }; + + /* The following is non-inverted tyche, which has better internal + * bit diffusion, but which is about 25% slower than tyche-i in JS. + me.next = function() { + var a = me.a, b = me.b, c = me.c, d = me.d; + a = (me.a + me.b | 0) >>> 0; + d = me.d ^ a; d = d << 16 ^ d >>> 16; + c = me.c + d | 0; + b = me.b ^ c; b = b << 12 ^ d >>> 20; + me.a = a = a + b | 0; + d = d ^ a; me.d = d = d << 8 ^ d >>> 24; + me.c = c = c + d | 0; + b = b ^ c; + return me.b = (b << 7 ^ b >>> 25); + } + */ + + me.a = 0; + me.b = 0; + me.c = 2654435769 | 0; + me.d = 1367130551; + + if (seed === Math.floor(seed)) { + // Integer seed. + me.a = (seed / 0x100000000) | 0; + me.b = seed | 0; + } else { + // String seed. + strseed += seed; + } + + // Mix in string seed, then discard an initial batch of 64 values. + for (var k = 0; k < strseed.length + 20; k++) { + me.b ^= strseed.charCodeAt(k) | 0; + me.next(); + } + } + + function copy(f, t) { + t.a = f.a; + t.b = f.b; + t.c = f.c; + t.d = f.d; + return t; + } + function impl(seed, opts) { + var xg = new XorGen(seed), + state = opts && opts.state, + prng = function() { return (xg.next() >>> 0) / 0x100000000; }; + prng.double = function() { + do { + var top = xg.next() >>> 11, + bot = (xg.next() >>> 0) / 0x100000000, + result = (top + bot) / (1 << 21); + } while (result === 0); + return result; + }; + prng.int32 = xg.next; + prng.quick = prng; + if (state) { + if (typeof(state) == 'object') copy(state, xg); + prng.state = function() { return copy(xg, {}); }; + } + return prng; + } + + if (module && module.exports) { + module.exports = impl; + } else { + this.tychei = impl; + } + + })( + tychei, + module); + } (tychei$1)); + return tychei$1.exports; + } + + var seedrandom$2 = {exports: {}}; /* Copyright 2019 David Bau. @@ -5078,300 +5064,315 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - - (function (module) { - (function (global, pool, math) { - // - // The following constants are related to IEEE 754 limits. - // - - var width = 256, // each RC4 output is 0 <= x < 256 - chunks = 6, // at least six RC4 outputs for each double - digits = 52, // there are 52 significant digits in a double - rngname = 'random', // rngname: name for Math.random and Math.seedrandom - startdenom = math.pow(width, chunks), - significance = math.pow(2, digits), - overflow = significance * 2, - mask = width - 1, - nodecrypto; // node.js crypto module, initialized at the bottom. - - // - // seedrandom() - // This is the seedrandom function described above. - // - function seedrandom(seed, options, callback) { - var key = []; - options = (options == true) ? { entropy: true } : (options || {}); - - // Flatten the seed string or build one from local entropy if needed. - var shortseed = mixkey(flatten( - options.entropy ? [seed, tostring(pool)] : - (seed == null) ? autoseed() : seed, 3), key); - - // Use the seed to initialize an ARC4 generator. - var arc4 = new ARC4(key); - - // This function returns a random double in [0, 1) that contains - // randomness in every bit of the mantissa of the IEEE 754 value. - var prng = function() { - var n = arc4.g(chunks), // Start with a numerator n < 2 ^ 48 - d = startdenom, // and denominator d = 2 ^ 48. - x = 0; // and no 'extra last byte'. - while (n < significance) { // Fill up all significant digits by - n = (n + x) * width; // shifting numerator and - d *= width; // denominator and generating a - x = arc4.g(1); // new least-significant-byte. - } - while (n >= overflow) { // To avoid rounding up, before adding - n /= 2; // last byte, shift everything - d /= 2; // right using integer math until - x >>>= 1; // we have exactly the desired bits. - } - return (n + x) / d; // Form the number within [0, 1). - }; - - prng.int32 = function() { return arc4.g(4) | 0; }; - prng.quick = function() { return arc4.g(4) / 0x100000000; }; - prng.double = prng; - - // Mix the randomness into accumulated entropy. - mixkey(tostring(arc4.S), pool); - - // Calling convention: what to return as a function of prng, seed, is_math. - return (options.pass || callback || - function(prng, seed, is_math_call, state) { - if (state) { - // Load the arc4 state from the given state if it has an S array. - if (state.S) { copy(state, arc4); } - // Only provide the .state method if requested via options.state. - prng.state = function() { return copy(arc4, {}); }; - } - - // If called as a method of Math (Math.seedrandom()), mutate - // Math.random because that is how seedrandom.js has worked since v1.0. - if (is_math_call) { math[rngname] = prng; return seed; } - - // Otherwise, it is a newer calling convention, so return the - // prng directly. - else return prng; - })( - prng, - shortseed, - 'global' in options ? options.global : (this == math), - options.state); - } - - // - // ARC4 - // - // An ARC4 implementation. The constructor takes a key in the form of - // an array of at most (width) integers that should be 0 <= x < (width). - // - // The g(count) method returns a pseudorandom integer that concatenates - // the next (count) outputs from ARC4. Its return value is a number x - // that is in the range 0 <= x < (width ^ count). - // - function ARC4(key) { - var t, keylen = key.length, - me = this, i = 0, j = me.i = me.j = 0, s = me.S = []; - - // The empty key [] is treated as [0]. - if (!keylen) { key = [keylen++]; } - - // Set up S using the standard key scheduling algorithm. - while (i < width) { - s[i] = i++; - } - for (i = 0; i < width; i++) { - s[i] = s[j = mask & (j + key[i % keylen] + (t = s[i]))]; - s[j] = t; - } - - // The "g" method returns the next (count) outputs as one number. - (me.g = function(count) { - // Using instance members instead of closure state nearly doubles speed. - var t, r = 0, - i = me.i, j = me.j, s = me.S; - while (count--) { - t = s[i = mask & (i + 1)]; - r = r * width + s[mask & ((s[i] = s[j = mask & (j + t)]) + (s[j] = t))]; - } - me.i = i; me.j = j; - return r; - // For robust unpredictability, the function call below automatically - // discards an initial batch of values. This is called RC4-drop[256]. - // See http://google.com/search?q=rsa+fluhrer+response&btnI - })(width); - } - - // - // copy() - // Copies internal state of ARC4 to or from a plain object. + var seedrandom$1 = seedrandom$2.exports; + + var hasRequiredSeedrandom$1; + + function requireSeedrandom$1 () { + if (hasRequiredSeedrandom$1) return seedrandom$2.exports; + hasRequiredSeedrandom$1 = 1; + (function (module) { + (function (global, pool, math) { + // + // The following constants are related to IEEE 754 limits. + // + + var width = 256, // each RC4 output is 0 <= x < 256 + chunks = 6, // at least six RC4 outputs for each double + digits = 52, // there are 52 significant digits in a double + rngname = 'random', // rngname: name for Math.random and Math.seedrandom + startdenom = math.pow(width, chunks), + significance = math.pow(2, digits), + overflow = significance * 2, + mask = width - 1, + nodecrypto; // node.js crypto module, initialized at the bottom. + + // + // seedrandom() + // This is the seedrandom function described above. + // + function seedrandom(seed, options, callback) { + var key = []; + options = (options == true) ? { entropy: true } : (options || {}); + + // Flatten the seed string or build one from local entropy if needed. + var shortseed = mixkey(flatten( + options.entropy ? [seed, tostring(pool)] : + (seed == null) ? autoseed() : seed, 3), key); + + // Use the seed to initialize an ARC4 generator. + var arc4 = new ARC4(key); + + // This function returns a random double in [0, 1) that contains + // randomness in every bit of the mantissa of the IEEE 754 value. + var prng = function() { + var n = arc4.g(chunks), // Start with a numerator n < 2 ^ 48 + d = startdenom, // and denominator d = 2 ^ 48. + x = 0; // and no 'extra last byte'. + while (n < significance) { // Fill up all significant digits by + n = (n + x) * width; // shifting numerator and + d *= width; // denominator and generating a + x = arc4.g(1); // new least-significant-byte. + } + while (n >= overflow) { // To avoid rounding up, before adding + n /= 2; // last byte, shift everything + d /= 2; // right using integer math until + x >>>= 1; // we have exactly the desired bits. + } + return (n + x) / d; // Form the number within [0, 1). + }; + + prng.int32 = function() { return arc4.g(4) | 0; }; + prng.quick = function() { return arc4.g(4) / 0x100000000; }; + prng.double = prng; + + // Mix the randomness into accumulated entropy. + mixkey(tostring(arc4.S), pool); + + // Calling convention: what to return as a function of prng, seed, is_math. + return (options.pass || callback || + function(prng, seed, is_math_call, state) { + if (state) { + // Load the arc4 state from the given state if it has an S array. + if (state.S) { copy(state, arc4); } + // Only provide the .state method if requested via options.state. + prng.state = function() { return copy(arc4, {}); }; + } + + // If called as a method of Math (Math.seedrandom()), mutate + // Math.random because that is how seedrandom.js has worked since v1.0. + if (is_math_call) { math[rngname] = prng; return seed; } + + // Otherwise, it is a newer calling convention, so return the + // prng directly. + else return prng; + })( + prng, + shortseed, + 'global' in options ? options.global : (this == math), + options.state); + } + + // + // ARC4 + // + // An ARC4 implementation. The constructor takes a key in the form of + // an array of at most (width) integers that should be 0 <= x < (width). + // + // The g(count) method returns a pseudorandom integer that concatenates + // the next (count) outputs from ARC4. Its return value is a number x + // that is in the range 0 <= x < (width ^ count). + // + function ARC4(key) { + var t, keylen = key.length, + me = this, i = 0, j = me.i = me.j = 0, s = me.S = []; + + // The empty key [] is treated as [0]. + if (!keylen) { key = [keylen++]; } + + // Set up S using the standard key scheduling algorithm. + while (i < width) { + s[i] = i++; + } + for (i = 0; i < width; i++) { + s[i] = s[j = mask & (j + key[i % keylen] + (t = s[i]))]; + s[j] = t; + } + + // The "g" method returns the next (count) outputs as one number. + (me.g = function(count) { + // Using instance members instead of closure state nearly doubles speed. + var t, r = 0, + i = me.i, j = me.j, s = me.S; + while (count--) { + t = s[i = mask & (i + 1)]; + r = r * width + s[mask & ((s[i] = s[j = mask & (j + t)]) + (s[j] = t))]; + } + me.i = i; me.j = j; + return r; + // For robust unpredictability, the function call below automatically + // discards an initial batch of values. This is called RC4-drop[256]. + // See http://google.com/search?q=rsa+fluhrer+response&btnI + })(width); + } + + // + // copy() + // Copies internal state of ARC4 to or from a plain object. + // + function copy(f, t) { + t.i = f.i; + t.j = f.j; + t.S = f.S.slice(); + return t; + } + // + // flatten() + // Converts an object tree to nested arrays of strings. + // + function flatten(obj, depth) { + var result = [], typ = (typeof obj), prop; + if (depth && typ == 'object') { + for (prop in obj) { + try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {} + } + } + return (result.length ? result : typ == 'string' ? obj : obj + '\0'); + } + + // + // mixkey() + // Mixes a string seed into a key that is an array of integers, and + // returns a shortened string seed that is equivalent to the result key. + // + function mixkey(seed, key) { + var stringseed = seed + '', smear, j = 0; + while (j < stringseed.length) { + key[mask & j] = + mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++)); + } + return tostring(key); + } + + // + // autoseed() + // Returns an object for autoseeding, using window.crypto and Node crypto + // module if available. + // + function autoseed() { + try { + var out; + if (nodecrypto && (out = nodecrypto.randomBytes)) { + // The use of 'out' to remember randomBytes makes tight minified code. + out = out(width); + } else { + out = new Uint8Array(width); + (global.crypto || global.msCrypto).getRandomValues(out); + } + return tostring(out); + } catch (e) { + var browser = global.navigator, + plugins = browser && browser.plugins; + return [+new Date, global, plugins, global.screen, tostring(pool)]; + } + } + + // + // tostring() + // Converts an array of charcodes to a string + // + function tostring(a) { + return String.fromCharCode.apply(0, a); + } + + // + // When seedrandom.js is loaded, we immediately mix a few bits + // from the built-in RNG into the entropy pool. Because we do + // not want to interfere with deterministic PRNG state later, + // seedrandom will not call math.random on its own again after + // initialization. + // + mixkey(math.random(), pool); + + // + // Nodejs and AMD support: export the implementation as a module using + // either convention. + // + if (module.exports) { + module.exports = seedrandom; + // When in node.js, try using crypto package for autoseeding. + try { + nodecrypto = require('crypto'); + } catch (ex) {} + } else { + // When included as a plain script, set up Math.seedrandom global. + math['seed' + rngname] = seedrandom; + } + + + // End anonymous scope, and pass initial values. + })( + // global: `self` in browsers (including strict mode and web workers), + // otherwise `this` in Node and other environments + (typeof self !== 'undefined') ? self : seedrandom$1, + [], // pool: entropy pool starts empty + Math // math: package containing random, pow, and seedrandom + ); + } (seedrandom$2)); + return seedrandom$2.exports; + } + + var seedrandom; + var hasRequiredSeedrandom; + + function requireSeedrandom () { + if (hasRequiredSeedrandom) return seedrandom; + hasRequiredSeedrandom = 1; + // A library of seedable RNGs implemented in Javascript. // - function copy(f, t) { - t.i = f.i; - t.j = f.j; - t.S = f.S.slice(); - return t; - } - // - // flatten() - // Converts an object tree to nested arrays of strings. - // - function flatten(obj, depth) { - var result = [], typ = (typeof obj), prop; - if (depth && typ == 'object') { - for (prop in obj) { - try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {} - } - } - return (result.length ? result : typ == 'string' ? obj : obj + '\0'); - } - - // - // mixkey() - // Mixes a string seed into a key that is an array of integers, and - // returns a shortened string seed that is equivalent to the result key. - // - function mixkey(seed, key) { - var stringseed = seed + '', smear, j = 0; - while (j < stringseed.length) { - key[mask & j] = - mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++)); - } - return tostring(key); - } - - // - // autoseed() - // Returns an object for autoseeding, using window.crypto and Node crypto - // module if available. - // - function autoseed() { - try { - var out; - if (nodecrypto && (out = nodecrypto.randomBytes)) { - // The use of 'out' to remember randomBytes makes tight minified code. - out = out(width); - } else { - out = new Uint8Array(width); - (global.crypto || global.msCrypto).getRandomValues(out); - } - return tostring(out); - } catch (e) { - var browser = global.navigator, - plugins = browser && browser.plugins; - return [+new Date, global, plugins, global.screen, tostring(pool)]; - } - } - - // - // tostring() - // Converts an array of charcodes to a string - // - function tostring(a) { - return String.fromCharCode.apply(0, a); - } - - // - // When seedrandom.js is loaded, we immediately mix a few bits - // from the built-in RNG into the entropy pool. Because we do - // not want to interfere with deterministic PRNG state later, - // seedrandom will not call math.random on its own again after - // initialization. - // - mixkey(math.random(), pool); - - // - // Nodejs and AMD support: export the implementation as a module using - // either convention. + // Usage: // - if (module.exports) { - module.exports = seedrandom; - // When in node.js, try using crypto package for autoseeding. - try { - nodecrypto = require('crypto'); - } catch (ex) {} - } else { - // When included as a plain script, set up Math.seedrandom global. - math['seed' + rngname] = seedrandom; - } - - - // End anonymous scope, and pass initial values. - })( - // global: `self` in browsers (including strict mode and web workers), - // otherwise `this` in Node and other environments - (typeof self !== 'undefined') ? self : commonjsGlobal, - [], // pool: entropy pool starts empty - Math // math: package containing random, pow, and seedrandom - ); - } (seedrandom$1)); - - var seedrandomExports = seedrandom$1.exports; - - // A library of seedable RNGs implemented in Javascript. - // - // Usage: - // - // var seedrandom = require('seedrandom'); - // var random = seedrandom(1); // or any seed. - // var x = random(); // 0 <= x < 1. Every bit is random. - // var x = random.quick(); // 0 <= x < 1. 32 bits of randomness. - - // alea, a 53-bit multiply-with-carry generator by Johannes Baagøe. - // Period: ~2^116 - // Reported to pass all BigCrush tests. - var alea = aleaExports; - - // xor128, a pure xor-shift generator by George Marsaglia. - // Period: 2^128-1. - // Reported to fail: MatrixRank and LinearComp. - var xor128 = xor128Exports; - - // xorwow, George Marsaglia's 160-bit xor-shift combined plus weyl. - // Period: 2^192-2^32 - // Reported to fail: CollisionOver, SimpPoker, and LinearComp. - var xorwow = xorwowExports; - - // xorshift7, by François Panneton and Pierre L'ecuyer, takes - // a different approach: it adds robustness by allowing more shifts - // than Marsaglia's original three. It is a 7-shift generator - // with 256 bits, that passes BigCrush with no systmatic failures. - // Period 2^256-1. - // No systematic BigCrush failures reported. - var xorshift7 = xorshift7Exports; - - // xor4096, by Richard Brent, is a 4096-bit xor-shift with a - // very long period that also adds a Weyl generator. It also passes - // BigCrush with no systematic failures. Its long period may - // be useful if you have many generators and need to avoid - // collisions. - // Period: 2^4128-2^32. - // No systematic BigCrush failures reported. - var xor4096 = xor4096Exports; - - // Tyche-i, by Samuel Neves and Filipe Araujo, is a bit-shifting random - // number generator derived from ChaCha, a modern stream cipher. - // https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf - // Period: ~2^127 - // No systematic BigCrush failures reported. - var tychei = tycheiExports; - - // The original ARC4-based prng included in this library. - // Period: ~2^1600 - var sr = seedrandomExports; - - sr.alea = alea; - sr.xor128 = xor128; - sr.xorwow = xorwow; - sr.xorshift7 = xorshift7; - sr.xor4096 = xor4096; - sr.tychei = tychei; - - var seedrandom = sr; - - var Seedrandom = /*@__PURE__*/getDefaultExportFromCjs(seedrandom); + // var seedrandom = require('seedrandom'); + // var random = seedrandom(1); // or any seed. + // var x = random(); // 0 <= x < 1. Every bit is random. + // var x = random.quick(); // 0 <= x < 1. 32 bits of randomness. + + // alea, a 53-bit multiply-with-carry generator by Johannes Baagøe. + // Period: ~2^116 + // Reported to pass all BigCrush tests. + var alea = requireAlea(); + + // xor128, a pure xor-shift generator by George Marsaglia. + // Period: 2^128-1. + // Reported to fail: MatrixRank and LinearComp. + var xor128 = requireXor128(); + + // xorwow, George Marsaglia's 160-bit xor-shift combined plus weyl. + // Period: 2^192-2^32 + // Reported to fail: CollisionOver, SimpPoker, and LinearComp. + var xorwow = requireXorwow(); + + // xorshift7, by François Panneton and Pierre L'ecuyer, takes + // a different approach: it adds robustness by allowing more shifts + // than Marsaglia's original three. It is a 7-shift generator + // with 256 bits, that passes BigCrush with no systmatic failures. + // Period 2^256-1. + // No systematic BigCrush failures reported. + var xorshift7 = requireXorshift7(); + + // xor4096, by Richard Brent, is a 4096-bit xor-shift with a + // very long period that also adds a Weyl generator. It also passes + // BigCrush with no systematic failures. Its long period may + // be useful if you have many generators and need to avoid + // collisions. + // Period: 2^4128-2^32. + // No systematic BigCrush failures reported. + var xor4096 = requireXor4096(); + + // Tyche-i, by Samuel Neves and Filipe Araujo, is a bit-shifting random + // number generator derived from ChaCha, a modern stream cipher. + // https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf + // Period: ~2^127 + // No systematic BigCrush failures reported. + var tychei = requireTychei(); + + // The original ARC4-based prng included in this library. + // Period: ~2^1600 + var sr = requireSeedrandom$1(); + + sr.alea = alea; + sr.xor128 = xor128; + sr.xorwow = xorwow; + sr.xorshift7 = xorshift7; + sr.xor4096 = xor4096; + sr.tychei = tychei; + + seedrandom = sr; + return seedrandom; + } + + var seedrandomExports = requireSeedrandom(); + var Seedrandom = /*@__PURE__*/getDefaultExportFromCjs(seedrandomExports); /** * @param {HTMLCanvasElement} canvas @@ -5896,7 +5897,7 @@ try { this.defineProperty(globalThis, property, { get: () => value, - // eslint-disable-next-line @typescript-eslint/no-empty-function + set: () => {}, configurable: true, enumerable: true @@ -8401,6 +8402,7 @@ /** * Append both to the shadow root */ + // eslint-disable-next-line @typescript-eslint/no-unused-expressions feedbackLink && this.placeholderBlocked.appendChild(feedbackLink); shadow.appendChild(this.placeholderBlocked); shadow.appendChild(style); @@ -10671,7 +10673,7 @@ }); // Listen to message from Platform letting CTL know that we're ready to // replace elements in the page - // eslint-disable-next-line promise/prefer-await-to-then + this.messaging.subscribe( 'displayClickToLoadPlaceholders', // TODO: Pass `message.options.ruleAction` through, that way only @@ -13036,7 +13038,7 @@ * @internal */ class DuckPlayerFeature extends ContentFeature { - // eslint-disable-next-line @typescript-eslint/no-unused-vars + init (args) { /** * This feature never operates in a frame diff --git a/node_modules/@duckduckgo/content-scope-scripts/build/android/pages/duckplayer/js/index.css b/node_modules/@duckduckgo/content-scope-scripts/build/android/pages/duckplayer/js/index.css index 97d77ce608d7..1a5823f3cb6b 100644 --- a/node_modules/@duckduckgo/content-scope-scripts/build/android/pages/duckplayer/js/index.css +++ b/node_modules/@duckduckgo/content-scope-scripts/build/android/pages/duckplayer/js/index.css @@ -413,7 +413,12 @@ body[data-display=app] { /* pages/duckplayer/app/components/Tooltip.module.css */ .Tooltip_tooltip { position: absolute; - background: linear-gradient(0deg, rgba(48, 48, 48, 0.35), rgba(48, 48, 48, 0.35)), rgba(33, 33, 33, 0.55); + background: + linear-gradient( + 0deg, + rgba(48, 48, 48, 0.35), + rgba(48, 48, 48, 0.35)), + rgba(33, 33, 33, 0.55); background-blend-mode: normal, luminosity; box-shadow: inset 0px 0px 1px #ffffff; filter: drop-shadow(0px 0px 1px #000000) drop-shadow(0px 0px 1px #000000) drop-shadow(0px 0px 1px #000000) drop-shadow(0px 8px 16px rgba(0, 0, 0, 0.2)); @@ -543,7 +548,12 @@ body[data-display=app] { position: absolute; inset: 0; height: 100%; - background: linear-gradient(0deg, rgba(0, 0, 0, 0.00) 0%, rgba(0, 0, 0, 0.48) 32.23%, #000 93.87%); + background: + linear-gradient( + 0deg, + rgba(0, 0, 0, 0.00) 0%, + rgba(0, 0, 0, 0.48) 32.23%, + #000 93.87%); transition: all .3s ease-in-out; } .Background_bg::after { @@ -551,7 +561,12 @@ body[data-display=app] { position: absolute; inset: 0; height: 100%; - background: linear-gradient(0deg, rgba(0, 0, 0, 0.48) 0%, rgba(0, 0, 0, 0.90) 34.34%, #000 100%); + background: + linear-gradient( + 0deg, + rgba(0, 0, 0, 0.48) 0%, + rgba(0, 0, 0, 0.90) 34.34%, + #000 100%); opacity: 0; visibility: hidden; transition: all .3s ease-in-out; diff --git a/node_modules/@duckduckgo/content-scope-scripts/build/android/pages/duckplayer/js/index.js b/node_modules/@duckduckgo/content-scope-scripts/build/android/pages/duckplayer/js/index.js index df62aec3b196..6eb419c4f485 100644 --- a/node_modules/@duckduckgo/content-scope-scripts/build/android/pages/duckplayer/js/index.js +++ b/node_modules/@duckduckgo/content-scope-scripts/build/android/pages/duckplayer/js/index.js @@ -32,36 +32,45 @@ (function() { "use strict"; var hasOwn = {}.hasOwnProperty; - var nativeCodeString = "[native code]"; function classNames() { - var classes = []; + var classes = ""; for (var i3 = 0; i3 < arguments.length; i3++) { var arg = arguments[i3]; - if (!arg) - continue; - var argType = typeof arg; - if (argType === "string" || argType === "number") { - classes.push(arg); - } else if (Array.isArray(arg)) { - if (arg.length) { - var inner = classNames.apply(null, arg); - if (inner) { - classes.push(inner); - } - } - } else if (argType === "object") { - if (arg.toString !== Object.prototype.toString && !arg.toString.toString().includes("[native code]")) { - classes.push(arg.toString()); - continue; - } - for (var key in arg) { - if (hasOwn.call(arg, key) && arg[key]) { - classes.push(key); - } - } + if (arg) { + classes = appendClass(classes, parseValue(arg)); } } - return classes.join(" "); + return classes; + } + function parseValue(arg) { + if (typeof arg === "string" || typeof arg === "number") { + return arg; + } + if (typeof arg !== "object") { + return ""; + } + if (Array.isArray(arg)) { + return classNames.apply(null, arg); + } + if (arg.toString !== Object.prototype.toString && !arg.toString.toString().includes("[native code]")) { + return arg.toString(); + } + var classes = ""; + for (var key in arg) { + if (hasOwn.call(arg, key) && arg[key]) { + classes = appendClass(classes, key); + } + } + return classes; + } + function appendClass(value, newClass) { + if (!newClass) { + return value; + } + if (value) { + return value + " " + newClass; + } + return value + newClass; } if (typeof module !== "undefined" && module.exports) { classNames.default = classNames; @@ -122,10 +131,8 @@ return eventData.featureName === msg.featureName && eventData.context === msg.context && eventData.id === msg.id; }; function isMessageResponse(data2) { - if ("result" in data2) - return true; - if ("error" in data2) - return true; + if ("result" in data2) return true; + if ("error" in data2) return true; return false; } return new this.globals.Promise((resolve, reject) => { @@ -186,8 +193,7 @@ return; } if (comparator(event.data)) { - if (!teardown) - throw new Error("unreachable"); + if (!teardown) throw new Error("unreachable"); callback(event.data, teardown); } }; @@ -537,8 +543,7 @@ */ captureWebkitHandlers(handlerNames) { const handlers = window.webkit.messageHandlers; - if (!handlers) - throw new MissingHandler("window.webkit.messageHandlers was absent", "all"); + if (!handlers) throw new MissingHandler("window.webkit.messageHandlers was absent", "all"); for (const webkitMessageHandlerName of handlerNames) { if (typeof handlers[webkitMessageHandlerName]?.postMessage === "function") { const original = handlers[webkitMessageHandlerName]; @@ -763,8 +768,7 @@ * @internal */ _dispatch(payload) { - if (!payload) - return this._log("no response"); + if (!payload) return this._log("no response"); if ("id" in payload) { if (this.listeners.has(payload.id)) { this._tryCatch(() => this.listeners.get(payload.id)?.(payload)); @@ -1020,10 +1024,8 @@ * @returns {Environment} */ withInjectName(injectName) { - if (!injectName) - return this; - if (!isInjectName(injectName)) - return this; + if (!injectName) return this; + if (!isInjectName(injectName)) return this; return new _Environment({ ...this, injectName @@ -1034,10 +1036,8 @@ * @returns {Environment} */ withEnv(env) { - if (!env) - return this; - if (env !== "production" && env !== "development") - return this; + if (!env) return this; + if (env !== "production" && env !== "development") return this; return new _Environment({ ...this, env @@ -1048,10 +1048,8 @@ * @returns {Environment} */ withDisplay(display) { - if (!display) - return this; - if (display !== "app" && display !== "components") - return this; + if (!display) return this; + if (display !== "app" && display !== "components") return this; return new _Environment({ ...this, display @@ -1062,12 +1060,9 @@ * @returns {Environment} */ withLocale(locale) { - if (!locale) - return this; - if (typeof locale !== "string") - return this; - if (locale.length !== 2) - return this; + if (!locale) return this; + if (typeof locale !== "string") return this; + if (locale.length !== 2) return this; return new _Environment({ ...this, locale @@ -1078,8 +1073,7 @@ * @returns {Environment} */ withTextLength(length) { - if (!length) - return this; + if (!length) return this; const num = Number(length); if (num >= 1 && num <= 2) { return new _Environment({ @@ -1145,7 +1139,6 @@ /** * @param {import('@duckduckgo/messaging').RequestMessage} msg */ - // eslint-disable-next-line @typescript-eslint/no-unused-vars request: (msg) => { console.log(msg); if (msg.method === "initialSetup") { @@ -1205,8 +1198,7 @@ var p = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i; var y = Array.isArray; function d(n2, l3) { - for (var u3 in l3) - n2[u3] = l3[u3]; + for (var u3 in l3) n2[u3] = l3[u3]; return n2; } function w(n2) { @@ -1214,11 +1206,8 @@ } function _(l3, u3, t3) { var i3, o3, r3, f3 = {}; - for (r3 in u3) - "key" == r3 ? i3 = u3[r3] : "ref" == r3 ? o3 = u3[r3] : f3[r3] = u3[r3]; - if (arguments.length > 2 && (f3.children = arguments.length > 3 ? n.call(arguments, 2) : t3), "function" == typeof l3 && null != l3.defaultProps) - for (r3 in l3.defaultProps) - void 0 === f3[r3] && (f3[r3] = l3.defaultProps[r3]); + for (r3 in u3) "key" == r3 ? i3 = u3[r3] : "ref" == r3 ? o3 = u3[r3] : f3[r3] = u3[r3]; + if (arguments.length > 2 && (f3.children = arguments.length > 3 ? n.call(arguments, 2) : t3), "function" == typeof l3 && null != l3.defaultProps) for (r3 in l3.defaultProps) void 0 === f3[r3] && (f3[r3] = l3.defaultProps[r3]); return g(l3, f3, i3, o3, null); } function g(n2, t3, i3, o3, r3) { @@ -1232,21 +1221,17 @@ this.props = n2, this.context = l3; } function x(n2, l3) { - if (null == l3) - return n2.__ ? x(n2.__, n2.__i + 1) : null; - for (var u3; l3 < n2.__k.length; l3++) - if (null != (u3 = n2.__k[l3]) && null != u3.__e) - return u3.__e; + if (null == l3) return n2.__ ? x(n2.__, n2.__i + 1) : null; + for (var u3; l3 < n2.__k.length; l3++) if (null != (u3 = n2.__k[l3]) && null != u3.__e) return u3.__e; return "function" == typeof n2.type ? x(n2) : null; } function C(n2) { var l3, u3; if (null != (n2 = n2.__) && null != n2.__c) { - for (n2.__e = n2.__c.base = null, l3 = 0; l3 < n2.__k.length; l3++) - if (null != (u3 = n2.__k[l3]) && null != u3.__e) { - n2.__e = n2.__c.base = u3.__e; - break; - } + for (n2.__e = n2.__c.base = null, l3 = 0; l3 < n2.__k.length; l3++) if (null != (u3 = n2.__k[l3]) && null != u3.__e) { + n2.__e = n2.__c.base = u3.__e; + break; + } return C(n2); } } @@ -1255,29 +1240,23 @@ } function M() { var n2, u3, t3, o3, r3, e3, c3, s3; - for (i.sort(f); n2 = i.shift(); ) - n2.__d && (u3 = i.length, o3 = void 0, e3 = (r3 = (t3 = n2).__v).__e, c3 = [], s3 = [], t3.__P && ((o3 = d({}, r3)).__v = r3.__v + 1, l.vnode && l.vnode(o3), O(t3.__P, o3, r3, t3.__n, t3.__P.namespaceURI, 32 & r3.__u ? [e3] : null, c3, null == e3 ? x(r3) : e3, !!(32 & r3.__u), s3), o3.__v = r3.__v, o3.__.__k[o3.__i] = o3, j(c3, o3, s3), o3.__e != e3 && C(o3)), i.length > u3 && i.sort(f)); + for (i.sort(f); n2 = i.shift(); ) n2.__d && (u3 = i.length, o3 = void 0, e3 = (r3 = (t3 = n2).__v).__e, c3 = [], s3 = [], t3.__P && ((o3 = d({}, r3)).__v = r3.__v + 1, l.vnode && l.vnode(o3), O(t3.__P, o3, r3, t3.__n, t3.__P.namespaceURI, 32 & r3.__u ? [e3] : null, c3, null == e3 ? x(r3) : e3, !!(32 & r3.__u), s3), o3.__v = r3.__v, o3.__.__k[o3.__i] = o3, j(c3, o3, s3), o3.__e != e3 && C(o3)), i.length > u3 && i.sort(f)); M.__r = 0; } function P(n2, l3, u3, t3, i3, o3, r3, f3, e3, c3, s3) { var a3, p3, y3, d3, w3, _3 = t3 && t3.__k || v, g3 = l3.length; - for (u3.__d = e3, $(u3, l3, _3), e3 = u3.__d, a3 = 0; a3 < g3; a3++) - null != (y3 = u3.__k[a3]) && (p3 = -1 === y3.__i ? h : _3[y3.__i] || h, y3.__i = a3, O(n2, y3, p3, i3, o3, r3, f3, e3, c3, s3), d3 = y3.__e, y3.ref && p3.ref != y3.ref && (p3.ref && N(p3.ref, null, y3), s3.push(y3.ref, y3.__c || d3, y3)), null == w3 && null != d3 && (w3 = d3), 65536 & y3.__u || p3.__k === y3.__k ? e3 = I(y3, e3, n2) : "function" == typeof y3.type && void 0 !== y3.__d ? e3 = y3.__d : d3 && (e3 = d3.nextSibling), y3.__d = void 0, y3.__u &= -196609); + for (u3.__d = e3, $(u3, l3, _3), e3 = u3.__d, a3 = 0; a3 < g3; a3++) null != (y3 = u3.__k[a3]) && (p3 = -1 === y3.__i ? h : _3[y3.__i] || h, y3.__i = a3, O(n2, y3, p3, i3, o3, r3, f3, e3, c3, s3), d3 = y3.__e, y3.ref && p3.ref != y3.ref && (p3.ref && N(p3.ref, null, y3), s3.push(y3.ref, y3.__c || d3, y3)), null == w3 && null != d3 && (w3 = d3), 65536 & y3.__u || p3.__k === y3.__k ? e3 = I(y3, e3, n2) : "function" == typeof y3.type && void 0 !== y3.__d ? e3 = y3.__d : d3 && (e3 = d3.nextSibling), y3.__d = void 0, y3.__u &= -196609); u3.__d = e3, u3.__e = w3; } function $(n2, l3, u3) { var t3, i3, o3, r3, f3, e3 = l3.length, c3 = u3.length, s3 = c3, a3 = 0; - for (n2.__k = [], t3 = 0; t3 < e3; t3++) - null != (i3 = l3[t3]) && "boolean" != typeof i3 && "function" != typeof i3 ? (r3 = t3 + a3, (i3 = n2.__k[t3] = "string" == typeof i3 || "number" == typeof i3 || "bigint" == typeof i3 || i3.constructor == String ? g(null, i3, null, null, null) : y(i3) ? g(b, { children: i3 }, null, null, null) : void 0 === i3.constructor && i3.__b > 0 ? g(i3.type, i3.props, i3.key, i3.ref ? i3.ref : null, i3.__v) : i3).__ = n2, i3.__b = n2.__b + 1, o3 = null, -1 !== (f3 = i3.__i = L(i3, u3, r3, s3)) && (s3--, (o3 = u3[f3]) && (o3.__u |= 131072)), null == o3 || null === o3.__v ? (-1 == f3 && a3--, "function" != typeof i3.type && (i3.__u |= 65536)) : f3 !== r3 && (f3 == r3 - 1 ? a3-- : f3 == r3 + 1 ? a3++ : (f3 > r3 ? a3-- : a3++, i3.__u |= 65536))) : i3 = n2.__k[t3] = null; - if (s3) - for (t3 = 0; t3 < c3; t3++) - null != (o3 = u3[t3]) && 0 == (131072 & o3.__u) && (o3.__e == n2.__d && (n2.__d = x(o3)), V(o3, o3)); + for (n2.__k = [], t3 = 0; t3 < e3; t3++) null != (i3 = l3[t3]) && "boolean" != typeof i3 && "function" != typeof i3 ? (r3 = t3 + a3, (i3 = n2.__k[t3] = "string" == typeof i3 || "number" == typeof i3 || "bigint" == typeof i3 || i3.constructor == String ? g(null, i3, null, null, null) : y(i3) ? g(b, { children: i3 }, null, null, null) : void 0 === i3.constructor && i3.__b > 0 ? g(i3.type, i3.props, i3.key, i3.ref ? i3.ref : null, i3.__v) : i3).__ = n2, i3.__b = n2.__b + 1, o3 = null, -1 !== (f3 = i3.__i = L(i3, u3, r3, s3)) && (s3--, (o3 = u3[f3]) && (o3.__u |= 131072)), null == o3 || null === o3.__v ? (-1 == f3 && a3--, "function" != typeof i3.type && (i3.__u |= 65536)) : f3 !== r3 && (f3 == r3 - 1 ? a3-- : f3 == r3 + 1 ? a3++ : (f3 > r3 ? a3-- : a3++, i3.__u |= 65536))) : i3 = n2.__k[t3] = null; + if (s3) for (t3 = 0; t3 < c3; t3++) null != (o3 = u3[t3]) && 0 == (131072 & o3.__u) && (o3.__e == n2.__d && (n2.__d = x(o3)), V(o3, o3)); } function I(n2, l3, u3) { var t3, i3; if ("function" == typeof n2.type) { - for (t3 = n2.__k, i3 = 0; t3 && i3 < t3.length; i3++) - t3[i3] && (t3[i3].__ = n2, l3 = I(t3[i3], l3, u3)); + for (t3 = n2.__k, i3 = 0; t3 && i3 < t3.length; i3++) t3[i3] && (t3[i3].__ = n2, l3 = I(t3[i3], l3, u3)); return l3; } n2.__e != l3 && (l3 && n2.type && !u3.contains(l3) && (l3 = x(n2)), u3.insertBefore(n2.__e, l3 || null), l3 = n2.__e); @@ -1288,21 +1267,17 @@ } function L(n2, l3, u3, t3) { var i3 = n2.key, o3 = n2.type, r3 = u3 - 1, f3 = u3 + 1, e3 = l3[u3]; - if (null === e3 || e3 && i3 == e3.key && o3 === e3.type && 0 == (131072 & e3.__u)) - return u3; - if (t3 > (null != e3 && 0 == (131072 & e3.__u) ? 1 : 0)) - for (; r3 >= 0 || f3 < l3.length; ) { - if (r3 >= 0) { - if ((e3 = l3[r3]) && 0 == (131072 & e3.__u) && i3 == e3.key && o3 === e3.type) - return r3; - r3--; - } - if (f3 < l3.length) { - if ((e3 = l3[f3]) && 0 == (131072 & e3.__u) && i3 == e3.key && o3 === e3.type) - return f3; - f3++; - } + if (null === e3 || e3 && i3 == e3.key && o3 === e3.type && 0 == (131072 & e3.__u)) return u3; + if (t3 > (null != e3 && 0 == (131072 & e3.__u) ? 1 : 0)) for (; r3 >= 0 || f3 < l3.length; ) { + if (r3 >= 0) { + if ((e3 = l3[r3]) && 0 == (131072 & e3.__u) && i3 == e3.key && o3 === e3.type) return r3; + r3--; + } + if (f3 < l3.length) { + if ((e3 = l3[f3]) && 0 == (131072 & e3.__u) && i3 == e3.key && o3 === e3.type) return f3; + f3++; } + } return -1; } function T(n2, l3, u3) { @@ -1310,93 +1285,70 @@ } function A(n2, l3, u3, t3, i3) { var o3; - n: - if ("style" === l3) - if ("string" == typeof u3) - n2.style.cssText = u3; - else { - if ("string" == typeof t3 && (n2.style.cssText = t3 = ""), t3) - for (l3 in t3) - u3 && l3 in u3 || T(n2.style, l3, ""); - if (u3) - for (l3 in u3) - t3 && u3[l3] === t3[l3] || T(n2.style, l3, u3[l3]); - } - else if ("o" === l3[0] && "n" === l3[1]) - o3 = l3 !== (l3 = l3.replace(/(PointerCapture)$|Capture$/i, "$1")), l3 = l3.toLowerCase() in n2 || "onFocusOut" === l3 || "onFocusIn" === l3 ? l3.toLowerCase().slice(2) : l3.slice(2), n2.l || (n2.l = {}), n2.l[l3 + o3] = u3, u3 ? t3 ? u3.u = t3.u : (u3.u = e, n2.addEventListener(l3, o3 ? s : c, o3)) : n2.removeEventListener(l3, o3 ? s : c, o3); - else { - if ("http://www.w3.org/2000/svg" == i3) - l3 = l3.replace(/xlink(H|:h)/, "h").replace(/sName$/, "s"); - else if ("width" != l3 && "height" != l3 && "href" != l3 && "list" != l3 && "form" != l3 && "tabIndex" != l3 && "download" != l3 && "rowSpan" != l3 && "colSpan" != l3 && "role" != l3 && "popover" != l3 && l3 in n2) - try { - n2[l3] = null == u3 ? "" : u3; - break n; - } catch (n3) { - } - "function" == typeof u3 || (null == u3 || false === u3 && "-" !== l3[4] ? n2.removeAttribute(l3) : n2.setAttribute(l3, "popover" == l3 && 1 == u3 ? "" : u3)); + n: if ("style" === l3) if ("string" == typeof u3) n2.style.cssText = u3; + else { + if ("string" == typeof t3 && (n2.style.cssText = t3 = ""), t3) for (l3 in t3) u3 && l3 in u3 || T(n2.style, l3, ""); + if (u3) for (l3 in u3) t3 && u3[l3] === t3[l3] || T(n2.style, l3, u3[l3]); + } + else if ("o" === l3[0] && "n" === l3[1]) o3 = l3 !== (l3 = l3.replace(/(PointerCapture)$|Capture$/i, "$1")), l3 = l3.toLowerCase() in n2 || "onFocusOut" === l3 || "onFocusIn" === l3 ? l3.toLowerCase().slice(2) : l3.slice(2), n2.l || (n2.l = {}), n2.l[l3 + o3] = u3, u3 ? t3 ? u3.u = t3.u : (u3.u = e, n2.addEventListener(l3, o3 ? s : c, o3)) : n2.removeEventListener(l3, o3 ? s : c, o3); + else { + if ("http://www.w3.org/2000/svg" == i3) l3 = l3.replace(/xlink(H|:h)/, "h").replace(/sName$/, "s"); + else if ("width" != l3 && "height" != l3 && "href" != l3 && "list" != l3 && "form" != l3 && "tabIndex" != l3 && "download" != l3 && "rowSpan" != l3 && "colSpan" != l3 && "role" != l3 && "popover" != l3 && l3 in n2) try { + n2[l3] = null == u3 ? "" : u3; + break n; + } catch (n3) { } + "function" == typeof u3 || (null == u3 || false === u3 && "-" !== l3[4] ? n2.removeAttribute(l3) : n2.setAttribute(l3, "popover" == l3 && 1 == u3 ? "" : u3)); + } } function F(n2) { return function(u3) { if (this.l) { var t3 = this.l[u3.type + n2]; - if (null == u3.t) - u3.t = e++; - else if (u3.t < t3.u) - return; + if (null == u3.t) u3.t = e++; + else if (u3.t < t3.u) return; return t3(l.event ? l.event(u3) : u3); } }; } function O(n2, u3, t3, i3, o3, r3, f3, e3, c3, s3) { var a3, h3, v3, p3, w3, _3, g3, m2, x3, C3, S2, M2, $2, I2, H, L2, T3 = u3.type; - if (void 0 !== u3.constructor) - return null; + if (void 0 !== u3.constructor) return null; 128 & t3.__u && (c3 = !!(32 & t3.__u), r3 = [e3 = u3.__e = t3.__e]), (a3 = l.__b) && a3(u3); - n: - if ("function" == typeof T3) - try { - if (m2 = u3.props, x3 = "prototype" in T3 && T3.prototype.render, C3 = (a3 = T3.contextType) && i3[a3.__c], S2 = a3 ? C3 ? C3.props.value : a3.__ : i3, t3.__c ? g3 = (h3 = u3.__c = t3.__c).__ = h3.__E : (x3 ? u3.__c = h3 = new T3(m2, S2) : (u3.__c = h3 = new k(m2, S2), h3.constructor = T3, h3.render = q), C3 && C3.sub(h3), h3.props = m2, h3.state || (h3.state = {}), h3.context = S2, h3.__n = i3, v3 = h3.__d = true, h3.__h = [], h3._sb = []), x3 && null == h3.__s && (h3.__s = h3.state), x3 && null != T3.getDerivedStateFromProps && (h3.__s == h3.state && (h3.__s = d({}, h3.__s)), d(h3.__s, T3.getDerivedStateFromProps(m2, h3.__s))), p3 = h3.props, w3 = h3.state, h3.__v = u3, v3) - x3 && null == T3.getDerivedStateFromProps && null != h3.componentWillMount && h3.componentWillMount(), x3 && null != h3.componentDidMount && h3.__h.push(h3.componentDidMount); - else { - if (x3 && null == T3.getDerivedStateFromProps && m2 !== p3 && null != h3.componentWillReceiveProps && h3.componentWillReceiveProps(m2, S2), !h3.__e && (null != h3.shouldComponentUpdate && false === h3.shouldComponentUpdate(m2, h3.__s, S2) || u3.__v === t3.__v)) { - for (u3.__v !== t3.__v && (h3.props = m2, h3.state = h3.__s, h3.__d = false), u3.__e = t3.__e, u3.__k = t3.__k, u3.__k.some(function(n3) { - n3 && (n3.__ = u3); - }), M2 = 0; M2 < h3._sb.length; M2++) - h3.__h.push(h3._sb[M2]); - h3._sb = [], h3.__h.length && f3.push(h3); - break n; - } - null != h3.componentWillUpdate && h3.componentWillUpdate(m2, h3.__s, S2), x3 && null != h3.componentDidUpdate && h3.__h.push(function() { - h3.componentDidUpdate(p3, w3, _3); - }); - } - if (h3.context = S2, h3.props = m2, h3.__P = n2, h3.__e = false, $2 = l.__r, I2 = 0, x3) { - for (h3.state = h3.__s, h3.__d = false, $2 && $2(u3), a3 = h3.render(h3.props, h3.state, h3.context), H = 0; H < h3._sb.length; H++) - h3.__h.push(h3._sb[H]); - h3._sb = []; - } else - do { - h3.__d = false, $2 && $2(u3), a3 = h3.render(h3.props, h3.state, h3.context), h3.state = h3.__s; - } while (h3.__d && ++I2 < 25); - h3.state = h3.__s, null != h3.getChildContext && (i3 = d(d({}, i3), h3.getChildContext())), x3 && !v3 && null != h3.getSnapshotBeforeUpdate && (_3 = h3.getSnapshotBeforeUpdate(p3, w3)), P(n2, y(L2 = null != a3 && a3.type === b && null == a3.key ? a3.props.children : a3) ? L2 : [L2], u3, t3, i3, o3, r3, f3, e3, c3, s3), h3.base = u3.__e, u3.__u &= -161, h3.__h.length && f3.push(h3), g3 && (h3.__E = h3.__ = null); - } catch (n3) { - if (u3.__v = null, c3 || null != r3) { - for (u3.__u |= c3 ? 160 : 128; e3 && 8 === e3.nodeType && e3.nextSibling; ) - e3 = e3.nextSibling; - r3[r3.indexOf(e3)] = null, u3.__e = e3; - } else - u3.__e = t3.__e, u3.__k = t3.__k; - l.__e(n3, u3, t3); - } - else - null == r3 && u3.__v === t3.__v ? (u3.__k = t3.__k, u3.__e = t3.__e) : u3.__e = z(t3.__e, u3, t3, i3, o3, r3, f3, c3, s3); + n: if ("function" == typeof T3) try { + if (m2 = u3.props, x3 = "prototype" in T3 && T3.prototype.render, C3 = (a3 = T3.contextType) && i3[a3.__c], S2 = a3 ? C3 ? C3.props.value : a3.__ : i3, t3.__c ? g3 = (h3 = u3.__c = t3.__c).__ = h3.__E : (x3 ? u3.__c = h3 = new T3(m2, S2) : (u3.__c = h3 = new k(m2, S2), h3.constructor = T3, h3.render = q), C3 && C3.sub(h3), h3.props = m2, h3.state || (h3.state = {}), h3.context = S2, h3.__n = i3, v3 = h3.__d = true, h3.__h = [], h3._sb = []), x3 && null == h3.__s && (h3.__s = h3.state), x3 && null != T3.getDerivedStateFromProps && (h3.__s == h3.state && (h3.__s = d({}, h3.__s)), d(h3.__s, T3.getDerivedStateFromProps(m2, h3.__s))), p3 = h3.props, w3 = h3.state, h3.__v = u3, v3) x3 && null == T3.getDerivedStateFromProps && null != h3.componentWillMount && h3.componentWillMount(), x3 && null != h3.componentDidMount && h3.__h.push(h3.componentDidMount); + else { + if (x3 && null == T3.getDerivedStateFromProps && m2 !== p3 && null != h3.componentWillReceiveProps && h3.componentWillReceiveProps(m2, S2), !h3.__e && (null != h3.shouldComponentUpdate && false === h3.shouldComponentUpdate(m2, h3.__s, S2) || u3.__v === t3.__v)) { + for (u3.__v !== t3.__v && (h3.props = m2, h3.state = h3.__s, h3.__d = false), u3.__e = t3.__e, u3.__k = t3.__k, u3.__k.some(function(n3) { + n3 && (n3.__ = u3); + }), M2 = 0; M2 < h3._sb.length; M2++) h3.__h.push(h3._sb[M2]); + h3._sb = [], h3.__h.length && f3.push(h3); + break n; + } + null != h3.componentWillUpdate && h3.componentWillUpdate(m2, h3.__s, S2), x3 && null != h3.componentDidUpdate && h3.__h.push(function() { + h3.componentDidUpdate(p3, w3, _3); + }); + } + if (h3.context = S2, h3.props = m2, h3.__P = n2, h3.__e = false, $2 = l.__r, I2 = 0, x3) { + for (h3.state = h3.__s, h3.__d = false, $2 && $2(u3), a3 = h3.render(h3.props, h3.state, h3.context), H = 0; H < h3._sb.length; H++) h3.__h.push(h3._sb[H]); + h3._sb = []; + } else do { + h3.__d = false, $2 && $2(u3), a3 = h3.render(h3.props, h3.state, h3.context), h3.state = h3.__s; + } while (h3.__d && ++I2 < 25); + h3.state = h3.__s, null != h3.getChildContext && (i3 = d(d({}, i3), h3.getChildContext())), x3 && !v3 && null != h3.getSnapshotBeforeUpdate && (_3 = h3.getSnapshotBeforeUpdate(p3, w3)), P(n2, y(L2 = null != a3 && a3.type === b && null == a3.key ? a3.props.children : a3) ? L2 : [L2], u3, t3, i3, o3, r3, f3, e3, c3, s3), h3.base = u3.__e, u3.__u &= -161, h3.__h.length && f3.push(h3), g3 && (h3.__E = h3.__ = null); + } catch (n3) { + if (u3.__v = null, c3 || null != r3) { + for (u3.__u |= c3 ? 160 : 128; e3 && 8 === e3.nodeType && e3.nextSibling; ) e3 = e3.nextSibling; + r3[r3.indexOf(e3)] = null, u3.__e = e3; + } else u3.__e = t3.__e, u3.__k = t3.__k; + l.__e(n3, u3, t3); + } + else null == r3 && u3.__v === t3.__v ? (u3.__k = t3.__k, u3.__e = t3.__e) : u3.__e = z(t3.__e, u3, t3, i3, o3, r3, f3, c3, s3); (a3 = l.diffed) && a3(u3); } function j(n2, u3, t3) { u3.__d = void 0; - for (var i3 = 0; i3 < t3.length; i3++) - N(t3[i3], t3[++i3], t3[++i3]); + for (var i3 = 0; i3 < t3.length; i3++) N(t3[i3], t3[++i3], t3[++i3]); l.__c && l.__c(u3, n2), n2.some(function(u4) { try { n2 = u4.__h, u4.__h = [], n2.some(function(n3) { @@ -1410,40 +1362,27 @@ function z(u3, t3, i3, o3, r3, f3, e3, c3, s3) { var a3, v3, p3, d3, _3, g3, m2, b2 = i3.props, k3 = t3.props, C3 = t3.type; if ("svg" === C3 ? r3 = "http://www.w3.org/2000/svg" : "math" === C3 ? r3 = "http://www.w3.org/1998/Math/MathML" : r3 || (r3 = "http://www.w3.org/1999/xhtml"), null != f3) { - for (a3 = 0; a3 < f3.length; a3++) - if ((_3 = f3[a3]) && "setAttribute" in _3 == !!C3 && (C3 ? _3.localName === C3 : 3 === _3.nodeType)) { - u3 = _3, f3[a3] = null; - break; - } + for (a3 = 0; a3 < f3.length; a3++) if ((_3 = f3[a3]) && "setAttribute" in _3 == !!C3 && (C3 ? _3.localName === C3 : 3 === _3.nodeType)) { + u3 = _3, f3[a3] = null; + break; + } } if (null == u3) { - if (null === C3) - return document.createTextNode(k3); + if (null === C3) return document.createTextNode(k3); u3 = document.createElementNS(r3, C3, k3.is && k3), c3 && (l.__m && l.__m(t3, f3), c3 = false), f3 = null; } - if (null === C3) - b2 === k3 || c3 && u3.data === k3 || (u3.data = k3); + if (null === C3) b2 === k3 || c3 && u3.data === k3 || (u3.data = k3); else { - if (f3 = f3 && n.call(u3.childNodes), b2 = i3.props || h, !c3 && null != f3) - for (b2 = {}, a3 = 0; a3 < u3.attributes.length; a3++) - b2[(_3 = u3.attributes[a3]).name] = _3.value; - for (a3 in b2) - if (_3 = b2[a3], "children" == a3) - ; - else if ("dangerouslySetInnerHTML" == a3) - p3 = _3; - else if (!(a3 in k3)) { - if ("value" == a3 && "defaultValue" in k3 || "checked" == a3 && "defaultChecked" in k3) - continue; - A(u3, a3, null, _3, r3); - } - for (a3 in k3) - _3 = k3[a3], "children" == a3 ? d3 = _3 : "dangerouslySetInnerHTML" == a3 ? v3 = _3 : "value" == a3 ? g3 = _3 : "checked" == a3 ? m2 = _3 : c3 && "function" != typeof _3 || b2[a3] === _3 || A(u3, a3, _3, b2[a3], r3); - if (v3) - c3 || p3 && (v3.__html === p3.__html || v3.__html === u3.innerHTML) || (u3.innerHTML = v3.__html), t3.__k = []; - else if (p3 && (u3.innerHTML = ""), P(u3, y(d3) ? d3 : [d3], t3, i3, o3, "foreignObject" === C3 ? "http://www.w3.org/1999/xhtml" : r3, f3, e3, f3 ? f3[0] : i3.__k && x(i3, 0), c3, s3), null != f3) - for (a3 = f3.length; a3--; ) - w(f3[a3]); + if (f3 = f3 && n.call(u3.childNodes), b2 = i3.props || h, !c3 && null != f3) for (b2 = {}, a3 = 0; a3 < u3.attributes.length; a3++) b2[(_3 = u3.attributes[a3]).name] = _3.value; + for (a3 in b2) if (_3 = b2[a3], "children" == a3) ; + else if ("dangerouslySetInnerHTML" == a3) p3 = _3; + else if (!(a3 in k3)) { + if ("value" == a3 && "defaultValue" in k3 || "checked" == a3 && "defaultChecked" in k3) continue; + A(u3, a3, null, _3, r3); + } + for (a3 in k3) _3 = k3[a3], "children" == a3 ? d3 = _3 : "dangerouslySetInnerHTML" == a3 ? v3 = _3 : "value" == a3 ? g3 = _3 : "checked" == a3 ? m2 = _3 : c3 && "function" != typeof _3 || b2[a3] === _3 || A(u3, a3, _3, b2[a3], r3); + if (v3) c3 || p3 && (v3.__html === p3.__html || v3.__html === u3.innerHTML) || (u3.innerHTML = v3.__html), t3.__k = []; + else if (p3 && (u3.innerHTML = ""), P(u3, y(d3) ? d3 : [d3], t3, i3, o3, "foreignObject" === C3 ? "http://www.w3.org/1999/xhtml" : r3, f3, e3, f3 ? f3[0] : i3.__k && x(i3, 0), c3, s3), null != f3) for (a3 = f3.length; a3--; ) w(f3[a3]); c3 || (a3 = "value", "progress" === C3 && null == g3 ? u3.removeAttribute("value") : void 0 !== g3 && (g3 !== u3[a3] || "progress" === C3 && !g3 || "option" === C3 && g3 !== b2[a3]) && A(u3, a3, g3, b2[a3], r3), a3 = "checked", void 0 !== m2 && m2 !== u3[a3] && A(u3, a3, m2, b2[a3], r3)); } return u3; @@ -1453,8 +1392,7 @@ if ("function" == typeof n2) { var i3 = "function" == typeof n2.__u; i3 && n2.__u(), i3 && null == u3 || (n2.__u = n2(u3)); - } else - n2.current = u3; + } else n2.current = u3; } catch (n3) { l.__e(n3, t3); } @@ -1462,17 +1400,14 @@ function V(n2, u3, t3) { var i3, o3; if (l.unmount && l.unmount(n2), (i3 = n2.ref) && (i3.current && i3.current !== n2.__e || N(i3, null, u3)), null != (i3 = n2.__c)) { - if (i3.componentWillUnmount) - try { - i3.componentWillUnmount(); - } catch (n3) { - l.__e(n3, u3); - } + if (i3.componentWillUnmount) try { + i3.componentWillUnmount(); + } catch (n3) { + l.__e(n3, u3); + } i3.base = i3.__P = null; } - if (i3 = n2.__k) - for (o3 = 0; o3 < i3.length; o3++) - i3[o3] && V(i3[o3], u3, t3 || "function" != typeof n2.type); + if (i3 = n2.__k) for (o3 = 0; o3 < i3.length; o3++) i3[o3] && V(i3[o3], u3, t3 || "function" != typeof n2.type); t3 || w(n2.__e), n2.__c = n2.__ = n2.__e = n2.__d = void 0; } function q(n2, l3, u3) { @@ -1506,14 +1441,11 @@ return u3.Provider.__ = u3.Consumer.contextType = u3; } n = v.slice, l = { __e: function(n2, l3, u3, t3) { - for (var i3, o3, r3; l3 = l3.__; ) - if ((i3 = l3.__c) && !i3.__) - try { - if ((o3 = i3.constructor) && null != o3.getDerivedStateFromError && (i3.setState(o3.getDerivedStateFromError(n2)), r3 = i3.__d), null != i3.componentDidCatch && (i3.componentDidCatch(n2, t3 || {}), r3 = i3.__d), r3) - return i3.__E = i3; - } catch (l4) { - n2 = l4; - } + for (var i3, o3, r3; l3 = l3.__; ) if ((i3 = l3.__c) && !i3.__) try { + if ((o3 = i3.constructor) && null != o3.getDerivedStateFromError && (i3.setState(o3.getDerivedStateFromError(n2)), r3 = i3.__d), null != i3.componentDidCatch && (i3.componentDidCatch(n2, t3 || {}), r3 = i3.__d), r3) return i3.__E = i3; + } catch (l4) { + n2 = l4; + } throw n2; } }, u = 0, t = function(n2) { return null != n2 && null == n2.constructor; @@ -1555,15 +1487,13 @@ t3 !== r3 && (o3.__N = [r3, o3.__[1]], o3.__c.setState({})); }], o3.__c = r2, !r2.u)) { var f3 = function(n3, t3, r3) { - if (!o3.__c.__H) - return true; + if (!o3.__c.__H) return true; var u4 = o3.__c.__H.__.filter(function(n4) { return !!n4.__c; }); if (u4.every(function(n4) { return !n4.__N; - })) - return !c3 || c3.call(this, n3, t3, r3); + })) return !c3 || c3.call(this, n3, t3, r3); var i4 = false; return u4.forEach(function(n4) { if (n4.__N) { @@ -1613,21 +1543,18 @@ function g2() { var n2 = d2(t2++, 11); if (!n2.__) { - for (var u3 = r2.__v; null !== u3 && !u3.__m && null !== u3.__; ) - u3 = u3.__; + for (var u3 = r2.__v; null !== u3 && !u3.__m && null !== u3.__; ) u3 = u3.__; var i3 = u3.__m || (u3.__m = [0, 0]); n2.__ = "P" + i3[0] + "-" + i3[1]++; } return n2.__; } function j2() { - for (var n2; n2 = f2.shift(); ) - if (n2.__P && n2.__H) - try { - n2.__H.__h.forEach(z2), n2.__H.__h.forEach(B2), n2.__H.__h = []; - } catch (t3) { - n2.__H.__h = [], c2.__e(t3, n2.__v); - } + for (var n2; n2 = f2.shift(); ) if (n2.__P && n2.__H) try { + n2.__H.__h.forEach(z2), n2.__H.__h.forEach(B2), n2.__H.__h = []; + } catch (t3) { + n2.__H.__h = [], c2.__e(t3, n2.__v); + } } c2.__b = function(n2) { r2 = null, e2 && e2(n2); @@ -1769,13 +1696,11 @@ // shared/translations.js function apply(subject, replacements, textLength = 1) { - if (typeof subject !== "string" || subject.length === 0) - return ""; + if (typeof subject !== "string" || subject.length === 0) return ""; let out = subject; if (replacements) { for (let [name, value] of Object.entries(replacements)) { - if (typeof value !== "string") - value = ""; + if (typeof value !== "string") value = ""; out = out.replaceAll(`{${name}}`, value); } } @@ -1853,8 +1778,7 @@ * @return {EmbedSettings} */ withAutoplay(autoplay) { - if (typeof autoplay !== "boolean") - return this; + if (typeof autoplay !== "boolean") return this; return new _EmbedSettings({ ...this, autoplay @@ -1865,8 +1789,7 @@ * @return {EmbedSettings} */ withMuted(muted) { - if (typeof muted !== "boolean") - return this; + if (typeof muted !== "boolean") return this; return new _EmbedSettings({ ...this, muted @@ -1925,11 +1848,9 @@ * @throws {Error} */ constructor(input) { - if (typeof input !== "string") - throw new Error("string required, got: " + input); + if (typeof input !== "string") throw new Error("string required, got: " + input); const sanitized = sanitizeYoutubeId(input); - if (sanitized === null) - throw new Error("invalid ID from: " + input); + if (sanitized === null) throw new Error("invalid ID from: " + input); this.id = sanitized; } /** @@ -1945,11 +1866,9 @@ * @throws {Error} */ constructor(input) { - if (typeof input !== "string") - throw new Error("string required for timestamp"); + if (typeof input !== "string") throw new Error("string required for timestamp"); const seconds = timestampInSeconds(input); - if (seconds === null) - throw new Error("invalid input for timestamp: " + input); + if (seconds === null) throw new Error("invalid input for timestamp: " + input); this.seconds = seconds; } /** @@ -1957,8 +1876,7 @@ * @return {Timestamp|null} */ static fromHref(href) { - if (typeof href !== "string") - return null; + if (typeof href !== "string") return null; const param = timestampFromHref(href); if (param) { try { @@ -1971,8 +1889,7 @@ } }; function idFromHref(href) { - if (typeof href !== "string") - return null; + if (typeof href !== "string") return null; let url; try { url = new URL(href); @@ -1980,8 +1897,7 @@ return null; } const fromParam = url.searchParams.get("videoID"); - if (fromParam) - return fromParam; + if (fromParam) return fromParam; if (url.protocol === "duck:") { return url.pathname.slice(1); } @@ -1991,8 +1907,7 @@ return null; } function timestampFromHref(href) { - if (typeof href !== "string") - return null; + if (typeof href !== "string") return null; let url; try { url = new URL(href); @@ -2014,8 +1929,7 @@ }; const parts = timestamp.split(/(\d+[hms]?)/); const totalSeconds = parts.reduce((total, part) => { - if (!part) - return total; + if (!part) return total; for (const unit in units) { if (part.includes(unit)) { return total + parseInt(part) * units[unit]; @@ -2103,8 +2017,7 @@ * @return {Settings} */ withFeatureState(named, settings) { - if (!settings) - return this; + if (!settings) return this; const valid = ["pip", "autoplay", "focusMode"]; if (!valid.includes(named)) { console.warn(`Excluding invalid feature key ${named}`); @@ -2249,8 +2162,7 @@ function useOpenOnYoutubeHandler() { const settings = x2(SettingsContext).settings; return (embed) => { - if (!embed) - return console.warn("unreachable, settings.embed must be present"); + if (!embed) return console.warn("unreachable, settings.embed must be present"); try { const base = new URL(settings.youtubeBase); window.location.href = embed.intoYoutubeUrl(base); @@ -2707,8 +2619,7 @@ off(); }); window.addEventListener(EVENT_ON, () => { - if (enabled === true) - return; + if (enabled === true) return; enabled = true; on(); }); @@ -2752,8 +2663,7 @@ setFocusMode("enabled"); } _2(() => { - if (!tooltipRef.current) - return; + if (!tooltipRef.current) return; const icon = tooltipRef.current; const rect = icon.getBoundingClientRect(); const iconTop = rect.top + window.scrollY; @@ -2811,8 +2721,7 @@ formfactor: "desktop", buttonProps: { onClick: () => { - if (embed) - openOnYoutube(embed); + if (embed) openOnYoutube(embed); } } }, @@ -2904,10 +2813,8 @@ let attempt = 0; let id; function check() { - if (!iframe.contentDocument) - return; - if (attempt > maxAttempts) - return; + if (!iframe.contentDocument) return; + if (attempt > maxAttempts) return; attempt += 1; const selector = "#player video"; const video = ( @@ -3019,11 +2926,9 @@ // pages/duckplayer/src/js/utils.js function createYoutubeURLForError(href, urlBase) { const valid = VideoParams.forWatchPage(href); - if (!valid) - return null; + if (!valid) return null; const original = new URL(href); - if (original.searchParams.get("feature") !== "emb_err_woyt") - return null; + if (original.searchParams.get("feature") !== "emb_err_woyt") return null; const url = new URL(urlBase); url.searchParams.set("v", valid.id); if (typeof valid.time === "string") { @@ -3032,10 +2937,8 @@ return url.toString(); } function getValidVideoTitle(iframeTitle) { - if (typeof iframeTitle !== "string") - return null; - if (iframeTitle === "YouTube") - return null; + if (typeof iframeTitle !== "string") return null; + if (iframeTitle === "YouTube") return null; return iframeTitle.replace(/ - YouTube$/g, ""); } @@ -3053,17 +2956,14 @@ */ iframeDidLoad(iframe) { const handler = (e3) => { - if (!e3.target) - return; + if (!e3.target) return; const target = ( /** @type {Element} */ e3.target ); - if (!("href" in target) || typeof target.href !== "string") - return; + if (!("href" in target) || typeof target.href !== "string") return; const next = createYoutubeURLForError(target.href, this.baseUrl); - if (!next) - return; + if (!next) return; e3.preventDefault(); e3.stopImmediatePropagation(); window.location.href = next; @@ -3135,7 +3035,6 @@ * @param {HTMLIFrameElement} iframe * @returns {(() => void) | null} */ - // eslint-disable-next-line @typescript-eslint/no-unused-vars iframeDidLoad(iframe) { return () => { console.log("teardown"); @@ -3240,8 +3139,7 @@ ); const settings = useSettings(); y2(() => { - if (!ref.current) - return; + if (!ref.current) return; const iframe = ref.current; const features = createIframeFeatures(settings); const iframeFeatures = [ @@ -3283,8 +3181,7 @@ }); let embed = EmbedSettings.fromHref("https://localhost?videoID=123"); let url = embed?.toEmbedUrl(); - if (!url) - throw new Error("unreachable"); + if (!url) throw new Error("unreachable"); return /* @__PURE__ */ _(b, null, /* @__PURE__ */ _("div", { "data-layout": "mobile" }, /* @__PURE__ */ _(Background, null)), /* @__PURE__ */ _("main", { class: Components_default.main }, /* @__PURE__ */ _("div", { class: Components_default.tube }, /* @__PURE__ */ _(Wordmark, null), /* @__PURE__ */ _("h2", null, "Floating Bar"), /* @__PURE__ */ _("div", { style: "position: relative; padding-left: 10em; min-height: 150px;" }, /* @__PURE__ */ _(InfoIcon, { debugStyles: true })), /* @__PURE__ */ _("h2", null, "Info Tooltip"), /* @__PURE__ */ _(FloatingBar, null, /* @__PURE__ */ _(Button, { icon: true }, /* @__PURE__ */ _(Icon, { src: info_data_default })), /* @__PURE__ */ _(Button, { icon: true }, /* @__PURE__ */ _(Icon, { src: cog_data_default })), /* @__PURE__ */ _(Button, { fill: true }, "Open in YouTube")), /* @__PURE__ */ _("h2", null, "Info Bar"), /* @__PURE__ */ _(SettingsProvider, { settings }, /* @__PURE__ */ _(SwitchProvider, null, /* @__PURE__ */ _(InfoBar, { embed }))), /* @__PURE__ */ _("br", null), /* @__PURE__ */ _("h2", null, "Mobile Switch Bar (ios)"), /* @__PURE__ */ _(SwitchProvider, null, /* @__PURE__ */ _(SwitchBarMobile, { platformName: "ios" })), /* @__PURE__ */ _("h2", null, "Mobile Switch Bar (android)"), /* @__PURE__ */ _(SwitchProvider, null, /* @__PURE__ */ _(SwitchBarMobile, { platformName: "android" })), /* @__PURE__ */ _("h2", null, "Desktop Switch bar"), /* @__PURE__ */ _("h3", null, "idle"), /* @__PURE__ */ _(SwitchProvider, null, /* @__PURE__ */ _(SwitchBarDesktop, null))), /* @__PURE__ */ _("h2", null, /* @__PURE__ */ _("code", null, "inset=false (desktop)")), /* @__PURE__ */ _(SettingsProvider, { settings }, /* @__PURE__ */ _(PlayerContainer, null, /* @__PURE__ */ _(Player, { src: url, layout: "desktop" }), /* @__PURE__ */ _(InfoBarContainer, null, /* @__PURE__ */ _(InfoBar, { embed })))), /* @__PURE__ */ _("br", null), /* @__PURE__ */ _("h2", null, /* @__PURE__ */ _("code", null, "inset=true (mobile)")), /* @__PURE__ */ _(PlayerContainer, { inset: true }, /* @__PURE__ */ _(PlayerInternal, { inset: true }, /* @__PURE__ */ _(PlayerError, { layout: "mobile", kind: "invalid-id" }), /* @__PURE__ */ _(SwitchBarMobile, { platformName: "ios" }))), /* @__PURE__ */ _("br", null))); } @@ -3353,8 +3250,7 @@ fill: true, buttonProps: { onClick: () => { - if (embed) - openOnYoutube(embed); + if (embed) openOnYoutube(embed); } } }, @@ -3463,8 +3359,7 @@ }; document.body.dataset.layout = settings.layout; const root = document.querySelector("body"); - if (!root) - throw new Error("could not render, root element missing"); + if (!root) throw new Error("could not render, root element missing"); if (environment.display === "app") { B( /* @__PURE__ */ _( @@ -3487,8 +3382,7 @@ } function createEmbedSettings(href, settings) { const embed = EmbedSettings.fromHref(href); - if (!embed) - return null; + if (!embed) return null; return embed.withAutoplay(settings.autoplay.state === "enabled").withMuted(settings.platform.name === "ios"); } async function getTranslationsFromStringOrLoadDynamically(stringInput, locale) { @@ -3675,8 +3569,7 @@ * ``` */ landscapeImpression() { - if (this.oneTimeEvents.has("landscapeImpression")) - return; + if (this.oneTimeEvents.has("landscapeImpression")) return; this.oneTimeEvents.add("landscapeImpression"); this._event({ attributes: { name: "impression", value: "landscape-layout" } }); } diff --git a/package-lock.json b/package-lock.json index bf1ff9daef9c..c567690b08bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "@duckduckgo/autoconsent": "^10.17.0", "@duckduckgo/autofill": "github:duckduckgo/duckduckgo-autofill#15.1.0", - "@duckduckgo/content-scope-scripts": "github:duckduckgo/content-scope-scripts#6.28.0", + "@duckduckgo/content-scope-scripts": "github:duckduckgo/content-scope-scripts#pr-releases/pr-1184", "@duckduckgo/privacy-dashboard": "github:duckduckgo/privacy-dashboard#7.0.2", "@duckduckgo/privacy-reference-tests": "github:duckduckgo/privacy-reference-tests#1724449523" }, @@ -26,6 +26,7 @@ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", @@ -40,6 +41,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -48,6 +50,7 @@ "version": "10.17.0", "resolved": "https://registry.npmjs.org/@duckduckgo/autoconsent/-/autoconsent-10.17.0.tgz", "integrity": "sha512-zMB4BE5fpiqvjXPA0k8bCorWgh6eFMlkedRfuRVQYhbWqwLgrnsA7lv4U0ORTIJkvbBjABuYaprwr1yd/15D/w==", + "license": "MPL-2.0", "dependencies": { "tldts-experimental": "^6.1.37" } @@ -58,7 +61,8 @@ "license": "Apache-2.0" }, "node_modules/@duckduckgo/content-scope-scripts": { - "resolved": "git+ssh://git@github.com/duckduckgo/content-scope-scripts.git#48fee2508995d4ac02d18b3d55424adedcb4ce4f", + "resolved": "git+ssh://git@github.com/duckduckgo/content-scope-scripts.git#af73b854e6045af4f72061f35dc57239ae4b66d1", + "license": "Apache-2.0", "workspaces": [ "injected", "special-pages", @@ -74,13 +78,15 @@ } }, "node_modules/@duckduckgo/privacy-reference-tests": { - "resolved": "git+ssh://git@github.com/duckduckgo/privacy-reference-tests.git#6133e7d9d9cd5f1b925cab1971b4d785dc639df7" + "resolved": "git+ssh://git@github.com/duckduckgo/privacy-reference-tests.git#6133e7d9d9cd5f1b925cab1971b4d785dc639df7", + "license": "Apache-2.0" }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -95,6 +101,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -104,6 +111,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -113,6 +121,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" @@ -122,13 +131,15 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -139,6 +150,7 @@ "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", "dev": true, + "license": "MIT", "dependencies": { "@rollup/pluginutils": "^3.0.8" }, @@ -151,6 +163,7 @@ "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz", "integrity": "sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==", "dev": true, + "license": "MIT", "dependencies": { "@rollup/pluginutils": "^3.1.0", "@types/resolve": "1.17.1", @@ -171,6 +184,7 @@ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "0.0.39", "estree-walker": "^1.0.1", @@ -187,13 +201,15 @@ "version": "0.0.39", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { - "version": "22.8.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.6.tgz", - "integrity": "sha512-tosuJYKrIqjQIlVCM4PEGxOmyg3FCPa/fViuJChnGeEIhjA46oy8FMVoF9su1/v8PNs2a8Q0iFNyOx0uOF91nw==", + "version": "22.8.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.7.tgz", + "integrity": "sha512-LidcG+2UeYIWcMuMUpBKOnryBWG/rnmOHQR5apjn8myTQcx3rinFRn7DcIFhMnS0PPFSC6OafdIKEad0lj6U0Q==", "dev": true, + "license": "MIT", "dependencies": { "undici-types": "~6.19.8" } @@ -203,6 +219,7 @@ "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -212,6 +229,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -223,13 +241,15 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/builtin-modules": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -241,13 +261,15 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -256,7 +278,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fsevents": { "version": "2.3.3", @@ -264,6 +287,7 @@ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -277,6 +301,7 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -286,6 +311,7 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -295,6 +321,7 @@ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -307,6 +334,7 @@ "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", "dev": true, + "license": "MIT", "dependencies": { "builtin-modules": "^3.3.0" }, @@ -322,6 +350,7 @@ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, + "license": "MIT", "dependencies": { "hasown": "^2.0.2" }, @@ -336,13 +365,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-worker": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -356,31 +387,36 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -393,6 +429,7 @@ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } @@ -402,6 +439,7 @@ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, + "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -419,6 +457,7 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "dev": true, + "license": "MIT", "bin": { "rollup": "dist/bin/rollup" }, @@ -435,6 +474,7 @@ "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.10.4", "jest-worker": "^26.2.1", @@ -463,13 +503,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/serialize-javascript": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } @@ -479,6 +521,7 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -488,6 +531,7 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -498,6 +542,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -510,6 +555,7 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -522,6 +568,7 @@ "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -536,23 +583,26 @@ } }, "node_modules/tldts-core": { - "version": "6.1.57", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.57.tgz", - "integrity": "sha512-lXnRhuQpx3zU9EONF9F7HfcRLvN1uRYUBIiKL+C/gehC/77XTU+Jye6ui86GA3rU6FjlJ0triD1Tkjt2F/2lEg==" + "version": "6.1.58", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.58.tgz", + "integrity": "sha512-dR936xmhBm7AeqHIhCWwK765gZ7dFyL+IqLSFAjJbFlUXGMLCb8i2PzlzaOuWBuplBTaBYseSb565nk/ZEM0Bg==", + "license": "MIT" }, "node_modules/tldts-experimental": { - "version": "6.1.57", - "resolved": "https://registry.npmjs.org/tldts-experimental/-/tldts-experimental-6.1.57.tgz", - "integrity": "sha512-Buk4fIUZF7ehTnXyTTYxa1fCwTT3V0LoUsBfvEziQ9mEsdrAQmdb1fZqrSehT7S7Eb4k1iburh3ShqNpVtSCVQ==", + "version": "6.1.58", + "resolved": "https://registry.npmjs.org/tldts-experimental/-/tldts-experimental-6.1.58.tgz", + "integrity": "sha512-oMXXM56JFUjwcw+2Vt7NP3LQUpK3ZLdGAqSAFwGtAPWjvKK36bJ162UjsnSdFsq6nU3Wae5HYlE8N/vULPZ00g==", + "license": "MIT", "dependencies": { - "tldts-core": "^6.1.57" + "tldts-core": "^6.1.58" } }, "node_modules/undici-types": { "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "dev": true + "dev": true, + "license": "MIT" } } } diff --git a/package.json b/package.json index d37157c221cd..b05426e572c3 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "dependencies": { "@duckduckgo/autoconsent": "^10.17.0", "@duckduckgo/autofill": "github:duckduckgo/duckduckgo-autofill#15.1.0", - "@duckduckgo/content-scope-scripts": "github:duckduckgo/content-scope-scripts#6.28.0", + "@duckduckgo/content-scope-scripts": "github:duckduckgo/content-scope-scripts#pr-releases/pr-1184", "@duckduckgo/privacy-dashboard": "github:duckduckgo/privacy-dashboard#7.0.2", "@duckduckgo/privacy-reference-tests": "github:duckduckgo/privacy-reference-tests#1724449523" }