Skip to content

Commit

Permalink
chore: Move webFrame scheme privilege methods to main process (#16625)
Browse files Browse the repository at this point in the history
* 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

* fix: update docs for protocol API (#16601)

* fix: update docs for protocol API

* upddate source for new attribute name

* update electron-typescript-definitions package
  • Loading branch information
nitsakh authored and MarshallOfSound committed Jan 30, 2019
1 parent 1d9abfd commit d6612d2
Show file tree
Hide file tree
Showing 21 changed files with 333 additions and 330 deletions.
18 changes: 15 additions & 3 deletions atom/app/atom_content_client.cc
Expand Up @@ -213,18 +213,30 @@ base::RefCountedMemory* AtomContentClient::GetDataResourceBytes(
}

void AtomContentClient::AddAdditionalSchemes(Schemes* schemes) {
schemes->standard_schemes.push_back("chrome-extension");

std::vector<std::string> splited;
ConvertStringWithSeparatorToVector(&splited, ",",
switches::kRegisterServiceWorkerSchemes);
switches::kServiceWorkerSchemes);
for (const std::string& scheme : splited)
schemes->service_worker_schemes.push_back(scheme);
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);
for (const std::string& scheme : splited)
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(
Expand Down
140 changes: 102 additions & 38 deletions atom/browser/api/atom_api_protocol.cc
Expand Up @@ -24,47 +24,119 @@

using content::BrowserThread;

namespace atom {

namespace api {

namespace {

// List of registered custom 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 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("privileges", &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() {
return g_standard_schemes;
}

void RegisterStandardSchemes(const std::vector<std::string>& schemes,
mate::Arguments* args) {
g_standard_schemes = schemes;
void RegisterSchemesAsPrivileged(v8::Local<v8::Value> val,
mate::Arguments* args) {
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;
bool secure = false;
args->GetNext(&opts) && opts.Get("secure", &secure);

// Dynamically register the schemes.
auto* policy = content::ChildProcessSecurityPolicy::GetInstance();
for (const std::string& scheme : schemes) {
url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITH_HOST);
if (secure) {
url::AddSecureScheme(scheme.c_str());
std::vector<std::string> secure_schemes, cspbypassing_schemes, fetch_schemes,
service_worker_schemes, cors_schemes;
for (const auto& custom_scheme : custom_schemes) {
// Register scheme to privileged list (https, wss, data, chrome-extension)
if (custom_scheme.options.standard) {
auto* policy = content::ChildProcessSecurityPolicy::GetInstance();
url::AddStandardScheme(custom_scheme.scheme.c_str(),
url::SCHEME_WITH_HOST);
g_standard_schemes.push_back(custom_scheme.scheme);
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);
}

// Add the schemes to command line switches, so child processes can also
// register them.
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
atom::switches::kStandardSchemes, base::JoinString(schemes, ","));
if (secure) {
const auto AppendSchemesToCmdLine = [](const char* switch_name,
std::vector<std::string> schemes) {
// Add the schemes to command line switches, so child processes can also
// register them.
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
atom::switches::kSecureSchemes, base::JoinString(schemes, ","));
}
switch_name, 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)
Expand All @@ -73,12 +145,6 @@ Protocol::Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context)
}

Protocol::~Protocol() {}

void Protocol::RegisterServiceWorkerSchemes(
const std::vector<std::string>& schemes) {
atom::AtomBrowserClient::SetCustomServiceWorkerSchemes(schemes);
}

void Protocol::UnregisterProtocol(const std::string& scheme,
mate::Arguments* args) {
CompletionCallback callback;
Expand Down Expand Up @@ -195,8 +261,6 @@ void Protocol::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> prototype) {
prototype->SetClassName(mate::StringToV8(isolate, "Protocol"));
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
.SetMethod("registerServiceWorkerSchemes",
&Protocol::RegisterServiceWorkerSchemes)
.SetMethod("registerStringProtocol",
&Protocol::RegisterProtocol<URLRequestStringJob>)
.SetMethod("registerBufferProtocol",
Expand Down Expand Up @@ -228,16 +292,16 @@ void Protocol::BuildPrototype(v8::Isolate* isolate,

namespace {

void RegisterStandardSchemes(const std::vector<std::string>& schemes,
mate::Arguments* args) {
void RegisterSchemesAsPrivileged(v8::Local<v8::Value> val,
mate::Arguments* args) {
if (atom::Browser::Get()->is_ready()) {
args->ThrowError(
"protocol.registerStandardSchemes should be called before "
"protocol.registerSchemesAsPrivileged should be called before "
"app is ready");
return;
}

atom::api::RegisterStandardSchemes(schemes, args);
atom::api::RegisterSchemesAsPrivileged(val, args);
}

void Initialize(v8::Local<v8::Object> exports,
Expand All @@ -246,7 +310,7 @@ void Initialize(v8::Local<v8::Object> exports,
void* priv) {
v8::Isolate* isolate = context->GetIsolate();
mate::Dictionary dict(isolate, exports);
dict.SetMethod("registerStandardSchemes", &RegisterStandardSchemes);
dict.SetMethod("registerSchemesAsPrivileged", &RegisterSchemesAsPrivileged);
dict.SetMethod("getStandardSchemes", &atom::api::GetStandardSchemes);
}

Expand Down
8 changes: 3 additions & 5 deletions atom/browser/api/atom_api_protocol.h
Expand Up @@ -34,8 +34,9 @@ namespace atom {
namespace api {

std::vector<std::string> GetStandardSchemes();
void RegisterStandardSchemes(const std::vector<std::string>& schemes,
mate::Arguments* args);

void RegisterSchemesAsPrivileged(v8::Local<v8::Value> val,
mate::Arguments* args);

class Protocol : public mate::TrackableObject<Protocol> {
public:
Expand Down Expand Up @@ -94,9 +95,6 @@ class Protocol : public mate::TrackableObject<Protocol> {
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.
template <typename RequestJob>
void RegisterProtocol(const std::string& scheme,
Expand Down
21 changes: 5 additions & 16 deletions atom/browser/atom_browser_client.cc
Expand Up @@ -114,9 +114,6 @@ namespace {
// Next navigation should not restart renderer process.
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,
const GURL& src_url,
const GURL& dest_url) {
Expand Down Expand Up @@ -148,11 +145,6 @@ void AtomBrowserClient::SuppressRendererProcessRestartForOnce() {
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() {
return g_browser_client;
}
Expand Down Expand Up @@ -477,18 +469,15 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
return;

// Copy following switches to child process.
static const char* const kCommonSwitchNames[] = {switches::kStandardSchemes,
switches::kEnableSandbox,
switches::kSecureSchemes};
static const char* const kCommonSwitchNames[] = {
switches::kStandardSchemes, switches::kEnableSandbox,
switches::kSecureSchemes, switches::kBypassCSPSchemes,
switches::kCORSSchemes, switches::kFetchSchemes,
switches::kServiceWorkerSchemes};
command_line->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(),
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)
// Append --app-user-model-id.
PWSTR current_app_id;
Expand Down
4 changes: 0 additions & 4 deletions atom/browser/atom_browser_client.h
Expand Up @@ -49,10 +49,6 @@ class AtomBrowserClient : public content::ContentBrowserClient,
// Don't force renderer process to restart for once.
static void SuppressRendererProcessRestartForOnce();

// Custom schemes to be registered to handle service worker.
static void SetCustomServiceWorkerSchemes(
const std::vector<std::string>& schemes);

NotificationPresenter* GetNotificationPresenter();

void WebNotificationAllowed(int render_process_id,
Expand Down
11 changes: 10 additions & 1 deletion atom/common/options_switches.cc
Expand Up @@ -179,11 +179,20 @@ const char kDisableHttpCache[] = "disable-http-cache";
const char kStandardSchemes[] = "standard-schemes";

// Register schemes to handle service worker.
const char kRegisterServiceWorkerSchemes[] = "register-service-worker-schemes";
const char kServiceWorkerSchemes[] = "service-worker-schemes";

// Register schemes as secure.
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
const char kAppUserModelId[] = "app-user-model-id";

Expand Down
5 changes: 4 additions & 1 deletion atom/common/options_switches.h
Expand Up @@ -89,8 +89,11 @@ extern const char kPpapiFlashPath[];
extern const char kPpapiFlashVersion[];
extern const char kDisableHttpCache[];
extern const char kStandardSchemes[];
extern const char kRegisterServiceWorkerSchemes[];
extern const char kServiceWorkerSchemes[];
extern const char kSecureSchemes[];
extern const char kBypassCSPSchemes[];
extern const char kFetchSchemes[];
extern const char kCORSSchemes[];
extern const char kAppUserModelId[];
extern const char kAppPath[];

Expand Down

0 comments on commit d6612d2

Please sign in to comment.