diff --git a/.github/actions/spelling/allow/apis.txt b/.github/actions/spelling/allow/apis.txt index dbd35f48fd..e023d2dc7c 100644 --- a/.github/actions/spelling/allow/apis.txt +++ b/.github/actions/spelling/allow/apis.txt @@ -179,6 +179,7 @@ ubrk UChar UFIELD ULARGE +UNCEx UOI UPDATEINIFILE urlmon diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp index a33bbbda89..fc6b0c9124 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp @@ -587,6 +587,16 @@ static void _resolveSingleMediaResourceInner(Model::OriginTag origin, std::wstri } } + if (origin == winrt::Microsoft::Terminal::Settings::Model::OriginTag::Fragment) + { + if (PathIsUNCEx(resourcePath.c_str(), nullptr)) + { + // A UNC path is just another type of network path, which fragments are not allowed to specify. + resource.Reject(); + return; + } + } + // Not a URI? Try a path. try { diff --git a/src/cascadia/UnitTests_SettingsModel/MediaResourceTests.cpp b/src/cascadia/UnitTests_SettingsModel/MediaResourceTests.cpp index 6b8be97427..294dbfd702 100644 --- a/src/cascadia/UnitTests_SettingsModel/MediaResourceTests.cpp +++ b/src/cascadia/UnitTests_SettingsModel/MediaResourceTests.cpp @@ -103,6 +103,7 @@ namespace SettingsModelUnitTests TEST_METHOD(RealResolverFilePaths); TEST_METHOD(RealResolverSpecialKeywords); TEST_METHOD(RealResolverUrlCases); + TEST_METHOD(RealResolverUNCCases); static constexpr std::wstring_view pingCommandline{ LR"(C:\Windows\System32\PING.EXE)" }; // Normalized by Profile (this is the casing that Windows stores on disk) static constexpr std::wstring_view overrideCommandline{ LR"(C:\Windows\System32\cscript.exe)" }; @@ -1342,5 +1343,95 @@ namespace SettingsModelUnitTests VERIFY_ARE_NOT_EQUAL(image.Resolved(), image.Path()); } } + + void MediaResourceTests::RealResolverUNCCases() + { + WEX::TestExecution::DisableVerifyExceptions disableVerifyExceptions{}; + + g_mediaResolverHook = nullptr; // Use the real resolver + + // For profile, we test images instead of icon because Icon has a fallback behavior. + auto settings = createSettingsWithFragments(R"({})", { Fragment{ L"fragment", fragmentBasePath1, R"( +{ + "profiles": { + "list": [ + { + "backgroundImage": "\\\\server", + "name": "ProfileUNCServerOnly" + }, + { + "backgroundImage": "\\\\server\\share", + "name": "ProfileUNCServerShare" + }, + { + "backgroundImage": "\\\\server\\share\\file", + "name": "ProfileUNCFullPath" + }, + { + "backgroundImage": "\\\\?\\UNC\\server", + "name": "ProfileWin32NamespaceUNCServerOnly" + }, + { + "backgroundImage": "\\\\?\\UNC\\server\\share", + "name": "ProfileWin32NamespaceUNCServerShare" + }, + { + "backgroundImage": "\\\\?\\UNC\\server\\share\\file", + "name": "ProfileWin32NamespaceUNCFullPath" + }, + { + "backgroundImage": "\\\\?\\C:\\Windows\\System32\\cmd.exe", + "name": "ProfileWin32NamespaceDrivePath" + }, + ] + } +})" } }); + + { + auto profile{ settings->GetProfileByName(L"ProfileUNCServerOnly") }; + auto image{ profile.DefaultAppearance().BackgroundImagePath() }; + VERIFY_IS_FALSE(image.Ok()); + } + + { + auto profile{ settings->GetProfileByName(L"ProfileUNCServerShare") }; + auto image{ profile.DefaultAppearance().BackgroundImagePath() }; + VERIFY_IS_FALSE(image.Ok()); + } + + { + auto profile{ settings->GetProfileByName(L"ProfileUNCFullPath") }; + auto image{ profile.DefaultAppearance().BackgroundImagePath() }; + VERIFY_IS_FALSE(image.Ok()); + } + + { + auto profile{ settings->GetProfileByName(L"ProfileWin32NamespaceUNCServerOnly") }; + auto image{ profile.DefaultAppearance().BackgroundImagePath() }; + VERIFY_IS_FALSE(image.Ok()); + } + + { + auto profile{ settings->GetProfileByName(L"ProfileWin32NamespaceUNCServerShare") }; + auto image{ profile.DefaultAppearance().BackgroundImagePath() }; + VERIFY_IS_FALSE(image.Ok()); + } + + { + auto profile{ settings->GetProfileByName(L"ProfileWin32NamespaceUNCFullPath") }; + auto image{ profile.DefaultAppearance().BackgroundImagePath() }; + VERIFY_IS_FALSE(image.Ok()); + } + + // The only one of these paths which is OK is the one to \\?\C:\Windows + { + auto profile{ settings->GetProfileByName(L"ProfileWin32NamespaceDrivePath") }; + auto image{ profile.DefaultAppearance().BackgroundImagePath() }; + VERIFY_IS_TRUE(image.Ok()); + } + + // We cannot test that user-originated UNC paths resolve properly because we cannot guarantee + // the existence of a network share on any test machine, be it in a lab or owned by a user. + } #pragma endregion } diff --git a/src/terminal/parser/InputStateMachineEngine.cpp b/src/terminal/parser/InputStateMachineEngine.cpp index cc9571b757..e0f663f3fb 100644 --- a/src/terminal/parser/InputStateMachineEngine.cpp +++ b/src/terminal/parser/InputStateMachineEngine.cpp @@ -391,19 +391,18 @@ bool InputStateMachineEngine::ActionCsiDispatch(const VTID id, const VTParameter // // Focus events in conpty are special, so don't flush those through either. // See GH#12799, GH#12900 for details - if (_pDispatch->IsVtInputEnabled() && - id != CsiActionCodes::Win32KeyboardInput && - id != CsiActionCodes::FocusIn && - id != CsiActionCodes::FocusOut) - { - return false; - } + const auto vtInputEnabled = _pDispatch->IsVtInputEnabled(); switch (id) { case CsiActionCodes::MouseDown: case CsiActionCodes::MouseUp: { + if (vtInputEnabled) + { + return false; + } + DWORD buttonState = 0; DWORD eventFlags = 0; const auto firstParameter = parameters.at(0).value_or(0); @@ -432,6 +431,10 @@ bool InputStateMachineEngine::ActionCsiDispatch(const VTID id, const VTParameter { return false; } + if (vtInputEnabled) + { + return false; + } [[fallthrough]]; case CsiActionCodes::ArrowUp: case CsiActionCodes::ArrowDown: @@ -443,6 +446,10 @@ bool InputStateMachineEngine::ActionCsiDispatch(const VTID id, const VTParameter case CsiActionCodes::CSI_F2: case CsiActionCodes::CSI_F4: { + if (vtInputEnabled) + { + return false; + } short vkey = 0; if (_GetCursorKeysVkey(id, vkey)) { @@ -453,6 +460,10 @@ bool InputStateMachineEngine::ActionCsiDispatch(const VTID id, const VTParameter } case CsiActionCodes::Generic: { + if (vtInputEnabled) + { + return false; + } short vkey = 0; if (_GetGenericVkey(parameters.at(0), vkey)) { @@ -462,6 +473,10 @@ bool InputStateMachineEngine::ActionCsiDispatch(const VTID id, const VTParameter return true; } case CsiActionCodes::CursorBackTab: + if (vtInputEnabled) + { + return false; + } _WriteSingleKey(VK_TAB, SHIFT_PRESSED); return true; case CsiActionCodes::FocusIn: