Skip to content

Gently rework icon and background image validation #19044

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 70 additions & 31 deletions src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,39 @@ void CascadiaSettings::_validateAllSchemesExist()
}
}

static bool _validateSingleMediaResource(std::wstring_view resource)
{
// URI
try
{
winrt::Windows::Foundation::Uri resourceUri{ resource };
if (!resourceUri)
{
return false;
}

const auto scheme{ resourceUri.SchemeName() };
// Only file: URIs and ms-* URIs are permissible. http, https, ftp, gopher, etc. are not.
return til::equals_insensitive_ascii(scheme, L"file") || til::starts_with_insensitive_ascii(scheme, L"ms-");
}
catch (...)
{
// fall through
}

// Not a URI? Try a path.
try
{
std::filesystem::path resourcePath{ resource };
return std::filesystem::exists(resourcePath);
}
catch (...)
{
// fall through
}
return false;
}

// Method Description:
// - Ensures that all specified images resources (icons and background images) are valid URIs.
// This does not verify that the icon or background image files are encoded as an image.
Expand All @@ -501,42 +534,45 @@ void CascadiaSettings::_validateAllSchemesExist()
// we find any invalid icon images.
void CascadiaSettings::_validateMediaResources()
{
auto invalidBackground{ false };
auto invalidIcon{ false };
auto warnInvalidBackground{ false };
auto warnInvalidIcon{ false };

for (auto profile : _allProfiles)
{
if (const auto path = profile.DefaultAppearance().ExpandedBackgroundImagePath(); !path.empty())
{
// Attempt to convert the path to a URI, the ctor will throw if it's invalid/unparseable.
// This covers file paths on the machine, app data, URLs, and other resource paths.
try
if (!_validateSingleMediaResource(path))
{
winrt::Windows::Foundation::Uri imagePath{ path };
}
catch (...)
{
// reset background image path
profile.DefaultAppearance().ClearBackgroundImagePath();
invalidBackground = true;
if (profile.DefaultAppearance().HasBackgroundImagePath())
{
// Only warn and delete if the user set this at the top level (do not warn for fragments, just clear it)
warnInvalidBackground = true;
profile.DefaultAppearance().ClearBackgroundImagePath();
}
else
{
// reset background image path (set it to blank as an override for any fragment value)
profile.DefaultAppearance().BackgroundImagePath({});
}
}
}

if (profile.UnfocusedAppearance())
{
if (const auto path = profile.UnfocusedAppearance().ExpandedBackgroundImagePath(); !path.empty())
{
// Attempt to convert the path to a URI, the ctor will throw if it's invalid/unparseable.
// This covers file paths on the machine, app data, URLs, and other resource paths.
try
if (!_validateSingleMediaResource(path))
{
winrt::Windows::Foundation::Uri imagePath{ path };
}
catch (...)
{
// reset background image path
profile.UnfocusedAppearance().ClearBackgroundImagePath();
invalidBackground = true;
if (profile.UnfocusedAppearance().HasBackgroundImagePath())
{
warnInvalidBackground = true;
profile.UnfocusedAppearance().ClearBackgroundImagePath();
}
else
{
// reset background image path (set it to blank as an override for any fragment value)
profile.UnfocusedAppearance().BackgroundImagePath({});
}
}
}
}
Expand All @@ -552,24 +588,27 @@ void CascadiaSettings::_validateMediaResources()
if (const auto icon = profile.Icon(); icon.size() > 2 && icon != HideIconValue)
{
const auto iconPath{ wil::ExpandEnvironmentStringsW<std::wstring>(icon.c_str()) };
try
{
winrt::Windows::Foundation::Uri imagePath{ iconPath };
}
catch (...)
if (!_validateSingleMediaResource(iconPath))
{
profile.ClearIcon();
invalidIcon = true;
if (profile.HasIcon())
{
warnInvalidIcon = true;
profile.ClearIcon();
}
else
{
profile.Icon({});
}
}
}
}

if (invalidBackground)
if (warnInvalidBackground)
{
_warnings.Append(SettingsLoadWarnings::InvalidBackgroundImage);
}

if (invalidIcon)
if (warnInvalidIcon)
{
_warnings.Append(SettingsLoadWarnings::InvalidIcon);
}
Expand Down
Loading