blob: 794accf2511637003180c6f0a3e428ba8a5d7127 [file] [log] [blame]
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/web_applications/sub_apps_service_impl.h"
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/check.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/web_applications/web_app_helpers.h"
#include "chrome/browser/web_applications/web_app_install_manager.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/browser/web_applications/web_app_utils.h"
#include "components/webapps/browser/install_result_code.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "url/gurl.h"
using blink::mojom::SubAppsServiceListResult;
using blink::mojom::SubAppsServiceResult;
namespace web_app {
namespace {
WebAppProvider* GetWebAppProvider(content::RenderFrameHost* render_frame_host) {
auto* const initiator_web_contents =
content::WebContents::FromRenderFrameHost(render_frame_host);
return web_app::WebAppProvider::GetForWebContents(initiator_web_contents);
}
absl::optional<AppId> GetAppId(content::RenderFrameHost* render_frame_host) {
GURL parent_url = render_frame_host->GetLastCommittedURL();
WebAppRegistrar& web_app_registrar =
GetWebAppProvider(render_frame_host)->registrar();
return web_app_registrar.FindAppWithUrlInScope(parent_url);
}
// Resolve the install_path in the context of the calling app to get the full
// URL. This looks a bit convoluted to guarantee that the resulting URL
// *always* has the same *origin* as the calling app (normally the renderer
// should only send the path, but a compromised renderer might send a full URL
// instead and we guard against that here).
GURL ResolvePathWithOrigin(const std::string& path, const GURL& origin) {
return origin.Resolve(origin.Resolve(path).PathForRequest());
}
void OnAdd(SubAppsServiceImpl::AddCallback result_callback,
const AppId& app_id,
webapps::InstallResultCode code) {
if (code == webapps::InstallResultCode::kSuccessAlreadyInstalled ||
code == webapps::InstallResultCode::kSuccessNewInstall) {
std::move(result_callback).Run(SubAppsServiceResult::kSuccess);
} else {
std::move(result_callback).Run(SubAppsServiceResult::kFailure);
}
}
} // namespace
SubAppsServiceImpl::SubAppsServiceImpl(
content::RenderFrameHost* render_frame_host,
mojo::PendingReceiver<blink::mojom::SubAppsService> receiver)
: DocumentService(render_frame_host, std::move(receiver)) {}
SubAppsServiceImpl::~SubAppsServiceImpl() = default;
// static
void SubAppsServiceImpl::CreateIfAllowed(
content::RenderFrameHost* render_frame_host,
mojo::PendingReceiver<blink::mojom::SubAppsService> receiver) {
// This class is created only on the main frame.
DCHECK(!render_frame_host->GetParent());
// Bail if Web Apps aren't enabled on current profile.
if (!AreWebAppsEnabled(Profile::FromBrowserContext(
content::WebContents::FromRenderFrameHost(render_frame_host)
->GetBrowserContext()))) {
return;
}
// The object is bound to the lifetime of |render_frame_host| and the mojo
// connection. See DocumentService for details.
new SubAppsServiceImpl(render_frame_host, std::move(receiver));
}
void SubAppsServiceImpl::Add(const std::string& install_path,
AddCallback result_callback) {
// Verify that the calling app is installed itself. This check is done here
// and not in |CreateIfAllowed| because of a potential race between doing the
// check there and then running the current function, and the parent app being
// installed/uninstalled.
absl::optional<AppId> parent_app_id = GetAppId(render_frame_host());
if (!parent_app_id.has_value()) {
return std::move(result_callback).Run(SubAppsServiceResult::kFailure);
}
// Resolve the install_path in the origin context of the calling app.
GURL install_url = ResolvePathWithOrigin(install_path, origin().GetURL());
GetWebAppProvider(render_frame_host())
->install_manager()
.InstallSubApp(*parent_app_id, install_url,
base::BindOnce(&OnAdd, std::move(result_callback)));
}
void SubAppsServiceImpl::List(ListCallback result_callback) {
// Verify that the calling app is installed itself (cf. |Add|).
absl::optional<AppId> parent_app_id = GetAppId(render_frame_host());
if (!parent_app_id.has_value()) {
return std::move(result_callback)
.Run(SubAppsServiceListResult::New(SubAppsServiceResult::kFailure,
std::vector<std::string>()));
}
WebAppRegistrar& registrar =
GetWebAppProvider(render_frame_host())->registrar();
std::vector<std::string> sub_app_ids;
for (const AppId& web_app_id : registrar.GetAllSubAppIds(*parent_app_id)) {
const WebApp* web_app = registrar.GetAppById(web_app_id);
sub_app_ids.push_back(
GenerateAppIdUnhashed(web_app->manifest_id(), web_app->start_url()));
}
std::move(result_callback)
.Run(SubAppsServiceListResult::New(SubAppsServiceResult::kSuccess,
std::move(sub_app_ids)));
}
} // namespace web_app