feat: move webFrame scheme privilege methods to main process (#16416)
* chore: deprecate webFrame.registerURLSchemeAsPrivileged * Add register schemes protocol api * update branch to enable browser process API * Revert deprecation changes * Fetch API support * Updated api to take an array, still working on tests * Update tests * Remove web frame API * Minor changes * update scheme registrations on browser and renderer process * fix: enable ses.getBlobData spec * Update breaking changes doc
This commit is contained in:
parent
257de6a963
commit
940c4c0787
19 changed files with 319 additions and 319 deletions
|
@ -213,18 +213,30 @@ base::RefCountedMemory* AtomContentClient::GetDataResourceBytes(
|
||||||
}
|
}
|
||||||
|
|
||||||
void AtomContentClient::AddAdditionalSchemes(Schemes* schemes) {
|
void AtomContentClient::AddAdditionalSchemes(Schemes* schemes) {
|
||||||
schemes->standard_schemes.push_back("chrome-extension");
|
|
||||||
|
|
||||||
std::vector<std::string> splited;
|
std::vector<std::string> splited;
|
||||||
ConvertStringWithSeparatorToVector(&splited, ",",
|
ConvertStringWithSeparatorToVector(&splited, ",",
|
||||||
switches::kRegisterServiceWorkerSchemes);
|
switches::kServiceWorkerSchemes);
|
||||||
for (const std::string& scheme : splited)
|
for (const std::string& scheme : splited)
|
||||||
schemes->service_worker_schemes.push_back(scheme);
|
schemes->service_worker_schemes.push_back(scheme);
|
||||||
schemes->service_worker_schemes.push_back(url::kFileScheme);
|
schemes->service_worker_schemes.push_back(url::kFileScheme);
|
||||||
|
|
||||||
|
ConvertStringWithSeparatorToVector(&splited, ",", switches::kStandardSchemes);
|
||||||
|
for (const std::string& scheme : splited)
|
||||||
|
schemes->standard_schemes.push_back(scheme);
|
||||||
|
schemes->standard_schemes.push_back("chrome-extension");
|
||||||
|
|
||||||
ConvertStringWithSeparatorToVector(&splited, ",", switches::kSecureSchemes);
|
ConvertStringWithSeparatorToVector(&splited, ",", switches::kSecureSchemes);
|
||||||
for (const std::string& scheme : splited)
|
for (const std::string& scheme : splited)
|
||||||
schemes->secure_schemes.push_back(scheme);
|
schemes->secure_schemes.push_back(scheme);
|
||||||
|
|
||||||
|
ConvertStringWithSeparatorToVector(&splited, ",",
|
||||||
|
switches::kBypassCSPSchemes);
|
||||||
|
for (const std::string& scheme : splited)
|
||||||
|
schemes->csp_bypassing_schemes.push_back(scheme);
|
||||||
|
|
||||||
|
ConvertStringWithSeparatorToVector(&splited, ",", switches::kCORSSchemes);
|
||||||
|
for (const std::string& scheme : splited)
|
||||||
|
schemes->cors_enabled_schemes.push_back(scheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AtomContentClient::AddPepperPlugins(
|
void AtomContentClient::AddPepperPlugins(
|
||||||
|
|
|
@ -24,47 +24,119 @@
|
||||||
|
|
||||||
using content::BrowserThread;
|
using content::BrowserThread;
|
||||||
|
|
||||||
namespace atom {
|
|
||||||
|
|
||||||
namespace api {
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// List of registered custom standard schemes.
|
// List of registered custom standard schemes.
|
||||||
std::vector<std::string> g_standard_schemes;
|
std::vector<std::string> g_standard_schemes;
|
||||||
|
|
||||||
|
struct SchemeOptions {
|
||||||
|
bool standard = false;
|
||||||
|
bool secure = false;
|
||||||
|
bool bypassCSP = false;
|
||||||
|
bool allowServiceWorkers = false;
|
||||||
|
bool supportFetchAPI = false;
|
||||||
|
bool corsEnabled = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CustomScheme {
|
||||||
|
std::string scheme;
|
||||||
|
SchemeOptions options;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
namespace mate {
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct Converter<CustomScheme> {
|
||||||
|
static bool FromV8(v8::Isolate* isolate,
|
||||||
|
v8::Local<v8::Value> val,
|
||||||
|
CustomScheme* out) {
|
||||||
|
mate::Dictionary dict;
|
||||||
|
if (!ConvertFromV8(isolate, val, &dict))
|
||||||
|
return false;
|
||||||
|
if (!dict.Get("scheme", &(out->scheme)))
|
||||||
|
return false;
|
||||||
|
mate::Dictionary opt;
|
||||||
|
// options are optional. Default values specified in SchemeOptions are used
|
||||||
|
if (dict.Get("options", &opt)) {
|
||||||
|
opt.Get("standard", &(out->options.standard));
|
||||||
|
opt.Get("supportFetchAPI", &(out->options.supportFetchAPI));
|
||||||
|
opt.Get("secure", &(out->options.secure));
|
||||||
|
opt.Get("bypassCSP", &(out->options.bypassCSP));
|
||||||
|
opt.Get("allowServiceWorkers", &(out->options.allowServiceWorkers));
|
||||||
|
opt.Get("supportFetchAPI", &(out->options.supportFetchAPI));
|
||||||
|
opt.Get("corsEnabled", &(out->options.corsEnabled));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mate
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
|
||||||
std::vector<std::string> GetStandardSchemes() {
|
std::vector<std::string> GetStandardSchemes() {
|
||||||
return g_standard_schemes;
|
return g_standard_schemes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterStandardSchemes(const std::vector<std::string>& schemes,
|
void RegisterSchemesAsPrivileged(v8::Local<v8::Value> val,
|
||||||
mate::Arguments* args) {
|
mate::Arguments* args) {
|
||||||
g_standard_schemes = schemes;
|
std::vector<CustomScheme> custom_schemes;
|
||||||
|
if (!mate::ConvertFromV8(args->isolate(), val, &custom_schemes)) {
|
||||||
|
args->ThrowError("Argument must be an array of custom schemes.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mate::Dictionary opts;
|
std::vector<std::string> secure_schemes, cspbypassing_schemes, fetch_schemes,
|
||||||
bool secure = false;
|
service_worker_schemes, cors_schemes;
|
||||||
args->GetNext(&opts) && opts.Get("secure", &secure);
|
for (const auto& custom_scheme : custom_schemes) {
|
||||||
|
// Register scheme to privileged list (https, wss, data, chrome-extension)
|
||||||
// Dynamically register the schemes.
|
if (custom_scheme.options.standard) {
|
||||||
auto* policy = content::ChildProcessSecurityPolicy::GetInstance();
|
auto* policy = content::ChildProcessSecurityPolicy::GetInstance();
|
||||||
for (const std::string& scheme : schemes) {
|
url::AddStandardScheme(custom_scheme.scheme.c_str(),
|
||||||
url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITH_HOST);
|
url::SCHEME_WITH_HOST);
|
||||||
if (secure) {
|
g_standard_schemes.push_back(custom_scheme.scheme);
|
||||||
url::AddSecureScheme(scheme.c_str());
|
policy->RegisterWebSafeScheme(custom_scheme.scheme);
|
||||||
|
}
|
||||||
|
if (custom_scheme.options.secure) {
|
||||||
|
secure_schemes.push_back(custom_scheme.scheme);
|
||||||
|
url::AddSecureScheme(custom_scheme.scheme.c_str());
|
||||||
|
}
|
||||||
|
if (custom_scheme.options.bypassCSP) {
|
||||||
|
cspbypassing_schemes.push_back(custom_scheme.scheme);
|
||||||
|
url::AddCSPBypassingScheme(custom_scheme.scheme.c_str());
|
||||||
|
}
|
||||||
|
if (custom_scheme.options.corsEnabled) {
|
||||||
|
cors_schemes.push_back(custom_scheme.scheme);
|
||||||
|
url::AddCorsEnabledScheme(custom_scheme.scheme.c_str());
|
||||||
|
}
|
||||||
|
if (custom_scheme.options.supportFetchAPI) {
|
||||||
|
fetch_schemes.push_back(custom_scheme.scheme);
|
||||||
|
}
|
||||||
|
if (custom_scheme.options.allowServiceWorkers) {
|
||||||
|
service_worker_schemes.push_back(custom_scheme.scheme);
|
||||||
}
|
}
|
||||||
policy->RegisterWebSafeScheme(scheme);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto AppendSchemesToCmdLine = [](const char* switch_name,
|
||||||
|
std::vector<std::string> schemes) {
|
||||||
// Add the schemes to command line switches, so child processes can also
|
// Add the schemes to command line switches, so child processes can also
|
||||||
// register them.
|
// register them.
|
||||||
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
|
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
|
||||||
atom::switches::kStandardSchemes, base::JoinString(schemes, ","));
|
switch_name, base::JoinString(schemes, ","));
|
||||||
if (secure) {
|
};
|
||||||
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
|
|
||||||
atom::switches::kSecureSchemes, base::JoinString(schemes, ","));
|
AppendSchemesToCmdLine(atom::switches::kSecureSchemes, secure_schemes);
|
||||||
}
|
AppendSchemesToCmdLine(atom::switches::kBypassCSPSchemes,
|
||||||
|
cspbypassing_schemes);
|
||||||
|
AppendSchemesToCmdLine(atom::switches::kCORSSchemes, cors_schemes);
|
||||||
|
AppendSchemesToCmdLine(atom::switches::kFetchSchemes, fetch_schemes);
|
||||||
|
AppendSchemesToCmdLine(atom::switches::kServiceWorkerSchemes,
|
||||||
|
service_worker_schemes);
|
||||||
|
AppendSchemesToCmdLine(atom::switches::kStandardSchemes, g_standard_schemes);
|
||||||
}
|
}
|
||||||
|
|
||||||
Protocol::Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context)
|
Protocol::Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context)
|
||||||
|
@ -73,12 +145,6 @@ Protocol::Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
Protocol::~Protocol() {}
|
Protocol::~Protocol() {}
|
||||||
|
|
||||||
void Protocol::RegisterServiceWorkerSchemes(
|
|
||||||
const std::vector<std::string>& schemes) {
|
|
||||||
atom::AtomBrowserClient::SetCustomServiceWorkerSchemes(schemes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Protocol::UnregisterProtocol(const std::string& scheme,
|
void Protocol::UnregisterProtocol(const std::string& scheme,
|
||||||
mate::Arguments* args) {
|
mate::Arguments* args) {
|
||||||
CompletionCallback callback;
|
CompletionCallback callback;
|
||||||
|
@ -195,8 +261,6 @@ void Protocol::BuildPrototype(v8::Isolate* isolate,
|
||||||
v8::Local<v8::FunctionTemplate> prototype) {
|
v8::Local<v8::FunctionTemplate> prototype) {
|
||||||
prototype->SetClassName(mate::StringToV8(isolate, "Protocol"));
|
prototype->SetClassName(mate::StringToV8(isolate, "Protocol"));
|
||||||
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
|
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
|
||||||
.SetMethod("registerServiceWorkerSchemes",
|
|
||||||
&Protocol::RegisterServiceWorkerSchemes)
|
|
||||||
.SetMethod("registerStringProtocol",
|
.SetMethod("registerStringProtocol",
|
||||||
&Protocol::RegisterProtocol<URLRequestStringJob>)
|
&Protocol::RegisterProtocol<URLRequestStringJob>)
|
||||||
.SetMethod("registerBufferProtocol",
|
.SetMethod("registerBufferProtocol",
|
||||||
|
@ -228,16 +292,16 @@ void Protocol::BuildPrototype(v8::Isolate* isolate,
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void RegisterStandardSchemes(const std::vector<std::string>& schemes,
|
void RegisterSchemesAsPrivileged(v8::Local<v8::Value> val,
|
||||||
mate::Arguments* args) {
|
mate::Arguments* args) {
|
||||||
if (atom::Browser::Get()->is_ready()) {
|
if (atom::Browser::Get()->is_ready()) {
|
||||||
args->ThrowError(
|
args->ThrowError(
|
||||||
"protocol.registerStandardSchemes should be called before "
|
"protocol.registerSchemesAsPrivileged should be called before "
|
||||||
"app is ready");
|
"app is ready");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
atom::api::RegisterStandardSchemes(schemes, args);
|
atom::api::RegisterSchemesAsPrivileged(val, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Initialize(v8::Local<v8::Object> exports,
|
void Initialize(v8::Local<v8::Object> exports,
|
||||||
|
@ -246,7 +310,7 @@ void Initialize(v8::Local<v8::Object> exports,
|
||||||
void* priv) {
|
void* priv) {
|
||||||
v8::Isolate* isolate = context->GetIsolate();
|
v8::Isolate* isolate = context->GetIsolate();
|
||||||
mate::Dictionary dict(isolate, exports);
|
mate::Dictionary dict(isolate, exports);
|
||||||
dict.SetMethod("registerStandardSchemes", &RegisterStandardSchemes);
|
dict.SetMethod("registerSchemesAsPrivileged", &RegisterSchemesAsPrivileged);
|
||||||
dict.SetMethod("getStandardSchemes", &atom::api::GetStandardSchemes);
|
dict.SetMethod("getStandardSchemes", &atom::api::GetStandardSchemes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,8 @@ namespace atom {
|
||||||
namespace api {
|
namespace api {
|
||||||
|
|
||||||
std::vector<std::string> GetStandardSchemes();
|
std::vector<std::string> GetStandardSchemes();
|
||||||
void RegisterStandardSchemes(const std::vector<std::string>& schemes,
|
|
||||||
|
void RegisterSchemesAsPrivileged(v8::Local<v8::Value> val,
|
||||||
mate::Arguments* args);
|
mate::Arguments* args);
|
||||||
|
|
||||||
class Protocol : public mate::TrackableObject<Protocol> {
|
class Protocol : public mate::TrackableObject<Protocol> {
|
||||||
|
@ -94,9 +95,6 @@ class Protocol : public mate::TrackableObject<Protocol> {
|
||||||
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
|
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Register schemes that can handle service worker.
|
|
||||||
void RegisterServiceWorkerSchemes(const std::vector<std::string>& schemes);
|
|
||||||
|
|
||||||
// Register the protocol with certain request job.
|
// Register the protocol with certain request job.
|
||||||
template <typename RequestJob>
|
template <typename RequestJob>
|
||||||
void RegisterProtocol(const std::string& scheme,
|
void RegisterProtocol(const std::string& scheme,
|
||||||
|
|
|
@ -114,9 +114,6 @@ namespace {
|
||||||
// Next navigation should not restart renderer process.
|
// Next navigation should not restart renderer process.
|
||||||
bool g_suppress_renderer_process_restart = false;
|
bool g_suppress_renderer_process_restart = false;
|
||||||
|
|
||||||
// Custom schemes to be registered to handle service worker.
|
|
||||||
base::NoDestructor<std::string> g_custom_service_worker_schemes;
|
|
||||||
|
|
||||||
bool IsSameWebSite(content::BrowserContext* browser_context,
|
bool IsSameWebSite(content::BrowserContext* browser_context,
|
||||||
const GURL& src_url,
|
const GURL& src_url,
|
||||||
const GURL& dest_url) {
|
const GURL& dest_url) {
|
||||||
|
@ -148,11 +145,6 @@ void AtomBrowserClient::SuppressRendererProcessRestartForOnce() {
|
||||||
g_suppress_renderer_process_restart = true;
|
g_suppress_renderer_process_restart = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AtomBrowserClient::SetCustomServiceWorkerSchemes(
|
|
||||||
const std::vector<std::string>& schemes) {
|
|
||||||
*g_custom_service_worker_schemes = base::JoinString(schemes, ",");
|
|
||||||
}
|
|
||||||
|
|
||||||
AtomBrowserClient* AtomBrowserClient::Get() {
|
AtomBrowserClient* AtomBrowserClient::Get() {
|
||||||
return g_browser_client;
|
return g_browser_client;
|
||||||
}
|
}
|
||||||
|
@ -477,18 +469,15 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Copy following switches to child process.
|
// Copy following switches to child process.
|
||||||
static const char* const kCommonSwitchNames[] = {switches::kStandardSchemes,
|
static const char* const kCommonSwitchNames[] = {
|
||||||
switches::kEnableSandbox,
|
switches::kStandardSchemes, switches::kEnableSandbox,
|
||||||
switches::kSecureSchemes};
|
switches::kSecureSchemes, switches::kBypassCSPSchemes,
|
||||||
|
switches::kCORSSchemes, switches::kFetchSchemes,
|
||||||
|
switches::kServiceWorkerSchemes};
|
||||||
command_line->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(),
|
command_line->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(),
|
||||||
kCommonSwitchNames,
|
kCommonSwitchNames,
|
||||||
arraysize(kCommonSwitchNames));
|
arraysize(kCommonSwitchNames));
|
||||||
|
|
||||||
// The registered service worker schemes.
|
|
||||||
if (!g_custom_service_worker_schemes->empty())
|
|
||||||
command_line->AppendSwitchASCII(switches::kRegisterServiceWorkerSchemes,
|
|
||||||
*g_custom_service_worker_schemes);
|
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
// Append --app-user-model-id.
|
// Append --app-user-model-id.
|
||||||
PWSTR current_app_id;
|
PWSTR current_app_id;
|
||||||
|
|
|
@ -49,10 +49,6 @@ class AtomBrowserClient : public content::ContentBrowserClient,
|
||||||
// Don't force renderer process to restart for once.
|
// Don't force renderer process to restart for once.
|
||||||
static void SuppressRendererProcessRestartForOnce();
|
static void SuppressRendererProcessRestartForOnce();
|
||||||
|
|
||||||
// Custom schemes to be registered to handle service worker.
|
|
||||||
static void SetCustomServiceWorkerSchemes(
|
|
||||||
const std::vector<std::string>& schemes);
|
|
||||||
|
|
||||||
NotificationPresenter* GetNotificationPresenter();
|
NotificationPresenter* GetNotificationPresenter();
|
||||||
|
|
||||||
void WebNotificationAllowed(int render_process_id,
|
void WebNotificationAllowed(int render_process_id,
|
||||||
|
|
|
@ -179,11 +179,20 @@ const char kDisableHttpCache[] = "disable-http-cache";
|
||||||
const char kStandardSchemes[] = "standard-schemes";
|
const char kStandardSchemes[] = "standard-schemes";
|
||||||
|
|
||||||
// Register schemes to handle service worker.
|
// Register schemes to handle service worker.
|
||||||
const char kRegisterServiceWorkerSchemes[] = "register-service-worker-schemes";
|
const char kServiceWorkerSchemes[] = "service-worker-schemes";
|
||||||
|
|
||||||
// Register schemes as secure.
|
// Register schemes as secure.
|
||||||
const char kSecureSchemes[] = "secure-schemes";
|
const char kSecureSchemes[] = "secure-schemes";
|
||||||
|
|
||||||
|
// Register schemes as bypassing CSP.
|
||||||
|
const char kBypassCSPSchemes[] = "bypasscsp-schemes";
|
||||||
|
|
||||||
|
// Register schemes as support fetch API.
|
||||||
|
const char kFetchSchemes[] = "fetch-schemes";
|
||||||
|
|
||||||
|
// Register schemes as CORS enabled.
|
||||||
|
const char kCORSSchemes[] = "cors-schemes";
|
||||||
|
|
||||||
// The browser process app model ID
|
// The browser process app model ID
|
||||||
const char kAppUserModelId[] = "app-user-model-id";
|
const char kAppUserModelId[] = "app-user-model-id";
|
||||||
|
|
||||||
|
|
|
@ -89,8 +89,11 @@ extern const char kPpapiFlashPath[];
|
||||||
extern const char kPpapiFlashVersion[];
|
extern const char kPpapiFlashVersion[];
|
||||||
extern const char kDisableHttpCache[];
|
extern const char kDisableHttpCache[];
|
||||||
extern const char kStandardSchemes[];
|
extern const char kStandardSchemes[];
|
||||||
extern const char kRegisterServiceWorkerSchemes[];
|
extern const char kServiceWorkerSchemes[];
|
||||||
extern const char kSecureSchemes[];
|
extern const char kSecureSchemes[];
|
||||||
|
extern const char kBypassCSPSchemes[];
|
||||||
|
extern const char kFetchSchemes[];
|
||||||
|
extern const char kCORSSchemes[];
|
||||||
extern const char kAppUserModelId[];
|
extern const char kAppUserModelId[];
|
||||||
extern const char kAppPath[];
|
extern const char kAppPath[];
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
#include "third_party/blink/public/web/web_script_execution_callback.h"
|
#include "third_party/blink/public/web/web_script_execution_callback.h"
|
||||||
#include "third_party/blink/public/web/web_script_source.h"
|
#include "third_party/blink/public/web/web_script_source.h"
|
||||||
#include "third_party/blink/public/web/web_view.h"
|
#include "third_party/blink/public/web/web_view.h"
|
||||||
#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
|
|
||||||
#include "url/url_util.h"
|
#include "url/url_util.h"
|
||||||
|
|
||||||
#include "atom/common/node_includes.h"
|
#include "atom/common/node_includes.h"
|
||||||
|
@ -262,54 +261,6 @@ void WebFrame::SetSpellCheckProvider(mate::Arguments* args,
|
||||||
new AtomWebFrameObserver(render_frame, std::move(spell_check_client));
|
new AtomWebFrameObserver(render_frame, std::move(spell_check_client));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebFrame::RegisterURLSchemeAsBypassingCSP(const std::string& scheme) {
|
|
||||||
// Register scheme to bypass pages's Content Security Policy.
|
|
||||||
blink::SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy(
|
|
||||||
WTF::String::FromUTF8(scheme.data(), scheme.length()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebFrame::RegisterURLSchemeAsPrivileged(const std::string& scheme,
|
|
||||||
mate::Arguments* args) {
|
|
||||||
// TODO(deepak1556): blink::SchemeRegistry methods should be called
|
|
||||||
// before any renderer threads are created. Fixing this would break
|
|
||||||
// current api. Change it with 2.0.
|
|
||||||
|
|
||||||
// Read optional flags
|
|
||||||
bool secure = true;
|
|
||||||
bool bypassCSP = true;
|
|
||||||
bool allowServiceWorkers = true;
|
|
||||||
bool supportFetchAPI = true;
|
|
||||||
bool corsEnabled = true;
|
|
||||||
if (args->Length() == 2) {
|
|
||||||
mate::Dictionary options;
|
|
||||||
if (args->GetNext(&options)) {
|
|
||||||
options.Get("secure", &secure);
|
|
||||||
options.Get("bypassCSP", &bypassCSP);
|
|
||||||
options.Get("allowServiceWorkers", &allowServiceWorkers);
|
|
||||||
options.Get("supportFetchAPI", &supportFetchAPI);
|
|
||||||
options.Get("corsEnabled", &corsEnabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Register scheme to privileged list (https, wss, data, chrome-extension)
|
|
||||||
WTF::String privileged_scheme(
|
|
||||||
WTF::String::FromUTF8(scheme.data(), scheme.length()));
|
|
||||||
if (bypassCSP) {
|
|
||||||
blink::SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy(
|
|
||||||
privileged_scheme);
|
|
||||||
}
|
|
||||||
if (allowServiceWorkers) {
|
|
||||||
blink::SchemeRegistry::RegisterURLSchemeAsAllowingServiceWorkers(
|
|
||||||
privileged_scheme);
|
|
||||||
}
|
|
||||||
if (supportFetchAPI) {
|
|
||||||
blink::SchemeRegistry::RegisterURLSchemeAsSupportingFetchAPI(
|
|
||||||
privileged_scheme);
|
|
||||||
}
|
|
||||||
if (corsEnabled) {
|
|
||||||
url::AddCorsEnabledScheme(scheme.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebFrame::InsertText(const std::string& text) {
|
void WebFrame::InsertText(const std::string& text) {
|
||||||
web_frame_->FrameWidget()->GetActiveWebInputMethodController()->CommitText(
|
web_frame_->FrameWidget()->GetActiveWebInputMethodController()->CommitText(
|
||||||
blink::WebString::FromUTF8(text),
|
blink::WebString::FromUTF8(text),
|
||||||
|
@ -522,10 +473,6 @@ void WebFrame::BuildPrototype(v8::Isolate* isolate,
|
||||||
&WebFrame::AllowGuestViewElementDefinition)
|
&WebFrame::AllowGuestViewElementDefinition)
|
||||||
.SetMethod("getWebFrameId", &WebFrame::GetWebFrameId)
|
.SetMethod("getWebFrameId", &WebFrame::GetWebFrameId)
|
||||||
.SetMethod("setSpellCheckProvider", &WebFrame::SetSpellCheckProvider)
|
.SetMethod("setSpellCheckProvider", &WebFrame::SetSpellCheckProvider)
|
||||||
.SetMethod("registerURLSchemeAsBypassingCSP",
|
|
||||||
&WebFrame::RegisterURLSchemeAsBypassingCSP)
|
|
||||||
.SetMethod("registerURLSchemeAsPrivileged",
|
|
||||||
&WebFrame::RegisterURLSchemeAsPrivileged)
|
|
||||||
.SetMethod("insertText", &WebFrame::InsertText)
|
.SetMethod("insertText", &WebFrame::InsertText)
|
||||||
.SetMethod("insertCSS", &WebFrame::InsertCSS)
|
.SetMethod("insertCSS", &WebFrame::InsertCSS)
|
||||||
.SetMethod("executeJavaScript", &WebFrame::ExecuteJavaScript)
|
.SetMethod("executeJavaScript", &WebFrame::ExecuteJavaScript)
|
||||||
|
|
|
@ -57,10 +57,6 @@ class WebFrame : public mate::Wrappable<WebFrame> {
|
||||||
const std::string& language,
|
const std::string& language,
|
||||||
v8::Local<v8::Object> provider);
|
v8::Local<v8::Object> provider);
|
||||||
|
|
||||||
void RegisterURLSchemeAsBypassingCSP(const std::string& scheme);
|
|
||||||
void RegisterURLSchemeAsPrivileged(const std::string& scheme,
|
|
||||||
mate::Arguments* args);
|
|
||||||
|
|
||||||
// Editing.
|
// Editing.
|
||||||
void InsertText(const std::string& text);
|
void InsertText(const std::string& text);
|
||||||
void InsertCSS(const std::string& css);
|
void InsertCSS(const std::string& css);
|
||||||
|
|
|
@ -163,6 +163,25 @@ void RendererClientBase::RenderThreadStarted() {
|
||||||
blink::SchemeRegistry::RegisterURLSchemeAsSecure(
|
blink::SchemeRegistry::RegisterURLSchemeAsSecure(
|
||||||
WTF::String::FromUTF8(scheme.data(), scheme.length()));
|
WTF::String::FromUTF8(scheme.data(), scheme.length()));
|
||||||
|
|
||||||
|
std::vector<std::string> fetch_enabled_schemes =
|
||||||
|
ParseSchemesCLISwitch(command_line, switches::kFetchSchemes);
|
||||||
|
for (const std::string& scheme : fetch_enabled_schemes) {
|
||||||
|
blink::WebSecurityPolicy::RegisterURLSchemeAsSupportingFetchAPI(
|
||||||
|
blink::WebString::FromASCII(scheme));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> service_worker_schemes =
|
||||||
|
ParseSchemesCLISwitch(command_line, switches::kServiceWorkerSchemes);
|
||||||
|
for (const std::string& scheme : service_worker_schemes)
|
||||||
|
blink::WebSecurityPolicy::RegisterURLSchemeAsAllowingServiceWorkers(
|
||||||
|
blink::WebString::FromASCII(scheme));
|
||||||
|
|
||||||
|
std::vector<std::string> csp_bypassing_schemes =
|
||||||
|
ParseSchemesCLISwitch(command_line, switches::kBypassCSPSchemes);
|
||||||
|
for (const std::string& scheme : csp_bypassing_schemes)
|
||||||
|
blink::SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy(
|
||||||
|
WTF::String::FromUTF8(scheme.data(), scheme.length()));
|
||||||
|
|
||||||
// Allow file scheme to handle service worker by default.
|
// Allow file scheme to handle service worker by default.
|
||||||
// FIXME(zcbenz): Can this be moved elsewhere?
|
// FIXME(zcbenz): Can this be moved elsewhere?
|
||||||
blink::WebSecurityPolicy::RegisterURLSchemeAsAllowingServiceWorkers("file");
|
blink::WebSecurityPolicy::RegisterURLSchemeAsAllowingServiceWorkers("file");
|
||||||
|
|
|
@ -57,6 +57,11 @@ The following `webPreferences` option default values are deprecated in favor of
|
||||||
|
|
||||||
Child windows opened with the `nativeWindowOpen` option will always have Node.js integration disabled.
|
Child windows opened with the `nativeWindowOpen` option will always have Node.js integration disabled.
|
||||||
|
|
||||||
|
## Privileged Schemes Registration
|
||||||
|
|
||||||
|
Renderer process APIs `webFrame.setRegisterURLSchemeAsPrivileged` and `webFrame.registerURLSchemeAsBypassingCSP` as well as browser process API `protocol.registerStandardSchemes` have been removed.
|
||||||
|
A new API, `protocol.registerSchemesAsPrivileged` has been added and should be used for registering custom schemes with the required privileges. Custom schemes are required to be registered before app ready.
|
||||||
|
|
||||||
# Planned Breaking API Changes (4.0)
|
# Planned Breaking API Changes (4.0)
|
||||||
|
|
||||||
The following list includes the breaking API changes planned for Electron 4.0.
|
The following list includes the breaking API changes planned for Electron 4.0.
|
||||||
|
|
|
@ -28,12 +28,26 @@ of the `app` module gets emitted.
|
||||||
|
|
||||||
The `protocol` module has the following methods:
|
The `protocol` module has the following methods:
|
||||||
|
|
||||||
### `protocol.registerStandardSchemes(schemes[, options])`
|
### `protocol.registerSchemesAsPrivileged(schemes[, options])`
|
||||||
|
|
||||||
* `schemes` String[] - Custom schemes to be registered as standard schemes.
|
* `custom_schemes` [CustomScheme[]](structures/custom-scheme.md)
|
||||||
* `options` Object (optional)
|
|
||||||
* `secure` Boolean (optional) - `true` to register the scheme as secure.
|
|
||||||
Default `false`.
|
**Note:** This method can only be used before the `ready` event of the `app`
|
||||||
|
module gets emitted and can be called only once.
|
||||||
|
|
||||||
|
Registers the `scheme` as standard, secure, bypasses content security policy for resources,
|
||||||
|
allows registering ServiceWorker and supports fetch API.
|
||||||
|
|
||||||
|
Specify an option with the value of `true` to enable the capability.
|
||||||
|
An example of registering a privileged scheme, with bypassing Content Security Policy:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const { protocol } = require('electron')
|
||||||
|
protocol.registerSchemesAsPrivileged([
|
||||||
|
{ scheme: 'foo', options: { bypassCSP: true } }
|
||||||
|
])
|
||||||
|
```
|
||||||
|
|
||||||
A standard scheme adheres to what RFC 3986 calls [generic URI
|
A standard scheme adheres to what RFC 3986 calls [generic URI
|
||||||
syntax](https://tools.ietf.org/html/rfc3986#section-3). For example `http` and
|
syntax](https://tools.ietf.org/html/rfc3986#section-3). For example `http` and
|
||||||
|
@ -59,23 +73,7 @@ error for the scheme.
|
||||||
|
|
||||||
By default web storage apis (localStorage, sessionStorage, webSQL, indexedDB, cookies)
|
By default web storage apis (localStorage, sessionStorage, webSQL, indexedDB, cookies)
|
||||||
are disabled for non standard schemes. So in general if you want to register a
|
are disabled for non standard schemes. So in general if you want to register a
|
||||||
custom protocol to replace the `http` protocol, you have to register it as a standard scheme:
|
custom protocol to replace the `http` protocol, you have to register it as a standard scheme.
|
||||||
|
|
||||||
```javascript
|
|
||||||
const { app, protocol } = require('electron')
|
|
||||||
|
|
||||||
protocol.registerStandardSchemes(['atom'])
|
|
||||||
app.on('ready', () => {
|
|
||||||
protocol.registerHttpProtocol('atom', '...')
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note:** This method can only be used before the `ready` event of the `app`
|
|
||||||
module gets emitted.
|
|
||||||
|
|
||||||
### `protocol.registerServiceWorkerSchemes(schemes)`
|
|
||||||
|
|
||||||
* `schemes` String[] - Custom schemes to be registered to handle service workers.
|
|
||||||
|
|
||||||
### `protocol.registerFileProtocol(scheme, handler[, completion])`
|
### `protocol.registerFileProtocol(scheme, handler[, completion])`
|
||||||
|
|
||||||
|
|
10
docs/api/structures/custom-scheme.md
Normal file
10
docs/api/structures/custom-scheme.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# CustomScheme Object
|
||||||
|
|
||||||
|
* `scheme` String - Custom schemes to be registered with options.
|
||||||
|
* `options` Object (optional)
|
||||||
|
* `standard` Boolean (optional) - Default false.
|
||||||
|
* `secure` Boolean (optional) - Default false.
|
||||||
|
* `bypassCSP` Boolean (optional) - Default false.
|
||||||
|
* `allowServiceWorkers` Boolean (optional) - Default false.
|
||||||
|
* `supportFetchAPI` Boolean (optional) - Default false.
|
||||||
|
* `corsEnabled` Boolean (optional) - Default false.
|
|
@ -95,34 +95,6 @@ webFrame.setSpellCheckProvider('en-US', {
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
### `webFrame.registerURLSchemeAsBypassingCSP(scheme)`
|
|
||||||
|
|
||||||
* `scheme` String
|
|
||||||
|
|
||||||
Resources will be loaded from this `scheme` regardless of the current page's
|
|
||||||
Content Security Policy.
|
|
||||||
|
|
||||||
### `webFrame.registerURLSchemeAsPrivileged(scheme[, options])`
|
|
||||||
|
|
||||||
* `scheme` String
|
|
||||||
* `options` Object (optional)
|
|
||||||
* `secure` Boolean (optional) - Default true.
|
|
||||||
* `bypassCSP` Boolean (optional) - Default true.
|
|
||||||
* `allowServiceWorkers` Boolean (optional) - Default true.
|
|
||||||
* `supportFetchAPI` Boolean (optional) - Default true.
|
|
||||||
* `corsEnabled` Boolean (optional) - Default true.
|
|
||||||
|
|
||||||
Registers the `scheme` as secure, bypasses content security policy for resources,
|
|
||||||
allows registering ServiceWorker and supports fetch API.
|
|
||||||
|
|
||||||
Specify an option with the value of `false` to omit it from the registration.
|
|
||||||
An example of registering a privileged scheme, without bypassing Content Security Policy:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const { webFrame } = require('electron')
|
|
||||||
webFrame.registerURLSchemeAsPrivileged('foo', { bypassCSP: false })
|
|
||||||
```
|
|
||||||
|
|
||||||
### `webFrame.insertText(text)`
|
### `webFrame.insertText(text)`
|
||||||
|
|
||||||
* `text` String
|
* `text` String
|
||||||
|
|
|
@ -1087,7 +1087,7 @@ describe('protocol module', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('protocol.registerStandardSchemes', () => {
|
describe('protocol.registerSchemesAsPrivileged standard', () => {
|
||||||
const standardScheme = remote.getGlobal('standardScheme')
|
const standardScheme = remote.getGlobal('standardScheme')
|
||||||
const origin = `${standardScheme}://fake-host`
|
const origin = `${standardScheme}://fake-host`
|
||||||
const imageURL = `${origin}/test.png`
|
const imageURL = `${origin}/test.png`
|
||||||
|
@ -1189,4 +1189,102 @@ describe('protocol module', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('protocol.registerSchemesAsPrivileged cors-fetch', function () {
|
||||||
|
const standardScheme = remote.getGlobal('standardScheme')
|
||||||
|
const fixtures = path.resolve(__dirname, 'fixtures')
|
||||||
|
let w = null
|
||||||
|
|
||||||
|
beforeEach((done) => {
|
||||||
|
protocol.unregisterProtocol(standardScheme, () => done())
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach((done) => {
|
||||||
|
closeWindow(w).then(() => {
|
||||||
|
w = null
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('supports fetch api by default', (done) => {
|
||||||
|
const url = 'file://' + fixtures + '/assets/logo.png'
|
||||||
|
window.fetch(url)
|
||||||
|
.then(function (response) {
|
||||||
|
assert(response.ok)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
done('unexpected error : ' + err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('allows CORS requests by default', (done) => {
|
||||||
|
allowsCORSRequests('cors', 200, `<html>
|
||||||
|
<script>
|
||||||
|
const {ipcRenderer} = require('electron')
|
||||||
|
fetch('cors://myhost').then(function (response) {
|
||||||
|
ipcRenderer.send('response', response.status)
|
||||||
|
}).catch(function (response) {
|
||||||
|
ipcRenderer.send('response', 'failed')
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</html>`, done)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('disallows CORS, but allows fetch requests, when specified', (done) => {
|
||||||
|
allowsCORSRequests('no-cors', 'failed', `<html>
|
||||||
|
<script>
|
||||||
|
const {ipcRenderer} = require('electron')
|
||||||
|
fetch('no-cors://myhost').then(function (response) {
|
||||||
|
ipcRenderer.send('response', response.status)
|
||||||
|
}).catch(function (response) {
|
||||||
|
ipcRenderer.send('response', 'failed')
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</html>`, done)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('allows CORS, but disallows fetch requests, when specified', (done) => {
|
||||||
|
allowsCORSRequests('no-fetch', 'failed', `<html>
|
||||||
|
<script>
|
||||||
|
const {ipcRenderer} = require('electron')
|
||||||
|
fetch('no-fetch://myhost').then(function
|
||||||
|
(response) {
|
||||||
|
ipcRenderer.send('response', response.status)
|
||||||
|
}).catch(function (response) {
|
||||||
|
ipcRenderer.send('response', 'failed')
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</html>`, done)
|
||||||
|
})
|
||||||
|
|
||||||
|
function allowsCORSRequests (corsScheme, expected, content, done) {
|
||||||
|
const url = standardScheme + '://fake-host'
|
||||||
|
w = new BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const handler = (request, callback) => {
|
||||||
|
callback({ data: content, mimeType: 'text/html' })
|
||||||
|
}
|
||||||
|
protocol.registerStringProtocol(standardScheme, handler, (error) => {
|
||||||
|
if (error) { return done(error) }
|
||||||
|
})
|
||||||
|
|
||||||
|
protocol.registerStringProtocol(corsScheme,
|
||||||
|
(request, callback) => {
|
||||||
|
callback('')
|
||||||
|
}, (error) => {
|
||||||
|
if (error) { return done(error) }
|
||||||
|
ipcMain.once('response', function (event, status) {
|
||||||
|
assert.strictEqual(status, expected)
|
||||||
|
protocol.unregisterProtocol(corsScheme, () => done())
|
||||||
|
})
|
||||||
|
w.loadURL(url)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -695,12 +695,9 @@ describe('session module', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// FIXME: Disabled with C71 upgrade
|
describe('ses.getBlobData(identifier, callback)', () => {
|
||||||
// Re-enable with new api from
|
|
||||||
// https://github.com/electron/electron/tree/webframe-scheme-api
|
|
||||||
xdescribe('ses.getBlobData(identifier, callback)', () => {
|
|
||||||
it('returns blob data for uuid', (done) => {
|
it('returns blob data for uuid', (done) => {
|
||||||
const scheme = 'temp'
|
const scheme = 'cors-blob'
|
||||||
const protocol = session.defaultSession.protocol
|
const protocol = session.defaultSession.protocol
|
||||||
const url = `${scheme}://host`
|
const url = `${scheme}://host`
|
||||||
before(() => {
|
before(() => {
|
||||||
|
@ -723,8 +720,6 @@ describe('session module', () => {
|
||||||
})
|
})
|
||||||
const content = `<html>
|
const content = `<html>
|
||||||
<script>
|
<script>
|
||||||
const {webFrame} = require('electron')
|
|
||||||
webFrame.registerURLSchemeAsPrivileged('${scheme}')
|
|
||||||
let fd = new FormData();
|
let fd = new FormData();
|
||||||
fd.append('file', new Blob(['${postData}'], {type:'application/json'}));
|
fd.append('file', new Blob(['${postData}'], {type:'application/json'}));
|
||||||
fetch('${url}', {method:'POST', body: fd });
|
fetch('${url}', {method:'POST', body: fd });
|
||||||
|
|
|
@ -4,7 +4,7 @@ const dirtyChai = require('dirty-chai')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const { closeWindow } = require('./window-helpers')
|
const { closeWindow } = require('./window-helpers')
|
||||||
const { remote, webFrame } = require('electron')
|
const { remote, webFrame } = require('electron')
|
||||||
const { BrowserWindow, protocol, ipcMain } = remote
|
const { BrowserWindow, ipcMain } = remote
|
||||||
|
|
||||||
const { expect } = chai
|
const { expect } = chai
|
||||||
chai.use(dirtyChai)
|
chai.use(dirtyChai)
|
||||||
|
@ -20,124 +20,6 @@ describe('webFrame module', function () {
|
||||||
return closeWindow(w).then(function () { w = null })
|
return closeWindow(w).then(function () { w = null })
|
||||||
})
|
})
|
||||||
|
|
||||||
// FIXME: Disabled with C70.
|
|
||||||
xdescribe('webFrame.registerURLSchemeAsPrivileged', function () {
|
|
||||||
it('supports fetch api by default', function (done) {
|
|
||||||
const url = 'file://' + fixtures + '/assets/logo.png'
|
|
||||||
window.fetch(url).then(function (response) {
|
|
||||||
assert(response.ok)
|
|
||||||
done()
|
|
||||||
}).catch(function (err) {
|
|
||||||
done('unexpected error : ' + err)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('allows CORS requests by default', function (done) {
|
|
||||||
allowsCORSRequests(200, `<html>
|
|
||||||
<script>
|
|
||||||
const {ipcRenderer, webFrame} = require('electron')
|
|
||||||
webFrame.registerURLSchemeAsPrivileged('cors1')
|
|
||||||
fetch('cors1://myhost').then(function (response) {
|
|
||||||
ipcRenderer.send('response', response.status)
|
|
||||||
}).catch(function (response) {
|
|
||||||
ipcRenderer.send('response', 'failed')
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</html>`, done)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('allows CORS and fetch requests when specified', function (done) {
|
|
||||||
allowsCORSRequests(200, `<html>
|
|
||||||
<script>
|
|
||||||
const {ipcRenderer, webFrame} = require('electron')
|
|
||||||
webFrame.registerURLSchemeAsPrivileged('cors2', { supportFetchAPI: true, corsEnabled: true })
|
|
||||||
fetch('cors2://myhost').then(function (response) {
|
|
||||||
ipcRenderer.send('response', response.status)
|
|
||||||
}).catch(function (response) {
|
|
||||||
ipcRenderer.send('response', 'failed')
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</html>`, done)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('allows CORS and fetch requests when half-specified', function (done) {
|
|
||||||
allowsCORSRequests(200, `<html>
|
|
||||||
<script>
|
|
||||||
const {ipcRenderer, webFrame} = require('electron')
|
|
||||||
webFrame.registerURLSchemeAsPrivileged('cors3', { supportFetchAPI: true })
|
|
||||||
fetch('cors3://myhost').then(function (response) {
|
|
||||||
ipcRenderer.send('response', response.status)
|
|
||||||
}).catch(function (response) {
|
|
||||||
ipcRenderer.send('response', 'failed')
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</html>`, done)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('disallows CORS, but allows fetch requests, when specified', function (done) {
|
|
||||||
allowsCORSRequests('failed', `<html>
|
|
||||||
<script>
|
|
||||||
const {ipcRenderer, webFrame} = require('electron')
|
|
||||||
webFrame.registerURLSchemeAsPrivileged('cors4', { supportFetchAPI: true, corsEnabled: false })
|
|
||||||
fetch('cors4://myhost').then(function (response) {
|
|
||||||
ipcRenderer.send('response', response.status)
|
|
||||||
}).catch(function (response) {
|
|
||||||
ipcRenderer.send('response', 'failed')
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</html>`, done)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('allows CORS, but disallows fetch requests, when specified', function (done) {
|
|
||||||
allowsCORSRequests('failed', `<html>
|
|
||||||
<script>
|
|
||||||
const {ipcRenderer, webFrame} = require('electron')
|
|
||||||
webFrame.registerURLSchemeAsPrivileged('cors5', { supportFetchAPI: false, corsEnabled: true })
|
|
||||||
fetch('cors5://myhost').then(function (response) {
|
|
||||||
ipcRenderer.send('response', response.status)
|
|
||||||
}).catch(function (response) {
|
|
||||||
ipcRenderer.send('response', 'failed')
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</html>`, done)
|
|
||||||
})
|
|
||||||
|
|
||||||
let runNumber = 1
|
|
||||||
function allowsCORSRequests (expected, content, done) {
|
|
||||||
const standardScheme = remote.getGlobal('standardScheme') + runNumber
|
|
||||||
const corsScheme = 'cors' + runNumber
|
|
||||||
runNumber++
|
|
||||||
|
|
||||||
const url = standardScheme + '://fake-host'
|
|
||||||
w = new BrowserWindow({ show: false })
|
|
||||||
after(function (done) {
|
|
||||||
protocol.unregisterProtocol(corsScheme, function () {
|
|
||||||
protocol.unregisterProtocol(standardScheme, function () {
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
const handler = function (request, callback) {
|
|
||||||
callback({ data: content, mimeType: 'text/html' })
|
|
||||||
}
|
|
||||||
protocol.registerStringProtocol(standardScheme, handler, function (error) {
|
|
||||||
if (error) return done(error)
|
|
||||||
})
|
|
||||||
|
|
||||||
protocol.registerStringProtocol(corsScheme, function (request, callback) {
|
|
||||||
callback('')
|
|
||||||
}, function (error) {
|
|
||||||
if (error) return done(error)
|
|
||||||
ipcMain.once('response', function (event, status) {
|
|
||||||
assert.strictEqual(status, expected)
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
w.loadURL(url)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it('supports setting the visual and layout zoom level limits', function () {
|
it('supports setting the visual and layout zoom level limits', function () {
|
||||||
assert.doesNotThrow(function () {
|
assert.doesNotThrow(function () {
|
||||||
webFrame.setVisualZoomLevelLimits(1, 50)
|
webFrame.setVisualZoomLevelLimits(1, 50)
|
||||||
|
|
32
spec/package-lock.json
generated
32
spec/package-lock.json
generated
|
@ -72,7 +72,7 @@
|
||||||
},
|
},
|
||||||
"bl": {
|
"bl": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
|
"resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
|
||||||
"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
|
"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -228,7 +228,7 @@
|
||||||
},
|
},
|
||||||
"commander": {
|
"commander": {
|
||||||
"version": "2.15.1",
|
"version": "2.15.1",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
|
"resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
|
||||||
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==",
|
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
@ -267,7 +267,7 @@
|
||||||
},
|
},
|
||||||
"dbus-native": {
|
"dbus-native": {
|
||||||
"version": "0.2.5",
|
"version": "0.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/dbus-native/-/dbus-native-0.2.5.tgz",
|
"resolved": "http://registry.npmjs.org/dbus-native/-/dbus-native-0.2.5.tgz",
|
||||||
"integrity": "sha512-ocxMKCV7QdiNhzhFSeEMhj258OGtvpANSb3oWGiotmI5h1ZIse0TMPcSLiXSpqvbYvQz2Y5RsYPMNYLWhg9eBw==",
|
"integrity": "sha512-ocxMKCV7QdiNhzhFSeEMhj258OGtvpANSb3oWGiotmI5h1ZIse0TMPcSLiXSpqvbYvQz2Y5RsYPMNYLWhg9eBw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -358,7 +358,7 @@
|
||||||
},
|
},
|
||||||
"duplexer": {
|
"duplexer": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
|
"resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
|
||||||
"integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
|
"integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
@ -512,7 +512,7 @@
|
||||||
},
|
},
|
||||||
"get-stream": {
|
"get-stream": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
|
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
|
||||||
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
|
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
@ -753,7 +753,7 @@
|
||||||
},
|
},
|
||||||
"mkdirp": {
|
"mkdirp": {
|
||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "0.0.8"
|
"minimist": "0.0.8"
|
||||||
|
@ -761,7 +761,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
|
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -941,7 +941,7 @@
|
||||||
},
|
},
|
||||||
"os-homedir": {
|
"os-homedir": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
|
"resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
|
||||||
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
|
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
@ -958,7 +958,7 @@
|
||||||
},
|
},
|
||||||
"os-tmpdir": {
|
"os-tmpdir": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
"resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
|
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
@ -1000,7 +1000,7 @@
|
||||||
},
|
},
|
||||||
"path-is-absolute": {
|
"path-is-absolute": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
"resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
@ -1018,7 +1018,7 @@
|
||||||
},
|
},
|
||||||
"pause-stream": {
|
"pause-stream": {
|
||||||
"version": "0.0.11",
|
"version": "0.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
|
"resolved": "http://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
|
||||||
"integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=",
|
"integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -1139,7 +1139,7 @@
|
||||||
},
|
},
|
||||||
"rimraf": {
|
"rimraf": {
|
||||||
"version": "2.2.8",
|
"version": "2.2.8",
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz",
|
"resolved": "http://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz",
|
||||||
"integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=",
|
"integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
@ -1305,7 +1305,7 @@
|
||||||
},
|
},
|
||||||
"string_decoder": {
|
"string_decoder": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"safe-buffer": "~5.1.0"
|
"safe-buffer": "~5.1.0"
|
||||||
|
@ -1321,7 +1321,7 @@
|
||||||
},
|
},
|
||||||
"strip-eof": {
|
"strip-eof": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
|
"resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
|
||||||
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
|
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
@ -1391,7 +1391,7 @@
|
||||||
},
|
},
|
||||||
"through": {
|
"through": {
|
||||||
"version": "2.3.8",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
"resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||||
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
|
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
@ -1486,7 +1486,7 @@
|
||||||
},
|
},
|
||||||
"wrap-ansi": {
|
"wrap-ansi": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
|
"resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
|
||||||
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
|
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
|
|
@ -97,7 +97,14 @@ global.nativeModulesEnabled = !process.env.ELECTRON_SKIP_NATIVE_MODULE_TESTS
|
||||||
// Register app as standard scheme.
|
// Register app as standard scheme.
|
||||||
global.standardScheme = 'app'
|
global.standardScheme = 'app'
|
||||||
global.zoomScheme = 'zoom'
|
global.zoomScheme = 'zoom'
|
||||||
protocol.registerStandardSchemes([global.standardScheme, global.zoomScheme], { secure: true })
|
protocol.registerSchemesAsPrivileged([
|
||||||
|
{ scheme: global.standardScheme, options: { standard: true, secure: true } },
|
||||||
|
{ scheme: global.zoomScheme, options: { standard: true, secure: true } },
|
||||||
|
{ scheme: 'cors', options: { corsEnabled: true, supportFetchAPI: true } },
|
||||||
|
{ scheme: 'cors-blob', options: { corsEnabled: true, supportFetchAPI: true } },
|
||||||
|
{ scheme: 'no-cors', options: { supportFetchAPI: true } },
|
||||||
|
{ scheme: 'no-fetch', options: { corsEnabled: true } }
|
||||||
|
])
|
||||||
|
|
||||||
app.on('window-all-closed', function () {
|
app.on('window-all-closed', function () {
|
||||||
app.quit()
|
app.quit()
|
||||||
|
|
Loading…
Add table
Reference in a new issue