Commits:
-
5b511dd7
by Arturo Mejia at 2024-11-25T15:23:58+01:00
Bug 1836921 - Improve dialogs a=dmeehan
Original Revision: https://phabricator.services.mozilla.com/D226961
Differential Revision: https://phabricator.services.mozilla.com/D228842
-
776b61f5
by Malte Juergens at 2024-11-25T15:24:00+01:00
Bug 1909396 - Remove HTTPS-Only exception button in iframes r=freddyb,fluent-reviewers
Rationale for this can be read in Bug 1909396, but the main reason is that the iframe will get blocked regardless by mixed content blocking.
Differential Revision: https://phabricator.services.mozilla.com/D220257
-
927d61a7
by Makoto Kato at 2024-11-25T15:24:02+01:00
Bug 1776646 - Support EXTRA_IS_SENSITIVE for clipboard. r=geckoview-reviewers,owlish
When nsITransferable.isPrivateData is true, such as coping password or
private mode, we should set EXTRA_IS_SENSITIVE to ClipData.
AndroidJunit test runner doesn't often get `ClipDescription.extras`
from clipboard service in test runner. So we cannot write a unit test
using AndroidJUnit test runner.
Differential Revision: https://phabricator.services.mozilla.com/D225326
-
cabb4f40
by Cathy Lu at 2024-11-25T15:24:04+01:00
Bug 1914797 - Part 1 + 2 + partial backout (details below)
Bug 1914797 - Part 1 - Revert bug 1868469 r=android-reviewers,jonalmeida, a=dmeehan
Differential Revision: https://phabricator.services.mozilla.com/D226431
Bug 1914797 - Part 2 - Add url change during onPageStart for slow loading sites r=android-reviewers,jonalmeida, a=dmeehan
Differential Revision: https://phabricator.services.mozilla.com/D226432
Backed out 1 changesets (bug 1914797) for causing Bug 1929028
Backed out changeset a79554879d7b (bug 1914797)
16 changed files:
Changes:
dom/ipc/WindowGlobalParent.cpp
| ... |
... |
@@ -1378,18 +1378,11 @@ mozilla::ipc::IPCResult WindowGlobalParent::RecvReloadWithHttpsOnlyException() { |
|
1378
|
1378
|
return IPC_FAIL(this, "HTTPS-only mode: Illegal state");
|
|
1379
|
1379
|
}
|
|
1380
|
1380
|
|
|
1381
|
|
- // If the error page is within an iFrame, we create an exception for whatever
|
|
1382
|
|
- // scheme the top-level site is currently on, because the user wants to
|
|
1383
|
|
- // unbreak the iFrame and not the top-level page. When the error page shows up
|
|
1384
|
|
- // on a top-level request, then we replace the scheme with http, because the
|
|
1385
|
|
- // user wants to unbreak the whole page.
|
|
|
1381
|
+ // We replace the scheme with http, because the user wants to unbreak the
|
|
|
1382
|
+ // whole page.
|
|
1386
|
1383
|
nsCOMPtr<nsIURI> newURI;
|
|
1387
|
|
- if (!BrowsingContext()->IsTop()) {
|
|
1388
|
|
- newURI = innerURI;
|
|
1389
|
|
- } else {
|
|
1390
|
|
- Unused << NS_MutateURI(innerURI).SetScheme("http"_ns).Finalize(
|
|
1391
|
|
- getter_AddRefs(newURI));
|
|
1392
|
|
- }
|
|
|
1384
|
+ Unused << NS_MutateURI(innerURI).SetScheme("http"_ns).Finalize(
|
|
|
1385
|
+ getter_AddRefs(newURI));
|
|
1393
|
1386
|
|
|
1394
|
1387
|
OriginAttributes originAttributes =
|
|
1395
|
1388
|
TopWindowContext()->DocumentPrincipal()->OriginAttributesRef();
|
dom/security/test/https-only/browser.toml
| ... |
... |
@@ -29,6 +29,9 @@ support-files = [ |
|
29
|
29
|
["browser_httpsonly_speculative_connect.js"]
|
|
30
|
30
|
support-files = ["file_httpsonly_speculative_connect.html"]
|
|
31
|
31
|
|
|
|
32
|
+["browser_iframe_buttons.js"]
|
|
|
33
|
+support-files = ["file_iframe_buttons.html"]
|
|
|
34
|
+
|
|
32
|
35
|
["browser_iframe_test.js"]
|
|
33
|
36
|
skip-if = [
|
|
34
|
37
|
"os == 'linux' && bits == 64", # Bug 1735565
|
dom/security/test/https-only/browser_iframe_buttons.js
|
|
1
|
+/* Any copyright is dedicated to the Public Domain.
|
|
|
2
|
+ https://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
3
|
+
|
|
|
4
|
+"use strict";
|
|
|
5
|
+
|
|
|
6
|
+// Ensure the buttons at the buttom of the HTTPS-Only error page do not get
|
|
|
7
|
+// displayed in an iframe (Bug 1909396).
|
|
|
8
|
+
|
|
|
9
|
+add_task(async function test_iframe_buttons() {
|
|
|
10
|
+ await BrowserTestUtils.withNewTab(
|
|
|
11
|
+ "https://example.com/browser/dom/security/test/https-only/file_iframe_buttons.html",
|
|
|
12
|
+ async function (browser) {
|
|
|
13
|
+ await SpecialPowers.pushPrefEnv({
|
|
|
14
|
+ set: [["dom.security.https_only_mode", true]],
|
|
|
15
|
+ });
|
|
|
16
|
+
|
|
|
17
|
+ await SpecialPowers.spawn(browser, [], async function () {
|
|
|
18
|
+ const iframe = content.document.getElementById("iframe");
|
|
|
19
|
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
|
|
|
20
|
+ iframe.src = "http://nocert.example.com";
|
|
|
21
|
+
|
|
|
22
|
+ await ContentTaskUtils.waitForCondition(
|
|
|
23
|
+ () => iframe.contentWindow.document.readyState === "interactive",
|
|
|
24
|
+ "Iframe error page should have loaded"
|
|
|
25
|
+ );
|
|
|
26
|
+
|
|
|
27
|
+ ok(
|
|
|
28
|
+ !!iframe.contentWindow.document.getElementById("explanation-iframe"),
|
|
|
29
|
+ "#explanation-iframe should exist"
|
|
|
30
|
+ );
|
|
|
31
|
+
|
|
|
32
|
+ is(
|
|
|
33
|
+ iframe.contentWindow.document
|
|
|
34
|
+ .getElementById("explanation-iframe")
|
|
|
35
|
+ .getAttribute("hidden"),
|
|
|
36
|
+ null,
|
|
|
37
|
+ "#explanation-iframe should not be hidden"
|
|
|
38
|
+ );
|
|
|
39
|
+
|
|
|
40
|
+ for (const id of ["explanation-continue", "goBack", "openInsecure"]) {
|
|
|
41
|
+ is(
|
|
|
42
|
+ iframe.contentWindow.document.getElementById(id),
|
|
|
43
|
+ null,
|
|
|
44
|
+ `#${id} should have been removed`
|
|
|
45
|
+ );
|
|
|
46
|
+ }
|
|
|
47
|
+ });
|
|
|
48
|
+ }
|
|
|
49
|
+ );
|
|
|
50
|
+}); |
dom/security/test/https-only/file_iframe_buttons.html
|
|
1
|
+<!DOCTYPE html>
|
|
|
2
|
+<html lang="en">
|
|
|
3
|
+<head>
|
|
|
4
|
+ <meta charset="UTF-8">
|
|
|
5
|
+</head>
|
|
|
6
|
+<body>
|
|
|
7
|
+ <iframe id="iframe" frameborder="0"></iframe>
|
|
|
8
|
+</body>
|
|
|
9
|
+</html> |
mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/SimpleRedirectDialogFragment.kt
| ... |
... |
@@ -11,6 +11,7 @@ import androidx.annotation.StringRes |
|
11
|
11
|
import androidx.annotation.StyleRes
|
|
12
|
12
|
import androidx.annotation.VisibleForTesting
|
|
13
|
13
|
import androidx.appcompat.app.AlertDialog
|
|
|
14
|
+import mozilla.components.support.ktx.util.PromptAbuserDetector
|
|
14
|
15
|
import mozilla.components.ui.widgets.withCenterAlignedButtons
|
|
15
|
16
|
|
|
16
|
17
|
/**
|
| ... |
... |
@@ -23,6 +24,10 @@ import mozilla.components.ui.widgets.withCenterAlignedButtons |
|
23
|
24
|
*/
|
|
24
|
25
|
class SimpleRedirectDialogFragment : RedirectDialogFragment() {
|
|
25
|
26
|
|
|
|
27
|
+ @VisibleForTesting
|
|
|
28
|
+ internal var promptAbuserDetector =
|
|
|
29
|
+ PromptAbuserDetector(maxSuccessiveDialogSecondsLimit = TIME_SHOWN_OFFSET_SECONDS)
|
|
|
30
|
+
|
|
26
|
31
|
@VisibleForTesting
|
|
27
|
32
|
internal var testingContext: Context? = null
|
|
28
|
33
|
|
| ... |
... |
@@ -32,6 +37,8 @@ class SimpleRedirectDialogFragment : RedirectDialogFragment() { |
|
32
|
37
|
return if (themeID == 0) AlertDialog.Builder(context) else AlertDialog.Builder(context, themeID)
|
|
33
|
38
|
}
|
|
34
|
39
|
|
|
|
40
|
+ promptAbuserDetector.updateJSDialogAbusedState()
|
|
|
41
|
+
|
|
35
|
42
|
return with(requireBundle()) {
|
|
36
|
43
|
val dialogTitleText = getInt(KEY_TITLE_TEXT, R.string.mozac_feature_applinks_normal_confirm_dialog_title)
|
|
37
|
44
|
val dialogMessageString = getString(KEY_MESSAGE_STRING, "")
|
| ... |
... |
@@ -40,18 +47,29 @@ class SimpleRedirectDialogFragment : RedirectDialogFragment() { |
|
40
|
47
|
val themeResId = getInt(KEY_THEME_ID, 0)
|
|
41
|
48
|
val cancelable = getBoolean(KEY_CANCELABLE, false)
|
|
42
|
49
|
|
|
43
|
|
- getBuilder(themeResId)
|
|
|
50
|
+ val dialog = getBuilder(themeResId)
|
|
44
|
51
|
.setTitle(dialogTitleText)
|
|
45
|
52
|
.setMessage(dialogMessageString)
|
|
46
|
|
- .setPositiveButton(positiveButtonText) { _, _ ->
|
|
47
|
|
- onConfirmRedirect()
|
|
48
|
|
- }
|
|
|
53
|
+ .setPositiveButton(positiveButtonText) { _, _ -> }
|
|
49
|
54
|
.setNegativeButton(negativeButtonText) { _, _ ->
|
|
50
|
55
|
onCancelRedirect()
|
|
51
|
56
|
}
|
|
52
|
57
|
.setCancelable(cancelable)
|
|
53
|
58
|
.create()
|
|
54
|
|
- .withCenterAlignedButtons()
|
|
|
59
|
+
|
|
|
60
|
+ dialog.withCenterAlignedButtons()
|
|
|
61
|
+ dialog.setOnShowListener {
|
|
|
62
|
+ val okButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
|
|
|
63
|
+ okButton.setOnClickListener {
|
|
|
64
|
+ if (promptAbuserDetector.areDialogsBeingAbused()) {
|
|
|
65
|
+ promptAbuserDetector.updateJSDialogAbusedState()
|
|
|
66
|
+ } else {
|
|
|
67
|
+ onConfirmRedirect()
|
|
|
68
|
+ dialog.dismiss()
|
|
|
69
|
+ }
|
|
|
70
|
+ }
|
|
|
71
|
+ }
|
|
|
72
|
+ dialog
|
|
55
|
73
|
}
|
|
56
|
74
|
}
|
|
57
|
75
|
|
| ... |
... |
@@ -101,6 +119,7 @@ class SimpleRedirectDialogFragment : RedirectDialogFragment() { |
|
101
|
119
|
const val KEY_THEME_ID = "KEY_THEME_ID"
|
|
102
|
120
|
|
|
103
|
121
|
const val KEY_CANCELABLE = "KEY_CANCELABLE"
|
|
|
122
|
+ private const val TIME_SHOWN_OFFSET_SECONDS = 1
|
|
104
|
123
|
}
|
|
105
|
124
|
|
|
106
|
125
|
private fun requireBundle(): Bundle {
|
mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/SimpleRedirectDialogFragmentTest.kt
| ... |
... |
@@ -13,6 +13,7 @@ import mozilla.components.support.test.mock |
|
13
|
13
|
import mozilla.components.support.test.robolectric.testContext
|
|
14
|
14
|
import org.junit.Assert.assertFalse
|
|
15
|
15
|
import org.junit.Assert.assertTrue
|
|
|
16
|
+import org.junit.Ignore
|
|
16
|
17
|
import org.junit.Test
|
|
17
|
18
|
import org.junit.runner.RunWith
|
|
18
|
19
|
import org.mockito.Mockito.doNothing
|
| ... |
... |
@@ -27,6 +28,7 @@ class SimpleRedirectDialogFragmentTest { |
|
27
|
28
|
private val themeResId = appcompatR.style.Theme_AppCompat_Light
|
|
28
|
29
|
|
|
29
|
30
|
@Test
|
|
|
31
|
+ @Ignore("This will be addressed in another follow up ticket")
|
|
30
|
32
|
fun `Dialog confirmed callback is called correctly`() {
|
|
31
|
33
|
var onConfirmCalled = false
|
|
32
|
34
|
var onCancelCalled = false
|
| ... |
... |
@@ -104,6 +106,7 @@ class SimpleRedirectDialogFragmentTest { |
|
104
|
106
|
assertFalse(onCancelCalled)
|
|
105
|
107
|
}
|
|
106
|
108
|
|
|
|
109
|
+ @Suppress("unused")
|
|
107
|
110
|
private fun mockFragmentManager(): FragmentManager {
|
|
108
|
111
|
val fragmentManager: FragmentManager = mock()
|
|
109
|
112
|
val transaction: FragmentTransaction = mock()
|
mobile/android/android-components/components/feature/session/src/main/java/mozilla/components/feature/session/SessionUseCases.kt
| ... |
... |
@@ -4,7 +4,6 @@ |
|
4
|
4
|
|
|
5
|
5
|
package mozilla.components.feature.session
|
|
6
|
6
|
|
|
7
|
|
-import mozilla.components.browser.state.action.ContentAction
|
|
8
|
7
|
import mozilla.components.browser.state.action.CrashAction
|
|
9
|
8
|
import mozilla.components.browser.state.action.EngineAction
|
|
10
|
9
|
import mozilla.components.browser.state.action.LastAccessAction
|
| ... |
... |
@@ -94,13 +93,6 @@ class SessionUseCases( |
|
94
|
93
|
flags = flags,
|
|
95
|
94
|
additionalHeaders = additionalHeaders,
|
|
96
|
95
|
)
|
|
97
|
|
- // Update the url in content immediately until the engine updates with any new changes to the state.
|
|
98
|
|
- store.dispatch(
|
|
99
|
|
- ContentAction.UpdateUrlAction(
|
|
100
|
|
- loadSessionId,
|
|
101
|
|
- url,
|
|
102
|
|
- ),
|
|
103
|
|
- )
|
|
104
|
96
|
store.dispatch(
|
|
105
|
97
|
EngineAction.OptimizedLoadUrlTriggeredAction(
|
|
106
|
98
|
loadSessionId,
|
mobile/android/android-components/components/feature/session/src/test/java/mozilla/components/feature/session/SessionUseCasesTest.kt
| ... |
... |
@@ -11,7 +11,6 @@ import mozilla.components.browser.state.action.EngineAction |
|
11
|
11
|
import mozilla.components.browser.state.action.TabListAction
|
|
12
|
12
|
import mozilla.components.browser.state.engine.EngineMiddleware
|
|
13
|
13
|
import mozilla.components.browser.state.selector.findTab
|
|
14
|
|
-import mozilla.components.browser.state.selector.selectedTab
|
|
15
|
14
|
import mozilla.components.browser.state.state.BrowserState
|
|
16
|
15
|
import mozilla.components.browser.state.state.TabSessionState
|
|
17
|
16
|
import mozilla.components.browser.state.state.createCustomTab
|
| ... |
... |
@@ -81,7 +80,6 @@ class SessionUseCasesTest { |
|
81
|
80
|
assertEquals("mozilla", action.tabId)
|
|
82
|
81
|
assertEquals("https://getpocket.com", action.url)
|
|
83
|
82
|
}
|
|
84
|
|
- assertEquals("https://getpocket.com", store.state.selectedTab?.content?.url)
|
|
85
|
83
|
|
|
86
|
84
|
useCases.loadUrl("https://www.mozilla.org", LoadUrlFlags.select(LoadUrlFlags.EXTERNAL))
|
|
87
|
85
|
store.waitUntilIdle()
|
| ... |
... |
@@ -95,7 +93,6 @@ class SessionUseCasesTest { |
|
95
|
93
|
assertEquals("https://www.mozilla.org", action.url)
|
|
96
|
94
|
assertEquals(LoadUrlFlags.select(LoadUrlFlags.EXTERNAL), action.flags)
|
|
97
|
95
|
}
|
|
98
|
|
- assertEquals("https://www.mozilla.org", store.state.selectedTab?.content?.url)
|
|
99
|
96
|
|
|
100
|
97
|
useCases.loadUrl("https://firefox.com", store.state.selectedTabId)
|
|
101
|
98
|
store.waitUntilIdle()
|
| ... |
... |
@@ -105,7 +102,6 @@ class SessionUseCasesTest { |
|
105
|
102
|
assertEquals("mozilla", action.tabId)
|
|
106
|
103
|
assertEquals("https://firefox.com", action.url)
|
|
107
|
104
|
}
|
|
108
|
|
- assertEquals("https://firefox.com", store.state.selectedTab?.content?.url)
|
|
109
|
105
|
|
|
110
|
106
|
useCases.loadUrl.invoke(
|
|
111
|
107
|
"https://developer.mozilla.org",
|
mobile/android/android-components/docs/changelog.md
| ... |
... |
@@ -109,9 +109,6 @@ permalink: /changelog/ |
|
109
|
109
|
* **feature-customtabs**
|
|
110
|
110
|
* Fallback behaviour when failing to open a new window in custom tab will now be loading the URL directly in the same custom tab. [Bug 1832357](https://bugzilla.mozilla.org/show_bug.cgi?id=1832357)
|
|
111
|
111
|
|
|
112
|
|
-* **feature-session**
|
|
113
|
|
- * Update URL in the store immediately when using the optimized load URL code path.
|
|
114
|
|
-
|
|
115
|
112
|
* **tooling-lint**
|
|
116
|
113
|
* Added a lint rule to detect when `Response#close` may not have been called. Note: Currently, this rule only runs on Android Components.
|
|
117
|
114
|
|
mobile/android/fenix/app/src/androidTest/java/org/mozilla/fenix/ui/CrashReportingTest.kt
| ... |
... |
@@ -83,7 +83,7 @@ class CrashReportingTest : TestSetup() { |
|
83
|
83
|
verifyPageContent(tabCrashMessage)
|
|
84
|
84
|
}.openTabDrawer(activityTestRule) {
|
|
85
|
85
|
verifyExistingOpenTabs(firstWebPage.title)
|
|
86
|
|
- verifyExistingOpenTabs("about:crashcontent")
|
|
|
86
|
+ verifyExistingOpenTabs(secondWebPage.title)
|
|
87
|
87
|
}.closeTabDrawer {
|
|
88
|
88
|
}.goToHomescreen {
|
|
89
|
89
|
verifyExistingTopSitesList()
|
mobile/android/geckoview/src/main/java/org/mozilla/gecko/Clipboard.java
| ... |
... |
@@ -11,6 +11,7 @@ import android.content.ClipboardManager.OnPrimaryClipChangedListener; |
|
11
|
11
|
import android.content.Context;
|
|
12
|
12
|
import android.content.res.AssetFileDescriptor;
|
|
13
|
13
|
import android.os.Build;
|
|
|
14
|
+import android.os.PersistableBundle;
|
|
14
|
15
|
import android.text.TextUtils;
|
|
15
|
16
|
import android.util.Log;
|
|
16
|
17
|
import java.io.ByteArrayOutputStream;
|
| ... |
... |
@@ -133,8 +134,9 @@ public final class Clipboard { |
|
133
|
134
|
* @return true if copy is successful.
|
|
134
|
135
|
*/
|
|
135
|
136
|
@WrapForJNI(calledFrom = "gecko")
|
|
136
|
|
- public static boolean setText(final Context context, final CharSequence text) {
|
|
137
|
|
- return setData(context, ClipData.newPlainText("text", text));
|
|
|
137
|
+ public static boolean setText(
|
|
|
138
|
+ final Context context, final CharSequence text, final boolean isPrivateData) {
|
|
|
139
|
+ return setData(context, ClipData.newPlainText("text", text), isPrivateData);
|
|
138
|
140
|
}
|
|
139
|
141
|
|
|
140
|
142
|
/**
|
| ... |
... |
@@ -147,8 +149,11 @@ public final class Clipboard { |
|
147
|
149
|
*/
|
|
148
|
150
|
@WrapForJNI(calledFrom = "gecko")
|
|
149
|
151
|
private static boolean setHTML(
|
|
150
|
|
- final Context context, final CharSequence text, final String htmlText) {
|
|
151
|
|
- return setData(context, ClipData.newHtmlText("html", text, htmlText));
|
|
|
152
|
+ final Context context,
|
|
|
153
|
+ final CharSequence text,
|
|
|
154
|
+ final String htmlText,
|
|
|
155
|
+ final boolean isPrivateData) {
|
|
|
156
|
+ return setData(context, ClipData.newHtmlText("html", text, htmlText), isPrivateData);
|
|
152
|
157
|
}
|
|
153
|
158
|
|
|
154
|
159
|
/**
|
| ... |
... |
@@ -158,11 +163,17 @@ public final class Clipboard { |
|
158
|
163
|
* @param clipData a {@link android.content.ClipData} to set to clipboard
|
|
159
|
164
|
* @return true if copy is successful.
|
|
160
|
165
|
*/
|
|
161
|
|
- private static boolean setData(final Context context, final ClipData clipData) {
|
|
|
166
|
+ private static boolean setData(
|
|
|
167
|
+ final Context context, final ClipData clipData, final boolean isPrivateData) {
|
|
162
|
168
|
// In API Level 11 and above, CLIPBOARD_SERVICE returns android.content.ClipboardManager,
|
|
163
|
169
|
// which is a subclass of android.text.ClipboardManager.
|
|
164
|
170
|
final ClipboardManager cm =
|
|
165
|
171
|
(ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
|
|
172
|
+ if (isPrivateData && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
|
173
|
+ final PersistableBundle extras = new PersistableBundle();
|
|
|
174
|
+ extras.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true);
|
|
|
175
|
+ clipData.getDescription().setExtras(extras);
|
|
|
176
|
+ }
|
|
166
|
177
|
try {
|
|
167
|
178
|
cm.setPrimaryClip(clipData);
|
|
168
|
179
|
} catch (final NullPointerException e) {
|
| ... |
... |
@@ -228,7 +239,7 @@ public final class Clipboard { |
|
228
|
239
|
@WrapForJNI(calledFrom = "gecko")
|
|
229
|
240
|
private static void clear(final Context context) {
|
|
230
|
241
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
|
|
231
|
|
- setText(context, null);
|
|
|
242
|
+ setText(context, null, false);
|
|
232
|
243
|
return;
|
|
233
|
244
|
}
|
|
234
|
245
|
// Although we don't know more details of https://crbug.com/1203377, Blink doesn't use
|
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoInputConnection.java
| ... |
... |
@@ -70,6 +70,7 @@ import org.mozilla.gecko.util.ThreadUtils; |
|
70
|
70
|
private ExtractedTextRequest mUpdateRequest;
|
|
71
|
71
|
private final InputConnection mKeyInputConnection;
|
|
72
|
72
|
private CursorAnchorInfo.Builder mCursorAnchorInfoBuilder;
|
|
|
73
|
+ private boolean mIsPrivateBrowsing;
|
|
73
|
74
|
|
|
74
|
75
|
public static SessionTextInput.InputConnectionClient create(
|
|
75
|
76
|
final GeckoSession session,
|
| ... |
... |
@@ -208,12 +209,13 @@ import org.mozilla.gecko.util.ThreadUtils; |
|
208
|
209
|
// If selection is empty, we'll select everything
|
|
209
|
210
|
if (selStart == selEnd) {
|
|
210
|
211
|
// Fill the clipboard
|
|
211
|
|
- Clipboard.setText(view.getContext(), editable);
|
|
|
212
|
+ Clipboard.setText(view.getContext(), editable, mIsPrivateBrowsing);
|
|
212
|
213
|
editable.clear();
|
|
213
|
214
|
} else {
|
|
214
|
215
|
Clipboard.setText(
|
|
215
|
216
|
view.getContext(),
|
|
216
|
|
- editable.subSequence(Math.min(selStart, selEnd), Math.max(selStart, selEnd)));
|
|
|
217
|
+ editable.subSequence(Math.min(selStart, selEnd), Math.max(selStart, selEnd)),
|
|
|
218
|
+ mIsPrivateBrowsing);
|
|
217
|
219
|
editable.delete(selStart, selEnd);
|
|
218
|
220
|
}
|
|
219
|
221
|
break;
|
| ... |
... |
@@ -231,7 +233,7 @@ import org.mozilla.gecko.util.ThreadUtils; |
|
231
|
233
|
: editable
|
|
232
|
234
|
.toString()
|
|
233
|
235
|
.substring(Math.min(selStart, selEnd), Math.max(selStart, selEnd));
|
|
234
|
|
- Clipboard.setText(view.getContext(), copiedText);
|
|
|
236
|
+ Clipboard.setText(view.getContext(), copiedText, mIsPrivateBrowsing);
|
|
235
|
237
|
break;
|
|
236
|
238
|
}
|
|
237
|
239
|
return true;
|
| ... |
... |
@@ -603,6 +605,9 @@ import org.mozilla.gecko.util.ThreadUtils; |
|
603
|
605
|
outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_FLAG_NO_FULLSCREEN;
|
|
604
|
606
|
}
|
|
605
|
607
|
|
|
|
608
|
+ mIsPrivateBrowsing =
|
|
|
609
|
+ ((outAttrs.imeOptions & InputMethods.IME_FLAG_NO_PERSONALIZED_LEARNING) != 0);
|
|
|
610
|
+
|
|
606
|
611
|
if (DEBUG) {
|
|
607
|
612
|
Log.d(
|
|
608
|
613
|
LOGTAG,
|
toolkit/components/httpsonlyerror/content/errorpage.html
| ... |
... |
@@ -70,6 +70,16 @@ |
|
70
|
70
|
inert
|
|
71
|
71
|
></button>
|
|
72
|
72
|
</div>
|
|
|
73
|
+
|
|
|
74
|
+ <p id="explanation-iframe" hidden>
|
|
|
75
|
+ <span data-l10n-id="about-httpsonly-explanation-iframe"></span>
|
|
|
76
|
+ <a
|
|
|
77
|
+ id="mixedContentLearnMoreLink"
|
|
|
78
|
+ target="_blank"
|
|
|
79
|
+ data-l10n-id="about-httpsonly-link-learn-more"
|
|
|
80
|
+ ></a>
|
|
|
81
|
+ </p>
|
|
|
82
|
+
|
|
73
|
83
|
<div class="suggestion-box" hidden>
|
|
74
|
84
|
<h2 data-l10n-id="about-httpsonly-suggestion-box-header"></h2>
|
|
75
|
85
|
</div>
|
toolkit/components/httpsonlyerror/content/errorpage.js
| ... |
... |
@@ -29,28 +29,35 @@ function initPage() { |
|
29
|
29
|
document
|
|
30
|
30
|
.getElementById("learnMoreLink")
|
|
31
|
31
|
.setAttribute("href", baseSupportURL + "https-only-prefs");
|
|
|
32
|
+ document
|
|
|
33
|
+ .getElementById("mixedContentLearnMoreLink")
|
|
|
34
|
+ .setAttribute("href", baseSupportURL + "mixed-content");
|
|
|
35
|
+
|
|
|
36
|
+ const isTopLevel = window.top == window;
|
|
|
37
|
+ if (!isTopLevel) {
|
|
|
38
|
+ for (const id of ["explanation-continue", "goBack", "openInsecure"]) {
|
|
|
39
|
+ document.getElementById(id).remove();
|
|
|
40
|
+ }
|
|
|
41
|
+ document.getElementById("explanation-iframe").removeAttribute("hidden");
|
|
|
42
|
+ return;
|
|
|
43
|
+ }
|
|
32
|
44
|
|
|
33
|
45
|
document
|
|
34
|
46
|
.getElementById("openInsecure")
|
|
35
|
47
|
.addEventListener("click", onOpenInsecureButtonClick);
|
|
|
48
|
+ document
|
|
|
49
|
+ .getElementById("goBack")
|
|
|
50
|
+ .addEventListener("click", onReturnButtonClick);
|
|
36
|
51
|
|
|
37
|
52
|
const delay = RPMGetIntPref("security.dialog_enable_delay", 1000);
|
|
38
|
53
|
setTimeout(() => {
|
|
39
|
54
|
document.getElementById("openInsecure").removeAttribute("inert");
|
|
40
|
55
|
}, delay);
|
|
41
|
56
|
|
|
42
|
|
- if (window.top == window) {
|
|
43
|
|
- document
|
|
44
|
|
- .getElementById("goBack")
|
|
45
|
|
- .addEventListener("click", onReturnButtonClick);
|
|
46
|
|
- addAutofocus("#goBack", "beforeend");
|
|
47
|
|
- } else {
|
|
48
|
|
- document.getElementById("goBack").remove();
|
|
49
|
|
- }
|
|
|
57
|
+ addAutofocus("#goBack", "beforeend");
|
|
50
|
58
|
|
|
51
|
|
- const isTopLevel = window.top == window;
|
|
52
|
59
|
const hasWWWPrefix = pageUrl.href.startsWith("https://www.");
|
|
53
|
|
- if (isTopLevel && !hasWWWPrefix) {
|
|
|
60
|
+ if (!hasWWWPrefix) {
|
|
54
|
61
|
// HTTPS-Only generally simply replaces http: with https:;
|
|
55
|
62
|
// here we additionally try to add www and see if that allows to upgrade the connection if it is top level
|
|
56
|
63
|
|
toolkit/locales/en-US/toolkit/about/aboutHttpsOnlyError.ftl
| ... |
... |
@@ -12,6 +12,7 @@ about-httpsonly-explanation-question = What could be causing this? |
|
12
|
12
|
about-httpsonly-explanation-nosupport = Most likely, the website simply does not support HTTPS.
|
|
13
|
13
|
about-httpsonly-explanation-risk = It’s also possible that an attacker is involved. If you decide to visit the website, you should not enter any sensitive information like passwords, emails, or credit card details.
|
|
14
|
14
|
about-httpsonly-explanation-continue = If you continue, HTTPS-Only Mode will be turned off temporarily for this site.
|
|
|
15
|
+about-httpsonly-explanation-iframe = Due to mixed content blocking, it is not possible to manually allow this frame to load.
|
|
15
|
16
|
|
|
16
|
17
|
about-httpsonly-button-continue-to-site = Continue to HTTP Site
|
|
17
|
18
|
about-httpsonly-button-go-back = Go Back
|
widget/android/nsClipboard.cpp
| ... |
... |
@@ -92,14 +92,16 @@ nsClipboard::SetNativeClipboardData(nsITransferable* aTransferable, |
|
92
|
92
|
return rv;
|
|
93
|
93
|
}
|
|
94
|
94
|
|
|
|
95
|
+ bool isPrivate = aTransferable->GetIsPrivateData();
|
|
|
96
|
+
|
|
95
|
97
|
if (!html.IsEmpty() &&
|
|
96
|
98
|
java::Clipboard::SetHTML(java::GeckoAppShell::GetApplicationContext(),
|
|
97
|
|
- text, html)) {
|
|
|
99
|
+ text, html, isPrivate)) {
|
|
98
|
100
|
return NS_OK;
|
|
99
|
101
|
}
|
|
100
|
102
|
if (!text.IsEmpty() &&
|
|
101
|
103
|
java::Clipboard::SetText(java::GeckoAppShell::GetApplicationContext(),
|
|
102
|
|
- text)) {
|
|
|
104
|
+ text, isPrivate)) {
|
|
103
|
105
|
return NS_OK;
|
|
104
|
106
|
}
|
|
105
|
107
|
|
|