feat: add support for the U2F Web API (#30438)

* feat: add support for the U2F Web API

* chore: fix lint

* chore: fix tests

* build: disable src caching

* Revert "build: disable src caching"

This reverts commit c4c8a60fc435a10788475ec171399a55ac2dd674.

* chore: update per feedback

* chore: consistent code removal
This commit is contained in:
Samuel Attard 2021-08-30 11:22:46 -07:00 коммит произвёл GitHub
Родитель c2da4ec2bc
Коммит 8007d01874
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
17 изменённых файлов: 579 добавлений и 3 удалений

Просмотреть файл

@ -19,6 +19,7 @@
<includes>
<include name="IDR_CONTENT_SHELL_DEVTOOLS_DISCOVERY_PAGE" file="${target_gen_dir}/shell_devtools_discovery_page.html" use_base_dir="false" type="BINDATA" />
<include name="IDR_PDF_MANIFEST" file="../chrome/browser/resources/pdf/manifest.json" type="BINDATA" />
<include name="IDR_CRYPTOTOKEN_MANIFEST" file="../chrome/browser/resources/cryptotoken/manifest.json" type="BINDATA" />
</includes>
</release>
</grit>

Просмотреть файл

@ -677,6 +677,8 @@ filenames = {
lib_sources_extensions = [
"shell/browser/extensions/api/i18n/i18n_api.cc",
"shell/browser/extensions/api/i18n/i18n_api.h",
"shell/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.cc",
"shell/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.h",
"shell/browser/extensions/api/management/electron_management_api_delegate.cc",
"shell/browser/extensions/api/management/electron_management_api_delegate.h",
"shell/browser/extensions/api/resources_private/resources_private_api.cc",

Просмотреть файл

@ -107,3 +107,4 @@ disable_use_lld_for_macos.patch
fix_media_key_usage_with_globalshortcuts.patch
feat_expose_raw_response_headers_from_urlloader.patch
revert_roll_clang_llvmorg-14-init-1002-gb5e470aa-1.patch
chore_do_not_use_chrome_windows_in_cryptotoken_webrequestsender.patch

Просмотреть файл

@ -0,0 +1,48 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Attard <samuel.r.attard@gmail.com>
Date: Fri, 6 Aug 2021 03:36:57 -0700
Subject: chore: do not use chrome.windows in cryptotoken webrequestsender
Electron does not support chrome.windows which this method depends on. It also does not need to, the method's goal is to determine if the webContents that triggered the cryptotoken request is still "active". In Chrome this means active tab in the tab strip === this tab + the window owning that tab strip is focused.
In Electron that can be simplified to webContents.isFocused() which maps to "is the webContents view focused and is the owning window the key window". We map tab.active to that IsFocused() value and we can remove the chrome.windows logic here.
This can't be upstreamed but the patch is minimal.
diff --git a/chrome/browser/resources/cryptotoken/webrequestsender.js b/chrome/browser/resources/cryptotoken/webrequestsender.js
index 734abbbf3132d245c2c39bbe9b7780acbea196b0..adff416286eaa10a099be83aaf07e56ec323fe3d 100644
--- a/chrome/browser/resources/cryptotoken/webrequestsender.js
+++ b/chrome/browser/resources/cryptotoken/webrequestsender.js
@@ -134,10 +134,11 @@ function tabInForeground(tabId) {
reject();
return;
}
- if (!chrome.windows || !chrome.windows.get) {
- reject();
- return;
- }
+ // Electron does not support chrome.windows
+ // if (!chrome.windows || !chrome.windows.get) {
+ // reject();
+ // return;
+ // }
chrome.tabs.get(tabId, function(tab) {
if (chrome.runtime.lastError) {
resolve(false);
@@ -147,9 +148,13 @@ function tabInForeground(tabId) {
resolve(false);
return;
}
- chrome.windows.get(tab.windowId, function(aWindow) {
- resolve(aWindow && aWindow.focused);
- });
+ // tab.active in Electron maps to the "focused" state of the view
+ // which is only true when both the webContents and the window are
+ // focused.
+ resolve(true);
+ // chrome.windows.get(tab.windowId, function(aWindow) {
+ // resolve(aWindow && aWindow.focused);
+ // });
});
});
}

Просмотреть файл

@ -142,6 +142,7 @@
#include "extensions/browser/api/mime_handler_private/mime_handler_private.h"
#include "extensions/browser/api/web_request/web_request_api.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_host.h"
#include "extensions/browser/extension_message_filter.h"
#include "extensions/browser/extension_navigation_throttle.h"
@ -163,6 +164,7 @@
#include "shell/browser/extensions/electron_extension_message_filter.h"
#include "shell/browser/extensions/electron_extension_system.h"
#include "shell/browser/extensions/electron_extension_web_contents_observer.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
#endif
#if BUILDFLAG(ENABLE_PLUGINS)
@ -1551,6 +1553,16 @@ void BindBeforeUnloadControl(
}
#endif
void ElectronBrowserClient::ExposeInterfacesToRenderer(
service_manager::BinderRegistry* registry,
blink::AssociatedInterfaceRegistry* associated_registry,
content::RenderProcessHost* render_process_host) {
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
associated_registry->AddInterface(base::BindRepeating(
&extensions::EventRouter::BindForRenderer, render_process_host->GetID()));
#endif
}
void ElectronBrowserClient::RegisterBrowserInterfaceBindersForFrame(
content::RenderFrameHost* render_frame_host,
mojo::BinderMapWithContext<content::RenderFrameHost*>* map) {

Просмотреть файл

@ -69,6 +69,10 @@ class ElectronBrowserClient : public content::ContentBrowserClient,
void BindHostReceiverForRenderer(
content::RenderProcessHost* render_process_host,
mojo::GenericPendingReceiver receiver) override;
void ExposeInterfacesToRenderer(
service_manager::BinderRegistry* registry,
blink::AssociatedInterfaceRegistry* associated_registry,
content::RenderProcessHost* render_process_host) override;
void RegisterBrowserInterfaceBindersForFrame(
content::RenderFrameHost* render_frame_host,
mojo::BinderMapWithContext<content::RenderFrameHost*>* map) override;

Просмотреть файл

@ -10,6 +10,7 @@ assert(enable_extensions,
function_registration("api_registration") {
sources = [
"//electron/shell/common/extensions/api/cryptotoken_private.idl",
"//electron/shell/common/extensions/api/extension.json",
"//electron/shell/common/extensions/api/i18n.json",
"//electron/shell/common/extensions/api/resources_private.idl",

Просмотреть файл

@ -0,0 +1,311 @@
// Copyright 2014 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 "shell/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.h"
#include <stddef.h>
#include <memory>
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/callback.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
// #include "chrome/browser/extensions/extension_tab_util.h"
// #include "chrome/browser/permissions/attestation_permission_request.h"
// #include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/pref_names.h"
// #include
// "components/page_load_metrics/browser/metrics_web_contents_observer.h"
// #include "components/permissions/permission_request_manager.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "crypto/sha2.h"
#include "device/fido/filter.h"
#include "extensions/browser/extension_api_frame_id_map.h"
#include "extensions/common/error_utils.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "shell/browser/api/electron_api_web_contents.h"
#include "url/origin.h"
#if defined(OS_WIN)
#include "device/fido/features.h"
#include "device/fido/win/webauthn_api.h"
#endif // defined(OS_WIN)
namespace extensions {
namespace api {
namespace {
const char kGoogleDotCom[] = "google.com";
constexpr const char* kGoogleGstaticAppIds[] = {
"https://www.gstatic.com/securitykey/origins.json",
"https://www.gstatic.com/securitykey/a/google.com/origins.json"};
// ContainsAppIdByHash returns true iff the SHA-256 hash of one of the
// elements of |list| equals |hash|.
bool ContainsAppIdByHash(const base::ListValue& list,
const std::vector<uint8_t>& hash) {
if (hash.size() != crypto::kSHA256Length) {
return false;
}
for (const auto& i : list.GetList()) {
const std::string& s = i.GetString();
if (s.find('/') == std::string::npos) {
// No slashes mean that this is a webauthn RP ID, not a U2F AppID.
continue;
}
if (crypto::SHA256HashString(s).compare(
0, crypto::kSHA256Length,
reinterpret_cast<const char*>(hash.data()),
crypto::kSHA256Length) == 0) {
return true;
}
}
return false;
}
content::RenderFrameHost* RenderFrameHostForTabAndFrameId(
content::BrowserContext* const browser_context,
const int tab_id,
const int frame_id) {
auto* contents = electron::api::WebContents::FromID(tab_id);
if (!contents || !contents->web_contents()) {
return nullptr;
}
return ExtensionApiFrameIdMap::GetRenderFrameHostById(
contents->web_contents(), frame_id);
}
} // namespace
// void CryptotokenRegisterProfilePrefs(
// user_prefs::PrefRegistrySyncable* registry) {
// registry->RegisterListPref(prefs::kSecurityKeyPermitAttestation);
// }
CryptotokenPrivateCanOriginAssertAppIdFunction::
CryptotokenPrivateCanOriginAssertAppIdFunction() = default;
ExtensionFunction::ResponseAction
CryptotokenPrivateCanOriginAssertAppIdFunction::Run() {
std::unique_ptr<cryptotoken_private::CanOriginAssertAppId::Params> params =
cryptotoken_private::CanOriginAssertAppId::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(params);
const GURL origin_url(params->security_origin);
if (!origin_url.is_valid()) {
return RespondNow(Error(extensions::ErrorUtils::FormatErrorMessage(
"Security origin * is not a valid URL", params->security_origin)));
}
const GURL app_id_url(params->app_id_url);
if (!app_id_url.is_valid()) {
return RespondNow(Error(extensions::ErrorUtils::FormatErrorMessage(
"appId * is not a valid URL", params->app_id_url)));
}
if (origin_url == app_id_url) {
return RespondNow(OneArgument(base::Value(true)));
}
// Fetch the eTLD+1 of both.
const std::string origin_etldp1 =
net::registry_controlled_domains::GetDomainAndRegistry(
origin_url,
net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
if (origin_etldp1.empty()) {
return RespondNow(Error(extensions::ErrorUtils::FormatErrorMessage(
"Could not find an eTLD for origin *", params->security_origin)));
}
const std::string app_id_etldp1 =
net::registry_controlled_domains::GetDomainAndRegistry(
app_id_url,
net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
if (app_id_etldp1.empty()) {
return RespondNow(Error(extensions::ErrorUtils::FormatErrorMessage(
"Could not find an eTLD for appId *", params->app_id_url)));
}
if (origin_etldp1 == app_id_etldp1) {
return RespondNow(OneArgument(base::Value(true)));
}
// For legacy purposes, allow google.com origins to assert certain
// gstatic.com appIds.
// TODO(juanlang): remove when legacy constraints are removed.
if (origin_etldp1 == kGoogleDotCom) {
for (const char* id : kGoogleGstaticAppIds) {
if (params->app_id_url == id)
return RespondNow(OneArgument(base::Value(true)));
}
}
return RespondNow(OneArgument(base::Value(false)));
}
CryptotokenPrivateIsAppIdHashInEnterpriseContextFunction::
CryptotokenPrivateIsAppIdHashInEnterpriseContextFunction() {}
ExtensionFunction::ResponseAction
CryptotokenPrivateIsAppIdHashInEnterpriseContextFunction::Run() {
std::unique_ptr<cryptotoken_private::IsAppIdHashInEnterpriseContext::Params>
params(
cryptotoken_private::IsAppIdHashInEnterpriseContext::Params::Create(
*args_));
EXTENSION_FUNCTION_VALIDATE(params);
#if 0
Profile* const profile = Profile::FromBrowserContext(browser_context());
const PrefService* const prefs = profile->GetPrefs();
const base::ListValue* const permit_attestation =
prefs->GetList(prefs::kSecurityKeyPermitAttestation);
#endif
const base::ListValue permit_attestation;
return RespondNow(ArgumentList(
cryptotoken_private::IsAppIdHashInEnterpriseContext::Results::Create(
ContainsAppIdByHash(permit_attestation, params->app_id_hash))));
}
CryptotokenPrivateCanAppIdGetAttestationFunction::
CryptotokenPrivateCanAppIdGetAttestationFunction() {}
ExtensionFunction::ResponseAction
CryptotokenPrivateCanAppIdGetAttestationFunction::Run() {
std::unique_ptr<cryptotoken_private::CanAppIdGetAttestation::Params> params =
cryptotoken_private::CanAppIdGetAttestation::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(params);
return RespondNow(Error("API not supported in Electron"));
#if 0
const GURL origin_url(params->options.origin);
if (!origin_url.is_valid()) {
return RespondNow(Error(extensions::ErrorUtils::FormatErrorMessage(
"Security origin * is not a valid URL", params->options.origin)));
}
const url::Origin origin(url::Origin::Create(origin_url));
const std::string& app_id = params->options.app_id;
// If the appId is permitted by the enterprise policy then no permission
// prompt is shown.
// Profile* const profile = Profile::FromBrowserContext(browser_context());
// const PrefService* const prefs = profile->GetPrefs();
// const base::ListValue* const permit_attestation =
// prefs->GetList(prefs::kSecurityKeyPermitAttestation);
// for (const auto& entry : permit_attestation->GetList()) {
// if (entry.GetString() == app_id)
// return RespondNow(OneArgument(base::Value(true)));
// }
// If the origin is blocked, reject attestation.
if (device::fido_filter::Evaluate(
device::fido_filter::Operation::MAKE_CREDENTIAL, origin.Serialize(),
/*device=*/absl::nullopt, /*id=*/absl::nullopt) ==
device::fido_filter::Action::NO_ATTESTATION) {
return RespondNow(OneArgument(base::Value(false)));
}
// If prompting is disabled, allow attestation because that is the historical
// behavior.
if (!base::FeatureList::IsEnabled(
::features::kSecurityKeyAttestationPrompt)) {
return RespondNow(OneArgument(base::Value(true)));
}
#if defined(OS_WIN)
// If the request was handled by the Windows WebAuthn API on a version of
// Windows that shows an attestation permission prompt, don't show another
// one.
//
// Note that this does not account for the possibility of the
// WinWebAuthnApi having been disabled by a FidoDiscoveryFactory override,
// which may be done in tests or via the Virtual Authenticator WebDriver
// API.
if (base::FeatureList::IsEnabled(device::kWebAuthUseNativeWinApi) &&
device::WinWebAuthnApi::GetDefault()->IsAvailable() &&
device::WinWebAuthnApi::GetDefault()->Version() >=
WEBAUTHN_API_VERSION_2) {
return RespondNow(OneArgument(base::Value(true)));
}
#endif // defined(OS_WIN)
// Otherwise, show a permission prompt and pass the user's decision back.
const GURL app_id_url(app_id);
EXTENSION_FUNCTION_VALIDATE(app_id_url.is_valid());
auto* contents = electron::api::WebContents::FromID(params->options.tab_id);
if (!contents || !contents->web_contents()) {
return RespondNow(Error("cannot find specified tab"));
}
// permissions::PermissionRequestManager* permission_request_manager =
// permissions::PermissionRequestManager::FromWebContents(web_contents);
// nullptr;
// if (!permission_request_manager) {
return RespondNow(Error("no PermissionRequestManager"));
// }
// // The created AttestationPermissionRequest deletes itself once complete.
// permission_request_manager->AddRequest(
// web_contents->GetMainFrame(), // Extension API targets a particular
// tab,
// // so select the current main frame to
// // handle the request.
// NewAttestationPermissionRequest(
// origin,
// base::BindOnce(
// &CryptotokenPrivateCanAppIdGetAttestationFunction::Complete,
// this)));
// return RespondLater();
#endif
}
void CryptotokenPrivateCanAppIdGetAttestationFunction::Complete(bool result) {
Respond(OneArgument(base::Value(result)));
}
ExtensionFunction::ResponseAction
CryptotokenPrivateRecordRegisterRequestFunction::Run() {
auto params =
cryptotoken_private::RecordRegisterRequest::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(params);
content::RenderFrameHost* frame = RenderFrameHostForTabAndFrameId(
browser_context(), params->tab_id, params->frame_id);
if (!frame) {
return RespondNow(Error("cannot find specified tab or frame"));
}
// page_load_metrics::MetricsWebContentsObserver::RecordFeatureUsage(
// frame, blink::mojom::WebFeature::kU2FCryptotokenRegister);
return RespondNow(NoArguments());
}
ExtensionFunction::ResponseAction
CryptotokenPrivateRecordSignRequestFunction::Run() {
auto params = cryptotoken_private::RecordSignRequest::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(params);
content::RenderFrameHost* frame = RenderFrameHostForTabAndFrameId(
browser_context(), params->tab_id, params->frame_id);
if (!frame) {
return RespondNow(Error("cannot find specified tab or frame"));
}
// page_load_metrics::MetricsWebContentsObserver::RecordFeatureUsage(
// frame, blink::mojom::WebFeature::kU2FCryptotokenSign);
return RespondNow(NoArguments());
}
} // namespace api
} // namespace extensions

Просмотреть файл

@ -0,0 +1,86 @@
// Copyright 2014 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.
#ifndef SHELL_BROWSER_EXTENSIONS_API_CRYPTOTOKEN_PRIVATE_CRYPTOTOKEN_PRIVATE_API_H_
#define SHELL_BROWSER_EXTENSIONS_API_CRYPTOTOKEN_PRIVATE_CRYPTOTOKEN_PRIVATE_API_H_
#include "chrome/common/extensions/api/cryptotoken_private.h"
#include "extensions/browser/extension_function.h"
namespace user_prefs {
class PrefRegistrySyncable;
}
// Implementations for chrome.cryptotokenPrivate API functions.
namespace extensions {
namespace api {
// void CryptotokenRegisterProfilePrefs(
// user_prefs::PrefRegistrySyncable* registry);
class CryptotokenPrivateCanOriginAssertAppIdFunction
: public ExtensionFunction {
public:
CryptotokenPrivateCanOriginAssertAppIdFunction();
DECLARE_EXTENSION_FUNCTION("cryptotokenPrivate.canOriginAssertAppId",
CRYPTOTOKENPRIVATE_CANORIGINASSERTAPPID)
protected:
~CryptotokenPrivateCanOriginAssertAppIdFunction() override {}
ResponseAction Run() override;
};
class CryptotokenPrivateIsAppIdHashInEnterpriseContextFunction
: public ExtensionFunction {
public:
CryptotokenPrivateIsAppIdHashInEnterpriseContextFunction();
DECLARE_EXTENSION_FUNCTION(
"cryptotokenPrivate.isAppIdHashInEnterpriseContext",
CRYPTOTOKENPRIVATE_ISAPPIDHASHINENTERPRISECONTEXT)
protected:
~CryptotokenPrivateIsAppIdHashInEnterpriseContextFunction() override {}
ResponseAction Run() override;
};
class CryptotokenPrivateCanAppIdGetAttestationFunction
: public ExtensionFunction {
public:
CryptotokenPrivateCanAppIdGetAttestationFunction();
DECLARE_EXTENSION_FUNCTION("cryptotokenPrivate.canAppIdGetAttestation",
CRYPTOTOKENPRIVATE_CANAPPIDGETATTESTATION)
protected:
~CryptotokenPrivateCanAppIdGetAttestationFunction() override {}
ResponseAction Run() override;
void Complete(bool result);
};
class CryptotokenPrivateRecordRegisterRequestFunction
: public ExtensionFunction {
public:
CryptotokenPrivateRecordRegisterRequestFunction() = default;
DECLARE_EXTENSION_FUNCTION("cryptotokenPrivate.recordRegisterRequest",
CRYPTOTOKENPRIVATE_RECORDREGISTERREQUEST)
protected:
~CryptotokenPrivateRecordRegisterRequestFunction() override = default;
ResponseAction Run() override;
};
class CryptotokenPrivateRecordSignRequestFunction : public ExtensionFunction {
public:
CryptotokenPrivateRecordSignRequestFunction() = default;
DECLARE_EXTENSION_FUNCTION("cryptotokenPrivate.recordSignRequest",
CRYPTOTOKENPRIVATE_RECORDSIGNREQUEST)
protected:
~CryptotokenPrivateRecordSignRequestFunction() override = default;
ResponseAction Run() override;
};
} // namespace api
} // namespace extensions
#endif // SHELL_BROWSER_EXTENSIONS_API_CRYPTOTOKEN_PRIVATE_CRYPTOTOKEN_PRIVATE_API_H_

Просмотреть файл

@ -200,6 +200,8 @@ ExtensionFunction::ResponseAction TabsGetFunction::Run() {
tab.url = std::make_unique<std::string>(
contents->web_contents()->GetLastCommittedURL().spec());
tab.active = contents->IsFocused();
return RespondNow(ArgumentList(tabs::Get::Results::Create(std::move(tab))));
}

Просмотреть файл

@ -22,6 +22,7 @@
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "electron/buildflags/buildflags.h"
#include "electron/grit/electron_resources.h"
#include "extensions/browser/api/app_runtime/app_runtime_api.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/info_map.h"
@ -36,6 +37,7 @@
#include "extensions/common/constants.h"
#include "extensions/common/file_util.h"
#include "shell/browser/extensions/electron_extension_loader.h"
#include "ui/base/resource/resource_bundle.h"
#if BUILDFLAG(ENABLE_PDF_VIEWER)
#include "chrome/browser/pdf/pdf_extension_util.h" // nogncheck
@ -46,6 +48,18 @@ using content::BrowserThread;
namespace extensions {
namespace {
std::string GetCryptoTokenManifest() {
std::string manifest_contents(
ui::ResourceBundle::GetSharedInstance().GetRawDataResource(
IDR_CRYPTOTOKEN_MANIFEST));
return manifest_contents;
}
} // namespace
ElectronExtensionSystem::ElectronExtensionSystem(
BrowserContext* browser_context)
: browser_context_(browser_context),
@ -109,8 +123,8 @@ std::unique_ptr<base::DictionaryValue> ParseManifest(
}
void ElectronExtensionSystem::LoadComponentExtensions() {
#if BUILDFLAG(ENABLE_PDF_VIEWER)
std::string utf8_error;
#if BUILDFLAG(ENABLE_PDF_VIEWER)
std::string pdf_manifest_string = pdf_extension_util::GetManifest();
std::unique_ptr<base::DictionaryValue> pdf_manifest =
ParseManifest(pdf_manifest_string);
@ -125,6 +139,22 @@ void ElectronExtensionSystem::LoadComponentExtensions() {
extension_loader_->registrar()->AddExtension(pdf_extension);
}
#endif
std::string cryptotoken_manifest_string = GetCryptoTokenManifest();
std::unique_ptr<base::DictionaryValue> cryptotoken_manifest =
ParseManifest(cryptotoken_manifest_string);
DCHECK(cryptotoken_manifest);
if (cryptotoken_manifest) {
base::FilePath root_directory;
CHECK(base::PathService::Get(chrome::DIR_RESOURCES, &root_directory));
root_directory = root_directory.Append(FILE_PATH_LITERAL("cryptotoken"));
scoped_refptr<const Extension> cryptotoken_extension =
extensions::Extension::Create(
root_directory, extensions::mojom::ManifestLocation::kComponent,
*cryptotoken_manifest, extensions::Extension::REQUIRE_KEY,
&utf8_error);
extension_loader_->registrar()->AddExtension(cryptotoken_extension);
}
}
ExtensionService* ElectronExtensionSystem::extension_service() {

Просмотреть файл

@ -36,6 +36,7 @@ group("extensions_features") {
generated_json_strings("generated_api_json_strings") {
sources = [
"cryptotoken_private.idl",
"extension.json",
"i18n.json",
"resources_private.idl",
@ -54,6 +55,7 @@ generated_json_strings("generated_api_json_strings") {
generated_types("generated_api_types") {
sources = [
"cryptotoken_private.idl",
"i18n.json",
"resources_private.idl",
"tabs.json",

Просмотреть файл

@ -37,5 +37,9 @@
"matches": [
"chrome://print/*"
]
}]
}],
"cryptotokenPrivate": {
"dependencies": ["permission:cryptotokenPrivate"],
"contexts": ["blessed_extension"]
}
}

Просмотреть файл

@ -11,5 +11,13 @@
"extension_types": [
"extension"
]
},
"cryptotokenPrivate": {
"channel": "stable",
"extension_types": ["extension"],
"location": "component",
"allowlist": [
"E24F1786D842E91E74C27929B0B3715A4689A473" // Cryptotoken
]
}
}

Просмотреть файл

@ -0,0 +1,63 @@
// Copyright 2014 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.
// <code>chrome.cryptotokenPrivate</code> API that provides hooks to Chrome to
// be used by cryptotoken component extension.
// <p>In the context of this API, an AppId is roughly an origin and is formally
// defined in
// <a href="https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-appid-and-facets-v1.2-ps-20170411.html">
// the FIDO spec</a></p>
namespace cryptotokenPrivate {
callback BooleanCallback = void(boolean result);
callback VoidCallback = void();
dictionary CanAppIdGetAttestationOptions {
// The AppId (see definition, above) that was used in the registration
// request and which has been authenticated by |canOriginAssertAppId|.
DOMString appId;
// The origin of the caller.
DOMString origin;
// Identifies the tab in which the registration is occuring so that any
// permissions prompt is correctly located.
long tabId;
};
interface Functions {
// Checks whether the origin is allowed to assert the appId, according to
// the same origin policy defined at
// http://fidoalliance.org/specs/fido-u2f-v1.0-ps-20141009/
// fido-appid-and-facets-ps-20141009.html
// |securityOrigin| is the origin as seen by the extension, and |appIdUrl|
// is the appId being asserted by the origin.
static void canOriginAssertAppId(DOMString securityOrigin,
DOMString appIdUrl,
BooleanCallback callback);
// Checks whether the given appId is specified in the
// SecurityKeyPermitAttestation policy. This causes a signal to be sent to
// the token that informs it that an individually-identifying attestation
// certificate may be used. Without that signal, the token is required to
// use its batch attestation certificate.
static void isAppIdHashInEnterpriseContext(ArrayBuffer appIdHash,
BooleanCallback callback);
// Checks whether the given appId may receive attestation data that
// identifies the token. If not, the attestation from the token must be
// substituted with a randomly generated certificate since webauthn and U2F
// require that some attestation be provided.
static void canAppIdGetAttestation(CanAppIdGetAttestationOptions options,
BooleanCallback callback);
// Increments the WebFeature::kU2FCryptotokenRegister UseCounter for the
// main frame associated with |tabId|.
static void recordRegisterRequest(long tabId, long frameId,
optional VoidCallback callback);
// Increments the WebFeature::kU2FCryptotokenSign UseCounter for the
// main frame associated with |tabId|.
static void recordSignRequest(long tabId, long frameId,
optional VoidCallback callback);
};
};

Просмотреть файл

@ -35,6 +35,7 @@ constexpr APIPermissionInfo::InitInfo permissions_to_register[] = {
{mojom::APIPermissionID::kResourcesPrivate, "resourcesPrivate",
APIPermissionInfo::kFlagCannotBeOptional},
{mojom::APIPermissionID::kManagement, "management"},
{mojom::APIPermissionID::kCryptotokenPrivate, "cryptotokenPrivate"},
};
base::span<const APIPermissionInfo::InitInfo> GetPermissionInfos() {
return base::make_span(permissions_to_register);

Просмотреть файл

@ -153,7 +153,7 @@ describe('chrome extensions', () => {
const extension = await customSession.loadExtension(path.join(fixtures, 'extensions', 'red-bg'));
const [, loadedExtension] = await loadedPromise;
const [, readyExtension] = await emittedUntil(customSession, 'extension-ready', (event: Event, extension: Extension) => {
return extension.name !== 'Chromium PDF Viewer';
return extension.name !== 'Chromium PDF Viewer' && extension.name !== 'CryptoTokenExtension';
});
expect(loadedExtension).to.deep.equal(extension);