blob: 65f5c84b3c38bc177ad3047ff2cbd522f95365a1 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_INSTALL_ISOLATED_WEB_APP_COMMAND_H_
#define CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_INSTALL_ISOLATED_WEB_APP_COMMAND_H_
#include <iosfwd>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <type_traits>
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/types/expected.h"
#include "base/values.h"
#include "base/version.h"
#include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
#include "chrome/browser/web_applications/commands/web_app_command.h"
#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_install_command_helper.h"
#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_install_source.h"
#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.h"
#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_storage_location.h"
#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
#include "chrome/browser/web_applications/locks/app_lock.h"
#include "chrome/browser/web_applications/web_app_install_info.h"
#include "components/keep_alive_registry/scoped_keep_alive.h"
#include "components/webapps/browser/install_result_code.h"
#include "components/webapps/browser/installable/installable_logging.h"
#include "components/webapps/common/web_app_id.h"
#include "third_party/blink/public/mojom/manifest/manifest.mojom-forward.h"
class Profile;
namespace content {
class WebContents;
} // namespace content
namespace webapps {
class WebAppUrlLoader;
enum class WebAppUrlLoaderResult;
} // namespace webapps
namespace web_app {
struct InstallIsolatedWebAppCommandSuccess {
InstallIsolatedWebAppCommandSuccess(base::Version installed_version,
IsolatedWebAppStorageLocation location);
InstallIsolatedWebAppCommandSuccess(
const InstallIsolatedWebAppCommandSuccess& other);
~InstallIsolatedWebAppCommandSuccess();
base::Version installed_version;
IsolatedWebAppStorageLocation location;
};
std::ostream& operator<<(std::ostream& os,
const InstallIsolatedWebAppCommandSuccess& success);
struct InstallIsolatedWebAppCommandError {
std::string message;
};
std::ostream& operator<<(std::ostream& os,
const InstallIsolatedWebAppCommandError& error);
// Isolated Web App requires:
// * no cross-origin navigation
// * content should never be loaded in normal tab
//
// |content::IsolatedWebAppThrottle| enforces that. The requirements prevent
// re-using web contents.
class InstallIsolatedWebAppCommand
: public WebAppCommand<AppLock,
base::expected<InstallIsolatedWebAppCommandSuccess,
InstallIsolatedWebAppCommandError>> {
public:
// `url_info` holds the origin information of the app. It is randomly
// generated for dev-proxy and the public key of signed bundle. It is
// guarantee to be valid.
//
// `location` holds information about the mode(dev-mod-proxy/signed-bundle)
// and the source.
//
// `expected_version`, if set, specifies the expected version of the IWA to
// install. If the version in the manifest differs, install is aborted.
//
// `callback` must be not null.
//
// The `id` in the application's manifest must equal "/".
//
// `response_reader_factory` should be created via
// `CreateDefaultResponseReaderFactory` and is used to create the
// `IsolatedWebAppResponseReader` for the Web Bundle.
InstallIsolatedWebAppCommand(
const IsolatedWebAppUrlInfo& url_info,
const IsolatedWebAppInstallSource& install_source,
const std::optional<base::Version>& expected_version,
std::unique_ptr<content::WebContents> web_contents,
std::unique_ptr<ScopedKeepAlive> optional_keep_alive,
std::unique_ptr<ScopedProfileKeepAlive> optional_profile_keep_alive,
base::OnceCallback<
void(base::expected<InstallIsolatedWebAppCommandSuccess,
InstallIsolatedWebAppCommandError>)> callback,
std::unique_ptr<IsolatedWebAppInstallCommandHelper> command_helper);
InstallIsolatedWebAppCommand(const InstallIsolatedWebAppCommand&) = delete;
InstallIsolatedWebAppCommand& operator=(const InstallIsolatedWebAppCommand&) =
delete;
InstallIsolatedWebAppCommand(InstallIsolatedWebAppCommand&&) = delete;
InstallIsolatedWebAppCommand& operator=(InstallIsolatedWebAppCommand&&) =
delete;
~InstallIsolatedWebAppCommand() override;
protected:
// WebAppCommand:
void StartWithLock(std::unique_ptr<AppLock> lock) override;
private:
void ReportFailure(std::string_view message);
void ReportSuccess();
template <typename T, std::enable_if_t<std::is_void_v<T>, bool> = true>
void RunNextStepOnSuccess(base::OnceClosure next_step_callback,
base::expected<T, std::string> status) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!status.has_value()) {
ReportFailure(status.error());
} else {
std::move(next_step_callback).Run();
}
}
template <typename T, std::enable_if_t<!std::is_void_v<T>, bool> = true>
void RunNextStepOnSuccess(base::OnceCallback<void(T)> next_step_callback,
base::expected<T, std::string> status) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!status.has_value()) {
ReportFailure(status.error());
} else {
std::move(next_step_callback).Run(std::move(*status));
}
}
Profile& profile();
void CopyToProfileDirectory(base::OnceClosure next_step_callback);
void OnCopiedToProfileDirectory(
base::OnceClosure next_step_callback,
base::expected<IsolatedWebAppStorageLocation, std::string> new_location);
void CheckTrustAndSignatures(base::OnceClosure next_step_callback);
void CreateStoragePartition(base::OnceClosure next_step_callback);
void LoadInstallUrl(base::OnceClosure next_step_callback);
void CheckInstallabilityAndRetrieveManifest(
base::OnceCallback<
void(IsolatedWebAppInstallCommandHelper::ManifestAndUrl)>
next_step_callback);
void ValidateManifestAndCreateInstallInfo(
base::OnceCallback<void(WebAppInstallInfo)> next_step_callback,
IsolatedWebAppInstallCommandHelper::ManifestAndUrl manifest_and_url);
void RetrieveIconsAndPopulateInstallInfo(
base::OnceCallback<void(WebAppInstallInfo)> next_step_callback,
WebAppInstallInfo install_info);
void FinalizeInstall(WebAppInstallInfo info);
void OnFinalizeInstall(const webapps::AppId& unused_app_id,
webapps::InstallResultCode install_result_code);
SEQUENCE_CHECKER(sequence_checker_);
std::unique_ptr<AppLock> lock_;
std::unique_ptr<webapps::WebAppUrlLoader> url_loader_;
const std::unique_ptr<IsolatedWebAppInstallCommandHelper> command_helper_;
const IsolatedWebAppUrlInfo url_info_;
const std::optional<base::Version> expected_version_;
const webapps::WebappInstallSource install_surface_;
std::optional<IwaSourceWithModeAndFileOp> install_source_;
std::optional<IwaSourceWithMode> destination_source_;
std::optional<IsolatedWebAppStorageLocation> destination_storage_location_;
std::optional<base::Version> actual_version_;
std::unique_ptr<content::WebContents> web_contents_;
const std::unique_ptr<ScopedKeepAlive> optional_keep_alive_;
const std::unique_ptr<ScopedProfileKeepAlive> optional_profile_keep_alive_;
base::WeakPtrFactory<InstallIsolatedWebAppCommand> weak_factory_{this};
};
} // namespace web_app
#endif // CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_INSTALL_ISOLATED_WEB_APP_COMMAND_H_