Commit 2a4e6ccf authored by Jesse McKenna's avatar Jesse McKenna Committed by Commit Bot

desktop-pwas: Disallow . in Win7 launcher filename

This change replaces any '.' characters in a PWA launcher's filename
with '_' on Windows 7 to prevent launchers from having misleading or
potentially unsafe file extensions, such as those in
net::IsShellIntegratedExtension(). This is largely a just-in-case
measure added because a PWA launcher on Windows 7 has no extension.

This change also simplifies the logic for legitimizing a reserved
filename on Windows by prepending '_' rather than appending it.

On Windows, each Progressive Web App (PWA) must have its own launcher
in order for the PWA to be able to register as a handler for file
types. On Windows 7, the filename of this launcher is used as the
PWA's display name in the Open With menu, because Windows 7 lacks an
alternate way to set multiple custom display names for one executable
(and PWA launchers are identical copies of chrome_pwa_launcher.exe).

The launcher filename is based on the PWA's name, with modifications
to ensure the resulting filename is legitimate.

These modifications are as follows:
* Replace illegal characters with '_'

* If filename is reserved on Windows:
  - OLD:
    + Append '_'
    + Replace all '.' with '_'; this was necessary because Windows'
      logic for checking reserved filenames views characters after '.'
      as file extensions, and only the pre-file-extension portion is
      checked for legitimacy (e.g. "nul" is reserved; "nul_" is
      allowed, but "nul.a_" is not).
  - NEW:
    + Prepend '_'

* NEW: On Windows 7, replace all '.' with '_'

Change-Id: Ibb2a183a8f023e5cbd98adb143e95551c49a1218
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2002982
Commit-Queue: Jesse McKenna <jessemckenna@google.com>
Reviewed-by: default avatarGiovanni Ortuño Urquidi <ortuno@chromium.org>
Reviewed-by: default avatarMatt Giuca <mgiuca@chromium.org>
Cr-Commit-Position: refs/heads/master@{#734265}
parent 9a683b82
...@@ -32,29 +32,31 @@ namespace { ...@@ -32,29 +32,31 @@ namespace {
// Returns the app-specific-launcher filename to be used for |app_name|. // Returns the app-specific-launcher filename to be used for |app_name|.
base::FilePath GetAppSpecificLauncherFilename(const base::string16& app_name) { base::FilePath GetAppSpecificLauncherFilename(const base::string16& app_name) {
// Remove any characters that are illegal in Windows filenames. // Remove any characters that are illegal in Windows filenames.
base::FilePath sanitized_app_name = base::string16 sanitized_app_name =
web_app::internals::GetSanitizedFileName(app_name); web_app::internals::GetSanitizedFileName(app_name).value();
// If |sanitized_app_name| is a reserved filename, append '_' to allow its use // On Windows 7, where the launcher has no file extension, replace any '.'
// as the launcher filename (e.g. "nul" => "nul_"). If |sanitized_app_name| // characters with '_' to prevent a portion of the filename from being
// starts with a reserved filename followed by '.', replace all '.' characters // interpreted as its extension.
// with '_' (e.g. "nul.l" => "nul_l"). This is needed because anything after const bool is_win_7 = base::win::GetVersion() == base::win::Version::WIN7;
// '.' is interpreted as part of a file extension for the purpose of if (is_win_7)
// identifying reserved filenames, so appending '_' fails to legitimize a base::ReplaceChars(sanitized_app_name, L".", L"_", &sanitized_app_name);
// reserved filename when a '.' is present (e.g. "nul.l_" is rejected).
if (net::IsReservedNameOnWindows(sanitized_app_name.value())) { // If |sanitized_app_name| is a reserved filename, prepend '_' to allow its
base::string16 allowed_filename = sanitized_app_name.value(); // use as the launcher filename (e.g. "nul" => "_nul"). Prepending is
if (!base::ReplaceChars(allowed_filename, L".", L"_", &allowed_filename)) // preferred over appending in order to handle filenames containing '.', as
allowed_filename.append(L"_"); // Windows' logic for checking reserved filenames views characters after '.'
sanitized_app_name = base::FilePath(allowed_filename); // as file extensions, and only the pre-file-extension portion is checked for
} // legitimacy (e.g. "nul_" is allowed, but "nul.a_" is not).
if (net::IsReservedNameOnWindows(sanitized_app_name))
// On Windows 8+, add .exe extension. On Windows 7, where the launcher sanitized_app_name = L"_" + sanitized_app_name;
// filename is used as the app's display name in the Open With menu, omit the
// extension. // On Windows 8+, add .exe extension. On Windows 7, where an app's display
if (base::win::GetVersion() > base::win::Version::WIN7) // name in the Open With menu can't be set programmatically, omit the
return sanitized_app_name.AddExtension(L"exe"); // extension to use the launcher filename as the app's display name.
return sanitized_app_name; if (!is_win_7)
return base::FilePath(sanitized_app_name).AddExtension(L"exe");
return base::FilePath(sanitized_app_name);
} }
} // namespace } // namespace
......
...@@ -226,16 +226,16 @@ TEST_F(WebAppFileHandlerRegistrationWinTest, AppNameWithInvalidChars) { ...@@ -226,16 +226,16 @@ TEST_F(WebAppFileHandlerRegistrationWinTest, AppNameWithInvalidChars) {
EXPECT_EQ(app_specific_launcher_path, registered_app_path); EXPECT_EQ(app_specific_launcher_path, registered_app_path);
} }
// Test that an app name that is a reserved filename on Windows has '_' appended // Test that an app name that is a reserved filename on Windows has '_'
// to it when used as a filename for its launcher. // prepended to it when used as a filename for its launcher.
TEST_F(WebAppFileHandlerRegistrationWinTest, AppNameIsReservedFilename) { TEST_F(WebAppFileHandlerRegistrationWinTest, AppNameIsReservedFilename) {
std::set<std::string> file_extensions({"txt"}); std::set<std::string> file_extensions({"txt"});
AppId app_id("app_id"); AppId app_id("app_id");
// "con" is a reserved filename on Windows, so it should have '_' appended. // "con" is a reserved filename on Windows, so it should have '_' prepended.
std::string app_name("con"); std::string app_name("con");
base::FilePath app_specific_launcher_path = base::FilePath app_specific_launcher_path =
CreateDataDirectoryAndGetLauncherPathForApp(profile(), app_id, "con_"); CreateDataDirectoryAndGetLauncherPathForApp(profile(), app_id, "_con");
RegisterFileHandlersWithOs(app_id, app_name, profile(), RegisterFileHandlersWithOs(app_id, app_name, profile(),
/*file_extensions*/ {"txt"}, /*mime_types=*/{}); /*file_extensions*/ {"txt"}, /*mime_types=*/{});
...@@ -248,20 +248,19 @@ TEST_F(WebAppFileHandlerRegistrationWinTest, AppNameIsReservedFilename) { ...@@ -248,20 +248,19 @@ TEST_F(WebAppFileHandlerRegistrationWinTest, AppNameIsReservedFilename) {
EXPECT_EQ(app_specific_launcher_path, registered_app_path); EXPECT_EQ(app_specific_launcher_path, registered_app_path);
} }
// Test that an app name that consists of a reserved filename on Windows plus // Test that an app name containing '.' characters has them replaced with '_' on
// '.' has all its '.' characters replaced by '_' when used as a filename for // Windows 7 when used as a filename for its launcher.
// its launcher. TEST_F(WebAppFileHandlerRegistrationWinTest, AppNameContainsDot) {
TEST_F(WebAppFileHandlerRegistrationWinTest, AppNameIsReservedFilenameWithDot) {
std::set<std::string> file_extensions({"txt"}); std::set<std::string> file_extensions({"txt"});
AppId app_id("app_id"); AppId app_id("app_id");
// "con" is a reserved filename on Windows, and appending '_' won't make it // "some.app.name" should become "some_app_name" on Windows 7.
// legitimate (because any text after '.' is interpreted as part of a file std::string app_name("some.app.name");
// extension), so all '.' characters should be replaced with '_'.
std::string app_name("con.nect");
base::FilePath app_specific_launcher_path = base::FilePath app_specific_launcher_path =
CreateDataDirectoryAndGetLauncherPathForApp(profile(), app_id, CreateDataDirectoryAndGetLauncherPathForApp(
"con_nect"); profile(), app_id,
base::win::GetVersion() > base::win::Version::WIN7 ? "some.app.name"
: "some_app_name");
RegisterFileHandlersWithOs(app_id, app_name, profile(), RegisterFileHandlersWithOs(app_id, app_name, profile(),
/*file_extensions*/ {"txt"}, /*mime_types=*/{}); /*file_extensions*/ {"txt"}, /*mime_types=*/{});
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment