blob: 87afa283d05a6b9edb143c8618639478fb796057 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/web_applications/web_app_helpers.h"
#include "base/base64.h"
#include "base/feature_list.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/common/webui_url_constants.h"
#include "components/crx_file/id_util.h"
#include "components/password_manager/content/common/web_ui_constants.h"
#include "components/prefs/pref_service.h"
#include "content/public/common/content_features.h"
#include "crypto/sha2.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/manifest/manifest.mojom.h"
#include "url/gurl.h"
#include "url/origin.h"
#include "url/url_constants.h"
namespace web_app {
// The following string is used to build the directory name for
// shortcuts to chrome applications (the kind which are installed
// from a CRX). Application shortcuts to URLs use the {host}_{path}
// for the name of this directory. Hosts can't include an underscore.
// By starting this string with an underscore, we ensure that there
// are no naming conflicts.
const char kCrxAppPrefix[] = "_crx_";
std::string GenerateApplicationNameFromURL(const GURL& url) {
return base::StrCat({url.host_piece(), "_", url.path_piece()});
}
std::string GenerateApplicationNameFromAppId(const AppId& app_id) {
std::string t(kCrxAppPrefix);
t.append(app_id);
return t;
}
AppId GetAppIdFromApplicationName(const std::string& app_name) {
std::string prefix(kCrxAppPrefix);
if (app_name.substr(0, prefix.length()) != prefix)
return std::string();
return app_name.substr(prefix.length());
}
AppId GenerateAppIdFromManifestId(const ManifestId& manifest_id) {
// The app ID is hashed twice: here and in GenerateId.
// The double-hashing is for historical reasons and it needs to stay
// this way for backwards compatibility. (Back then, a web app's input to the
// hash needed to be formatted like an extension public key.)
return crx_file::id_util::GenerateId(
crypto::SHA256HashString(manifest_id.spec()));
}
AppId GenerateAppId(const absl::optional<std::string>& manifest_id_path,
const GURL& start_url) {
if (!manifest_id_path) {
return GenerateAppIdFromManifestId(
GenerateManifestIdFromStartUrlOnly(start_url));
}
return GenerateAppIdFromManifestId(
GenerateManifestId(manifest_id_path.value(), start_url));
}
ManifestId GenerateManifestId(const std::string& manifest_id_path,
const GURL& start_url) {
// When manifest_id is specified, the app id is generated from
// <start_url_origin>/<manifest_id_path>.
// Note: start_url.DeprecatedGetOriginAsURL().spec() returns the origin ending
// with slash.
GURL app_id(start_url.DeprecatedGetOriginAsURL().spec() + manifest_id_path);
CHECK(app_id.is_valid()) << "start_url: " << start_url
<< ", manifest_id = " << manifest_id_path;
return app_id.GetWithoutRef();
}
AppId GenerateAppIdFromManifest(const blink::mojom::Manifest& manifest) {
CHECK(manifest.id.is_valid());
return GenerateAppIdFromManifestId(manifest.id);
}
ManifestId GenerateManifestIdFromStartUrlOnly(const GURL& start_url) {
CHECK(start_url.is_valid()) << start_url.spec();
return start_url.GetWithoutRef();
}
bool IsValidWebAppUrl(const GURL& app_url) {
if (app_url.is_empty() || app_url.inner_url())
return false;
// TODO(crbug.com/1253234): Remove chrome-extension scheme.
return app_url.SchemeIs(url::kHttpScheme) ||
app_url.SchemeIs(url::kHttpsScheme) ||
app_url.SchemeIs("chrome-extension") ||
(app_url.SchemeIs("chrome") &&
(app_url.host() == password_manager::kChromeUIPasswordManagerHost));
}
absl::optional<AppId> FindInstalledAppWithUrlInScope(Profile* profile,
const GURL& url,
bool window_only) {
auto* provider = WebAppProvider::GetForLocalAppsUnchecked(profile);
return provider ? provider->registrar_unsafe().FindInstalledAppWithUrlInScope(
url, window_only)
: absl::nullopt;
}
bool IsNonLocallyInstalledAppWithUrlInScope(Profile* profile, const GURL& url) {
auto* provider = WebAppProvider::GetForWebApps(profile);
return provider ? provider->registrar_unsafe()
.IsNonLocallyInstalledAppWithUrlInScope(url)
: false;
}
bool LooksLikePlaceholder(const WebApp& app) {
for (const auto& [install_source, config] :
app.management_to_external_config_map()) {
if (config.is_placeholder) {
return true;
}
for (const GURL& install_url : config.install_urls) {
if (app.untranslated_name() == install_url.spec()) {
return true;
}
}
}
return false;
}
} // namespace web_app