Bug 1774317 - part 2: Make `TSFTextStore` support `GUID_PROP_URL` r=m_kato

`GUID_PROP_URL` is defined here:
https://learn.microsoft.com/en-us/windows/win32/tsf/predefined-properties

> Contains a BSTR value representing the URL of the text control source, where
> applicable.

The URL may contain sensitive information, e.g., user name, password, query
string.  However, they are already leaked via MSAA/UIA.
https://searchfox.org/mozilla-central/rev/b1e5f2c7c96be36974262551978d54f457db2cae/accessible/generic/DocAccessible.cpp#350

Therefore, this patch just has prefs to completely prevent to expose the URL
for users who don't like this feature.

Differential Revision: https://phabricator.services.mozilla.com/D157894
This commit is contained in:
Masayuki Nakano 2022-09-28 11:46:59 +00:00
Родитель b3600e6d25
Коммит 58fa8fca99
3 изменённых файлов: 116 добавлений и 38 удалений

Просмотреть файл

@ -6844,6 +6844,23 @@
value: @IS_NOT_EARLY_BETA_OR_EARLIER@
mirror: always
# If true, TSF and TIP (IME) can retrieve URL of the document containing
# the focused element. When this is set to true, Gecko exposes the spec
# of the URL.
# And Gecko exposes only "http" and "https" URLs. E.g., "data", "blob",
# "file" URLs are never exposed.
- name: intl.tsf.expose_url.allowed
type: bool
value: true
mirror: always
# If true, TSF and TIP (IME) can retrieve URL of the document containing
# the focused element in the private browsing mode too.
- name: intl.tsf.expose_url_in_private_browsing.allowed
type: bool
value: false
mirror: always
#if defined(ENABLE_TESTS)
# If true, NS_GetComplexLineBreaks compares the line breaks produced in the
# content process using the Uniscribe line breaker, with those from a

Просмотреть файл

@ -7,8 +7,10 @@
#define TEXTATTRS_INIT_GUID
#include "TSFTextStore.h"
#include <olectl.h>
#include <algorithm>
#include <comutil.h> // for _bstr_t
#include <oleauto.h> // for SysAllocString
#include <olectl.h>
#include "nscore.h"
#include "IMMHandler.h"
@ -26,6 +28,7 @@
#include "mozilla/WindowsVersion.h"
#include "nsWindow.h"
#include "nsPrintfCString.h"
#include "nsReadableUtils.h" // for VoidString()
// Workaround for mingw32
#ifndef TS_SD_INPUTPANEMANUALDISPLAYENABLE
@ -38,6 +41,14 @@
// Therefore you shouldn't use `LogLevel::Verbose` for logging usual behavior.
mozilla::LazyLogModule gIMELog("IMEHandler");
// TODO: GUID_PROP_URL has not been declared in the SDK yet. We should drop the
// `s` prefix after it's released by a new SDK and define it with #if.
static const GUID sGUID_PROP_URL = {
0xd5138268,
0xa1bf,
0x4308,
{0xbc, 0xbf, 0x2e, 0x73, 0x93, 0x98, 0xe2, 0x34}};
namespace mozilla {
namespace widget {
@ -228,6 +239,7 @@ static nsCString GetGUIDNameStrWithTable(REFGUID aGUID) {
}
RETURN_GUID_NAME(GUID_PROP_INPUTSCOPE)
RETURN_GUID_NAME(sGUID_PROP_URL)
RETURN_GUID_NAME(TSATTRID_OTHERS)
RETURN_GUID_NAME(TSATTRID_Font)
RETURN_GUID_NAME(TSATTRID_Font_FaceName)
@ -1807,22 +1819,7 @@ TSFTextStore::TSFTextStore()
mSinkMask(0),
mLock(0),
mLockQueued(0),
mHandlingKeyMessage(0),
mRequestedAttrValues(false),
mIsRecordingActionsWithoutLock(false),
mHasReturnedNoLayoutError(false),
mWaitingQueryLayout(false),
mPendingDestroy(false),
mDeferClearingContentForTSF(false),
mDeferNotifyingTSF(false),
mDeferCommittingComposition(false),
mDeferCancellingComposition(false),
mDestroyed(false),
mBeingDestroyed(false) {
for (int32_t i = 0; i < NUM_OF_SUPPORTED_ATTRS; i++) {
mRequestedAttrs[i] = false;
}
mHandlingKeyMessage(0) {
// We hope that 5 or more actions don't occur at once.
mPendingActions.SetCapacity(5);
@ -1871,8 +1868,16 @@ bool TSFTextStore::Init(nsWindow* aWidget, const InputContext& aContext) {
return false;
}
SetInputScope(aContext.mHTMLInputType, aContext.mHTMLInputInputmode,
aContext.mInPrivateBrowsing);
mInPrivateBrowsing = aContext.mInPrivateBrowsing;
SetInputScope(aContext.mHTMLInputType, aContext.mHTMLInputInputmode);
if (aContext.mURI) {
// We don't need the document URL if it fails, let's ignore the error.
nsAutoCString spec;
if (NS_SUCCEEDED(aContext.mURI->GetSpec(spec))) {
CopyUTF8toUTF16(spec, mDocumentURL);
}
}
// Create document manager
RefPtr<ITfThreadMgr> threadMgr = sThreadMgr;
@ -2000,6 +2005,7 @@ void TSFTextStore::ReleaseTSFObjects() {
MOZ_LOG(gIMELog, LogLevel::Info,
("0x%p TSFTextStore::ReleaseTSFObjects()", this));
mDocumentURL.Truncate();
mContext = nullptr;
if (mDocumentMgr) {
RefPtr<ITfDocumentMgr> documentMgr = mDocumentMgr.forget();
@ -3911,8 +3917,7 @@ bool TSFTextStore::ShouldSetInputScopeOfURLBarToDefault() {
}
void TSFTextStore::SetInputScope(const nsString& aHTMLInputType,
const nsString& aHTMLInputInputMode,
bool aInPrivateBrowsing) {
const nsString& aHTMLInputInputMode) {
mInputScopes.Clear();
// IME may refer only first input scope, but we will append inputmode's
@ -3920,7 +3925,7 @@ void TSFTextStore::SetInputScope(const nsString& aHTMLInputType,
IMEHandler::AppendInputScopeFromType(aHTMLInputType, mInputScopes);
IMEHandler::AppendInputScopeFromInputmode(aHTMLInputInputMode, mInputScopes);
if (aInPrivateBrowsing) {
if (mInPrivateBrowsing) {
mInputScopes.AppendElement(IS_PRIVATE);
}
}
@ -3929,6 +3934,9 @@ int32_t TSFTextStore::GetRequestedAttrIndex(const TS_ATTRID& aAttrID) {
if (IsEqualGUID(aAttrID, GUID_PROP_INPUTSCOPE)) {
return eInputScope;
}
if (IsEqualGUID(aAttrID, sGUID_PROP_URL)) {
return eDocumentURL;
}
if (IsEqualGUID(aAttrID, TSATTRID_Text_VerticalWriting)) {
return eTextVerticalWriting;
}
@ -3943,6 +3951,8 @@ TSFTextStore::GetAttrID(int32_t aIndex) {
switch (aIndex) {
case eInputScope:
return GUID_PROP_INPUTSCOPE;
case eDocumentURL:
return sGUID_PROP_URL;
case eTextVerticalWriting:
return TSATTRID_Text_VerticalWriting;
case eTextOrientation:
@ -4049,6 +4059,9 @@ TSFTextStore::FindNextAttrTransition(LONG acpStart, LONG acpHalt,
return S_OK;
}
// To test the document URL result, define this to out put it to the stdout
// #define DEBUG_PRINT_DOCUMENT_URL
STDMETHODIMP
TSFTextStore::RetrieveRequestedAttrs(ULONG ulCount, TS_ATTRVAL* paAttrVals,
ULONG* pcFetched) {
@ -4079,6 +4092,32 @@ TSFTextStore::RetrieveRequestedAttrs(ULONG ulCount, TS_ATTRVAL* paAttrVals,
"ulCount=%lu, mRequestedAttrValues=%s",
this, ulCount, GetBoolName(mRequestedAttrValues)));
auto GetExposingURL = [&]() -> BSTR {
const bool allowed =
StaticPrefs::intl_tsf_expose_url_allowed() &&
(!mInPrivateBrowsing ||
StaticPrefs::intl_tsf_expose_url_in_private_browsing_allowed());
if (!allowed) {
MOZ_ASSERT(EmptyString().get());
return ::SysAllocString(EmptyString().get());
}
if (mDocumentURL.IsEmpty()) {
MOZ_ASSERT(EmptyString().get());
return ::SysAllocString(EmptyString().get());
}
return ::SysAllocString(mDocumentURL.get());
};
#ifdef DEBUG_PRINT_DOCUMENT_URL
{
BSTR exposingURL = GetExposingURL();
printf("TSFTextStore::RetrieveRequestedAttrs: DocumentURL=\"%s\"\n",
NS_ConvertUTF16toUTF8(static_cast<char16ptr_t>(_bstr_t(exposingURL)))
.get());
::SysFreeString(exposingURL);
}
#endif // #ifdef DEBUG_PRINT_DOCUMENT_URL
int32_t count = 0;
for (int32_t i = 0; i < NUM_OF_SUPPORTED_ATTRS; i++) {
if (!mRequestedAttrs[i]) {
@ -4105,6 +4144,11 @@ TSFTextStore::RetrieveRequestedAttrs(ULONG ulCount, TS_ATTRVAL* paAttrVals,
paAttrVals[count].varValue.punkVal = inputScope.forget().take();
break;
}
case eDocumentURL: {
paAttrVals[count].varValue.vt = VT_BSTR;
paAttrVals[count].varValue.bstrVal = GetExposingURL();
break;
}
case eTextVerticalWriting: {
Maybe<Selection>& selectionForTSF = SelectionForTSF();
paAttrVals[count].varValue.vt = VT_BOOL;
@ -4151,6 +4195,8 @@ TSFTextStore::RetrieveRequestedAttrs(ULONG ulCount, TS_ATTRVAL* paAttrVals,
return S_OK;
}
#undef DEBUG_PRINT_DOCUMENT_URL
STDMETHODIMP
TSFTextStore::GetEndACP(LONG* pacp) {
MOZ_LOG(gIMELog, LogLevel::Info,
@ -6652,9 +6698,19 @@ void TSFTextStore::SetInputContext(nsWindow* aWidget,
"Why is this called when TSF is disabled?");
if (sEnabledTextStore) {
RefPtr<TSFTextStore> textStore(sEnabledTextStore);
textStore->mInPrivateBrowsing = aContext.mInPrivateBrowsing;
textStore->SetInputScope(aContext.mHTMLInputType,
aContext.mHTMLInputInputmode,
aContext.mInPrivateBrowsing);
aContext.mHTMLInputInputmode);
if (aContext.mURI) {
nsAutoCString spec;
if (NS_SUCCEEDED(aContext.mURI->GetSpec(spec))) {
CopyUTF8toUTF16(spec, textStore->mDocumentURL);
} else {
textStore->mDocumentURL.Truncate();
}
} else {
textStore->mDocumentURL.Truncate();
}
}
return;
}

Просмотреть файл

@ -382,8 +382,7 @@ class TSFTextStore final : public ITextStoreACP,
HRESULT HandleRequestAttrs(DWORD aFlags, ULONG aFilterCount,
const TS_ATTRID* aFilterAttrs);
void SetInputScope(const nsString& aHTMLInputType,
const nsString& aHTMLInputInputmode,
bool aInPrivateBrowsing);
const nsString& aHTMLInputInputMode);
// Creates native caret over our caret. This method only works on desktop
// application. Otherwise, this does nothing.
@ -1018,6 +1017,9 @@ class TSFTextStore final : public ITextStoreACP,
// The input scopes for this context, defaults to IS_DEFAULT.
nsTArray<InputScope> mInputScopes;
// The URL cache of the focused document.
nsString mDocumentURL;
// Support retrieving attributes.
// TODO: We should support RightToLeft, perhaps.
enum {
@ -1026,56 +1028,59 @@ class TSFTextStore final : public ITextStoreACP,
// Supported attributes
eInputScope = 0,
eDocumentURL,
eTextVerticalWriting,
eTextOrientation,
// Count of the supported attributes
NUM_OF_SUPPORTED_ATTRS
};
bool mRequestedAttrs[NUM_OF_SUPPORTED_ATTRS];
bool mRequestedAttrs[NUM_OF_SUPPORTED_ATTRS]{false};
int32_t GetRequestedAttrIndex(const TS_ATTRID& aAttrID);
TS_ATTRID GetAttrID(int32_t aIndex);
bool mRequestedAttrValues;
bool mRequestedAttrValues = false;
// If edit actions are being recorded without document lock, this is true.
// Otherwise, false.
bool mIsRecordingActionsWithoutLock;
bool mIsRecordingActionsWithoutLock = false;
// If GetTextExt() or GetACPFromPoint() is called and the layout hasn't been
// calculated yet, these methods return TS_E_NOLAYOUT. At that time,
// mHasReturnedNoLayoutError is set to true.
bool mHasReturnedNoLayoutError;
bool mHasReturnedNoLayoutError = false;
// Before calling ITextStoreACPSink::OnLayoutChange() and
// ITfContextOwnerServices::OnLayoutChange(), mWaitingQueryLayout is set to
// true. This is set to false when GetTextExt() or GetACPFromPoint() is
// called.
bool mWaitingQueryLayout;
// During the documet is locked, we shouldn't destroy the instance.
bool mWaitingQueryLayout = false;
// During the document is locked, we shouldn't destroy the instance.
// If this is true, the instance will be destroyed after unlocked.
bool mPendingDestroy;
// If this is false, MaybeFlushPendingNotifications() will clear the
// mContentForTSF.
bool mDeferClearingContentForTSF;
bool mDeferClearingContentForTSF = false;
// While the instance is dispatching events, the event may not be handled
// synchronously in e10s mode. So, in such case, in strictly speaking,
// we shouldn't query layout information. However, TS_E_NOLAYOUT bugs of
// ITextStoreAPC::GetTextExt() blocks us to behave ideally.
// For preventing it to be called, we should put off notifying TSF of
// anything until layout information becomes available.
bool mDeferNotifyingTSF;
bool mDeferNotifyingTSF = false;
// While the document is locked, committing composition always fails since
// TSF needs another document lock for modifying the composition, selection
// and etc. So, committing composition should be performed after the
// document is unlocked.
bool mDeferCommittingComposition;
bool mDeferCancellingComposition;
bool mDeferCommittingComposition = false;
bool mDeferCancellingComposition = false;
// Immediately after a call of Destroy(), mDestroyed becomes true. If this
// is true, the instance shouldn't grant any requests from the TIP anymore.
bool mDestroyed;
bool mDestroyed = false;
// While the instance is being destroyed, this is set to true for avoiding
// recursive Destroy() calls.
bool mBeingDestroyed;
bool mBeingDestroyed = false;
// Whether we're in the private browsing mode.
bool mInPrivateBrowsing = true;
// TSF thread manager object for the current application
static StaticRefPtr<ITfThreadMgr> sThreadMgr;