[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [Git][tpo/applications/tor-browser][tor-browser-128.2.0esr-14.0-1] fixup! [android] Modify add-on support



Title: GitLab

ma1 pushed to branch tor-browser-128.2.0esr-14.0-1 at The Tor Project / Applications / Tor Browser

Commits:

  • 4eb9b64f
    by hackademix at 2024-09-11T21:59:25+02:00
    fixup! [android] Modify add-on support
    
    Bug 43097: Use default (non-builtin) extension installation method which works with xpi files.
    

6 changed files:

Changes:

  • mobile/android/android-components/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/webextension/GeckoWebExtension.kt
    ... ... @@ -393,6 +393,7 @@ class GeckoWebExtension(
    393 393
     
    
    394 394
         override fun isAllowedInPrivateBrowsing(): Boolean {
    
    395 395
             return isBuiltIn() || nativeExtension.metaData.allowedInPrivateBrowsing
    
    396
    +            || isBundled()
    
    396 397
         }
    
    397 398
     
    
    398 399
         override suspend fun loadIcon(size: Int): Bitmap? {
    

  • mobile/android/android-components/components/concept/engine/src/main/java/mozilla/components/concept/engine/webextension/WebExtension.kt
    ... ... @@ -164,6 +164,14 @@ abstract class WebExtension(
    164 164
          */
    
    165 165
         open fun isBuiltIn(): Boolean = Uri.parse(url).scheme == "resource"
    
    166 166
     
    
    167
    +    /**
    
    168
    +     * Checks whether or not this extension is bundled with this browser,
    
    169
    +     * but otherwise behaves as an unprivileged (non built-in) extension,
    
    170
    +     * except it cannot be disabled or uninstalled from the UI (e.g.
    
    171
    +     * NoScript in the Tor Browser).
    
    172
    +     */
    
    173
    +    open fun isBundled(): Boolean = id == "{73a6fe31-595d-460b-a920-fcc0f8843232}"
    
    174
    +
    
    167 175
         /**
    
    168 176
          * Checks whether or not this extension is enabled.
    
    169 177
          */
    

  • mobile/android/android-components/components/support/webextensions/src/main/java/mozilla/components/support/webextensions/WebExtensionSupport.kt
    ... ... @@ -234,6 +234,7 @@ object WebExtensionSupport {
    234 234
                         // when the add-on has already been installed, we don't need to show anything
    
    235 235
                         // either.
    
    236 236
                         val shouldDispatchAction = !installedExtensions.containsKey(extension.id) && !extension.isBuiltIn()
    
    237
    +                        && !extension.isBundled()
    
    237 238
                         registerInstalledExtension(store, extension)
    
    238 239
                         if (shouldDispatchAction) {
    
    239 240
                             store.dispatch(
    

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/addons/InstalledAddonDetailsFragment.kt
    ... ... @@ -44,6 +44,8 @@ class InstalledAddonDetailsFragment : Fragment() {
    44 44
     
    
    45 45
         private var _binding: FragmentInstalledAddOnDetailsBinding? = null
    
    46 46
     
    
    47
    +    private var isBundledAddon = false;
    
    48
    +
    
    47 49
         override fun onCreateView(
    
    48 50
             inflater: LayoutInflater,
    
    49 51
             container: ViewGroup?,
    
    ... ... @@ -51,6 +53,7 @@ class InstalledAddonDetailsFragment : Fragment() {
    51 53
         ): View {
    
    52 54
             if (!::addon.isInitialized) {
    
    53 55
                 addon = AddonDetailsFragmentArgs.fromBundle(requireNotNull(arguments)).addon
    
    56
    +            isBundledAddon = installedExtensions[addon.id]?.isBundled() ?: false
    
    54 57
             }
    
    55 58
     
    
    56 59
             setBindingAndBindUI(
    
    ... ... @@ -148,6 +151,7 @@ class InstalledAddonDetailsFragment : Fragment() {
    148 151
             // When the ad-on is blocklisted or not correctly signed, we do not want to enable the toggle switch
    
    149 152
             // because users shouldn't be able to re-enable an add-on in this state.
    
    150 153
             if (
    
    154
    +            isBundledAddon ||
    
    151 155
                 addon.isDisabledAsBlocklisted() ||
    
    152 156
                 addon.isDisabledAsNotCorrectlySigned() ||
    
    153 157
                 addon.isDisabledAsIncompatible()
    
    ... ... @@ -303,6 +307,7 @@ class InstalledAddonDetailsFragment : Fragment() {
    303 307
         }
    
    304 308
     
    
    305 309
         private fun bindReportButton() {
    
    310
    +        binding.reportAddOn.isVisible = !isBundledAddon
    
    306 311
             binding.reportAddOn.setOnClickListener {
    
    307 312
                 val shouldCreatePrivateSession = (activity as HomeActivity).browsingModeManager.mode.isPrivate
    
    308 313
     
    
    ... ... @@ -367,8 +372,7 @@ class InstalledAddonDetailsFragment : Fragment() {
    367 372
         }
    
    368 373
     
    
    369 374
         private fun bindRemoveButton() {
    
    370
    -        val isBuiltin = installedExtensions[addon.id]?.isBuiltIn() ?: false
    
    371
    -        binding.removeAddOn.isVisible = !isBuiltin
    
    375
    +        binding.removeAddOn.isVisible = !isBundledAddon
    
    372 376
             binding.removeAddOn.setOnClickListener {
    
    373 377
                 setAllInteractiveViewsClickable(binding, false)
    
    374 378
                 requireContext().components.addonManager.uninstallAddon(
    

  • mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/TorBrowserFeatures.kt
    ... ... @@ -6,12 +6,14 @@
    6 6
     
    
    7 7
     package org.mozilla.fenix.components
    
    8 8
     
    
    9
    +import android.os.StrictMode
    
    9 10
     import android.content.Context
    
    10 11
     import kotlinx.coroutines.DelicateCoroutinesApi
    
    11 12
     import kotlinx.coroutines.Dispatchers
    
    12 13
     import kotlinx.coroutines.GlobalScope
    
    13 14
     import kotlinx.coroutines.launch
    
    14 15
     import kotlinx.coroutines.withContext
    
    16
    +import java.io.IOException
    
    15 17
     import mozilla.components.concept.engine.webextension.WebExtension
    
    16 18
     import mozilla.components.concept.engine.webextension.WebExtensionRuntime
    
    17 19
     import mozilla.components.support.webextensions.WebExtensionSupport
    
    ... ... @@ -25,14 +27,39 @@ object TorBrowserFeatures {
    25 27
         private const val NOSCRIPT_ID = "{73a6fe31-595d-460b-a920-fcc0f8843232}"
    
    26 28
     
    
    27 29
         private fun installNoScript(
    
    30
    +        context: Context,
    
    28 31
             runtime: WebExtensionRuntime,
    
    29 32
             onSuccess: ((WebExtension) -> Unit),
    
    30 33
             onError: ((Throwable) -> Unit)
    
    31 34
         ) {
    
    35
    +        /**
    
    36
    +         * Copy the xpi from assets to cacheDir, we do not care if the file is later deleted.
    
    37
    +         */
    
    38
    +        val xpiName = "$NOSCRIPT_ID.xpi"
    
    39
    +        val addonPath = context.cacheDir.resolve(xpiName)
    
    40
    +        val policy = StrictMode.getThreadPolicy()
    
    41
    +        try {
    
    42
    +            context.assets.open("extensions/$xpiName")
    
    43
    +                .use { inStream ->
    
    44
    +                    // we don't want penaltyDeath() on disk write
    
    45
    +                    StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.LAX)
    
    32 46
     
    
    33
    -        runtime.installBuiltInWebExtension(
    
    34
    -            id = NOSCRIPT_ID,
    
    35
    -            url = "resource://android/assets/extensions/" + NOSCRIPT_ID + ".xpi",
    
    47
    +                    addonPath.outputStream().use { outStream ->
    
    48
    +                        inStream.copyTo(outStream)
    
    49
    +                    }
    
    50
    +                }
    
    51
    +        } catch (throwable: IOException) {
    
    52
    +            onError(throwable)
    
    53
    +            return
    
    54
    +        } finally {
    
    55
    +            StrictMode.setThreadPolicy(policy)
    
    56
    +        }
    
    57
    +
    
    58
    +        /**
    
    59
    +         * Install with a file:// URI pointing to the temp location where the addon was copied to.
    
    60
    +         */
    
    61
    +        runtime.installWebExtension(
    
    62
    +            url = addonPath.toURI().toString(),
    
    36 63
                 onSuccess = { extension ->
    
    37 64
                     runtime.setAllowedInPrivateBrowsing(
    
    38 65
                         extension,
    
    ... ... @@ -95,6 +122,7 @@ object TorBrowserFeatures {
    95 122
              */
    
    96 123
             if (!settings.noscriptInstalled) {
    
    97 124
                 installNoScript(
    
    125
    +                context,
    
    98 126
                     runtime,
    
    99 127
                     onSuccess = {
    
    100 128
                         settings.noscriptInstalled = true
    

  • mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtensionController.java
    ... ... @@ -1166,6 +1166,27 @@ public class WebExtensionController {
    1166 1166
                 });
    
    1167 1167
       }
    
    1168 1168
     
    
    1169
    +  private boolean isBundledExtension(final String extensionId) {
    
    1170
    +    return "{73a6fe31-595d-460b-a920-fcc0f8843232}".equals(extensionId);
    
    1171
    +  }
    
    1172
    +
    
    1173
    +  private boolean promptBypass(final WebExtension extension, final EventCallback callback) {
    
    1174
    +    // allow bundled extensions, e.g. NoScript, to be installed with no prompt
    
    1175
    +    if (isBundledExtension(extension.id)) {
    
    1176
    +      callback.resolveTo(
    
    1177
    +        GeckoResult.allow().map(
    
    1178
    +          allowOrDeny -> {
    
    1179
    +            final GeckoBundle response = new GeckoBundle(1);
    
    1180
    +            response.putBoolean("allow", true);
    
    1181
    +            return response;
    
    1182
    +          }
    
    1183
    +        )
    
    1184
    +      );
    
    1185
    +      return true;
    
    1186
    +    }
    
    1187
    +    return false;
    
    1188
    +  }
    
    1189
    +
    
    1169 1190
       private void installPrompt(final GeckoBundle message, final EventCallback callback) {
    
    1170 1191
         final GeckoBundle extensionBundle = message.getBundle("extension");
    
    1171 1192
         if (extensionBundle == null
    
    ... ... @@ -1181,6 +1202,10 @@ public class WebExtensionController {
    1181 1202
     
    
    1182 1203
         final WebExtension extension = new WebExtension(mDelegateControllerProvider, extensionBundle);
    
    1183 1204
     
    
    1205
    +    if (promptBypass(extension, callback)) {
    
    1206
    +      return;
    
    1207
    +    }
    
    1208
    +
    
    1184 1209
         if (mPromptDelegate == null) {
    
    1185 1210
           Log.e(
    
    1186 1211
               LOGTAG, "Tried to install extension " + extension.id + " but no delegate is registered");
    
    ... ... @@ -1220,6 +1245,10 @@ public class WebExtensionController {
    1220 1245
         final WebExtension currentExtension =
    
    1221 1246
             new WebExtension(mDelegateControllerProvider, currentBundle);
    
    1222 1247
     
    
    1248
    +    if (promptBypass(currentExtension, callback)) {
    
    1249
    +      return;
    
    1250
    +    }
    
    1251
    +
    
    1223 1252
         final WebExtension updatedExtension =
    
    1224 1253
             new WebExtension(mDelegateControllerProvider, updatedBundle);
    
    1225 1254
     
    

  • _______________________________________________
    tor-commits mailing list
    tor-commits@xxxxxxxxxxxxxxxxxxxx
    https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits