mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
44 Commits
v25.9.5
...
v5.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a498e0c033 | ||
|
|
0f66918825 | ||
|
|
050b866b6a | ||
|
|
8115a899df | ||
|
|
3dcb7cfef9 | ||
|
|
502f24e50d | ||
|
|
6ebef9d876 | ||
|
|
60af6c2791 | ||
|
|
6d76da55e2 | ||
|
|
b31057ca16 | ||
|
|
16dfa56c77 | ||
|
|
a7ed504575 | ||
|
|
dc4c32972d | ||
|
|
d1d0efbd07 | ||
|
|
afa684ad45 | ||
|
|
f66d21e426 | ||
|
|
9a68ce87eb | ||
|
|
ecb737760c | ||
|
|
5d32cd0269 | ||
|
|
499efd5ee7 | ||
|
|
c4115ed783 | ||
|
|
969a97b54f | ||
|
|
5be0851434 | ||
|
|
233d346d5a | ||
|
|
a879981dfb | ||
|
|
3d90bd4e8e | ||
|
|
ba1dd09be2 | ||
|
|
80aa832ebd | ||
|
|
a950e1d040 | ||
|
|
4d7ddcd750 | ||
|
|
d6612d230b | ||
|
|
1d9abfdb10 | ||
|
|
871ba507a6 | ||
|
|
5d64df141b | ||
|
|
ae846204cb | ||
|
|
6dcf5c5c79 | ||
|
|
e55a9b35b6 | ||
|
|
ae85864959 | ||
|
|
5cc0539919 | ||
|
|
b070774f5c | ||
|
|
7a8548d48f | ||
|
|
ac172abda7 | ||
|
|
29e5195c63 | ||
|
|
3926d9d717 |
@@ -1 +1 @@
|
||||
5.0.0-nightly.20190122
|
||||
5.0.0-beta.2
|
||||
@@ -81,8 +81,6 @@ test_script:
|
||||
if ((-Not (Test-Path Env:\ELECTRON_RELEASE)) -And ($env:GN_CONFIG -in "testing", "release")) {
|
||||
$env:RUN_TESTS="true"
|
||||
}
|
||||
- if "%RUN_TESTS%"=="true" ( echo Verifying non proprietary ffmpeg & python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg )
|
||||
- if "%RUN_TESTS%"=="true" ( echo Verifying mksnapshot & python electron\script\verify-mksnapshot.py --build-dir out\Default --source-root %cd% )
|
||||
- ps: >-
|
||||
if ($env:RUN_TESTS -eq 'true') {
|
||||
New-Item .\out\Default\gen\node_headers\Release -Type directory
|
||||
@@ -91,8 +89,9 @@ test_script:
|
||||
echo "Skipping tests for $env:GN_CONFIG build"
|
||||
}
|
||||
- cd electron
|
||||
- if "%RUN_TESTS%"=="true" ( echo Running test suite & npm run test -- --ci )
|
||||
- if "%RUN_TESTS%"=="true" ( echo Running test suite & npm run test -- --ci --enable-logging)
|
||||
- cd ..
|
||||
- if "%RUN_TESTS%"=="true" ( echo Verifying non proprietary ffmpeg & python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg )
|
||||
deploy_script:
|
||||
- cd electron
|
||||
- ps: >-
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -164,6 +164,9 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
|
||||
if (env->HasVar("ELECTRON_ENABLE_STACK_DUMPING"))
|
||||
base::debug::EnableInProcessStackDumping();
|
||||
|
||||
if (env->HasVar("ELECTRON_DISABLE_SANDBOX"))
|
||||
command_line->AppendSwitch(service_manager::switches::kNoSandbox);
|
||||
|
||||
chrome::RegisterPathProvider();
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/native_mate_converters/value_converter.h"
|
||||
#include "atom/common/promise_util.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "content/public/browser/tracing_controller.h"
|
||||
@@ -65,23 +66,53 @@ scoped_refptr<TracingController::TraceDataEndpoint> GetTraceDataEndpoint(
|
||||
result_file_path, base::Bind(callback, result_file_path));
|
||||
}
|
||||
|
||||
void StopRecording(const base::FilePath& path,
|
||||
const CompletionCallback& callback) {
|
||||
void OnRecordingStopped(scoped_refptr<atom::util::Promise> promise,
|
||||
const base::FilePath& path) {
|
||||
promise->Resolve(path);
|
||||
}
|
||||
|
||||
v8::Local<v8::Promise> StopRecording(v8::Isolate* isolate,
|
||||
const base::FilePath& path) {
|
||||
scoped_refptr<atom::util::Promise> promise = new atom::util::Promise(isolate);
|
||||
|
||||
TracingController::GetInstance()->StopTracing(
|
||||
GetTraceDataEndpoint(path, callback));
|
||||
GetTraceDataEndpoint(path, base::Bind(&OnRecordingStopped, promise)));
|
||||
|
||||
return promise->GetHandle();
|
||||
}
|
||||
|
||||
bool GetCategories(
|
||||
const base::RepeatingCallback<void(const std::set<std::string>&)>&
|
||||
callback) {
|
||||
return TracingController::GetInstance()->GetCategories(
|
||||
base::BindOnce(callback));
|
||||
void OnCategoriesAvailable(scoped_refptr<atom::util::Promise> promise,
|
||||
const std::set<std::string>& categories) {
|
||||
promise->Resolve(categories);
|
||||
}
|
||||
|
||||
bool StartTracing(const base::trace_event::TraceConfig& trace_config,
|
||||
const base::RepeatingCallback<void()>& callback) {
|
||||
return TracingController::GetInstance()->StartTracing(
|
||||
trace_config, base::BindOnce(callback));
|
||||
v8::Local<v8::Promise> GetCategories(v8::Isolate* isolate) {
|
||||
scoped_refptr<atom::util::Promise> promise = new atom::util::Promise(isolate);
|
||||
bool success = TracingController::GetInstance()->GetCategories(
|
||||
base::BindOnce(&OnCategoriesAvailable, promise));
|
||||
|
||||
if (!success)
|
||||
promise->RejectWithErrorMessage("Could not get categories.");
|
||||
|
||||
return promise->GetHandle();
|
||||
}
|
||||
|
||||
void OnTracingStarted(scoped_refptr<atom::util::Promise> promise) {
|
||||
promise->Resolve();
|
||||
}
|
||||
|
||||
v8::Local<v8::Promise> StartTracing(
|
||||
v8::Isolate* isolate,
|
||||
const base::trace_event::TraceConfig& trace_config) {
|
||||
scoped_refptr<atom::util::Promise> promise = new atom::util::Promise(isolate);
|
||||
|
||||
bool success = TracingController::GetInstance()->StartTracing(
|
||||
trace_config, base::BindOnce(&OnTracingStarted, promise));
|
||||
|
||||
if (!success)
|
||||
promise->RejectWithErrorMessage("Could not start tracing");
|
||||
|
||||
return promise->GetHandle();
|
||||
}
|
||||
|
||||
bool GetTraceBufferUsage(
|
||||
|
||||
@@ -136,6 +136,21 @@ inline net::CookieStore* GetCookieStore(
|
||||
return getter->GetURLRequestContext()->cookie_store();
|
||||
}
|
||||
|
||||
void ResolvePromiseWithCookies(scoped_refptr<util::Promise> promise,
|
||||
net::CookieList cookieList) {
|
||||
promise->Resolve(cookieList);
|
||||
}
|
||||
|
||||
void ResolvePromise(scoped_refptr<util::Promise> promise) {
|
||||
promise->Resolve();
|
||||
}
|
||||
|
||||
// Resolve |promise| in UI thread.
|
||||
void ResolvePromiseInUI(scoped_refptr<util::Promise> promise) {
|
||||
base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
|
||||
base::BindOnce(ResolvePromise, std::move(promise)));
|
||||
}
|
||||
|
||||
// Run |callback| on UI thread.
|
||||
void RunCallbackInUI(const base::Closure& callback) {
|
||||
base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, callback);
|
||||
@@ -143,25 +158,28 @@ void RunCallbackInUI(const base::Closure& callback) {
|
||||
|
||||
// Remove cookies from |list| not matching |filter|, and pass it to |callback|.
|
||||
void FilterCookies(std::unique_ptr<base::DictionaryValue> filter,
|
||||
const Cookies::GetCallback& callback,
|
||||
scoped_refptr<util::Promise> promise,
|
||||
const net::CookieList& list) {
|
||||
net::CookieList result;
|
||||
for (const auto& cookie : list) {
|
||||
if (MatchesCookie(filter.get(), cookie))
|
||||
result.push_back(cookie);
|
||||
}
|
||||
RunCallbackInUI(base::Bind(callback, Cookies::SUCCESS, result));
|
||||
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {BrowserThread::UI},
|
||||
base::BindOnce(ResolvePromiseWithCookies, std::move(promise), result));
|
||||
}
|
||||
|
||||
// Receives cookies matching |filter| in IO thread.
|
||||
void GetCookiesOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||
std::unique_ptr<base::DictionaryValue> filter,
|
||||
const Cookies::GetCallback& callback) {
|
||||
scoped_refptr<util::Promise> promise) {
|
||||
std::string url;
|
||||
filter->GetString("url", &url);
|
||||
|
||||
auto filtered_callback =
|
||||
base::Bind(FilterCookies, base::Passed(&filter), callback);
|
||||
base::Bind(FilterCookies, base::Passed(&filter), std::move(promise));
|
||||
|
||||
// Empty url will match all url cookies.
|
||||
if (url.empty())
|
||||
@@ -172,31 +190,42 @@ void GetCookiesOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||
}
|
||||
|
||||
// Removes cookie with |url| and |name| in IO thread.
|
||||
void RemoveCookieOnIOThread(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||
const GURL& url,
|
||||
const std::string& name,
|
||||
const base::Closure& callback) {
|
||||
void RemoveCookieOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||
const GURL& url,
|
||||
const std::string& name,
|
||||
scoped_refptr<util::Promise> promise) {
|
||||
GetCookieStore(getter)->DeleteCookieAsync(
|
||||
url, name, base::BindOnce(RunCallbackInUI, callback));
|
||||
url, name, base::BindOnce(ResolvePromiseInUI, promise));
|
||||
}
|
||||
|
||||
// Resolves/rejects the |promise| in UI thread.
|
||||
void SettlePromiseInUI(scoped_refptr<util::Promise> promise,
|
||||
const std::string& errmsg) {
|
||||
if (errmsg.empty()) {
|
||||
promise->Resolve();
|
||||
} else {
|
||||
promise->RejectWithErrorMessage(errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
// Callback of SetCookie.
|
||||
void OnSetCookie(const Cookies::SetCallback& callback, bool success) {
|
||||
RunCallbackInUI(
|
||||
base::Bind(callback, success ? Cookies::SUCCESS : Cookies::FAILED));
|
||||
void OnSetCookie(scoped_refptr<util::Promise> promise, bool success) {
|
||||
const std::string errmsg = success ? "" : "Setting cookie failed";
|
||||
RunCallbackInUI(base::Bind(SettlePromiseInUI, std::move(promise), errmsg));
|
||||
}
|
||||
|
||||
// Flushes cookie store in IO thread.
|
||||
void FlushCookieStoreOnIOThread(
|
||||
scoped_refptr<net::URLRequestContextGetter> getter,
|
||||
const base::Closure& callback) {
|
||||
GetCookieStore(getter)->FlushStore(base::BindOnce(RunCallbackInUI, callback));
|
||||
scoped_refptr<util::Promise> promise) {
|
||||
GetCookieStore(getter)->FlushStore(
|
||||
base::BindOnce(ResolvePromiseInUI, promise));
|
||||
}
|
||||
|
||||
// Sets cookie with |details| in IO thread.
|
||||
void SetCookieOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||
std::unique_ptr<base::DictionaryValue> details,
|
||||
const Cookies::SetCallback& callback) {
|
||||
scoped_refptr<util::Promise> promise) {
|
||||
std::string url, name, value, domain, path;
|
||||
bool secure = false;
|
||||
bool http_only = false;
|
||||
@@ -237,7 +266,7 @@ void SetCookieOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||
GURL(url), name, value, domain, path, creation_time, expiration_time,
|
||||
last_access_time, secure, http_only,
|
||||
net::CookieSameSite::DEFAULT_MODE, net::COOKIE_PRIORITY_DEFAULT));
|
||||
auto completion_callback = base::BindOnce(OnSetCookie, callback);
|
||||
auto completion_callback = base::BindOnce(OnSetCookie, std::move(promise));
|
||||
if (!canonical_cookie || !canonical_cookie->IsCanonical()) {
|
||||
std::move(completion_callback).Run(false);
|
||||
return;
|
||||
@@ -267,43 +296,56 @@ Cookies::Cookies(v8::Isolate* isolate, AtomBrowserContext* browser_context)
|
||||
|
||||
Cookies::~Cookies() {}
|
||||
|
||||
void Cookies::Get(const base::DictionaryValue& filter,
|
||||
const GetCallback& callback) {
|
||||
v8::Local<v8::Promise> Cookies::Get(const base::DictionaryValue& filter) {
|
||||
scoped_refptr<util::Promise> promise = new util::Promise(isolate());
|
||||
|
||||
auto copy = base::DictionaryValue::From(
|
||||
base::Value::ToUniquePtrValue(filter.Clone()));
|
||||
auto* getter = browser_context_->GetRequestContext();
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {BrowserThread::IO},
|
||||
base::BindOnce(GetCookiesOnIO, base::RetainedRef(getter), std::move(copy),
|
||||
callback));
|
||||
promise));
|
||||
|
||||
return promise->GetHandle();
|
||||
}
|
||||
|
||||
void Cookies::Remove(const GURL& url,
|
||||
const std::string& name,
|
||||
const base::Closure& callback) {
|
||||
v8::Local<v8::Promise> Cookies::Remove(const GURL& url,
|
||||
const std::string& name) {
|
||||
scoped_refptr<util::Promise> promise = new util::Promise(isolate());
|
||||
|
||||
auto* getter = browser_context_->GetRequestContext();
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {BrowserThread::IO},
|
||||
base::BindOnce(RemoveCookieOnIOThread, base::RetainedRef(getter), url,
|
||||
name, callback));
|
||||
base::BindOnce(RemoveCookieOnIO, base::RetainedRef(getter), url, name,
|
||||
promise));
|
||||
|
||||
return promise->GetHandle();
|
||||
}
|
||||
|
||||
void Cookies::Set(const base::DictionaryValue& details,
|
||||
const SetCallback& callback) {
|
||||
v8::Local<v8::Promise> Cookies::Set(const base::DictionaryValue& details) {
|
||||
scoped_refptr<util::Promise> promise = new util::Promise(isolate());
|
||||
|
||||
auto copy = base::DictionaryValue::From(
|
||||
base::Value::ToUniquePtrValue(details.Clone()));
|
||||
auto* getter = browser_context_->GetRequestContext();
|
||||
base::PostTaskWithTraits(
|
||||
FROM_HERE, {BrowserThread::IO},
|
||||
base::BindOnce(SetCookieOnIO, base::RetainedRef(getter), std::move(copy),
|
||||
callback));
|
||||
promise));
|
||||
|
||||
return promise->GetHandle();
|
||||
}
|
||||
|
||||
void Cookies::FlushStore(const base::Closure& callback) {
|
||||
v8::Local<v8::Promise> Cookies::FlushStore() {
|
||||
scoped_refptr<util::Promise> promise = new util::Promise(isolate());
|
||||
|
||||
auto* getter = browser_context_->GetRequestContext();
|
||||
base::PostTaskWithTraits(FROM_HERE, {BrowserThread::IO},
|
||||
base::BindOnce(FlushCookieStoreOnIOThread,
|
||||
base::RetainedRef(getter), callback));
|
||||
base::RetainedRef(getter), promise));
|
||||
|
||||
return promise->GetHandle();
|
||||
}
|
||||
|
||||
void Cookies::OnCookieChanged(const CookieDetails* details) {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "atom/browser/net/cookie_details.h"
|
||||
#include "atom/common/promise_util.h"
|
||||
#include "base/callback_list.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "net/cookies/canonical_cookie.h"
|
||||
@@ -35,9 +36,6 @@ class Cookies : public mate::TrackableObject<Cookies> {
|
||||
FAILED,
|
||||
};
|
||||
|
||||
using GetCallback = base::Callback<void(Error, const net::CookieList&)>;
|
||||
using SetCallback = base::Callback<void(Error)>;
|
||||
|
||||
static mate::Handle<Cookies> Create(v8::Isolate* isolate,
|
||||
AtomBrowserContext* browser_context);
|
||||
|
||||
@@ -49,12 +47,10 @@ class Cookies : public mate::TrackableObject<Cookies> {
|
||||
Cookies(v8::Isolate* isolate, AtomBrowserContext* browser_context);
|
||||
~Cookies() override;
|
||||
|
||||
void Get(const base::DictionaryValue& filter, const GetCallback& callback);
|
||||
void Remove(const GURL& url,
|
||||
const std::string& name,
|
||||
const base::Closure& callback);
|
||||
void Set(const base::DictionaryValue& details, const SetCallback& callback);
|
||||
void FlushStore(const base::Closure& callback);
|
||||
v8::Local<v8::Promise> Get(const base::DictionaryValue& filter);
|
||||
v8::Local<v8::Promise> Set(const base::DictionaryValue& details);
|
||||
v8::Local<v8::Promise> Remove(const GURL& url, const std::string& name);
|
||||
v8::Local<v8::Promise> FlushStore();
|
||||
|
||||
// CookieChangeNotifier subscription:
|
||||
void OnCookieChanged(const CookieDetails*);
|
||||
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
@@ -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",
|
||||
@@ -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,
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -455,7 +455,7 @@ bool AtomBrowserMainParts::MainMessageLoopRun(int* result_code) {
|
||||
|
||||
void AtomBrowserMainParts::PreDefaultMainMessageLoopRun(
|
||||
base::OnceClosure quit_closure) {
|
||||
Browser::SetMainMessageLoopQuitClosure(std::move(quit_closure));
|
||||
Browser::Get()->SetMainMessageLoopQuitClosure(std::move(quit_closure));
|
||||
}
|
||||
|
||||
void AtomBrowserMainParts::PostMainMessageLoopStart() {
|
||||
|
||||
@@ -100,23 +100,58 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
|
||||
if (relay)
|
||||
window = relay->GetNativeWindow();
|
||||
|
||||
auto* web_preferences = WebContentsPreferences::From(web_contents);
|
||||
bool offscreen =
|
||||
!web_preferences || web_preferences->IsEnabled(options::kOffscreen);
|
||||
|
||||
// Show save dialog if save path was not set already on item
|
||||
base::FilePath path;
|
||||
GetItemSavePath(item, &path);
|
||||
// Show save dialog if save path was not set already on item
|
||||
file_dialog::DialogSettings settings;
|
||||
GetItemSaveDialogOptions(item, &settings);
|
||||
if (!settings.parent_window)
|
||||
settings.parent_window = window;
|
||||
settings.force_detached = offscreen;
|
||||
if (settings.title.size() == 0)
|
||||
settings.title = item->GetURL().spec();
|
||||
if (!settings.default_path.empty())
|
||||
settings.default_path = default_path;
|
||||
if (path.empty() && file_dialog::ShowSaveDialog(settings, &path)) {
|
||||
if (path.empty()) {
|
||||
file_dialog::DialogSettings settings;
|
||||
GetItemSaveDialogOptions(item, &settings);
|
||||
|
||||
if (!settings.parent_window)
|
||||
settings.parent_window = window;
|
||||
if (settings.title.size() == 0)
|
||||
settings.title = item->GetURL().spec();
|
||||
if (!settings.default_path.empty())
|
||||
settings.default_path = default_path;
|
||||
|
||||
auto* web_preferences = WebContentsPreferences::From(web_contents);
|
||||
const bool offscreen =
|
||||
!web_preferences || web_preferences->IsEnabled(options::kOffscreen);
|
||||
settings.force_detached = offscreen;
|
||||
|
||||
auto dialog_callback =
|
||||
base::Bind(&AtomDownloadManagerDelegate::OnDownloadSaveDialogDone,
|
||||
base::Unretained(this), download_id, callback);
|
||||
file_dialog::ShowSaveDialog(settings, dialog_callback);
|
||||
} else {
|
||||
callback.Run(path, download::DownloadItem::TARGET_DISPOSITION_PROMPT,
|
||||
download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path,
|
||||
download::DOWNLOAD_INTERRUPT_REASON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(MAS_BUILD)
|
||||
void AtomDownloadManagerDelegate::OnDownloadSaveDialogDone(
|
||||
uint32_t download_id,
|
||||
const content::DownloadTargetCallback& download_callback,
|
||||
bool result,
|
||||
const base::FilePath& path,
|
||||
const std::string& bookmark)
|
||||
#else
|
||||
void AtomDownloadManagerDelegate::OnDownloadSaveDialogDone(
|
||||
uint32_t download_id,
|
||||
const content::DownloadTargetCallback& download_callback,
|
||||
bool result,
|
||||
const base::FilePath& path)
|
||||
#endif
|
||||
{
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
||||
auto* item = download_manager_->GetDownload(download_id);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
if (result) {
|
||||
// Remember the last selected download directory.
|
||||
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
|
||||
download_manager_->GetBrowserContext());
|
||||
@@ -133,12 +168,16 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
|
||||
}
|
||||
|
||||
// Running the DownloadTargetCallback with an empty FilePath signals that the
|
||||
// download should be cancelled.
|
||||
// If user cancels the file save dialog, run the callback with empty FilePath.
|
||||
callback.Run(path, download::DownloadItem::TARGET_DISPOSITION_PROMPT,
|
||||
download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path,
|
||||
path.empty() ? download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
|
||||
: download::DOWNLOAD_INTERRUPT_REASON_NONE);
|
||||
// download should be cancelled. If user cancels the file save dialog, run
|
||||
// the callback with empty FilePath.
|
||||
const base::FilePath download_path = result ? path : base::FilePath();
|
||||
const auto interrupt_reason =
|
||||
download_path.empty() ? download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
|
||||
: download::DOWNLOAD_INTERRUPT_REASON_NONE;
|
||||
download_callback.Run(download_path,
|
||||
download::DownloadItem::TARGET_DISPOSITION_PROMPT,
|
||||
download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
|
||||
download_path, interrupt_reason);
|
||||
}
|
||||
|
||||
void AtomDownloadManagerDelegate::Shutdown() {
|
||||
|
||||
@@ -25,10 +25,6 @@ class AtomDownloadManagerDelegate : public content::DownloadManagerDelegate {
|
||||
explicit AtomDownloadManagerDelegate(content::DownloadManager* manager);
|
||||
~AtomDownloadManagerDelegate() override;
|
||||
|
||||
void OnDownloadPathGenerated(uint32_t download_id,
|
||||
const content::DownloadTargetCallback& callback,
|
||||
const base::FilePath& default_path);
|
||||
|
||||
// content::DownloadManagerDelegate:
|
||||
void Shutdown() override;
|
||||
bool DetermineDownloadTarget(
|
||||
@@ -45,6 +41,25 @@ class AtomDownloadManagerDelegate : public content::DownloadManagerDelegate {
|
||||
void GetItemSaveDialogOptions(download::DownloadItem* item,
|
||||
file_dialog::DialogSettings* settings);
|
||||
|
||||
void OnDownloadPathGenerated(uint32_t download_id,
|
||||
const content::DownloadTargetCallback& callback,
|
||||
const base::FilePath& default_path);
|
||||
|
||||
#if defined(MAS_BUILD)
|
||||
void OnDownloadSaveDialogDone(
|
||||
uint32_t download_id,
|
||||
const content::DownloadTargetCallback& download_callback,
|
||||
bool result,
|
||||
const base::FilePath& path,
|
||||
const std::string& bookmark);
|
||||
#else
|
||||
void OnDownloadSaveDialogDone(
|
||||
uint32_t download_id,
|
||||
const content::DownloadTargetCallback& download_callback,
|
||||
bool result,
|
||||
const base::FilePath& path);
|
||||
#endif
|
||||
|
||||
content::DownloadManager* download_manager_;
|
||||
base::WeakPtrFactory<AtomDownloadManagerDelegate> weak_ptr_factory_;
|
||||
|
||||
|
||||
@@ -25,9 +25,6 @@
|
||||
|
||||
namespace atom {
|
||||
|
||||
// Null until/unless the default main message loop is running.
|
||||
base::NoDestructor<base::OnceClosure> g_quit_main_message_loop;
|
||||
|
||||
Browser::LoginItemSettings::LoginItemSettings() = default;
|
||||
Browser::LoginItemSettings::~LoginItemSettings() = default;
|
||||
Browser::LoginItemSettings::LoginItemSettings(const LoginItemSettings& other) =
|
||||
@@ -95,11 +92,12 @@ void Browser::Shutdown() {
|
||||
for (BrowserObserver& observer : observers_)
|
||||
observer.OnQuit();
|
||||
|
||||
if (*g_quit_main_message_loop) {
|
||||
std::move(*g_quit_main_message_loop).Run();
|
||||
if (quit_main_message_loop_) {
|
||||
std::move(quit_main_message_loop_).Run();
|
||||
} else {
|
||||
// There is no message loop available so we are in early stage.
|
||||
exit(0);
|
||||
// There is no message loop available so we are in early stage, wait until
|
||||
// the quit_main_message_loop_ is available.
|
||||
// Exiting now would leave defunct processes behind.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +194,10 @@ void Browser::PreMainMessageLoopRun() {
|
||||
}
|
||||
|
||||
void Browser::SetMainMessageLoopQuitClosure(base::OnceClosure quit_closure) {
|
||||
*g_quit_main_message_loop = std::move(quit_closure);
|
||||
if (is_shutdown_)
|
||||
std::move(quit_closure).Run();
|
||||
else
|
||||
quit_main_message_loop_ = std::move(quit_closure);
|
||||
}
|
||||
|
||||
void Browser::NotifyAndShutdown() {
|
||||
|
||||
@@ -244,7 +244,7 @@ class Browser : public WindowListObserver {
|
||||
|
||||
// Stores the supplied |quit_closure|, to be run when the last Browser
|
||||
// instance is destroyed.
|
||||
static void SetMainMessageLoopQuitClosure(base::OnceClosure quit_closure);
|
||||
void SetMainMessageLoopQuitClosure(base::OnceClosure quit_closure);
|
||||
|
||||
void AddObserver(BrowserObserver* obs) { observers_.AddObserver(obs); }
|
||||
|
||||
@@ -287,6 +287,9 @@ class Browser : public WindowListObserver {
|
||||
// The browser is being shutdown.
|
||||
bool is_shutdown_ = false;
|
||||
|
||||
// Null until/unless the default main message loop is running.
|
||||
base::OnceClosure quit_main_message_loop_;
|
||||
|
||||
int badge_count_ = 0;
|
||||
|
||||
util::Promise* ready_promise_ = nullptr;
|
||||
|
||||
@@ -141,6 +141,7 @@ void URLRequestStreamJob::StartAsync(
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::OnData(std::vector<char>&& buffer) { // NOLINT
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
if (write_buffer_.empty()) {
|
||||
// Quick branch without copying.
|
||||
write_buffer_ = std::move(buffer);
|
||||
@@ -175,7 +176,7 @@ void URLRequestStreamJob::OnError(int error) {
|
||||
int URLRequestStreamJob::ReadRawData(net::IOBuffer* dest, int dest_size) {
|
||||
response_start_time_ = base::TimeTicks::Now();
|
||||
|
||||
if (ended_)
|
||||
if (ended_ && write_buffer_.empty())
|
||||
return 0;
|
||||
|
||||
// When write_buffer_ is empty, there is no data valable yet, we have to save
|
||||
|
||||
@@ -252,6 +252,50 @@ class AtomBeginFrameTimer : public viz::DelayBasedTimeSourceClient {
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomBeginFrameTimer);
|
||||
};
|
||||
|
||||
#if !defined(OS_MACOSX)
|
||||
class AtomDelegatedFrameHostClient : public content::DelegatedFrameHostClient {
|
||||
public:
|
||||
explicit AtomDelegatedFrameHostClient(OffScreenRenderWidgetHostView* view)
|
||||
: view_(view) {}
|
||||
|
||||
ui::Layer* DelegatedFrameHostGetLayer() const override {
|
||||
return view_->GetRootLayer();
|
||||
}
|
||||
|
||||
bool DelegatedFrameHostIsVisible() const override {
|
||||
return view_->IsShowing();
|
||||
}
|
||||
|
||||
SkColor DelegatedFrameHostGetGutterColor() const override {
|
||||
if (view_->render_widget_host()->delegate() &&
|
||||
view_->render_widget_host()->delegate()->IsFullscreenForCurrentTab()) {
|
||||
return SK_ColorWHITE;
|
||||
}
|
||||
return *view_->GetBackgroundColor();
|
||||
}
|
||||
|
||||
void OnFrameTokenChanged(uint32_t frame_token) override {
|
||||
view_->render_widget_host()->DidProcessFrame(frame_token);
|
||||
}
|
||||
|
||||
float GetDeviceScaleFactor() const override {
|
||||
return view_->GetDeviceScaleFactor();
|
||||
}
|
||||
|
||||
std::vector<viz::SurfaceId> CollectSurfaceIdsForEviction() override {
|
||||
return view_->render_widget_host()->CollectSurfaceIdsForEviction();
|
||||
}
|
||||
|
||||
void OnBeginFrame(base::TimeTicks frame_time) override {}
|
||||
void InvalidateLocalSurfaceIdOnEviction() override {}
|
||||
|
||||
private:
|
||||
OffScreenRenderWidgetHostView* const view_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomDelegatedFrameHostClient);
|
||||
};
|
||||
#endif // !defined(OS_MACOSX)
|
||||
|
||||
OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView(
|
||||
bool transparent,
|
||||
bool painting,
|
||||
@@ -274,18 +318,22 @@ OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView(
|
||||
weak_ptr_factory_(this) {
|
||||
DCHECK(render_widget_host_);
|
||||
bool is_guest_view_hack = parent_host_view_ != nullptr;
|
||||
|
||||
current_device_scale_factor_ = kDefaultScaleFactor;
|
||||
|
||||
#if !defined(OS_MACOSX)
|
||||
local_surface_id_allocator_.GenerateId();
|
||||
local_surface_id_allocation_ =
|
||||
local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation();
|
||||
delegated_frame_host_client_.reset(new AtomDelegatedFrameHostClient(this));
|
||||
delegated_frame_host_ = std::make_unique<content::DelegatedFrameHost>(
|
||||
AllocateFrameSinkId(is_guest_view_hack), this,
|
||||
AllocateFrameSinkId(is_guest_view_hack),
|
||||
delegated_frame_host_client_.get(),
|
||||
true /* should_register_frame_sink_id */);
|
||||
|
||||
root_layer_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
|
||||
#endif
|
||||
|
||||
current_device_scale_factor_ = kDefaultScaleFactor;
|
||||
|
||||
local_surface_id_ = local_surface_id_allocator_.GenerateId();
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
last_frame_root_background_color_ = SK_ColorTRANSPARENT;
|
||||
CreatePlatformWidget(is_guest_view_hack);
|
||||
@@ -374,7 +422,7 @@ void OffScreenRenderWidgetHostView::SendBeginFrame(
|
||||
begin_frame_number_++;
|
||||
|
||||
if (renderer_compositor_frame_sink_)
|
||||
renderer_compositor_frame_sink_->OnBeginFrame(begin_frame_args);
|
||||
renderer_compositor_frame_sink_->OnBeginFrame(begin_frame_args, {});
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::InitAsChild(gfx::NativeView) {
|
||||
@@ -433,8 +481,9 @@ void OffScreenRenderWidgetHostView::Show() {
|
||||
browser_compositor_->SetRenderWidgetHostIsHidden(false);
|
||||
#else
|
||||
delegated_frame_host_->AttachToCompositor(compositor_.get());
|
||||
delegated_frame_host_->WasShown(GetLocalSurfaceId(),
|
||||
GetRootLayer()->bounds().size(), false);
|
||||
delegated_frame_host_->WasShown(
|
||||
GetLocalSurfaceIdAllocation().local_surface_id(),
|
||||
GetRootLayer()->bounds().size(), false);
|
||||
#endif
|
||||
|
||||
if (render_widget_host_)
|
||||
@@ -525,19 +574,22 @@ void OffScreenRenderWidgetHostView::TakeFallbackContentFrom(
|
||||
void OffScreenRenderWidgetHostView::DidCreateNewRendererCompositorFrameSink(
|
||||
viz::mojom::CompositorFrameSinkClient* renderer_compositor_frame_sink) {
|
||||
renderer_compositor_frame_sink_ = renderer_compositor_frame_sink;
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
browser_compositor_->DidCreateNewRendererCompositorFrameSink(
|
||||
renderer_compositor_frame_sink_);
|
||||
#else
|
||||
if (GetDelegatedFrameHost()) {
|
||||
GetDelegatedFrameHost()->DidCreateNewRendererCompositorFrameSink(
|
||||
renderer_compositor_frame_sink_);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::SubmitCompositorFrame(
|
||||
const viz::LocalSurfaceId& local_surface_id,
|
||||
viz::CompositorFrame frame,
|
||||
base::Optional<viz::HitTestRegionList> hit_test_region_list) {
|
||||
TRACE_EVENT0("electron",
|
||||
"OffScreenRenderWidgetHostView::SubmitCompositorFrame");
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
last_frame_root_background_color_ = frame.metadata.root_background_color;
|
||||
#endif
|
||||
@@ -587,7 +639,7 @@ void OffScreenRenderWidgetHostView::SubmitCompositorFrame(
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::ClearCompositorFrame() {
|
||||
GetDelegatedFrameHost()->ClearDelegatedFrame();
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::ResetFallbackToFirstNavigationSurface() {
|
||||
@@ -667,9 +719,6 @@ void OffScreenRenderWidgetHostView::Destroy() {
|
||||
|
||||
void OffScreenRenderWidgetHostView::SetTooltipText(const base::string16&) {}
|
||||
|
||||
void OffScreenRenderWidgetHostView::SelectionBoundsChanged(
|
||||
const ViewHostMsg_SelectionBounds_Params&) {}
|
||||
|
||||
uint32_t OffScreenRenderWidgetHostView::GetCaptureSequenceNumber() const {
|
||||
return latest_capture_sequence_number_;
|
||||
}
|
||||
@@ -698,7 +747,6 @@ void OffScreenRenderWidgetHostView::InitAsGuest(
|
||||
content::RenderWidgetHostView* parent_host_view,
|
||||
content::RenderWidgetHostViewGuest* guest_view) {
|
||||
parent_host_view_->AddGuestHostView(this);
|
||||
parent_host_view_->RegisterGuestViewFrameSwappedCallback(guest_view);
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::TransformPointToRootSurface(
|
||||
@@ -745,40 +793,6 @@ OffScreenRenderWidgetHostView::CreateViewForWidget(
|
||||
render_widget_host, embedder_host_view, size());
|
||||
}
|
||||
|
||||
#if !defined(OS_MACOSX)
|
||||
ui::Layer* OffScreenRenderWidgetHostView::DelegatedFrameHostGetLayer() const {
|
||||
return const_cast<ui::Layer*>(root_layer_.get());
|
||||
}
|
||||
|
||||
bool OffScreenRenderWidgetHostView::DelegatedFrameHostIsVisible() const {
|
||||
return is_showing_;
|
||||
}
|
||||
|
||||
SkColor OffScreenRenderWidgetHostView::DelegatedFrameHostGetGutterColor()
|
||||
const {
|
||||
if (render_widget_host_->delegate() &&
|
||||
render_widget_host_->delegate()->IsFullscreenForCurrentTab()) {
|
||||
return SK_ColorWHITE;
|
||||
}
|
||||
return background_color_;
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::OnFirstSurfaceActivation(
|
||||
const viz::SurfaceInfo& surface_info) {}
|
||||
|
||||
void OffScreenRenderWidgetHostView::OnBeginFrame(base::TimeTicks frame_time) {}
|
||||
|
||||
void OffScreenRenderWidgetHostView::OnFrameTokenChanged(uint32_t frame_token) {
|
||||
render_widget_host_->DidProcessFrame(frame_token);
|
||||
}
|
||||
|
||||
const viz::LocalSurfaceId& OffScreenRenderWidgetHostView::GetLocalSurfaceId()
|
||||
const {
|
||||
return local_surface_id_;
|
||||
}
|
||||
|
||||
#endif // !defined(OS_MACOSX)
|
||||
|
||||
const viz::FrameSinkId& OffScreenRenderWidgetHostView::GetFrameSinkId() const {
|
||||
return GetDelegatedFrameHost()->frame_sink_id();
|
||||
}
|
||||
@@ -875,21 +889,6 @@ void OffScreenRenderWidgetHostView::ProxyViewDestroyed(
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::RegisterGuestViewFrameSwappedCallback(
|
||||
content::RenderWidgetHostViewGuest* guest_host_view) {
|
||||
guest_host_view->RegisterFrameSwappedCallback(base::BindOnce(
|
||||
&OffScreenRenderWidgetHostView::OnGuestViewFrameSwapped,
|
||||
weak_ptr_factory_.GetWeakPtr(), base::Unretained(guest_host_view)));
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::OnGuestViewFrameSwapped(
|
||||
content::RenderWidgetHostViewGuest* guest_host_view) {
|
||||
InvalidateBounds(gfx::ConvertRectToPixel(current_device_scale_factor_,
|
||||
guest_host_view->GetViewBounds()));
|
||||
|
||||
RegisterGuestViewFrameSwappedCallback(guest_host_view);
|
||||
}
|
||||
|
||||
std::unique_ptr<viz::SoftwareOutputDevice>
|
||||
OffScreenRenderWidgetHostView::CreateSoftwareOutputDevice(
|
||||
ui::Compositor* compositor) {
|
||||
@@ -925,7 +924,7 @@ void OffScreenRenderWidgetHostView::SetNeedsBeginFrames(
|
||||
begin_frame_timer_->SetActive(needs_begin_frames);
|
||||
|
||||
if (software_output_device_) {
|
||||
software_output_device_->SetActive(needs_begin_frames && painting_, false);
|
||||
software_output_device_->SetActive(painting_, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -937,8 +936,6 @@ void OffScreenRenderWidgetHostView::SetWantsAnimateOnlyBeginFrames() {
|
||||
|
||||
void OffScreenRenderWidgetHostView::OnPaint(const gfx::Rect& damage_rect,
|
||||
const SkBitmap& bitmap) {
|
||||
TRACE_EVENT0("electron", "OffScreenRenderWidgetHostView::OnPaint");
|
||||
|
||||
HoldResize();
|
||||
|
||||
if (parent_callback_) {
|
||||
@@ -1023,10 +1020,6 @@ void OffScreenRenderWidgetHostView::SynchronizeVisualProperties() {
|
||||
}
|
||||
|
||||
ResizeRootLayer(false);
|
||||
if (render_widget_host_)
|
||||
render_widget_host_->SynchronizeVisualProperties();
|
||||
GetDelegatedFrameHost()->EmbedSurface(
|
||||
local_surface_id_, size_, cc::DeadlinePolicy::UseDefaultDeadline());
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::SendMouseEvent(
|
||||
@@ -1192,6 +1185,13 @@ ui::Layer* OffScreenRenderWidgetHostView::GetRootLayer() const {
|
||||
return root_layer_.get();
|
||||
}
|
||||
|
||||
#if !defined(OS_MACOSX)
|
||||
const viz::LocalSurfaceIdAllocation&
|
||||
OffScreenRenderWidgetHostView::GetLocalSurfaceIdAllocation() const {
|
||||
return local_surface_id_allocation_;
|
||||
}
|
||||
#endif // defined(OS_MACOSX)
|
||||
|
||||
content::DelegatedFrameHost*
|
||||
OffScreenRenderWidgetHostView::GetDelegatedFrameHost() const {
|
||||
return delegated_frame_host_.get();
|
||||
@@ -1204,11 +1204,6 @@ void OffScreenRenderWidgetHostView::SetupFrameRate(bool force) {
|
||||
|
||||
frame_rate_threshold_us_ = 1000000 / frame_rate_;
|
||||
|
||||
if (GetCompositor()) {
|
||||
GetCompositor()->SetAuthoritativeVSyncInterval(
|
||||
base::TimeDelta::FromMicroseconds(frame_rate_threshold_us_));
|
||||
}
|
||||
|
||||
if (copy_frame_generator_.get()) {
|
||||
copy_frame_generator_->set_frame_rate_threshold_us(
|
||||
frame_rate_threshold_us_);
|
||||
@@ -1257,28 +1252,32 @@ void OffScreenRenderWidgetHostView::ResizeRootLayer(bool force) {
|
||||
size == GetRootLayer()->bounds().size())
|
||||
return;
|
||||
|
||||
const gfx::Size& size_in_pixels =
|
||||
gfx::ConvertSizeToPixel(current_device_scale_factor_, size);
|
||||
|
||||
local_surface_id_ = local_surface_id_allocator_.GenerateId();
|
||||
|
||||
GetRootLayer()->SetBounds(gfx::Rect(size));
|
||||
GetCompositor()->SetScaleAndSize(current_device_scale_factor_, size_in_pixels,
|
||||
local_surface_id_);
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
bool resized = UpdateNSViewAndDisplay();
|
||||
#else
|
||||
const gfx::Size& size_in_pixels =
|
||||
gfx::ConvertSizeToPixel(current_device_scale_factor_, size);
|
||||
|
||||
local_surface_id_allocator_.GenerateId();
|
||||
local_surface_id_allocation_ =
|
||||
local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation();
|
||||
|
||||
GetCompositor()->SetScaleAndSize(current_device_scale_factor_, size_in_pixels,
|
||||
local_surface_id_allocation_);
|
||||
bool resized = true;
|
||||
GetDelegatedFrameHost()->EmbedSurface(
|
||||
local_surface_id_, size, cc::DeadlinePolicy::UseDefaultDeadline());
|
||||
local_surface_id_allocation_.local_surface_id(), size,
|
||||
cc::DeadlinePolicy::UseDefaultDeadline());
|
||||
#endif
|
||||
|
||||
// Note that |render_widget_host_| will retrieve resize parameters from the
|
||||
// DelegatedFrameHost, so it must have SynchronizeVisualProperties called
|
||||
// after.
|
||||
if (resized && render_widget_host_)
|
||||
if (resized && render_widget_host_) {
|
||||
render_widget_host_->SynchronizeVisualProperties();
|
||||
}
|
||||
}
|
||||
|
||||
viz::FrameSinkId OffScreenRenderWidgetHostView::AllocateFrameSinkId(
|
||||
|
||||
@@ -66,13 +66,12 @@ class AtomBeginFrameTimer;
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
class MacHelper;
|
||||
#else
|
||||
class AtomDelegatedFrameHostClient;
|
||||
#endif
|
||||
|
||||
class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
|
||||
public ui::CompositorDelegate,
|
||||
#if !defined(OS_MACOSX)
|
||||
public content::DelegatedFrameHostClient,
|
||||
#endif
|
||||
public OffscreenViewProxyObserver {
|
||||
public:
|
||||
OffScreenRenderWidgetHostView(bool transparent,
|
||||
@@ -118,7 +117,6 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
|
||||
void SetActive(bool active) override;
|
||||
void ShowDefinitionForSelection() override;
|
||||
void SpeakSelection() override;
|
||||
bool ShouldContinueToPauseForFrame() override;
|
||||
bool UpdateNSViewAndDisplay();
|
||||
#endif // defined(OS_MACOSX)
|
||||
|
||||
@@ -144,8 +142,6 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
|
||||
void Destroy(void) override;
|
||||
void SetTooltipText(const base::string16&) override;
|
||||
content::CursorManager* GetCursorManager() override;
|
||||
void SelectionBoundsChanged(
|
||||
const ViewHostMsg_SelectionBounds_Params&) override;
|
||||
void CopyFromSurface(
|
||||
const gfx::Rect& src_rect,
|
||||
const gfx::Size& output_size,
|
||||
@@ -170,18 +166,8 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
|
||||
content::RenderWidgetHost*,
|
||||
content::WebContentsView*) override;
|
||||
|
||||
#if !defined(OS_MACOSX)
|
||||
// content::DelegatedFrameHostClient:
|
||||
int DelegatedFrameHostGetGpuMemoryBufferClientId(void) const;
|
||||
ui::Layer* DelegatedFrameHostGetLayer(void) const override;
|
||||
bool DelegatedFrameHostIsVisible(void) const override;
|
||||
SkColor DelegatedFrameHostGetGutterColor() const override;
|
||||
void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
|
||||
void OnBeginFrame(base::TimeTicks frame_time) override;
|
||||
void OnFrameTokenChanged(uint32_t frame_token) override;
|
||||
#endif // !defined(OS_MACOSX)
|
||||
|
||||
const viz::LocalSurfaceId& GetLocalSurfaceId() const override;
|
||||
const viz::LocalSurfaceIdAllocation& GetLocalSurfaceIdAllocation()
|
||||
const override;
|
||||
const viz::FrameSinkId& GetFrameSinkId() const override;
|
||||
|
||||
void DidNavigate() override;
|
||||
@@ -220,16 +206,13 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
|
||||
void RemoveViewProxy(OffscreenViewProxy* proxy);
|
||||
void ProxyViewDestroyed(OffscreenViewProxy* proxy) override;
|
||||
|
||||
void RegisterGuestViewFrameSwappedCallback(
|
||||
content::RenderWidgetHostViewGuest* guest_host_view);
|
||||
void OnGuestViewFrameSwapped(
|
||||
content::RenderWidgetHostViewGuest* guest_host_view);
|
||||
|
||||
void OnPaint(const gfx::Rect& damage_rect, const SkBitmap& bitmap);
|
||||
void OnPopupPaint(const gfx::Rect& damage_rect, const SkBitmap& bitmap);
|
||||
void OnProxyViewPaint(const gfx::Rect& damage_rect) override;
|
||||
|
||||
bool IsPopupWidget() const { return popup_type_ != blink::kWebPopupTypeNone; }
|
||||
bool IsPopupWidget() const {
|
||||
return widget_type_ == content::WidgetType::kPopup;
|
||||
}
|
||||
|
||||
void HoldResize();
|
||||
void ReleaseResize();
|
||||
@@ -322,7 +305,7 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
|
||||
|
||||
bool paint_callback_running_ = false;
|
||||
|
||||
viz::LocalSurfaceId local_surface_id_;
|
||||
viz::LocalSurfaceIdAllocation local_surface_id_allocation_;
|
||||
viz::ParentLocalSurfaceIdAllocator local_surface_id_allocator_;
|
||||
|
||||
std::unique_ptr<ui::Layer> root_layer_;
|
||||
@@ -349,6 +332,8 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
|
||||
|
||||
// Selected text on the renderer.
|
||||
std::string selected_text_;
|
||||
#else
|
||||
std::unique_ptr<AtomDelegatedFrameHostClient> delegated_frame_host_client_;
|
||||
#endif
|
||||
|
||||
content::MouseWheelPhaseHandler mouse_wheel_phase_handler_;
|
||||
|
||||
@@ -11,13 +11,15 @@
|
||||
#include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
|
||||
#include "ui/display/screen.h"
|
||||
|
||||
#include "components/viz/common/features.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class MacHelper : public content::BrowserCompositorMacClient,
|
||||
public ui::AcceleratedWidgetMacNSView {
|
||||
public:
|
||||
explicit MacHelper(OffScreenRenderWidgetHostView* view) : view_(view) {
|
||||
[view_->GetNativeView() setWantsLayer:YES];
|
||||
[view_->GetNativeView().GetNativeNSView() setWantsLayer:YES];
|
||||
}
|
||||
|
||||
virtual ~MacHelper() {}
|
||||
@@ -44,25 +46,14 @@ class MacHelper : public content::BrowserCompositorMacClient,
|
||||
|
||||
void DestroyCompositorForShutdown() override {}
|
||||
|
||||
bool SynchronizeVisualProperties(
|
||||
const base::Optional<viz::LocalSurfaceId>&
|
||||
child_allocated_local_surface_id) override {
|
||||
auto* browser_compositor = view_->browser_compositor();
|
||||
if (child_allocated_local_surface_id) {
|
||||
browser_compositor->UpdateRendererLocalSurfaceIdFromChild(
|
||||
*child_allocated_local_surface_id);
|
||||
} else {
|
||||
browser_compositor->AllocateNewRendererLocalSurfaceId();
|
||||
}
|
||||
|
||||
if (auto* host = browser_compositor->GetDelegatedFrameHost()) {
|
||||
host->EmbedSurface(browser_compositor->GetRendererLocalSurfaceId(),
|
||||
browser_compositor->GetRendererSize(),
|
||||
cc::DeadlinePolicy::UseDefaultDeadline());
|
||||
}
|
||||
bool OnBrowserCompositorSurfaceIdChanged() override {
|
||||
return view_->render_widget_host()->SynchronizeVisualProperties();
|
||||
}
|
||||
|
||||
std::vector<viz::SurfaceId> CollectSurfaceIdsForEviction() override {
|
||||
return view_->render_widget_host()->CollectSurfaceIdsForEviction();
|
||||
}
|
||||
|
||||
private:
|
||||
OffScreenRenderWidgetHostView* view_;
|
||||
|
||||
@@ -76,20 +67,20 @@ void OffScreenRenderWidgetHostView::ShowDefinitionForSelection() {}
|
||||
void OffScreenRenderWidgetHostView::SpeakSelection() {}
|
||||
|
||||
bool OffScreenRenderWidgetHostView::UpdateNSViewAndDisplay() {
|
||||
return browser_compositor_->UpdateNSViewAndDisplay(
|
||||
return browser_compositor_->UpdateSurfaceFromNSView(
|
||||
GetRootLayer()->bounds().size(), GetDisplay());
|
||||
}
|
||||
|
||||
bool OffScreenRenderWidgetHostView::ShouldContinueToPauseForFrame() {
|
||||
return browser_compositor_->ShouldContinueToPauseForFrame();
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::CreatePlatformWidget(
|
||||
bool is_guest_view_hack) {
|
||||
mac_helper_ = new MacHelper(this);
|
||||
browser_compositor_.reset(new content::BrowserCompositorMac(
|
||||
mac_helper_, mac_helper_, render_widget_host_->is_hidden(), GetDisplay(),
|
||||
AllocateFrameSinkId(is_guest_view_hack)));
|
||||
|
||||
if (!base::FeatureList::IsEnabled(features::kVizDisplayCompositor)) {
|
||||
SetNeedsBeginFrames(true);
|
||||
}
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::DestroyPlatformWidget() {
|
||||
@@ -132,14 +123,15 @@ display::Display OffScreenRenderWidgetHostView::GetDisplay() {
|
||||
void OffScreenRenderWidgetHostView::OnDidUpdateVisualPropertiesComplete(
|
||||
const cc::RenderFrameMetadata& metadata) {
|
||||
DCHECK_EQ(current_device_scale_factor_, metadata.device_scale_factor);
|
||||
browser_compositor_->SynchronizeVisualProperties(
|
||||
browser_compositor_->UpdateSurfaceFromChild(
|
||||
metadata.device_scale_factor, metadata.viewport_size_in_pixels,
|
||||
metadata.local_surface_id.value_or(viz::LocalSurfaceId()));
|
||||
metadata.local_surface_id_allocation.value_or(
|
||||
viz::LocalSurfaceIdAllocation()));
|
||||
}
|
||||
|
||||
const viz::LocalSurfaceId& OffScreenRenderWidgetHostView::GetLocalSurfaceId()
|
||||
const {
|
||||
return browser_compositor_->GetRendererLocalSurfaceId();
|
||||
const viz::LocalSurfaceIdAllocation&
|
||||
OffScreenRenderWidgetHostView::GetLocalSurfaceIdAllocation() const {
|
||||
return browser_compositor_->GetRendererLocalSurfaceIdAllocation();
|
||||
}
|
||||
|
||||
ui::Compositor* OffScreenRenderWidgetHostView::GetCompositor() const {
|
||||
|
||||
@@ -128,7 +128,7 @@ OffScreenWebContentsView::CreateViewForWidget(
|
||||
}
|
||||
|
||||
content::RenderWidgetHostViewBase*
|
||||
OffScreenWebContentsView::CreateViewForPopupWidget(
|
||||
OffScreenWebContentsView::CreateViewForChildWidget(
|
||||
content::RenderWidgetHost* render_widget_host) {
|
||||
content::WebContentsImpl* web_contents_impl =
|
||||
static_cast<content::WebContentsImpl*>(web_contents_);
|
||||
|
||||
@@ -57,7 +57,7 @@ class OffScreenWebContentsView : public content::WebContentsView,
|
||||
content::RenderWidgetHostViewBase* CreateViewForWidget(
|
||||
content::RenderWidgetHost* render_widget_host,
|
||||
bool is_guest_view_hack) override;
|
||||
content::RenderWidgetHostViewBase* CreateViewForPopupWidget(
|
||||
content::RenderWidgetHostViewBase* CreateViewForChildWidget(
|
||||
content::RenderWidgetHost* render_widget_host) override;
|
||||
void SetPageTitle(const base::string16& title) override;
|
||||
void RenderViewCreated(content::RenderViewHost* host) override;
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>electron.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.0.0-nightly.20190122</string>
|
||||
<string>5.0.0-beta.2</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.0.0-nightly.20190122</string>
|
||||
<string>5.0.0-beta.2</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.developer-tools</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
||||
@@ -50,8 +50,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 5,0,0,20190122
|
||||
PRODUCTVERSION 5,0,0,20190122
|
||||
FILEVERSION 5,0,0,2
|
||||
PRODUCTVERSION 5,0,0,2
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#define ATOM_MINOR_VERSION 0
|
||||
#define ATOM_PATCH_VERSION 0
|
||||
// clang-format off
|
||||
#define ATOM_PRE_RELEASE_VERSION -nightly.20190122
|
||||
#define ATOM_PRE_RELEASE_VERSION -beta.2
|
||||
// clang-format on
|
||||
|
||||
#ifndef ATOM_STRINGIFY
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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[];
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "atom/renderer/api/atom_api_web_frame.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "atom/common/api/api_messages.h"
|
||||
#include "atom/common/api/event_emitter_caller.h"
|
||||
#include "atom/common/native_mate_converters/blink_converter.h"
|
||||
@@ -29,7 +31,6 @@
|
||||
#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_view.h"
|
||||
#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
|
||||
#include "url/url_util.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
@@ -137,6 +138,26 @@ class FrameSpellChecker : public content::RenderFrameVisitor {
|
||||
|
||||
} // namespace
|
||||
|
||||
class AtomWebFrameObserver : public content::RenderFrameObserver {
|
||||
public:
|
||||
explicit AtomWebFrameObserver(
|
||||
content::RenderFrame* render_frame,
|
||||
std::unique_ptr<SpellCheckClient> spell_check_client)
|
||||
: content::RenderFrameObserver(render_frame),
|
||||
spell_check_client_(std::move(spell_check_client)) {}
|
||||
~AtomWebFrameObserver() final {}
|
||||
|
||||
// RenderFrameObserver implementation.
|
||||
void OnDestruct() final {
|
||||
spell_check_client_.reset();
|
||||
// Frame observers should delete themselves
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<SpellCheckClient> spell_check_client_;
|
||||
};
|
||||
|
||||
WebFrame::WebFrame(v8::Isolate* isolate)
|
||||
: web_frame_(blink::WebLocalFrame::FrameForCurrentContext()) {
|
||||
Init(isolate);
|
||||
@@ -229,63 +250,15 @@ void WebFrame::SetSpellCheckProvider(mate::Arguments* args,
|
||||
return;
|
||||
}
|
||||
|
||||
auto client =
|
||||
auto spell_check_client =
|
||||
std::make_unique<SpellCheckClient>(language, args->isolate(), provider);
|
||||
// Set spellchecker for all live frames in the same process or
|
||||
// in the sandbox mode for all live sub frames to this WebFrame.
|
||||
FrameSpellChecker spell_checker(
|
||||
client.get(), content::RenderFrame::FromWebFrame(web_frame_));
|
||||
auto* render_frame = content::RenderFrame::FromWebFrame(web_frame_);
|
||||
FrameSpellChecker spell_checker(spell_check_client.get(), render_frame);
|
||||
content::RenderFrame::ForEach(&spell_checker);
|
||||
spell_check_client_.swap(client);
|
||||
web_frame_->SetSpellCheckPanelHostClient(spell_check_client_.get());
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
web_frame_->SetSpellCheckPanelHostClient(spell_check_client.get());
|
||||
new AtomWebFrameObserver(render_frame, std::move(spell_check_client));
|
||||
}
|
||||
|
||||
void WebFrame::InsertText(const std::string& text) {
|
||||
@@ -500,10 +473,6 @@ void WebFrame::BuildPrototype(v8::Isolate* isolate,
|
||||
&WebFrame::AllowGuestViewElementDefinition)
|
||||
.SetMethod("getWebFrameId", &WebFrame::GetWebFrameId)
|
||||
.SetMethod("setSpellCheckProvider", &WebFrame::SetSpellCheckProvider)
|
||||
.SetMethod("registerURLSchemeAsBypassingCSP",
|
||||
&WebFrame::RegisterURLSchemeAsBypassingCSP)
|
||||
.SetMethod("registerURLSchemeAsPrivileged",
|
||||
&WebFrame::RegisterURLSchemeAsPrivileged)
|
||||
.SetMethod("insertText", &WebFrame::InsertText)
|
||||
.SetMethod("insertCSS", &WebFrame::InsertCSS)
|
||||
.SetMethod("executeJavaScript", &WebFrame::ExecuteJavaScript)
|
||||
|
||||
@@ -26,8 +26,6 @@ namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
class SpellCheckClient;
|
||||
|
||||
class WebFrame : public mate::Wrappable<WebFrame> {
|
||||
public:
|
||||
static mate::Handle<WebFrame> Create(v8::Isolate* isolate);
|
||||
@@ -59,10 +57,6 @@ class WebFrame : public mate::Wrappable<WebFrame> {
|
||||
const std::string& language,
|
||||
v8::Local<v8::Object> provider);
|
||||
|
||||
void RegisterURLSchemeAsBypassingCSP(const std::string& scheme);
|
||||
void RegisterURLSchemeAsPrivileged(const std::string& scheme,
|
||||
mate::Arguments* args);
|
||||
|
||||
// Editing.
|
||||
void InsertText(const std::string& text);
|
||||
void InsertCSS(const std::string& css);
|
||||
@@ -97,8 +91,6 @@ class WebFrame : public mate::Wrappable<WebFrame> {
|
||||
v8::Local<v8::Value> FindFrameByRoutingId(int routing_id) const;
|
||||
v8::Local<v8::Value> RoutingId() const;
|
||||
|
||||
std::unique_ptr<SpellCheckClient> spell_check_client_;
|
||||
|
||||
blink::WebLocalFrame* web_frame_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WebFrame);
|
||||
|
||||
@@ -163,6 +163,25 @@ void RendererClientBase::RenderThreadStarted() {
|
||||
blink::SchemeRegistry::RegisterURLSchemeAsSecure(
|
||||
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.
|
||||
// FIXME(zcbenz): Can this be moved elsewhere?
|
||||
blink::WebSecurityPolicy::RegisterURLSchemeAsAllowingServiceWorkers("file");
|
||||
|
||||
@@ -8,7 +8,7 @@ declare_args() {
|
||||
# Allow running Electron as a node binary.
|
||||
enable_run_as_node = true
|
||||
|
||||
enable_osr = false
|
||||
enable_osr = true
|
||||
|
||||
enable_view_api = false
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
## 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)
|
||||
|
||||
The following list includes the breaking API changes planned for Electron 4.0.
|
||||
|
||||
@@ -12,7 +12,6 @@ result.
|
||||
**Note:** You should not use this module until the `ready` event of the app
|
||||
module is emitted.
|
||||
|
||||
|
||||
```javascript
|
||||
const { app, contentTracing } = require('electron')
|
||||
|
||||
@@ -43,11 +42,18 @@ The `contentTracing` module has the following methods:
|
||||
* `callback` Function
|
||||
* `categories` String[]
|
||||
|
||||
Get a set of category groups. The category groups can change as new code paths
|
||||
are reached.
|
||||
Get a set of category groups. The category groups can change as new code paths are reached.
|
||||
|
||||
Once all child processes have acknowledged the `getCategories` request the `callback` is invoked with an array of category groups.
|
||||
|
||||
**[Deprecated Soon](promisification.md)**
|
||||
|
||||
### `contentTracing.getCategories()`
|
||||
|
||||
Returns `Promise<String[]>` - resolves with an array of category groups once all child processes have acknowledged the `getCategories` request
|
||||
|
||||
Get a set of category groups. The category groups can change as new code paths are reached.
|
||||
|
||||
Once all child processes have acknowledged the `getCategories` request the
|
||||
`callback` is invoked with an array of category groups.
|
||||
|
||||
### `contentTracing.startRecording(options, callback)`
|
||||
|
||||
@@ -60,6 +66,19 @@ Recording begins immediately locally and asynchronously on child processes
|
||||
as soon as they receive the EnableRecording request. The `callback` will be
|
||||
called once all child processes have acknowledged the `startRecording` request.
|
||||
|
||||
**[Deprecated Soon](promisification.md)**
|
||||
|
||||
### `contentTracing.startRecording(options)`
|
||||
|
||||
* `options` ([TraceCategoriesAndOptions](structures/trace-categories-and-options.md) | [TraceConfig](structures/trace-config.md))
|
||||
|
||||
Returns `Promise<void>` - resolved once all child processes have acknowledged the `startRecording` request.
|
||||
|
||||
Start recording on all processes.
|
||||
|
||||
Recording begins immediately locally and asynchronously on child processes
|
||||
as soon as they receive the EnableRecording request.
|
||||
|
||||
### `contentTracing.stopRecording(resultFilePath, callback)`
|
||||
|
||||
* `resultFilePath` String
|
||||
@@ -81,47 +100,24 @@ Trace data will be written into `resultFilePath` if it is not empty or into a
|
||||
temporary file. The actual file path will be passed to `callback` if it's not
|
||||
`null`.
|
||||
|
||||
### `contentTracing.startMonitoring(options, callback)`
|
||||
**[Deprecated Soon](promisification.md)**
|
||||
|
||||
* `options` Object
|
||||
* `categoryFilter` String
|
||||
* `traceOptions` String
|
||||
* `callback` Function
|
||||
|
||||
Start monitoring on all processes.
|
||||
|
||||
Monitoring begins immediately locally and asynchronously on child processes as
|
||||
soon as they receive the `startMonitoring` request.
|
||||
|
||||
Once all child processes have acknowledged the `startMonitoring` request the
|
||||
`callback` will be called.
|
||||
|
||||
### `contentTracing.stopMonitoring(callback)`
|
||||
|
||||
* `callback` Function
|
||||
|
||||
Stop monitoring on all processes.
|
||||
|
||||
Once all child processes have acknowledged the `stopMonitoring` request the
|
||||
`callback` is called.
|
||||
|
||||
### `contentTracing.captureMonitoringSnapshot(resultFilePath, callback)`
|
||||
### `contentTracing.stopRecording(resultFilePath)`
|
||||
|
||||
* `resultFilePath` String
|
||||
* `callback` Function
|
||||
* `resultFilePath` String
|
||||
|
||||
Get the current monitoring traced data.
|
||||
Returns `Promise<String>` - resolves with a file that contains the traced data once all child processes have acknowledged the `stopRecording` request
|
||||
|
||||
Stop recording on all processes.
|
||||
|
||||
Child processes typically cache trace data and only rarely flush and send
|
||||
trace data back to the main process. This is because it may be an expensive
|
||||
operation to send the trace data over IPC and we would like to avoid unneeded
|
||||
runtime overhead from tracing. So, to end tracing, we must asynchronously ask
|
||||
all child processes to flush any pending trace data.
|
||||
|
||||
Once all child processes have acknowledged the `captureMonitoringSnapshot`
|
||||
request the `callback` will be called with a file that contains the traced data.
|
||||
trace data back to the main process. This helps to minimize the runtime overhead
|
||||
of tracing since sending trace data over IPC can be an expensive operation. So,
|
||||
to end tracing, we must asynchronously ask all child processes to flush any
|
||||
pending trace data.
|
||||
|
||||
Trace data will be written into `resultFilePath` if it is not empty or into a
|
||||
temporary file.
|
||||
|
||||
### `contentTracing.getTraceBufferUsage(callback)`
|
||||
|
||||
|
||||
@@ -13,21 +13,30 @@ For example:
|
||||
const { session } = require('electron')
|
||||
|
||||
// Query all cookies.
|
||||
session.defaultSession.cookies.get({}, (error, cookies) => {
|
||||
console.log(error, cookies)
|
||||
})
|
||||
session.defaultSession.cookies.get({})
|
||||
.then((cookies) => {
|
||||
console.log(cookies)
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
// Query all cookies associated with a specific url.
|
||||
session.defaultSession.cookies.get({ url: 'http://www.github.com' }, (error, cookies) => {
|
||||
console.log(error, cookies)
|
||||
})
|
||||
session.defaultSession.cookies.get({ url: 'http://www.github.com' })
|
||||
.then((cookies) => {
|
||||
console.log(cookies)
|
||||
}).catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
// Set a cookie with the given cookie data;
|
||||
// may overwrite equivalent cookies if they exist.
|
||||
const cookie = { url: 'http://www.github.com', name: 'dummy_name', value: 'dummy' }
|
||||
session.defaultSession.cookies.set(cookie, (error) => {
|
||||
if (error) console.error(error)
|
||||
})
|
||||
session.defaultSession.cookies.set(cookie)
|
||||
.then(() => {
|
||||
// success
|
||||
}, (error) => {
|
||||
console.error(error)
|
||||
})
|
||||
```
|
||||
|
||||
### Instance Events
|
||||
@@ -55,6 +64,23 @@ expired.
|
||||
|
||||
The following methods are available on instances of `Cookies`:
|
||||
|
||||
#### `cookies.get(filter)`
|
||||
|
||||
* `filter` Object
|
||||
* `url` String (optional) - Retrieves cookies which are associated with
|
||||
`url`. Empty implies retrieving cookies of all urls.
|
||||
* `name` String (optional) - Filters cookies by name.
|
||||
* `domain` String (optional) - Retrieves cookies whose domains match or are
|
||||
subdomains of `domains`.
|
||||
* `path` String (optional) - Retrieves cookies whose path matches `path`.
|
||||
* `secure` Boolean (optional) - Filters cookies by their Secure property.
|
||||
* `session` Boolean (optional) - Filters out session or persistent cookies.
|
||||
|
||||
Returns `Promise<Cookie[]>` - A promise which resolves an array of cookie objects.
|
||||
|
||||
Sends a request to get all cookies matching `filter`, and resolves a promise with
|
||||
the response.
|
||||
|
||||
#### `cookies.get(filter, callback)`
|
||||
|
||||
* `filter` Object
|
||||
@@ -73,6 +99,28 @@ The following methods are available on instances of `Cookies`:
|
||||
Sends a request to get all cookies matching `filter`, `callback` will be called
|
||||
with `callback(error, cookies)` on complete.
|
||||
|
||||
**[Deprecated Soon](promisification.md)**
|
||||
|
||||
#### `cookies.set(details)`
|
||||
|
||||
* `details` Object
|
||||
* `url` String - The url to associate the cookie with.
|
||||
* `name` String (optional) - The name of the cookie. Empty by default if omitted.
|
||||
* `value` String (optional) - The value of the cookie. Empty by default if omitted.
|
||||
* `domain` String (optional) - The domain of the cookie. Empty by default if omitted.
|
||||
* `path` String (optional) - The path of the cookie. Empty by default if omitted.
|
||||
* `secure` Boolean (optional) - Whether the cookie should be marked as Secure. Defaults to
|
||||
false.
|
||||
* `httpOnly` Boolean (optional) - Whether the cookie should be marked as HTTP only.
|
||||
Defaults to false.
|
||||
* `expirationDate` Double (optional) - The expiration date of the cookie as the number of
|
||||
seconds since the UNIX epoch. If omitted then the cookie becomes a session
|
||||
cookie and will not be retained between sessions.
|
||||
|
||||
Returns `Promise<void>` - A promise which resolves when the cookie has been set
|
||||
|
||||
Sets a cookie with `details`.
|
||||
|
||||
#### `cookies.set(details, callback)`
|
||||
|
||||
* `details` Object
|
||||
@@ -94,6 +142,17 @@ with `callback(error, cookies)` on complete.
|
||||
Sets a cookie with `details`, `callback` will be called with `callback(error)`
|
||||
on complete.
|
||||
|
||||
**[Deprecated Soon](promisification.md)**
|
||||
|
||||
#### `cookies.remove(url, name)`
|
||||
|
||||
* `url` String - The URL associated with the cookie.
|
||||
* `name` String - The name of cookie to remove.
|
||||
|
||||
Returns `Promise<void>` - A promise which resolves when the cookie has been removed
|
||||
|
||||
Removes the cookies matching `url` and `name`
|
||||
|
||||
#### `cookies.remove(url, name, callback)`
|
||||
|
||||
* `url` String - The URL associated with the cookie.
|
||||
@@ -103,8 +162,18 @@ on complete.
|
||||
Removes the cookies matching `url` and `name`, `callback` will called with
|
||||
`callback()` on complete.
|
||||
|
||||
**[Deprecated Soon](promisification.md)**
|
||||
|
||||
#### `cookies.flushStore()`
|
||||
|
||||
Returns `Promise<void>` - A promise which resolves when the cookie store has been flushed
|
||||
|
||||
Writes any unwritten cookies data to disk.
|
||||
|
||||
#### `cookies.flushStore(callback)`
|
||||
|
||||
* `callback` Function
|
||||
|
||||
Writes any unwritten cookies data to disk.
|
||||
|
||||
**[Deprecated Soon](promisification.md)**
|
||||
|
||||
@@ -269,7 +269,7 @@ const { remote } = require('electron')
|
||||
const { Menu, MenuItem } = remote
|
||||
|
||||
const menu = new Menu()
|
||||
menu.append(new MenuItem({ label: 'MenuItem1', click() { console.log('item 1 clicked') } })))
|
||||
menu.append(new MenuItem({ label: 'MenuItem1', click() { console.log('item 1 clicked') } }))
|
||||
menu.append(new MenuItem({ type: 'separator' }))
|
||||
menu.append(new MenuItem({ label: 'MenuItem2', type: 'checkbox', checked: true }))
|
||||
|
||||
|
||||
@@ -11,17 +11,7 @@ When a majority of affected functions are migrated, this flag will be enabled by
|
||||
- [app.importCertificate(options, callback)](https://github.com/electron/electron/blob/master/docs/api/app.md#importCertificate)
|
||||
- [request.write(chunk[, encoding][, callback])](https://github.com/electron/electron/blob/master/docs/api/client-request.md#write)
|
||||
- [request.end([chunk][, encoding][, callback])](https://github.com/electron/electron/blob/master/docs/api/client-request.md#end)
|
||||
- [contentTracing.getCategories(callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#getCategories)
|
||||
- [contentTracing.startRecording(options, callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#startRecording)
|
||||
- [contentTracing.stopRecording(resultFilePath, callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#stopRecording)
|
||||
- [contentTracing.startMonitoring(options, callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#startMonitoring)
|
||||
- [contentTracing.stopMonitoring(callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#stopMonitoring)
|
||||
- [contentTracing.captureMonitoringSnapshot(resultFilePath, callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#captureMonitoringSnapshot)
|
||||
- [contentTracing.getTraceBufferUsage(callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#getTraceBufferUsage)
|
||||
- [cookies.get(filter, callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#get)
|
||||
- [cookies.set(details, callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#set)
|
||||
- [cookies.remove(url, name, callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#remove)
|
||||
- [cookies.flushStore(callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#flushStore)
|
||||
- [debugger.sendCommand(method[, commandParams, callback])](https://github.com/electron/electron/blob/master/docs/api/debugger.md#sendCommand)
|
||||
- [dialog.showOpenDialog([browserWindow, ]options[, callback])](https://github.com/electron/electron/blob/master/docs/api/dialog.md#showOpenDialog)
|
||||
- [dialog.showSaveDialog([browserWindow, ]options[, callback])](https://github.com/electron/electron/blob/master/docs/api/dialog.md#showSaveDialog)
|
||||
@@ -52,10 +42,17 @@ When a majority of affected functions are migrated, this flag will be enabled by
|
||||
|
||||
### Converted Functions
|
||||
|
||||
- [win.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/browser-window.md#capturePage)
|
||||
- [webviewTag.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#capturePage)
|
||||
- [contents.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#capturePage)
|
||||
- [app.getFileIcon(path[, options], callback)](https://github.com/electron/electron/blob/master/docs/api/app.md#getFileIcon)
|
||||
- [shell.openExternal(url[, options, callback])](https://github.com/electron/electron/blob/master/docs/api/shell.md#openExternal)
|
||||
- [contents.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#capturePage)
|
||||
- [contentTracing.getCategories(callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#getCategories)
|
||||
- [contentTracing.startRecording(options, callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#startRecording)
|
||||
- [contentTracing.stopRecording(resultFilePath, callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#stopRecording)
|
||||
- [cookies.flushStore(callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#flushStore)
|
||||
- [cookies.get(filter, callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#get)
|
||||
- [cookies.remove(url, name, callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#remove)
|
||||
- [cookies.set(details, callback)](https://github.com/electron/electron/blob/master/docs/api/cookies.md#set)
|
||||
- [desktopCapturer.getSources(options, callback)](https://github.com/electron/electron/blob/master/docs/api/desktop-capturer.md#getSources)
|
||||
- [protocol.isProtocolHandled(scheme, callback)](https://github.com/electron/electron/blob/master/docs/api/protocol.md#isProtocolHandled)
|
||||
- [desktopCapturer.getSources(options, callback)](https://github.com/electron/electron/blob/master/docs/api/desktop-capturer.md#getSources)
|
||||
- [shell.openExternal(url[, options, callback])](https://github.com/electron/electron/blob/master/docs/api/shell.md#openExternal)
|
||||
- [webviewTag.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#capturePage)
|
||||
- [win.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/browser-window.md#capturePage)
|
||||
|
||||
@@ -28,12 +28,26 @@ of the `app` module gets emitted.
|
||||
|
||||
The `protocol` module has the following methods:
|
||||
|
||||
### `protocol.registerStandardSchemes(schemes[, options])`
|
||||
### `protocol.registerSchemesAsPrivileged(customSchemes)`
|
||||
|
||||
* `schemes` String[] - Custom schemes to be registered as standard schemes.
|
||||
* `options` Object (optional)
|
||||
* `secure` Boolean (optional) - `true` to register the scheme as secure.
|
||||
Default `false`.
|
||||
* `customSchemes` [CustomScheme[]](structures/custom-scheme.md)
|
||||
|
||||
|
||||
**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 a privilege 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', privileges: { bypassCSP: true } }
|
||||
])
|
||||
```
|
||||
|
||||
A standard scheme adheres to what RFC 3986 calls [generic URI
|
||||
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)
|
||||
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:
|
||||
|
||||
```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.
|
||||
custom protocol to replace the `http` protocol, you have to register it as a standard scheme.
|
||||
|
||||
### `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.
|
||||
* `privileges` 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)`
|
||||
|
||||
* `text` String
|
||||
|
||||
@@ -32,7 +32,7 @@ const filter = {
|
||||
|
||||
session.defaultSession.webRequest.onBeforeSendHeaders(filter, (details, callback) => {
|
||||
details.requestHeaders['User-Agent'] = 'MyAgent'
|
||||
callback({ cancel: false, requestHeaders: details.requestHeaders })
|
||||
callback({ requestHeaders: details.requestHeaders })
|
||||
})
|
||||
```
|
||||
|
||||
@@ -130,7 +130,7 @@ response are visible by the time this listener is fired.
|
||||
* `responseHeaders` Object
|
||||
* `callback` Function
|
||||
* `response` Object
|
||||
* `cancel` Boolean
|
||||
* `cancel` Boolean (optional)
|
||||
* `responseHeaders` Object (optional) - When provided, the server is assumed
|
||||
to have responded with these headers.
|
||||
* `statusLine` String (optional) - Should be provided when overriding
|
||||
@@ -200,6 +200,7 @@ redirect is about to occur.
|
||||
* `method` String
|
||||
* `webContentsId` Integer (optional)
|
||||
* `resourceType` String
|
||||
* `referrer` String
|
||||
* `timestamp` Double
|
||||
* `responseHeaders` Object
|
||||
* `fromCache` Boolean
|
||||
|
||||
@@ -36,7 +36,7 @@ Object.assign(app, {
|
||||
}
|
||||
})
|
||||
|
||||
app.getFileIcon = deprecate.promisify(app.getFileIcon, 3)
|
||||
app.getFileIcon = deprecate.promisify(app.getFileIcon)
|
||||
|
||||
const nativeAppMetrics = app.getAppMetrics
|
||||
app.getAppMetrics = () => {
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
'use strict'
|
||||
const { deprecate } = require('electron')
|
||||
const contentTracing = process.atomBinding('content_tracing')
|
||||
|
||||
module.exports = process.atomBinding('content_tracing')
|
||||
contentTracing.startRecording = deprecate.promisify(contentTracing.startRecording)
|
||||
contentTracing.stopRecording = deprecate.promisify(contentTracing.stopRecording)
|
||||
contentTracing.getCategories = deprecate.promisify(contentTracing.getCategories)
|
||||
|
||||
module.exports = contentTracing
|
||||
|
||||
@@ -2,7 +2,22 @@
|
||||
|
||||
const { EventEmitter } = require('events')
|
||||
const { app, deprecate } = require('electron')
|
||||
const { fromPartition, Session, Cookies } = process.atomBinding('session')
|
||||
const { Session, Cookies } = process.atomBinding('session')
|
||||
const realFromPartition = process.atomBinding('session').fromPartition
|
||||
|
||||
const wrappedSymbol = Symbol('wrapped-deprecate')
|
||||
const fromPartition = (partition) => {
|
||||
const session = realFromPartition(partition)
|
||||
if (!session[wrappedSymbol]) {
|
||||
session[wrappedSymbol] = true
|
||||
const { cookies } = session
|
||||
cookies.flushStore = deprecate.promisify(cookies.flushStore)
|
||||
cookies.get = deprecate.promisify(cookies.get)
|
||||
cookies.remove = deprecate.promisify(cookies.remove)
|
||||
cookies.set = deprecate.promisify(cookies.set)
|
||||
}
|
||||
return session
|
||||
}
|
||||
|
||||
// Public API.
|
||||
Object.defineProperties(exports, {
|
||||
@@ -20,6 +35,6 @@ Object.setPrototypeOf(Session.prototype, EventEmitter.prototype)
|
||||
Object.setPrototypeOf(Cookies.prototype, EventEmitter.prototype)
|
||||
|
||||
Session.prototype._init = function () {
|
||||
this.protocol.isProtocolHandled = deprecate.promisify(this.protocol.isProtocolHandled, 2)
|
||||
this.protocol.isProtocolHandled = deprecate.promisify(this.protocol.isProtocolHandled)
|
||||
app.emit('session-created', this)
|
||||
}
|
||||
|
||||
@@ -358,6 +358,17 @@ const addReplyInternalToEvent = (event) => {
|
||||
})
|
||||
}
|
||||
|
||||
const safeProtocols = new Set([
|
||||
'chrome-devtools:',
|
||||
'chrome-extension:'
|
||||
])
|
||||
|
||||
const isWebContentsTrusted = function (contents) {
|
||||
const pageURL = contents._getURL()
|
||||
const { protocol } = url.parse(pageURL)
|
||||
return safeProtocols.has(protocol)
|
||||
}
|
||||
|
||||
// Add JavaScript wrappers for WebContents class.
|
||||
WebContents.prototype._init = function () {
|
||||
// The navigation controller.
|
||||
@@ -367,7 +378,7 @@ WebContents.prototype._init = function () {
|
||||
// render-view-deleted event, so ignore the listeners warning.
|
||||
this.setMaxListeners(0)
|
||||
|
||||
this.capturePage = deprecate.promisify(this.capturePage, 2)
|
||||
this.capturePage = deprecate.promisify(this.capturePage)
|
||||
|
||||
// Dispatch IPC messages to the ipc module.
|
||||
this.on('-ipc-message', function (event, [channel, ...args]) {
|
||||
@@ -428,7 +439,9 @@ WebContents.prototype._init = function () {
|
||||
|
||||
for (const eventName of forwardedEvents) {
|
||||
this.on(eventName, (event, ...args) => {
|
||||
app.emit(eventName, event, this, ...args)
|
||||
if (!isWebContentsTrusted(event.sender)) {
|
||||
app.emit(eventName, event, this, ...args)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -441,7 +454,7 @@ WebContents.prototype._init = function () {
|
||||
})
|
||||
|
||||
// Handle window.open for BrowserWindow and BrowserView.
|
||||
if (['browserview', 'window'].includes(this.getType())) {
|
||||
if (['browserView', 'window'].includes(this.getType())) {
|
||||
// Make new windows requested by links behave like "window.open".
|
||||
this.on('-new-window', (event, url, frameName, disposition,
|
||||
additionalFeatures, postData,
|
||||
|
||||
@@ -534,8 +534,7 @@ ipcMain.on('ELECTRON_BROWSER_CLIPBOARD_WRITE_FIND_TEXT', function (event, text)
|
||||
setReturnValue(event, () => electron.clipboard.writeFindText(text))
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_SANDBOX_LOAD', function (event) {
|
||||
const preloadPath = event.sender._getPreloadPath()
|
||||
const getPreloadScript = function (preloadPath) {
|
||||
let preloadSrc = null
|
||||
let preloadError = null
|
||||
if (preloadPath) {
|
||||
@@ -545,10 +544,17 @@ ipcMain.on('ELECTRON_BROWSER_SANDBOX_LOAD', function (event) {
|
||||
preloadError = errorUtils.serialize(err)
|
||||
}
|
||||
}
|
||||
return { preloadPath, preloadSrc, preloadError }
|
||||
}
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_SANDBOX_LOAD', function (event) {
|
||||
const preloadPaths = [
|
||||
...(event.sender.session ? event.sender.session.getPreloads() : []),
|
||||
event.sender._getPreloadPath()
|
||||
]
|
||||
|
||||
event.returnValue = {
|
||||
preloadPath,
|
||||
preloadSrc,
|
||||
preloadError,
|
||||
preloadScripts: preloadPaths.map(path => getPreloadScript(path)),
|
||||
isRemoteModuleEnabled: event.sender._isRemoteModuleEnabled(),
|
||||
isWebViewTagEnabled: guestViewManager.isWebViewTagEnabled(event.sender),
|
||||
process: {
|
||||
|
||||
@@ -69,27 +69,27 @@ const deprecate = {
|
||||
})
|
||||
},
|
||||
|
||||
promisify: (fn, cbParamIndex) => {
|
||||
promisify: (fn) => {
|
||||
const fnName = fn.name || 'function'
|
||||
const oldName = `${fnName} with callbacks`
|
||||
const newName = `${fnName} with Promises`
|
||||
const warn = warnOnce(oldName, newName)
|
||||
|
||||
return function (...params) {
|
||||
const cb = params.splice(cbParamIndex, 1)[0]
|
||||
let cb
|
||||
if (params.length > 0 && typeof params[params.length - 1] === 'function') {
|
||||
cb = params.pop()
|
||||
}
|
||||
const promise = fn.apply(this, params)
|
||||
|
||||
if (typeof cb !== 'function') return promise
|
||||
if (!cb) return promise
|
||||
if (process.enablePromiseAPIs) warn()
|
||||
return promise
|
||||
.then(res => {
|
||||
process.nextTick(() => {
|
||||
cb(null, res)
|
||||
cb.length === 2 ? cb(null, res) : cb(res)
|
||||
})
|
||||
}, err => {
|
||||
process.nextTick(() => {
|
||||
cb(err)
|
||||
})
|
||||
process.nextTick(() => cb(err))
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
@@ -56,4 +56,4 @@ const getSources = (options) => {
|
||||
})
|
||||
}
|
||||
|
||||
exports.getSources = deprecate.promisify(getSources, 1)
|
||||
exports.getSources = deprecate.promisify(getSources)
|
||||
|
||||
@@ -17,7 +17,7 @@ function handleFocusBlur (guestInstanceId) {
|
||||
}
|
||||
|
||||
module.exports = function (contextIsolation, webviewTag, guestInstanceId) {
|
||||
// Load webview tag implementation.
|
||||
// Don't allow recursive `<webview>`.
|
||||
if (webviewTag && guestInstanceId == null) {
|
||||
const webViewImpl = require('@electron/internal/renderer/web-view/web-view-impl')
|
||||
if (contextIsolation) {
|
||||
|
||||
@@ -29,7 +29,7 @@ Object.setPrototypeOf(process, EventEmitter.prototype)
|
||||
const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal')
|
||||
|
||||
const {
|
||||
preloadPath, preloadSrc, preloadError, isRemoteModuleEnabled, isWebViewTagEnabled, process: processProps
|
||||
preloadScripts, isRemoteModuleEnabled, isWebViewTagEnabled, process: processProps
|
||||
} = ipcRenderer.sendSync('ELECTRON_BROWSER_SANDBOX_LOAD')
|
||||
|
||||
process.isRemoteModuleEnabled = isRemoteModuleEnabled
|
||||
@@ -127,7 +127,9 @@ switch (window.location.protocol) {
|
||||
const guestInstanceId = binding.guestInstanceId && parseInt(binding.guestInstanceId)
|
||||
|
||||
// Load webview tag implementation.
|
||||
require('@electron/internal/renderer/web-view/web-view-init')(contextIsolation, isWebViewTagEnabled, guestInstanceId)
|
||||
if (process.isMainFrame) {
|
||||
require('@electron/internal/renderer/web-view/web-view-init')(contextIsolation, isWebViewTagEnabled, guestInstanceId)
|
||||
}
|
||||
|
||||
const errorUtils = require('@electron/internal/common/error-utils')
|
||||
|
||||
@@ -162,18 +164,22 @@ function runPreloadScript (preloadSrc) {
|
||||
preloadFn(preloadRequire, preloadProcess, Buffer, global, setImmediate, clearImmediate)
|
||||
}
|
||||
|
||||
try {
|
||||
if (preloadSrc) {
|
||||
runPreloadScript(preloadSrc)
|
||||
} else if (preloadError) {
|
||||
throw errorUtils.deserialize(preloadError)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Unable to load preload script: ${preloadPath}`)
|
||||
console.error(`${error}`)
|
||||
for (const { preloadPath, preloadSrc, preloadError } of preloadScripts) {
|
||||
try {
|
||||
if (preloadSrc) {
|
||||
runPreloadScript(preloadSrc)
|
||||
} else if (preloadError) {
|
||||
throw errorUtils.deserialize(preloadError)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Unable to load preload script: ${preloadPath}`)
|
||||
console.error(`${error}`)
|
||||
|
||||
ipcRenderer.send('ELECTRON_BROWSER_PRELOAD_ERROR', preloadPath, errorUtils.serialize(error))
|
||||
ipcRenderer.send('ELECTRON_BROWSER_PRELOAD_ERROR', preloadPath, errorUtils.serialize(error))
|
||||
}
|
||||
}
|
||||
|
||||
// Warn about security issues
|
||||
require('@electron/internal/renderer/security-warnings')()
|
||||
if (process.isMainFrame) {
|
||||
require('@electron/internal/renderer/security-warnings')()
|
||||
}
|
||||
|
||||
27
package-lock.json
generated
27
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "5.0.0-nightly.20190122",
|
||||
"version": "5.0.0-beta.2",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -2951,9 +2951,9 @@
|
||||
}
|
||||
},
|
||||
"electron-typescript-definitions": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/electron-typescript-definitions/-/electron-typescript-definitions-4.0.0.tgz",
|
||||
"integrity": "sha512-UekaKgK8omivfj37xs1G09j5MctHCFSyPYvW67j30xYHVCvgjDLur1Vqd7CaaJCDuaYLsHjsmms4QjG8uOFb4A==",
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/electron-typescript-definitions/-/electron-typescript-definitions-6.0.0.tgz",
|
||||
"integrity": "sha512-W2CHJ1bUtbDXXzIAEbQ+s2XewpSdUUqNECJmhniV0GbPoIhwjAg90++BkMxH6wPBxHWOxesvUMipUEeJN9+wlQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "^7.0.18",
|
||||
@@ -4384,7 +4384,8 @@
|
||||
"version": "2.1.1",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
@@ -4849,7 +4850,8 @@
|
||||
"version": "5.1.1",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
@@ -4913,6 +4915,7 @@
|
||||
"resolved": false,
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
@@ -4961,13 +4964,15 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.2",
|
||||
"resolved": false,
|
||||
"integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -13104,9 +13109,9 @@
|
||||
}
|
||||
},
|
||||
"write-file-atomic": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz",
|
||||
"integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==",
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.2.tgz",
|
||||
"integrity": "sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.11",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "5.0.0-nightly.20190122",
|
||||
"version": "5.0.0-beta.2",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
@@ -16,7 +16,7 @@
|
||||
"dotenv-safe": "^4.0.4",
|
||||
"dugite": "^1.45.0",
|
||||
"electron-docs-linter": "^2.4.0",
|
||||
"electron-typescript-definitions": "^4.0.0",
|
||||
"electron-typescript-definitions": "^6.0.0",
|
||||
"eslint": "^5.6.0",
|
||||
"eslint-config-standard": "^12.0.0",
|
||||
"eslint-plugin-mocha": "^5.2.0",
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
add_ec_group_order_bits_for_openssl_compatibility.patch
|
||||
add_ec_key_key2buf_for_openssl_compatibility.patch
|
||||
expose_ripemd160.patch
|
||||
expose_aes-cfb.patch
|
||||
|
||||
84
patches/common/boringssl/expose_aes-cfb.patch
Normal file
84
patches/common/boringssl/expose_aes-cfb.patch
Normal file
@@ -0,0 +1,84 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jeremy Apthorp <nornagon@nornagon.net>
|
||||
Date: Fri, 18 Jan 2019 14:23:28 -0800
|
||||
Subject: expose aes-{128,256}-cfb
|
||||
|
||||
|
||||
diff --git a/crypto/cipher_extra/cipher_extra.c b/crypto/cipher_extra/cipher_extra.c
|
||||
index 1b23ad32f8cff2a00512ba58d24b47b628e7920c..be7ef07b2c188a76890deb0f305cf92fcc57a64e 100644
|
||||
--- a/crypto/cipher_extra/cipher_extra.c
|
||||
+++ b/crypto/cipher_extra/cipher_extra.c
|
||||
@@ -101,10 +101,14 @@ const EVP_CIPHER *EVP_get_cipherbyname(const char *name) {
|
||||
return EVP_des_ede3_cbc();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-128-cbc") == 0) {
|
||||
return EVP_aes_128_cbc();
|
||||
+ } else if (OPENSSL_strcasecmp(name, "aes-128-cfb") == 0) {
|
||||
+ return EVP_aes_128_cfb128();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-192-cbc") == 0) {
|
||||
return EVP_aes_192_cbc();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-256-cbc") == 0) {
|
||||
return EVP_aes_256_cbc();
|
||||
+ } else if (OPENSSL_strcasecmp(name, "aes-256-cfb") == 0) {
|
||||
+ return EVP_aes_256_cfb128();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-128-ctr") == 0) {
|
||||
return EVP_aes_128_ctr();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-192-ctr") == 0) {
|
||||
diff --git a/decrepit/cfb/cfb.c b/decrepit/cfb/cfb.c
|
||||
index d3a176163303a202baeb1f95727c6ed3525439d6..21d108a7b73d454aa6b0e324df4b67088d60302a 100644
|
||||
--- a/decrepit/cfb/cfb.c
|
||||
+++ b/decrepit/cfb/cfb.c
|
||||
@@ -57,4 +57,12 @@ static const EVP_CIPHER aes_128_cfb128 = {
|
||||
NULL /* cleanup */, NULL /* ctrl */,
|
||||
};
|
||||
|
||||
+static const EVP_CIPHER aes_256_cfb128 = {
|
||||
+ NID_aes_128_cfb128, 1 /* block_size */, 32 /* key_size */,
|
||||
+ 16 /* iv_len */, sizeof(EVP_CFB_CTX), EVP_CIPH_CFB_MODE,
|
||||
+ NULL /* app_data */, aes_cfb_init_key, aes_cfb128_cipher,
|
||||
+ NULL /* cleanup */, NULL /* ctrl */,
|
||||
+};
|
||||
+
|
||||
const EVP_CIPHER *EVP_aes_128_cfb128(void) { return &aes_128_cfb128; }
|
||||
+const EVP_CIPHER *EVP_aes_256_cfb128(void) { return &aes_256_cfb128; }
|
||||
diff --git a/decrepit/evp/evp_do_all.c b/decrepit/evp/evp_do_all.c
|
||||
index acc4719b7e9c4c4461fc6142f2ae9156b407915b..8b008a401ec2f2d0673f6876609dd5786cace4c2 100644
|
||||
--- a/decrepit/evp/evp_do_all.c
|
||||
+++ b/decrepit/evp/evp_do_all.c
|
||||
@@ -20,10 +20,12 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher,
|
||||
const char *unused, void *arg),
|
||||
void *arg) {
|
||||
callback(EVP_aes_128_cbc(), "AES-128-CBC", NULL, arg);
|
||||
+ callback(EVP_aes_128_cfb128(), "AES-128-CFB", NULL, arg);
|
||||
callback(EVP_aes_128_ctr(), "AES-128-CTR", NULL, arg);
|
||||
callback(EVP_aes_128_ecb(), "AES-128-ECB", NULL, arg);
|
||||
callback(EVP_aes_128_ofb(), "AES-128-OFB", NULL, arg);
|
||||
callback(EVP_aes_256_cbc(), "AES-256-CBC", NULL, arg);
|
||||
+ callback(EVP_aes_256_cfb128(), "AES-256-CFB", NULL, arg);
|
||||
callback(EVP_aes_256_ctr(), "AES-256-CTR", NULL, arg);
|
||||
callback(EVP_aes_256_ecb(), "AES-256-ECB", NULL, arg);
|
||||
callback(EVP_aes_256_ofb(), "AES-256-OFB", NULL, arg);
|
||||
@@ -38,10 +40,12 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher,
|
||||
|
||||
// OpenSSL returns everything twice, the second time in lower case.
|
||||
callback(EVP_aes_128_cbc(), "aes-128-cbc", NULL, arg);
|
||||
+ callback(EVP_aes_128_cfb128(), "aes-128-cfb", NULL, arg);
|
||||
callback(EVP_aes_128_ctr(), "aes-128-ctr", NULL, arg);
|
||||
callback(EVP_aes_128_ecb(), "aes-128-ecb", NULL, arg);
|
||||
callback(EVP_aes_128_ofb(), "aes-128-ofb", NULL, arg);
|
||||
callback(EVP_aes_256_cbc(), "aes-256-cbc", NULL, arg);
|
||||
+ callback(EVP_aes_256_cfb128(), "aes-256-cfb", NULL, arg);
|
||||
callback(EVP_aes_256_ctr(), "aes-256-ctr", NULL, arg);
|
||||
callback(EVP_aes_256_ecb(), "aes-256-ecb", NULL, arg);
|
||||
callback(EVP_aes_256_ofb(), "aes-256-ofb", NULL, arg);
|
||||
diff --git a/include/openssl/cipher.h b/include/openssl/cipher.h
|
||||
index 59634138cb60237f008eb99e7d8df54da7629c1a..b30b8434b301fb5b8630ae954698b6fee255df77 100644
|
||||
--- a/include/openssl/cipher.h
|
||||
+++ b/include/openssl/cipher.h
|
||||
@@ -421,6 +421,7 @@ OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_192_ofb(void);
|
||||
|
||||
// EVP_aes_128_cfb128 is only available in decrepit.
|
||||
OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_cfb128(void);
|
||||
+OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_cfb128(void);
|
||||
|
||||
// The following flags do nothing and are included only to make it easier to
|
||||
// compile code with BoringSSL.
|
||||
95
patches/common/boringssl/expose_ripemd160.patch
Normal file
95
patches/common/boringssl/expose_ripemd160.patch
Normal file
@@ -0,0 +1,95 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jeremy Apthorp <nornagon@nornagon.net>
|
||||
Date: Fri, 18 Jan 2019 13:56:52 -0800
|
||||
Subject: expose ripemd160
|
||||
|
||||
This adds references to the decrepit/ module from non-decrepit source,
|
||||
which is not allowed in upstream. Until upstream has a way to interface
|
||||
with node.js that allows exposing additional digests without patching,
|
||||
this patch is required to provide ripemd160 support in the nodejs crypto
|
||||
module.
|
||||
|
||||
diff --git a/crypto/digest_extra/digest_extra.c b/crypto/digest_extra/digest_extra.c
|
||||
index 4b4bb38135e6089eaf6f47afda0199567a2397ef..43b7eca808b82a032055f56ce726ce4f38c5f2c5 100644
|
||||
--- a/crypto/digest_extra/digest_extra.c
|
||||
+++ b/crypto/digest_extra/digest_extra.c
|
||||
@@ -81,6 +81,7 @@ static const struct nid_to_digest nid_to_digest_mapping[] = {
|
||||
{NID_sha384, EVP_sha384, SN_sha384, LN_sha384},
|
||||
{NID_sha512, EVP_sha512, SN_sha512, LN_sha512},
|
||||
{NID_md5_sha1, EVP_md5_sha1, SN_md5_sha1, LN_md5_sha1},
|
||||
+ {NID_ripemd160, EVP_ripemd160, SN_ripemd160, LN_ripemd160},
|
||||
// As a remnant of signing |EVP_MD|s, OpenSSL returned the corresponding
|
||||
// hash function when given a signature OID. To avoid unintended lax parsing
|
||||
// of hash OIDs, this is no longer supported for lookup by OID or NID.
|
||||
diff --git a/crypto/fipsmodule/digest/digests.c b/crypto/fipsmodule/digest/digests.c
|
||||
index f2fa349c2b32ae88766624af3109ece4b1d69909..bcaed59c5401bef071acba9b9919d9069e3ccd4d 100644
|
||||
--- a/crypto/fipsmodule/digest/digests.c
|
||||
+++ b/crypto/fipsmodule/digest/digests.c
|
||||
@@ -63,6 +63,7 @@
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/nid.h>
|
||||
#include <openssl/sha.h>
|
||||
+#include <openssl/ripemd.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "../delocate.h"
|
||||
@@ -277,4 +278,27 @@ DEFINE_METHOD_FUNCTION(EVP_MD, EVP_md5_sha1) {
|
||||
out->ctx_size = sizeof(MD5_SHA1_CTX);
|
||||
}
|
||||
|
||||
+static void ripemd160_init(EVP_MD_CTX *ctx) {
|
||||
+ CHECK(RIPEMD160_Init(ctx->md_data));
|
||||
+}
|
||||
+
|
||||
+static void ripemd160_update(EVP_MD_CTX *ctx, const void *data, size_t count) {
|
||||
+ CHECK(RIPEMD160_Update(ctx->md_data, data, count));
|
||||
+}
|
||||
+
|
||||
+static void ripemd160_final(EVP_MD_CTX *ctx, uint8_t *md) {
|
||||
+ CHECK(RIPEMD160_Final(md, ctx->md_data));
|
||||
+}
|
||||
+
|
||||
+DEFINE_METHOD_FUNCTION(EVP_MD, EVP_ripemd160) {
|
||||
+ out->type = NID_ripemd160;
|
||||
+ out->md_size = RIPEMD160_DIGEST_LENGTH;
|
||||
+ out->flags = 0;
|
||||
+ out->init = ripemd160_init;
|
||||
+ out->update = ripemd160_update;
|
||||
+ out->final = ripemd160_final;
|
||||
+ out->block_size = 64;
|
||||
+ out->ctx_size = sizeof(RIPEMD160_CTX);
|
||||
+}
|
||||
+
|
||||
#undef CHECK
|
||||
diff --git a/decrepit/evp/evp_do_all.c b/decrepit/evp/evp_do_all.c
|
||||
index 38b8f9f78f76050174096740596ac59a0fe18757..acc4719b7e9c4c4461fc6142f2ae9156b407915b 100644
|
||||
--- a/decrepit/evp/evp_do_all.c
|
||||
+++ b/decrepit/evp/evp_do_all.c
|
||||
@@ -66,6 +66,7 @@ void EVP_MD_do_all_sorted(void (*callback)(const EVP_MD *cipher,
|
||||
callback(EVP_sha256(), "SHA256", NULL, arg);
|
||||
callback(EVP_sha384(), "SHA384", NULL, arg);
|
||||
callback(EVP_sha512(), "SHA512", NULL, arg);
|
||||
+ callback(EVP_ripemd160(), "RIPEMD160", NULL, arg);
|
||||
|
||||
callback(EVP_md4(), "md4", NULL, arg);
|
||||
callback(EVP_md5(), "md5", NULL, arg);
|
||||
@@ -74,4 +75,5 @@ void EVP_MD_do_all_sorted(void (*callback)(const EVP_MD *cipher,
|
||||
callback(EVP_sha256(), "sha256", NULL, arg);
|
||||
callback(EVP_sha384(), "sha384", NULL, arg);
|
||||
callback(EVP_sha512(), "sha512", NULL, arg);
|
||||
+ callback(EVP_ripemd160(), "ripemd160", NULL, arg);
|
||||
}
|
||||
diff --git a/include/openssl/digest.h b/include/openssl/digest.h
|
||||
index 1a1ca29732afae317c8e8740c629e8922fc83093..48ebdd1eb93b3febecddbc2545b7aae583f21525 100644
|
||||
--- a/include/openssl/digest.h
|
||||
+++ b/include/openssl/digest.h
|
||||
@@ -88,6 +88,9 @@ OPENSSL_EXPORT const EVP_MD *EVP_sha512(void);
|
||||
// MD5 and SHA-1, as used in TLS 1.1 and below.
|
||||
OPENSSL_EXPORT const EVP_MD *EVP_md5_sha1(void);
|
||||
|
||||
+// EVP_ripemd160 is in decrepit and not available by default.
|
||||
+OPENSSL_EXPORT const EVP_MD *EVP_ripemd160(void);
|
||||
+
|
||||
// EVP_get_digestbynid returns an |EVP_MD| for the given NID, or NULL if no
|
||||
// such digest is known.
|
||||
OPENSSL_EXPORT const EVP_MD *EVP_get_digestbynid(int nid);
|
||||
@@ -1,16 +1,15 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jeremy Apthorp <nornagon@nornagon.net>
|
||||
Date: Thu, 20 Sep 2018 17:48:05 -0700
|
||||
Subject: boringssl_build_gn.patch
|
||||
Subject: boringssl BUILD.gn
|
||||
|
||||
Build BoringSSL with some extra functions that nodejs needs. Only affects
|
||||
the GN build; with the GYP build, nodejs is still built with OpenSSL.
|
||||
Build BoringSSL with some extra functions that nodejs needs.
|
||||
|
||||
diff --git a/third_party/boringssl/BUILD.gn b/third_party/boringssl/BUILD.gn
|
||||
index 6e4fc85f124ed6dd4a7ac1812686fa59c4e50cdf..2fbd44c0ac71bbd84706ef50dd0d98b2466d4295 100644
|
||||
index 6e4fc85f124ed6dd4a7ac1812686fa59c4e50cdf..fd45cfcb50fb659ff8d5a07b06aeecc8f0ecd3ee 100644
|
||||
--- a/third_party/boringssl/BUILD.gn
|
||||
+++ b/third_party/boringssl/BUILD.gn
|
||||
@@ -45,6 +45,13 @@ config("no_asm_config") {
|
||||
@@ -45,6 +45,19 @@ config("no_asm_config") {
|
||||
|
||||
all_sources = crypto_sources + ssl_sources
|
||||
all_headers = crypto_headers + ssl_headers
|
||||
@@ -20,6 +19,12 @@ index 6e4fc85f124ed6dd4a7ac1812686fa59c4e50cdf..2fbd44c0ac71bbd84706ef50dd0d98b2
|
||||
+ "src/decrepit/evp/evp_do_all.c",
|
||||
+ "src/decrepit/xts/xts.c",
|
||||
+ ]
|
||||
+
|
||||
+ all_sources += [
|
||||
+ "src/decrepit/ripemd/internal.h",
|
||||
+ "src/decrepit/ripemd/ripemd.c",
|
||||
+ "src/decrepit/cfb/cfb.c",
|
||||
+ ]
|
||||
+}
|
||||
|
||||
# Windows' assembly is built with NASM. The other platforms use the platform
|
||||
|
||||
@@ -47,7 +47,7 @@ async function nextBeta (v) {
|
||||
tags.sort((t1, t2) => semver.gt(t1, t2))
|
||||
|
||||
// increment the latest existing beta tag or start at beta.1 if it's a new beta line
|
||||
return tags.length === 0 ? semver.inc(next, 'beta', 'prerelease') : semver.inc(tags.pop(), 'prerelease')
|
||||
return tags.length === 0 ? `${next}-beta.1` : semver.inc(tags.pop(), 'prerelease')
|
||||
}
|
||||
|
||||
async function getElectronVersion () {
|
||||
|
||||
@@ -63,6 +63,35 @@ const setPullRequest = (commit, owner, repo, number) => {
|
||||
}
|
||||
}
|
||||
|
||||
const getNoteFromClerk = async (number, owner, repo) => {
|
||||
const comments = await getComments(number, owner, repo)
|
||||
if (!comments && !comments.data) {
|
||||
return
|
||||
}
|
||||
|
||||
const CLERK_LOGIN = 'release-clerk[bot]'
|
||||
const PERSIST_LEAD = '**Release Notes Persisted**\n\n'
|
||||
const QUOTE_LEAD = '> '
|
||||
|
||||
for (const comment of comments.data.reverse()) {
|
||||
if (comment.user.login !== CLERK_LOGIN) {
|
||||
continue
|
||||
}
|
||||
if (!comment.body.startsWith(PERSIST_LEAD)) {
|
||||
continue
|
||||
}
|
||||
const note = comment.body
|
||||
.slice(PERSIST_LEAD.length).trim() // remove PERSIST_LEAD
|
||||
.split('\r?\n') // break into lines
|
||||
.map(line => line.trim())
|
||||
.filter(line => line.startsWith(QUOTE_LEAD)) // notes are quoted
|
||||
.map(line => line.slice(QUOTE_LEAD.length)) // unquote the lines
|
||||
.join(' ') // join the note lines
|
||||
.trim()
|
||||
return note
|
||||
}
|
||||
}
|
||||
|
||||
// copied from https://github.com/electron/clerk/blob/master/src/index.ts#L4-L13
|
||||
const OMIT_FROM_RELEASE_NOTES_KEYS = [
|
||||
'no-notes',
|
||||
@@ -81,10 +110,12 @@ const getNoteFromBody = body => {
|
||||
}
|
||||
|
||||
const NOTE_PREFIX = 'Notes: '
|
||||
const NOTE_HEADER = '#### Release Notes'
|
||||
|
||||
let note = body
|
||||
.split(/\r?\n\r?\n/) // split into paragraphs
|
||||
.map(paragraph => paragraph.trim())
|
||||
.map(paragraph => paragraph.startsWith(NOTE_HEADER) ? paragraph.slice(NOTE_HEADER.length).trim() : paragraph)
|
||||
.find(paragraph => paragraph.startsWith(NOTE_PREFIX))
|
||||
|
||||
if (note) {
|
||||
@@ -185,9 +216,9 @@ const parseCommitMessage = (commitMessage, owner, repo, commit = {}) => {
|
||||
|
||||
// https://www.conventionalcommits.org/en
|
||||
if (commitMessage
|
||||
.split(/\r?\n\r?\n/) // split into paragraphs
|
||||
.map(paragraph => paragraph.trim())
|
||||
.some(paragraph => paragraph.startsWith('BREAKING CHANGE'))) {
|
||||
.split(/\r?\n/) // split into lines
|
||||
.map(line => line.trim())
|
||||
.some(line => line.startsWith('BREAKING CHANGE'))) {
|
||||
commit.type = 'breaking-change'
|
||||
}
|
||||
|
||||
@@ -295,6 +326,22 @@ const getPullRequest = async (number, owner, repo) => {
|
||||
})
|
||||
}
|
||||
|
||||
const getComments = async (number, owner, repo) => {
|
||||
const name = `${owner}-${repo}-pull-${number}-comments`
|
||||
return checkCache(name, async () => {
|
||||
try {
|
||||
return await octokit.issues.listComments({ number, owner, repo, per_page: 100 })
|
||||
} catch (error) {
|
||||
// Silently eat 404s.
|
||||
// We can get a bad pull number if someone manually lists
|
||||
// an issue number in PR number notation, e.g. 'fix: foo (#123)'
|
||||
if (error.code !== 404) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const addRepoToPool = async (pool, repo, from, to) => {
|
||||
const commonAncestor = await getCommonAncestor(repo.dir, from, to)
|
||||
const oldHashes = await getLocalCommitHashes(repo.dir, from)
|
||||
@@ -393,6 +440,28 @@ const getDependencyCommits = async (pool, from, to) => {
|
||||
: getDependencyCommitsGN(pool, from, to)
|
||||
}
|
||||
|
||||
// Changes are interesting if they make a change relative to a previous
|
||||
// release in the same series. For example if you fix a Y.0.0 bug, that
|
||||
// should be included in the Y.0.1 notes even if it's also tropped back
|
||||
// to X.0.1.
|
||||
//
|
||||
// The phrase 'previous release' is important: if this is the first
|
||||
// prerelease or first stable release in a series, we omit previous
|
||||
// branches' changes. Otherwise we will have an overwhelmingly long
|
||||
// list of mostly-irrelevant changes.
|
||||
const shouldIncludeMultibranchChanges = (version) => {
|
||||
let show = true
|
||||
|
||||
if (semver.valid(version)) {
|
||||
const prerelease = semver.prerelease(version)
|
||||
show = prerelease
|
||||
? parseInt(prerelease.pop()) > 1
|
||||
: semver.patch(version) > 0
|
||||
}
|
||||
|
||||
return show
|
||||
}
|
||||
|
||||
/***
|
||||
**** Main
|
||||
***/
|
||||
@@ -445,8 +514,19 @@ const getNotes = async (fromRef, toRef, newVersion) => {
|
||||
// scrape PRs for release note 'Notes:' comments
|
||||
for (const commit of pool.commits) {
|
||||
let pr = commit.pr
|
||||
|
||||
let prSubject
|
||||
while (pr && !commit.note) {
|
||||
const note = await getNoteFromClerk(pr.number, pr.owner, pr.repo)
|
||||
if (note) {
|
||||
commit.note = note
|
||||
}
|
||||
|
||||
// if we already have all the data we need, stop scraping the PRs
|
||||
if (commit.note && commit.type && prSubject) {
|
||||
break
|
||||
}
|
||||
|
||||
const prData = await getPullRequest(pr.number, pr.owner, pr.repo)
|
||||
if (!prData || !prData.data) {
|
||||
break
|
||||
@@ -472,9 +552,7 @@ const getNotes = async (fromRef, toRef, newVersion) => {
|
||||
.filter(commit => commit.note !== NO_NOTES)
|
||||
.filter(commit => !((commit.note || commit.subject).match(/^[Bb]ump v\d+\.\d+\.\d+/)))
|
||||
|
||||
// if this is a stable release,
|
||||
// remove notes for changes that already landed in a previous major/minor series
|
||||
if (semver.valid(newVersion) && !semver.prerelease(newVersion)) {
|
||||
if (!shouldIncludeMultibranchChanges(newVersion)) {
|
||||
// load all the prDatas
|
||||
await Promise.all(
|
||||
pool.commits.map(commit => new Promise(async (resolve) => {
|
||||
|
||||
@@ -836,7 +836,7 @@ describe('app module', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('getFileIcon() API', (done) => {
|
||||
describe('getFileIcon() API', () => {
|
||||
const iconPath = path.join(__dirname, 'fixtures/assets/icon.ico')
|
||||
const sizes = {
|
||||
small: 16,
|
||||
@@ -859,7 +859,7 @@ describe('app module', () => {
|
||||
})
|
||||
|
||||
// TODO(codebytere): remove when promisification is complete
|
||||
it('fetches a non-empty icon (callback)', () => {
|
||||
it('fetches a non-empty icon (callback)', (done) => {
|
||||
app.getFileIcon(iconPath, (icon) => {
|
||||
expect(icon.isEmpty()).to.be.false()
|
||||
done()
|
||||
@@ -875,7 +875,7 @@ describe('app module', () => {
|
||||
})
|
||||
|
||||
// TODO(codebytere): remove when promisification is complete
|
||||
it('fetches normal icon size by default (callback)', () => {
|
||||
it('fetches normal icon size by default (callback)', (done) => {
|
||||
app.getFileIcon(iconPath, (icon) => {
|
||||
const size = icon.getSize()
|
||||
|
||||
@@ -903,7 +903,7 @@ describe('app module', () => {
|
||||
})
|
||||
|
||||
// TODO(codebytere): remove when promisification is complete
|
||||
it('fetches a normal icon (callback)', () => {
|
||||
it('fetches a normal icon (callback)', (done) => {
|
||||
app.getFileIcon(iconPath, { size: 'normal' }, (icon) => {
|
||||
const size = icon.getSize()
|
||||
|
||||
|
||||
@@ -507,7 +507,7 @@ describe('BrowserWindow module', () => {
|
||||
})
|
||||
|
||||
// TODO(codebytere): remove when promisification is complete
|
||||
it('returns a Promise with a Buffer (callback)', () => {
|
||||
it('returns a Promise with a Buffer (callback)', (done) => {
|
||||
w.capturePage({
|
||||
x: 0,
|
||||
y: 0,
|
||||
@@ -540,24 +540,25 @@ describe('BrowserWindow module', () => {
|
||||
})
|
||||
|
||||
// TODO(codebytere): remove when promisification is complete
|
||||
it('preserves transparency (callback)', async () => {
|
||||
const w = await openTheWindow({
|
||||
it('preserves transparency (callback)', (done) => {
|
||||
openTheWindow({
|
||||
show: false,
|
||||
width: 400,
|
||||
height: 400,
|
||||
transparent: true
|
||||
})
|
||||
const p = emittedOnce(w, 'ready-to-show')
|
||||
w.loadURL('data:text/html,<html><body background-color: rgba(255,255,255,0)></body></html>')
|
||||
await p
|
||||
w.show()
|
||||
|
||||
w.capturePage((image) => {
|
||||
const imgBuffer = image.toPNG()
|
||||
// Check the 25th byte in the PNG.
|
||||
// Values can be 0,2,3,4, or 6. We want 6, which is RGB + Alpha
|
||||
expect(imgBuffer[25]).to.equal(6)
|
||||
done()
|
||||
}).then(w => {
|
||||
const p = emittedOnce(w, 'ready-to-show')
|
||||
w.loadURL('data:text/html,<html><body background-color: rgba(255,255,255,0)></body></html>')
|
||||
p.then(() => {
|
||||
w.show()
|
||||
w.capturePage((image) => {
|
||||
const imgBuffer = image.toPNG()
|
||||
// Check the 25th byte in the PNG.
|
||||
// Values can be 0,2,3,4, or 6. We want 6, which is RGB + Alpha
|
||||
expect(imgBuffer[25]).to.equal(6)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1382,23 +1383,29 @@ describe('BrowserWindow module', () => {
|
||||
assert.deepStrictEqual(defaultSession.getPreloads(), preloads)
|
||||
})
|
||||
|
||||
it('loads the script before other scripts in window including normal preloads', function (done) {
|
||||
ipcMain.once('vars', function (event, preload1, preload2, preload3) {
|
||||
assert.strictEqual(preload1, 'preload-1')
|
||||
assert.strictEqual(preload2, 'preload-1-2')
|
||||
assert.strictEqual(preload3, 'preload-1-2-3')
|
||||
done()
|
||||
const generateSpecs = (description, sandbox) => {
|
||||
describe(description, () => {
|
||||
it('loads the script before other scripts in window including normal preloads', function (done) {
|
||||
ipcMain.once('vars', function (event, preload1, preload2) {
|
||||
assert.strictEqual(preload1, 'preload-1')
|
||||
assert.strictEqual(preload2, 'preload-1-2')
|
||||
done()
|
||||
})
|
||||
w.destroy()
|
||||
w = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
sandbox,
|
||||
preload: path.join(fixtures, 'module', 'get-global-preload.js')
|
||||
}
|
||||
})
|
||||
w.loadURL('about:blank')
|
||||
})
|
||||
})
|
||||
w.destroy()
|
||||
w = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
preload: path.join(fixtures, 'module', 'set-global-preload-3.js')
|
||||
}
|
||||
})
|
||||
w.loadFile(path.join(fixtures, 'api', 'preloads.html'))
|
||||
})
|
||||
}
|
||||
|
||||
generateSpecs('without sandbox', false)
|
||||
generateSpecs('with sandbox', true)
|
||||
})
|
||||
|
||||
describe('"additionalArguments" option', () => {
|
||||
|
||||
@@ -28,6 +28,28 @@ describe('contentTracing', () => {
|
||||
}
|
||||
})
|
||||
|
||||
const record = async (options, outputFilePath, recordTimeInMilliseconds = 1e3) => {
|
||||
await app.whenReady()
|
||||
|
||||
await contentTracing.startRecording(options)
|
||||
await timeout(recordTimeInMilliseconds)
|
||||
const resultFilePath = await contentTracing.stopRecording(outputFilePath)
|
||||
|
||||
return resultFilePath
|
||||
}
|
||||
|
||||
// TODO(codebytere): remove when promisification is complete
|
||||
const recordCallback = async (options, outputFilePath, recordTimeInMilliseconds = 1e3) => {
|
||||
await app.whenReady()
|
||||
|
||||
await startRecording(options)
|
||||
await timeout(recordTimeInMilliseconds)
|
||||
const resultFilePath = await stopRecording(outputFilePath)
|
||||
|
||||
return resultFilePath
|
||||
}
|
||||
|
||||
// TODO(codebytere): remove when promisification is complete
|
||||
const startRecording = async (options) => {
|
||||
return new Promise((resolve) => {
|
||||
contentTracing.startRecording(options, () => {
|
||||
@@ -36,6 +58,7 @@ describe('contentTracing', () => {
|
||||
})
|
||||
}
|
||||
|
||||
// TODO(codebytere): remove when promisification is complete
|
||||
const stopRecording = async (filePath) => {
|
||||
return new Promise((resolve) => {
|
||||
contentTracing.stopRecording(filePath, (resultFilePath) => {
|
||||
@@ -44,16 +67,6 @@ describe('contentTracing', () => {
|
||||
})
|
||||
}
|
||||
|
||||
const record = async (options, outputFilePath, recordTimeInMilliseconds = 1e3) => {
|
||||
await app.whenReady()
|
||||
|
||||
await startRecording(options)
|
||||
await timeout(recordTimeInMilliseconds)
|
||||
const resultFilePath = await stopRecording(outputFilePath)
|
||||
|
||||
return resultFilePath
|
||||
}
|
||||
|
||||
const outputFilePath = getPathInATempFolder('trace.json')
|
||||
beforeEach(() => {
|
||||
if (fs.existsSync(outputFilePath)) {
|
||||
@@ -82,6 +95,18 @@ describe('contentTracing', () => {
|
||||
`the trace output file is empty, check "${outputFilePath}"`)
|
||||
})
|
||||
|
||||
// TODO(codebytere): remove when promisification is complete
|
||||
it('accepts an empty config (callback)', async () => {
|
||||
const config = {}
|
||||
await recordCallback(config, outputFilePath)
|
||||
|
||||
expect(fs.existsSync(outputFilePath)).to.be.true()
|
||||
|
||||
const fileSizeInKiloBytes = getFileSizeInKiloBytes(outputFilePath)
|
||||
expect(fileSizeInKiloBytes).to.be.above(0,
|
||||
`the trace output file is empty, check "${outputFilePath}"`)
|
||||
})
|
||||
|
||||
it('accepts a trace config', async () => {
|
||||
// (alexeykuzmin): All categories are excluded on purpose,
|
||||
// so only metadata gets into the output file.
|
||||
@@ -104,6 +129,29 @@ describe('contentTracing', () => {
|
||||
check "${outputFilePath}"`)
|
||||
})
|
||||
|
||||
// TODO(codebytere): remove when promisification is complete
|
||||
it('accepts a trace config (callback)', async () => {
|
||||
// (alexeykuzmin): All categories are excluded on purpose,
|
||||
// so only metadata gets into the output file.
|
||||
const config = {
|
||||
excluded_categories: ['*']
|
||||
}
|
||||
await recordCallback(config, outputFilePath)
|
||||
|
||||
expect(fs.existsSync(outputFilePath)).to.be.true()
|
||||
|
||||
// If the `excluded_categories` param above is not respected
|
||||
// the file size will be above 50KB.
|
||||
const fileSizeInKiloBytes = getFileSizeInKiloBytes(outputFilePath)
|
||||
const expectedMaximumFileSize = 10 // Depends on a platform.
|
||||
|
||||
expect(fileSizeInKiloBytes).to.be.above(0,
|
||||
`the trace output file is empty, check "${outputFilePath}"`)
|
||||
expect(fileSizeInKiloBytes).to.be.below(expectedMaximumFileSize,
|
||||
`the trace output file is suspiciously large (${fileSizeInKiloBytes}KB),
|
||||
check "${outputFilePath}"`)
|
||||
})
|
||||
|
||||
it('accepts "categoryFilter" and "traceOptions" as a config', async () => {
|
||||
// (alexeykuzmin): All categories are excluded on purpose,
|
||||
// so only metadata gets into the output file.
|
||||
@@ -126,6 +174,30 @@ describe('contentTracing', () => {
|
||||
`the trace output file is suspiciously large (${fileSizeInKiloBytes}KB),
|
||||
check "${outputFilePath}"`)
|
||||
})
|
||||
|
||||
// TODO(codebytere): remove when promisification is complete
|
||||
it('accepts "categoryFilter" and "traceOptions" as a config (callback)', async () => {
|
||||
// (alexeykuzmin): All categories are excluded on purpose,
|
||||
// so only metadata gets into the output file.
|
||||
const config = {
|
||||
categoryFilter: '__ThisIsANonexistentCategory__',
|
||||
traceOptions: ''
|
||||
}
|
||||
await recordCallback(config, outputFilePath)
|
||||
|
||||
expect(fs.existsSync(outputFilePath)).to.be.true()
|
||||
|
||||
// If the `categoryFilter` param above is not respected
|
||||
// the file size will be above 50KB.
|
||||
const fileSizeInKiloBytes = getFileSizeInKiloBytes(outputFilePath)
|
||||
const expectedMaximumFileSize = 10 // Depends on a platform.
|
||||
|
||||
expect(fileSizeInKiloBytes).to.be.above(0,
|
||||
`the trace output file is empty, check "${outputFilePath}"`)
|
||||
expect(fileSizeInKiloBytes).to.be.below(expectedMaximumFileSize,
|
||||
`the trace output file is suspiciously large (${fileSizeInKiloBytes}KB),
|
||||
check "${outputFilePath}"`)
|
||||
})
|
||||
})
|
||||
|
||||
describe('stopRecording', function () {
|
||||
@@ -136,6 +208,12 @@ describe('contentTracing', () => {
|
||||
expect(resultFilePath).to.be.a('string').and.be.equal(outputFilePath)
|
||||
})
|
||||
|
||||
// TODO(codebytere): remove when promisification is complete
|
||||
it('calls its callback with a result file path (callback)', async () => {
|
||||
const resultFilePath = await recordCallback(/* options */ {}, outputFilePath)
|
||||
expect(resultFilePath).to.be.a('string').and.be.equal(outputFilePath)
|
||||
})
|
||||
|
||||
// FIXME(alexeykuzmin): https://github.com/electron/electron/issues/16019
|
||||
xit('creates a temporary file when an empty string is passed', async function () {
|
||||
const resultFilePath = await record(/* options */ {}, /* outputFilePath */ '')
|
||||
|
||||
@@ -138,7 +138,7 @@ describe('deprecations', () => {
|
||||
|
||||
it('acts as a pass-through for promise-based invocations', async () => {
|
||||
enableCallbackWarnings()
|
||||
promiseFunc = deprecate.promisify(promiseFunc, 1)
|
||||
promiseFunc = deprecate.promisify(promiseFunc)
|
||||
|
||||
const actual = await promiseFunc(expected)
|
||||
expect(actual).to.equal(expected)
|
||||
@@ -147,7 +147,7 @@ describe('deprecations', () => {
|
||||
|
||||
it('warns exactly once for callback-based invocations', (done) => {
|
||||
enableCallbackWarnings()
|
||||
promiseFunc = deprecate.promisify(promiseFunc, 1)
|
||||
promiseFunc = deprecate.promisify(promiseFunc)
|
||||
|
||||
let callbackCount = 0
|
||||
const invocationCount = 3
|
||||
|
||||
@@ -65,6 +65,7 @@ describe('desktopCapturer', () => {
|
||||
const callback = (error, sources) => {
|
||||
callCount++
|
||||
expect(error).to.be.null()
|
||||
expect(sources).to.not.be.null()
|
||||
if (callCount === 2) done()
|
||||
}
|
||||
|
||||
|
||||
@@ -550,12 +550,12 @@ describe('net module', () => {
|
||||
handleUnexpectedURL(request, response)
|
||||
}
|
||||
})
|
||||
|
||||
customSession.cookies.set({
|
||||
url: `${server.url}`,
|
||||
name: 'test',
|
||||
value: '11111'
|
||||
}, (error) => {
|
||||
if (error) return done(error)
|
||||
}).then(() => { // resolved
|
||||
const urlRequest = net.request({
|
||||
method: 'GET',
|
||||
url: `${server.url}${requestUrl}`,
|
||||
@@ -575,6 +575,8 @@ describe('net module', () => {
|
||||
assert.strictEqual(urlRequest.getHeader(cookieHeaderName),
|
||||
cookieHeaderValue)
|
||||
urlRequest.end()
|
||||
}, (error) => {
|
||||
done(error)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -654,16 +654,40 @@ describe('protocol module', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('can handle large responses', async () => {
|
||||
const data = Buffer.alloc(128 * 1024)
|
||||
const handler = (request, callback) => {
|
||||
callback(getStream(data.length, data))
|
||||
}
|
||||
await new Promise((resolve, reject) => {
|
||||
protocol.registerStreamProtocol(protocolName, handler, err => {
|
||||
if (err) return reject(err)
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
const r = await new Promise((resolve, reject) => {
|
||||
$.ajax({
|
||||
url: protocolName + '://fake-host',
|
||||
cache: false,
|
||||
success: resolve,
|
||||
error: (xhr, errorType, error) => {
|
||||
reject(error || new Error(`Request failed: ${xhr.status}`))
|
||||
}
|
||||
})
|
||||
})
|
||||
assert.strictEqual(r.length, data.length)
|
||||
})
|
||||
})
|
||||
|
||||
describe('protocol.isProtocolHandled', (done) => {
|
||||
describe('protocol.isProtocolHandled', () => {
|
||||
it('returns true for about:', async () => {
|
||||
const result = await protocol.isProtocolHandled('about')
|
||||
assert.strictEqual(result, true)
|
||||
})
|
||||
|
||||
// TODO(codebytere): remove when promisification is complete
|
||||
it('returns true for about: (callback)', () => {
|
||||
it('returns true for about: (callback)', (done) => {
|
||||
protocol.isProtocolHandled('about', (result) => {
|
||||
assert.strictEqual(result, true)
|
||||
done()
|
||||
@@ -676,7 +700,7 @@ describe('protocol module', () => {
|
||||
})
|
||||
|
||||
// TODO(codebytere): remove when promisification is complete
|
||||
it('returns true for file: (callback)', () => {
|
||||
it('returns true for file: (callback)', (done) => {
|
||||
protocol.isProtocolHandled('file', (result) => {
|
||||
assert.strictEqual(result, true)
|
||||
done()
|
||||
@@ -698,7 +722,7 @@ describe('protocol module', () => {
|
||||
assert.strictEqual(result, false)
|
||||
})
|
||||
|
||||
it('returns true for custom protocol', () => {
|
||||
it('returns true for custom protocol', (done) => {
|
||||
const emptyHandler = (request, callback) => callback()
|
||||
protocol.registerStringProtocol(protocolName, emptyHandler, async (error) => {
|
||||
assert.strictEqual(error, null)
|
||||
@@ -709,7 +733,7 @@ describe('protocol module', () => {
|
||||
})
|
||||
|
||||
// TODO(codebytere): remove when promisification is complete
|
||||
it('returns true for custom protocol (callback)', () => {
|
||||
it('returns true for custom protocol (callback)', (done) => {
|
||||
const emptyHandler = (request, callback) => callback()
|
||||
protocol.registerStringProtocol(protocolName, emptyHandler, (error) => {
|
||||
assert.strictEqual(error, null)
|
||||
@@ -720,7 +744,7 @@ describe('protocol module', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('returns true for intercepted protocol', () => {
|
||||
it('returns true for intercepted protocol', (done) => {
|
||||
const emptyHandler = (request, callback) => callback()
|
||||
protocol.interceptStringProtocol('http', emptyHandler, async (error) => {
|
||||
assert.strictEqual(error, null)
|
||||
@@ -731,7 +755,7 @@ describe('protocol module', () => {
|
||||
})
|
||||
|
||||
// TODO(codebytere): remove when promisification is complete
|
||||
it('returns true for intercepted protocol (callback)', () => {
|
||||
it('returns true for intercepted protocol (callback)', (done) => {
|
||||
const emptyHandler = (request, callback) => callback()
|
||||
protocol.interceptStringProtocol('http', emptyHandler, (error) => {
|
||||
assert.strictEqual(error, null)
|
||||
@@ -1063,7 +1087,7 @@ describe('protocol module', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('protocol.registerStandardSchemes', () => {
|
||||
describe('protocol.registerSchemesAsPrivileged standard', () => {
|
||||
const standardScheme = remote.getGlobal('standardScheme')
|
||||
const origin = `${standardScheme}://fake-host`
|
||||
const imageURL = `${origin}/test.png`
|
||||
@@ -1165,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)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -68,151 +68,212 @@ describe('session module', () => {
|
||||
})
|
||||
|
||||
describe('ses.cookies', () => {
|
||||
it('should get cookies', (done) => {
|
||||
const name = '0'
|
||||
const value = '0'
|
||||
|
||||
it('should get cookies with promises', (done) => {
|
||||
const server = http.createServer((req, res) => {
|
||||
res.setHeader('Set-Cookie', ['0=0'])
|
||||
res.setHeader('Set-Cookie', [`${name}=${value}`])
|
||||
res.end('finished')
|
||||
server.close()
|
||||
})
|
||||
server.listen(0, '127.0.0.1', () => {
|
||||
const port = server.address().port
|
||||
w.webContents.once('did-finish-load', () => {
|
||||
w.webContents.session.cookies.get({ url }, (error, list) => {
|
||||
if (error) return done(error)
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const cookie = list[i]
|
||||
if (cookie.name === '0') {
|
||||
if (cookie.value === '0') {
|
||||
return done()
|
||||
} else {
|
||||
return done(`cookie value is ${cookie.value} while expecting 0`)
|
||||
}
|
||||
}
|
||||
}
|
||||
done('Can\'t find cookie')
|
||||
})
|
||||
w.webContents.once('did-finish-load', async () => {
|
||||
const list = await w.webContents.session.cookies.get({ url })
|
||||
const cookie = list.find(cookie => cookie.name === name)
|
||||
|
||||
expect(cookie).to.exist.and.to.have.property('value', value)
|
||||
done()
|
||||
})
|
||||
const { port } = server.address()
|
||||
w.loadURL(`${url}:${port}`)
|
||||
})
|
||||
})
|
||||
|
||||
it('calls back with an error when setting a cookie with missing required fields', (done) => {
|
||||
session.defaultSession.cookies.set({
|
||||
url: '',
|
||||
name: '1',
|
||||
value: '1'
|
||||
}, (error) => {
|
||||
assert(error, 'Should have an error')
|
||||
assert.strictEqual(error.message, 'Setting cookie failed')
|
||||
done()
|
||||
it('should get cookies with callbacks', (done) => {
|
||||
const server = http.createServer((req, res) => {
|
||||
res.setHeader('Set-Cookie', [`${name}=${value}`])
|
||||
res.end('finished')
|
||||
server.close()
|
||||
})
|
||||
})
|
||||
|
||||
it('should over-write the existent cookie', (done) => {
|
||||
session.defaultSession.cookies.set({
|
||||
url,
|
||||
name: '1',
|
||||
value: '1'
|
||||
}, (error) => {
|
||||
if (error) return done(error)
|
||||
session.defaultSession.cookies.get({ url }, (error, list) => {
|
||||
if (error) return done(error)
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const cookie = list[i]
|
||||
if (cookie.name === '1') {
|
||||
if (cookie.value === '1') {
|
||||
return done()
|
||||
} else {
|
||||
return done(`cookie value is ${cookie.value} while expecting 1`)
|
||||
}
|
||||
}
|
||||
}
|
||||
done('Can\'t find cookie')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should remove cookies', (done) => {
|
||||
session.defaultSession.cookies.set({
|
||||
url: url,
|
||||
name: '2',
|
||||
value: '2'
|
||||
}, (error) => {
|
||||
if (error) return done(error)
|
||||
session.defaultSession.cookies.remove(url, '2', () => {
|
||||
session.defaultSession.cookies.get({ url }, (error, list) => {
|
||||
server.listen(0, '127.0.0.1', () => {
|
||||
w.webContents.once('did-finish-load', () => {
|
||||
w.webContents.session.cookies.get({ url }, (error, list) => {
|
||||
if (error) return done(error)
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const cookie = list[i]
|
||||
if (cookie.name === '2') return done('Cookie not deleted')
|
||||
}
|
||||
const cookie = list.find(cookie => cookie.name === name)
|
||||
expect(cookie).to.exist.and.to.have.property('value', value)
|
||||
done()
|
||||
})
|
||||
})
|
||||
const { port } = server.address()
|
||||
w.loadURL(`${url}:${port}`)
|
||||
})
|
||||
})
|
||||
|
||||
it('sets cookies with promises', async () => {
|
||||
let error
|
||||
try {
|
||||
const { cookies } = session.defaultSession
|
||||
const name = '1'
|
||||
const value = '1'
|
||||
|
||||
await cookies.set({ url, name, value })
|
||||
} catch (e) {
|
||||
error = e
|
||||
}
|
||||
expect(error).to.be.undefined(error)
|
||||
})
|
||||
|
||||
it('sets cookies with callbacks', (done) => {
|
||||
const { cookies } = session.defaultSession
|
||||
const name = '1'
|
||||
const value = '1'
|
||||
cookies.set({ url, name, value }, (error, list) => done(error))
|
||||
})
|
||||
|
||||
it('yields an error when setting a cookie with missing required fields', async () => {
|
||||
let error
|
||||
try {
|
||||
const { cookies } = session.defaultSession
|
||||
const name = '1'
|
||||
const value = '1'
|
||||
await cookies.set({ url: '', name, value })
|
||||
} catch (e) {
|
||||
error = e
|
||||
}
|
||||
expect(error).is.an('Error')
|
||||
expect(error).to.have.property('message').which.equals('Setting cookie failed')
|
||||
})
|
||||
|
||||
it('should overwrite previous cookies', async () => {
|
||||
let error
|
||||
try {
|
||||
const { cookies } = session.defaultSession
|
||||
const name = 'DidOverwrite'
|
||||
for (const value of [ 'No', 'Yes' ]) {
|
||||
await cookies.set({ url, name, value })
|
||||
const list = await cookies.get({ url })
|
||||
|
||||
assert(list.some(cookie => cookie.name === name && cookie.value === value))
|
||||
}
|
||||
} catch (e) {
|
||||
error = e
|
||||
}
|
||||
expect(error).to.be.undefined(error)
|
||||
})
|
||||
|
||||
it('should remove cookies with promises', async () => {
|
||||
let error
|
||||
try {
|
||||
const { cookies } = session.defaultSession
|
||||
const name = '2'
|
||||
const value = '2'
|
||||
|
||||
await cookies.set({ url, name, value })
|
||||
await cookies.remove(url, name)
|
||||
const list = await cookies.get({ url })
|
||||
|
||||
assert(!list.some(cookie => cookie.name === name && cookie.value === value))
|
||||
} catch (e) {
|
||||
error = e
|
||||
}
|
||||
expect(error).to.be.undefined(error)
|
||||
})
|
||||
|
||||
it('should remove cookies with callbacks', (done) => {
|
||||
const { cookies } = session.defaultSession
|
||||
const name = '2'
|
||||
const value = '2'
|
||||
|
||||
cookies.set({ url, name, value }, (error) => {
|
||||
if (error) return done(error)
|
||||
cookies.remove(url, name, (error) => {
|
||||
if (error) return done(error)
|
||||
cookies.get({ url }, (error, list) => {
|
||||
if (error) return done(error)
|
||||
assert(!list.some(cookie => cookie.name === name))
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should set cookie for standard scheme', (done) => {
|
||||
const standardScheme = remote.getGlobal('standardScheme')
|
||||
const origin = standardScheme + '://fake-host'
|
||||
session.defaultSession.cookies.set({
|
||||
url: origin,
|
||||
name: 'custom',
|
||||
value: '1'
|
||||
}, (error) => {
|
||||
if (error) return done(error)
|
||||
session.defaultSession.cookies.get({ url: origin }, (error, list) => {
|
||||
if (error) return done(error)
|
||||
assert.strictEqual(list.length, 1)
|
||||
assert.strictEqual(list[0].name, 'custom')
|
||||
assert.strictEqual(list[0].value, '1')
|
||||
assert.strictEqual(list[0].domain, 'fake-host')
|
||||
done()
|
||||
})
|
||||
})
|
||||
it('should set cookie for standard scheme', async () => {
|
||||
let error
|
||||
try {
|
||||
const { cookies } = session.defaultSession
|
||||
const standardScheme = remote.getGlobal('standardScheme')
|
||||
const domain = 'fake-host'
|
||||
const url = `${standardScheme}://${domain}`
|
||||
const name = 'custom'
|
||||
const value = '1'
|
||||
|
||||
await cookies.set({ url, name, value })
|
||||
const list = await cookies.get({ url })
|
||||
|
||||
expect(list).to.have.lengthOf(1)
|
||||
expect(list[0]).to.have.property('name', name)
|
||||
expect(list[0]).to.have.property('value', value)
|
||||
expect(list[0]).to.have.property('domain', domain)
|
||||
} catch (e) {
|
||||
error = e
|
||||
}
|
||||
|
||||
expect(error).to.be.undefined(error)
|
||||
})
|
||||
|
||||
it('emits a changed event when a cookie is added or removed', (done) => {
|
||||
const { cookies } = session.fromPartition('cookies-changed')
|
||||
it('emits a changed event when a cookie is added or removed', async () => {
|
||||
let error
|
||||
const changes = []
|
||||
|
||||
cookies.once('changed', (event, cookie, cause, removed) => {
|
||||
assert.strictEqual(cookie.name, 'foo')
|
||||
assert.strictEqual(cookie.value, 'bar')
|
||||
assert.strictEqual(cause, 'explicit')
|
||||
assert.strictEqual(removed, false)
|
||||
try {
|
||||
const { cookies } = session.fromPartition('cookies-changed')
|
||||
const name = 'foo'
|
||||
const value = 'bar'
|
||||
const eventName = 'changed'
|
||||
const listener = (event, cookie, cause, removed) => { changes.push({ cookie, cause, removed }) }
|
||||
|
||||
cookies.once('changed', (event, cookie, cause, removed) => {
|
||||
assert.strictEqual(cookie.name, 'foo')
|
||||
assert.strictEqual(cookie.value, 'bar')
|
||||
assert.strictEqual(cause, 'explicit')
|
||||
assert.strictEqual(removed, true)
|
||||
done()
|
||||
})
|
||||
cookies.on(eventName, listener)
|
||||
await cookies.set({ url, name, value })
|
||||
await cookies.remove(url, name)
|
||||
cookies.off(eventName, listener)
|
||||
|
||||
cookies.remove(url, 'foo', (error) => {
|
||||
if (error) return done(error)
|
||||
})
|
||||
})
|
||||
|
||||
cookies.set({
|
||||
url: url,
|
||||
name: 'foo',
|
||||
value: 'bar'
|
||||
}, (error) => {
|
||||
if (error) return done(error)
|
||||
})
|
||||
expect(changes).to.have.lengthOf(2)
|
||||
expect(changes.every(change => change.cookie.name === name))
|
||||
expect(changes.every(change => change.cookie.value === value))
|
||||
expect(changes.every(change => change.cause === 'explicit'))
|
||||
expect(changes[0].removed).to.be.false()
|
||||
expect(changes[1].removed).to.be.true()
|
||||
} catch (e) {
|
||||
error = e
|
||||
}
|
||||
expect(error).to.be.undefined(error)
|
||||
})
|
||||
|
||||
describe('ses.cookies.flushStore(callback)', () => {
|
||||
it('flushes the cookies to disk and invokes the callback when done', (done) => {
|
||||
session.defaultSession.cookies.set({
|
||||
url: url,
|
||||
name: 'foo',
|
||||
value: 'bar'
|
||||
}, (error) => {
|
||||
if (error) return done(error)
|
||||
session.defaultSession.cookies.flushStore(() => {
|
||||
done()
|
||||
describe('ses.cookies.flushStore()', async () => {
|
||||
describe('flushes the cookies to disk and invokes the callback when done', async () => {
|
||||
it('with promises', async () => {
|
||||
let error
|
||||
try {
|
||||
const name = 'foo'
|
||||
const value = 'bar'
|
||||
const { cookies } = session.defaultSession
|
||||
|
||||
await cookies.set({ url, name, value })
|
||||
await cookies.flushStore()
|
||||
} catch (e) {
|
||||
error = e
|
||||
}
|
||||
expect(error).to.be.undefined(error)
|
||||
})
|
||||
it('with callbacks', (done) => {
|
||||
const name = 'foo'
|
||||
const value = 'bar'
|
||||
const { cookies } = session.defaultSession
|
||||
|
||||
cookies.set({ url, name, value }, error => {
|
||||
if (error) return done(error)
|
||||
cookies.flushStore(error => done(error))
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -232,7 +293,7 @@ describe('session module', () => {
|
||||
{ env: { PHASE: phase, ...process.env } }
|
||||
)
|
||||
|
||||
appProcess.stdout.on('data', (data) => { output += data })
|
||||
appProcess.stdout.on('data', data => { output += data })
|
||||
appProcess.stdout.on('end', () => {
|
||||
output = output.replace(/(\r\n|\n|\r)/gm, '')
|
||||
assert.strictEqual(output, result)
|
||||
@@ -620,12 +681,9 @@ describe('session module', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// FIXME: Disabled with C71 upgrade
|
||||
// Re-enable with new api from
|
||||
// https://github.com/electron/electron/tree/webframe-scheme-api
|
||||
xdescribe('ses.getBlobData(identifier, callback)', () => {
|
||||
describe('ses.getBlobData(identifier, callback)', () => {
|
||||
it('returns blob data for uuid', (done) => {
|
||||
const scheme = 'temp'
|
||||
const scheme = 'cors-blob'
|
||||
const protocol = session.defaultSession.protocol
|
||||
const url = `${scheme}://host`
|
||||
before(() => {
|
||||
@@ -648,8 +706,6 @@ describe('session module', () => {
|
||||
})
|
||||
const content = `<html>
|
||||
<script>
|
||||
const {webFrame} = require('electron')
|
||||
webFrame.registerURLSchemeAsPrivileged('${scheme}')
|
||||
let fd = new FormData();
|
||||
fd.append('file', new Blob(['${postData}'], {type:'application/json'}));
|
||||
fetch('${url}', {method:'POST', body: fd });
|
||||
|
||||
@@ -4,7 +4,7 @@ const dirtyChai = require('dirty-chai')
|
||||
const path = require('path')
|
||||
const { closeWindow } = require('./window-helpers')
|
||||
const { remote, webFrame } = require('electron')
|
||||
const { BrowserWindow, protocol, ipcMain } = remote
|
||||
const { BrowserWindow, ipcMain } = remote
|
||||
|
||||
const { expect } = chai
|
||||
chai.use(dirtyChai)
|
||||
@@ -20,124 +20,6 @@ describe('webFrame module', function () {
|
||||
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 () {
|
||||
assert.doesNotThrow(function () {
|
||||
webFrame.setVisualZoomLevelLimits(1, 50)
|
||||
|
||||
59
spec/fixtures/api/cookie-app/main.js
vendored
59
spec/fixtures/api/cookie-app/main.js
vendored
@@ -3,51 +3,30 @@ const { app, session } = require('electron')
|
||||
app.on('ready', async function () {
|
||||
const url = 'http://foo.bar'
|
||||
const persistentSession = session.fromPartition('persist:ence-test')
|
||||
const name = 'test'
|
||||
const value = 'true'
|
||||
|
||||
const set = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
persistentSession.cookies.set({
|
||||
url,
|
||||
name: 'test',
|
||||
value: 'true',
|
||||
expirationDate: Date.now() + 60000
|
||||
}, error => {
|
||||
if (error) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
const set = () => persistentSession.cookies.set({
|
||||
url,
|
||||
name,
|
||||
value,
|
||||
expirationDate: Date.now() + 60000
|
||||
})
|
||||
|
||||
const get = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
persistentSession.cookies.get({ url }, (error, list) => {
|
||||
if (error) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve(list)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
const get = () => persistentSession.cookies.get({
|
||||
url
|
||||
})
|
||||
|
||||
const maybeRemove = (pred) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const maybeRemove = async (pred) => new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
if (pred()) {
|
||||
persistentSession.cookies.remove(url, 'test', error => {
|
||||
if (error) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
resolve()
|
||||
await persistentSession.cookies.remove(url, name)
|
||||
}
|
||||
})
|
||||
}
|
||||
resolve()
|
||||
} catch (error) {
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
await maybeRemove(() => process.env.PHASE === 'one')
|
||||
|
||||
1
spec/fixtures/module/get-global-preload.js
vendored
Normal file
1
spec/fixtures/module/get-global-preload.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
require('electron').ipcRenderer.send('vars', window.preload1, window.preload2)
|
||||
1
spec/fixtures/module/set-global-preload-3.js
vendored
1
spec/fixtures/module/set-global-preload-3.js
vendored
@@ -1 +0,0 @@
|
||||
window.preload3 = window.preload2 + '-3'
|
||||
@@ -428,6 +428,30 @@ describe('node feature', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('crypto', () => {
|
||||
it('should list the ripemd160 hash in getHashes', () => {
|
||||
expect(require('crypto').getHashes()).to.include('ripemd160')
|
||||
})
|
||||
|
||||
it('should be able to create a ripemd160 hash and use it', () => {
|
||||
const hash = require('crypto').createHash('ripemd160')
|
||||
hash.update('electron-ripemd160')
|
||||
expect(hash.digest('hex')).to.equal('fa7fec13c624009ab126ebb99eda6525583395fe')
|
||||
})
|
||||
|
||||
it('should list aes-{128,256}-cfb in getCiphers', () => {
|
||||
expect(require('crypto').getCiphers()).to.include.members(['aes-128-cfb', 'aes-256-cfb'])
|
||||
})
|
||||
|
||||
it('should be able to create an aes-128-cfb cipher', () => {
|
||||
require('crypto').createCipheriv('aes-128-cfb', '0123456789abcdef', '0123456789abcdef')
|
||||
})
|
||||
|
||||
it('should be able to create an aes-256-cfb cipher', () => {
|
||||
require('crypto').createCipheriv('aes-256-cfb', '0123456789abcdef0123456789abcdef', '0123456789abcdef')
|
||||
})
|
||||
})
|
||||
|
||||
it('includes the electron version in process.versions', () => {
|
||||
expect(process.versions)
|
||||
.to.have.own.property('electron')
|
||||
|
||||
32
spec/package-lock.json
generated
32
spec/package-lock.json
generated
@@ -72,7 +72,7 @@
|
||||
},
|
||||
"bl": {
|
||||
"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==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -228,7 +228,7 @@
|
||||
},
|
||||
"commander": {
|
||||
"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==",
|
||||
"dev": true
|
||||
},
|
||||
@@ -267,7 +267,7 @@
|
||||
},
|
||||
"dbus-native": {
|
||||
"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==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -358,7 +358,7 @@
|
||||
},
|
||||
"duplexer": {
|
||||
"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=",
|
||||
"dev": true
|
||||
},
|
||||
@@ -512,7 +512,7 @@
|
||||
},
|
||||
"get-stream": {
|
||||
"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=",
|
||||
"dev": true
|
||||
},
|
||||
@@ -753,7 +753,7 @@
|
||||
},
|
||||
"mkdirp": {
|
||||
"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=",
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
@@ -761,7 +761,7 @@
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"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="
|
||||
}
|
||||
}
|
||||
@@ -941,7 +941,7 @@
|
||||
},
|
||||
"os-homedir": {
|
||||
"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=",
|
||||
"optional": true
|
||||
},
|
||||
@@ -958,7 +958,7 @@
|
||||
},
|
||||
"os-tmpdir": {
|
||||
"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=",
|
||||
"dev": true
|
||||
},
|
||||
@@ -1000,7 +1000,7 @@
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"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=",
|
||||
"dev": true
|
||||
},
|
||||
@@ -1018,7 +1018,7 @@
|
||||
},
|
||||
"pause-stream": {
|
||||
"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=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -1139,7 +1139,7 @@
|
||||
},
|
||||
"rimraf": {
|
||||
"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=",
|
||||
"dev": true
|
||||
},
|
||||
@@ -1305,7 +1305,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"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==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
@@ -1321,7 +1321,7 @@
|
||||
},
|
||||
"strip-eof": {
|
||||
"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=",
|
||||
"dev": true
|
||||
},
|
||||
@@ -1391,7 +1391,7 @@
|
||||
},
|
||||
"through": {
|
||||
"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=",
|
||||
"dev": true
|
||||
},
|
||||
@@ -1486,7 +1486,7 @@
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"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=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
||||
@@ -97,7 +97,14 @@ global.nativeModulesEnabled = !process.env.ELECTRON_SKIP_NATIVE_MODULE_TESTS
|
||||
// Register app as standard scheme.
|
||||
global.standardScheme = 'app'
|
||||
global.zoomScheme = 'zoom'
|
||||
protocol.registerStandardSchemes([global.standardScheme, global.zoomScheme], { secure: true })
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
{ scheme: global.standardScheme, privileges: { standard: true, secure: true } },
|
||||
{ scheme: global.zoomScheme, privileges: { standard: true, secure: true } },
|
||||
{ scheme: 'cors', privileges: { corsEnabled: true, supportFetchAPI: true } },
|
||||
{ scheme: 'cors-blob', privileges: { corsEnabled: true, supportFetchAPI: true } },
|
||||
{ scheme: 'no-cors', privileges: { supportFetchAPI: true } },
|
||||
{ scheme: 'no-fetch', privileges: { corsEnabled: true } }
|
||||
])
|
||||
|
||||
app.on('window-all-closed', function () {
|
||||
app.quit()
|
||||
|
||||
@@ -70,18 +70,24 @@ steps:
|
||||
python electron/script/verify-ffmpeg.py --source-root "$PWD" --build-dir out/Default --ffmpeg-path out/ffmpeg
|
||||
displayName: Verify non proprietary ffmpeg
|
||||
timeoutInMinutes: 5
|
||||
env:
|
||||
ELECTRON_DISABLE_SANDBOX: 1
|
||||
|
||||
- bash: |
|
||||
cd src
|
||||
python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default
|
||||
displayName: Verify mksnapshot
|
||||
timeoutInMinutes: 5
|
||||
env:
|
||||
ELECTRON_DISABLE_SANDBOX: 1
|
||||
|
||||
- bash: |
|
||||
cd src
|
||||
./out/Default/electron electron/spec --ci
|
||||
displayName: 'Run Electron tests'
|
||||
timeoutInMinutes: 10
|
||||
env:
|
||||
ELECTRON_DISABLE_SANDBOX: 1
|
||||
|
||||
- task: PublishTestResults@2
|
||||
displayName: 'Publish Test Results'
|
||||
|
||||
Reference in New Issue
Block a user