Disallow launching unknown apps via browser client.
CVE-2018-1000006
This commit is contained in:
		
					parent
					
						
							
								32a1395bcf
							
						
					
				
			
			
				commit
				
					
						c49cb29ddf
					
				
			
		
					 17 changed files with 1553 additions and 101 deletions
				
			
		| 
						 | 
				
			
			@ -10,7 +10,7 @@
 | 
			
		|||
#if defined(OS_MACOSX)
 | 
			
		||||
extern "C" {
 | 
			
		||||
__attribute__((visibility("default")))
 | 
			
		||||
int AtomMain(int argc, const char* argv[]);
 | 
			
		||||
int AtomMain(int argc, char* argv[]);
 | 
			
		||||
 | 
			
		||||
__attribute__((visibility("default")))
 | 
			
		||||
int AtomInitializeICUandStartNode(int argc, char *argv[]);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,11 +15,11 @@
 | 
			
		|||
#include "content/public/app/content_main.h"
 | 
			
		||||
 | 
			
		||||
#if defined(OS_MACOSX)
 | 
			
		||||
int AtomMain(int argc, const char* argv[]) {
 | 
			
		||||
int AtomMain(int argc, char* argv[]) {
 | 
			
		||||
  atom::AtomMainDelegate delegate;
 | 
			
		||||
  content::ContentMainParams params(&delegate);
 | 
			
		||||
  params.argc = argc;
 | 
			
		||||
  params.argv = argv;
 | 
			
		||||
  params.argv = const_cast<const char**>(argv);
 | 
			
		||||
  atom::AtomCommandLine::Init(argc, argv);
 | 
			
		||||
  return content::ContentMain(params);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,8 @@
 | 
			
		|||
 | 
			
		||||
#include "atom/app/atom_main.h"
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#if defined(OS_WIN)
 | 
			
		||||
#include <windows.h>  // windows.h must be included first
 | 
			
		||||
| 
						 | 
				
			
			@ -15,9 +16,11 @@
 | 
			
		|||
#include <tchar.h>
 | 
			
		||||
 | 
			
		||||
#include "atom/app/atom_main_delegate.h"
 | 
			
		||||
#include "atom/app/command_line_args.h"
 | 
			
		||||
#include "atom/common/crash_reporter/win/crash_service_main.h"
 | 
			
		||||
#include "base/environment.h"
 | 
			
		||||
#include "base/process/launch.h"
 | 
			
		||||
#include "base/strings/utf_string_conversions.h"
 | 
			
		||||
#include "base/win/windows_version.h"
 | 
			
		||||
#include "content/public/app/sandbox_helper_win.h"
 | 
			
		||||
#include "sandbox/win/src/sandbox_types.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -52,18 +55,23 @@ bool IsEnvSet(const char* name) {
 | 
			
		|||
 | 
			
		||||
#if defined(OS_WIN)
 | 
			
		||||
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
 | 
			
		||||
  int argc = 0;
 | 
			
		||||
  wchar_t** wargv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
 | 
			
		||||
  struct Arguments {
 | 
			
		||||
    int argc = 0;
 | 
			
		||||
    wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
 | 
			
		||||
 | 
			
		||||
  bool run_as_node = IsEnvSet(kRunAsNode);
 | 
			
		||||
    ~Arguments() { LocalFree(argv); }
 | 
			
		||||
  } arguments;
 | 
			
		||||
 | 
			
		||||
  if (!arguments.argv)
 | 
			
		||||
    return -1;
 | 
			
		||||
 | 
			
		||||
#ifdef _DEBUG
 | 
			
		||||
  // Don't display assert dialog boxes in CI test runs
 | 
			
		||||
  static const auto kCI = "ELECTRON_CI";
 | 
			
		||||
  bool is_ci = IsEnvSet(kCI);
 | 
			
		||||
  if (!is_ci) {
 | 
			
		||||
    for (int i = 0; i < argc; ++i) {
 | 
			
		||||
      if (!_wcsicmp(wargv[i], L"--ci")) {
 | 
			
		||||
    for (int i = 0; i < arguments.argc; ++i) {
 | 
			
		||||
      if (!_wcsicmp(arguments.argv[i], L"--ci")) {
 | 
			
		||||
        is_ci = true;
 | 
			
		||||
        _putenv_s(kCI, "1");  // set flag for child processes
 | 
			
		||||
        break;
 | 
			
		||||
| 
						 | 
				
			
			@ -81,44 +89,12 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
 | 
			
		|||
  }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  bool run_as_node = IsEnvSet(kRunAsNode);
 | 
			
		||||
 | 
			
		||||
  // Make sure the output is printed to console.
 | 
			
		||||
  if (run_as_node || !IsEnvSet("ELECTRON_NO_ATTACH_CONSOLE"))
 | 
			
		||||
    base::RouteStdioToConsole(false);
 | 
			
		||||
 | 
			
		||||
  // Convert argv to to UTF8
 | 
			
		||||
  char** argv = new char*[argc];
 | 
			
		||||
  for (int i = 0; i < argc; i++) {
 | 
			
		||||
    // Compute the size of the required buffer
 | 
			
		||||
    DWORD size = WideCharToMultiByte(CP_UTF8,
 | 
			
		||||
                                     0,
 | 
			
		||||
                                     wargv[i],
 | 
			
		||||
                                     -1,
 | 
			
		||||
                                     NULL,
 | 
			
		||||
                                     0,
 | 
			
		||||
                                     NULL,
 | 
			
		||||
                                     NULL);
 | 
			
		||||
    if (size == 0) {
 | 
			
		||||
      // This should never happen.
 | 
			
		||||
      fprintf(stderr, "Could not convert arguments to utf8.");
 | 
			
		||||
      exit(1);
 | 
			
		||||
    }
 | 
			
		||||
    // Do the actual conversion
 | 
			
		||||
    argv[i] = new char[size];
 | 
			
		||||
    DWORD result = WideCharToMultiByte(CP_UTF8,
 | 
			
		||||
                                       0,
 | 
			
		||||
                                       wargv[i],
 | 
			
		||||
                                       -1,
 | 
			
		||||
                                       argv[i],
 | 
			
		||||
                                       size,
 | 
			
		||||
                                       NULL,
 | 
			
		||||
                                       NULL);
 | 
			
		||||
    if (result == 0) {
 | 
			
		||||
      // This should never happen.
 | 
			
		||||
      fprintf(stderr, "Could not convert arguments to utf8.");
 | 
			
		||||
      exit(1);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#ifndef DEBUG
 | 
			
		||||
  // Chromium has its own TLS subsystem which supports automatic destruction
 | 
			
		||||
  // of thread-local data, and also depends on memory allocation routines
 | 
			
		||||
| 
						 | 
				
			
			@ -139,14 +115,23 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
  if (run_as_node) {
 | 
			
		||||
    // Now that argv conversion is done, we can finally start.
 | 
			
		||||
    std::vector<char*> argv(arguments.argc);
 | 
			
		||||
    std::transform(
 | 
			
		||||
        arguments.argv, arguments.argv + arguments.argc, argv.begin(),
 | 
			
		||||
        [](auto& a) { return _strdup(base::WideToUTF8(a).c_str()); });
 | 
			
		||||
 | 
			
		||||
    base::AtExitManager atexit_manager;
 | 
			
		||||
    base::i18n::InitializeICU();
 | 
			
		||||
    return atom::NodeMain(argc, argv);
 | 
			
		||||
    auto ret = atom::NodeMain(argv.size(), argv.data());
 | 
			
		||||
    std::for_each(argv.begin(), argv.end(), free);
 | 
			
		||||
    return ret;
 | 
			
		||||
  } else if (IsEnvSet("ELECTRON_INTERNAL_CRASH_SERVICE")) {
 | 
			
		||||
    return crash_service::Main(cmd);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!atom::CheckCommandLineArguments(arguments.argc, arguments.argv))
 | 
			
		||||
    return -1;
 | 
			
		||||
 | 
			
		||||
  sandbox::SandboxInterfaceInfo sandbox_info = {0};
 | 
			
		||||
  content::InitializeSandboxInfo(&sandbox_info);
 | 
			
		||||
  atom::AtomMainDelegate delegate;
 | 
			
		||||
| 
						 | 
				
			
			@ -154,33 +139,32 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
 | 
			
		|||
  content::ContentMainParams params(&delegate);
 | 
			
		||||
  params.instance = instance;
 | 
			
		||||
  params.sandbox_info = &sandbox_info;
 | 
			
		||||
  atom::AtomCommandLine::Init(argc, argv);
 | 
			
		||||
  atom::AtomCommandLine::InitW(argc, wargv);
 | 
			
		||||
  atom::AtomCommandLine::Init(arguments.argc, arguments.argv);
 | 
			
		||||
  return content::ContentMain(params);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#elif defined(OS_LINUX)  // defined(OS_WIN)
 | 
			
		||||
 | 
			
		||||
int main(int argc, const char* argv[]) {
 | 
			
		||||
int main(int argc, char* argv[]) {
 | 
			
		||||
  if (IsEnvSet(kRunAsNode)) {
 | 
			
		||||
    base::i18n::InitializeICU();
 | 
			
		||||
    base::AtExitManager atexit_manager;
 | 
			
		||||
    return atom::NodeMain(argc, const_cast<char**>(argv));
 | 
			
		||||
    return atom::NodeMain(argc, argv);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  atom::AtomMainDelegate delegate;
 | 
			
		||||
  content::ContentMainParams params(&delegate);
 | 
			
		||||
  params.argc = argc;
 | 
			
		||||
  params.argv = argv;
 | 
			
		||||
  params.argv = const_cast<const char**>(argv);
 | 
			
		||||
  atom::AtomCommandLine::Init(argc, argv);
 | 
			
		||||
  return content::ContentMain(params);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#else  // defined(OS_LINUX)
 | 
			
		||||
 | 
			
		||||
int main(int argc, const char* argv[]) {
 | 
			
		||||
int main(int argc, char* argv[]) {
 | 
			
		||||
  if (IsEnvSet(kRunAsNode)) {
 | 
			
		||||
    return AtomInitializeICUandStartNode(argc, const_cast<char**>(argv));
 | 
			
		||||
    return AtomInitializeICUandStartNode(argc, argv);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return AtomMain(argc, argv);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1411
									
								
								atom/app/command_line_args.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1411
									
								
								atom/app/command_line_args.cc
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										17
									
								
								atom/app/command_line_args.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								atom/app/command_line_args.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
// Copyright (c) 2018 GitHub, Inc.
 | 
			
		||||
// Use of this source code is governed by the MIT license that can be
 | 
			
		||||
// found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
#ifndef ATOM_APP_COMMAND_LINE_ARGS_H_
 | 
			
		||||
#define ATOM_APP_COMMAND_LINE_ARGS_H_
 | 
			
		||||
 | 
			
		||||
#include "base/command_line.h"
 | 
			
		||||
 | 
			
		||||
namespace atom {
 | 
			
		||||
 | 
			
		||||
bool CheckCommandLineArguments(int argc, base::CommandLine::CharType** argv);
 | 
			
		||||
 | 
			
		||||
}  // namespace atom
 | 
			
		||||
 | 
			
		||||
#endif  // ATOM_APP_COMMAND_LINE_ARGS_H_
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -897,11 +897,7 @@ bool App::Relaunch(mate::Arguments* js_args) {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  if (!override_argv) {
 | 
			
		||||
#if defined(OS_WIN)
 | 
			
		||||
    const relauncher::StringVector& argv = atom::AtomCommandLine::wargv();
 | 
			
		||||
#else
 | 
			
		||||
    const relauncher::StringVector& argv = atom::AtomCommandLine::argv();
 | 
			
		||||
#endif
 | 
			
		||||
    return relauncher::RelaunchApp(argv);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,6 +38,7 @@
 | 
			
		|||
#include "content/public/browser/resource_dispatcher_host.h"
 | 
			
		||||
#include "content/public/browser/site_instance.h"
 | 
			
		||||
#include "content/public/browser/web_contents.h"
 | 
			
		||||
#include "content/public/common/content_paths.h"
 | 
			
		||||
#include "content/public/common/content_switches.h"
 | 
			
		||||
#include "content/public/common/resource_request_body.h"
 | 
			
		||||
#include "content/public/common/url_constants.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -237,6 +238,11 @@ void AtomBrowserClient::OverrideSiteInstanceForNavigation(
 | 
			
		|||
void AtomBrowserClient::AppendExtraCommandLineSwitches(
 | 
			
		||||
    base::CommandLine* command_line,
 | 
			
		||||
    int process_id) {
 | 
			
		||||
  // Make sure we're about to launch a known executable
 | 
			
		||||
  base::FilePath child_path;
 | 
			
		||||
  PathService::Get(content::CHILD_PROCESS_EXE, &child_path);
 | 
			
		||||
  CHECK(base::MakeAbsoluteFilePath(command_line->GetProgram()) == child_path);
 | 
			
		||||
 | 
			
		||||
  std::string process_type =
 | 
			
		||||
      command_line->GetSwitchValueASCII(::switches::kProcessType);
 | 
			
		||||
  if (process_type != ::switches::kRendererProcess)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -140,11 +140,7 @@ bool RelaunchAppWithHelper(const base::FilePath& helper,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
int RelauncherMain(const content::MainFunctionParams& main_parameters) {
 | 
			
		||||
#if defined(OS_WIN)
 | 
			
		||||
  const StringVector& argv = atom::AtomCommandLine::wargv();
 | 
			
		||||
#else
 | 
			
		||||
  const StringVector& argv = atom::AtomCommandLine::argv();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  if (argv.size() < 4 || argv[1] != internal::kRelauncherTypeArg) {
 | 
			
		||||
    LOG(ERROR) << "relauncher process invoked with unexpected arguments";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,31 +10,22 @@
 | 
			
		|||
namespace atom {
 | 
			
		||||
 | 
			
		||||
// static
 | 
			
		||||
std::vector<std::string> AtomCommandLine::argv_;
 | 
			
		||||
 | 
			
		||||
#if defined(OS_WIN)
 | 
			
		||||
// static
 | 
			
		||||
std::vector<std::wstring> AtomCommandLine::wargv_;
 | 
			
		||||
#endif
 | 
			
		||||
base::CommandLine::StringVector AtomCommandLine::argv_;
 | 
			
		||||
 | 
			
		||||
// static
 | 
			
		||||
void AtomCommandLine::Init(int argc, const char* const* argv) {
 | 
			
		||||
void AtomCommandLine::Init(int argc, base::CommandLine::CharType** argv) {
 | 
			
		||||
  DCHECK(argv_.empty());
 | 
			
		||||
 | 
			
		||||
  // NOTE: uv_setup_args does nothing on Windows, so we don't need to call it.
 | 
			
		||||
  // Otherwise we'd have to convert the arguments from UTF16.
 | 
			
		||||
#if !defined(OS_WIN)
 | 
			
		||||
  // Hack around with the argv pointer. Used for process.title = "blah"
 | 
			
		||||
  char** new_argv = uv_setup_args(argc, const_cast<char**>(argv));
 | 
			
		||||
  for (int i = 0; i < argc; ++i) {
 | 
			
		||||
    argv_.push_back(new_argv[i]);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined(OS_WIN)
 | 
			
		||||
// static
 | 
			
		||||
void AtomCommandLine::InitW(int argc, const wchar_t* const* argv) {
 | 
			
		||||
  for (int i = 0; i < argc; ++i) {
 | 
			
		||||
    wargv_.push_back(argv[i]);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
  argv = uv_setup_args(argc, argv);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  argv_.assign(argv, argv + argc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined(OS_LINUX)
 | 
			
		||||
// static
 | 
			
		||||
void AtomCommandLine::InitializeFromCommandLine() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@
 | 
			
		|||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "base/command_line.h"
 | 
			
		||||
#include "base/macros.h"
 | 
			
		||||
#include "build/build_config.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -16,13 +17,9 @@ namespace atom {
 | 
			
		|||
// Singleton to remember the original "argc" and "argv".
 | 
			
		||||
class AtomCommandLine {
 | 
			
		||||
 public:
 | 
			
		||||
  static void Init(int argc, const char* const* argv);
 | 
			
		||||
  static std::vector<std::string> argv() { return argv_; }
 | 
			
		||||
  static const base::CommandLine::StringVector& argv() { return argv_; }
 | 
			
		||||
 | 
			
		||||
#if defined(OS_WIN)
 | 
			
		||||
  static void InitW(int argc, const wchar_t* const* argv);
 | 
			
		||||
  static std::vector<std::wstring> wargv() { return wargv_; }
 | 
			
		||||
#endif
 | 
			
		||||
  static void Init(int argc, base::CommandLine::CharType** argv);
 | 
			
		||||
 | 
			
		||||
#if defined(OS_LINUX)
 | 
			
		||||
  // On Linux the command line has to be read from base::CommandLine since
 | 
			
		||||
| 
						 | 
				
			
			@ -31,11 +28,7 @@ class AtomCommandLine {
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  static std::vector<std::string> argv_;
 | 
			
		||||
 | 
			
		||||
#if defined(OS_WIN)
 | 
			
		||||
  static std::vector<std::wstring> wargv_;
 | 
			
		||||
#endif
 | 
			
		||||
  static base::CommandLine::StringVector argv_;
 | 
			
		||||
 | 
			
		||||
  DISALLOW_IMPLICIT_CONSTRUCTORS(AtomCommandLine);
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@
 | 
			
		|||
 | 
			
		||||
#include "atom/common/node_bindings.h"
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -17,6 +18,7 @@
 | 
			
		|||
#include "base/files/file_path.h"
 | 
			
		||||
#include "base/path_service.h"
 | 
			
		||||
#include "base/run_loop.h"
 | 
			
		||||
#include "base/strings/utf_string_conversions.h"
 | 
			
		||||
#include "base/threading/thread_task_runner_handle.h"
 | 
			
		||||
#include "base/trace_event/trace_event.h"
 | 
			
		||||
#include "content/public/browser/browser_thread.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -179,7 +181,14 @@ void NodeBindings::Initialize() {
 | 
			
		|||
 | 
			
		||||
node::Environment* NodeBindings::CreateEnvironment(
 | 
			
		||||
    v8::Handle<v8::Context> context) {
 | 
			
		||||
#if defined(OS_WIN)
 | 
			
		||||
  auto& atom_args = AtomCommandLine::argv();
 | 
			
		||||
  std::vector<std::string> args(atom_args.size());
 | 
			
		||||
  std::transform(atom_args.cbegin(), atom_args.cend(), args.begin(),
 | 
			
		||||
                 [](auto& a) { return base::WideToUTF8(a); });
 | 
			
		||||
#else
 | 
			
		||||
  auto args = AtomCommandLine::argv();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  // Feed node the path to initialization script.
 | 
			
		||||
  base::FilePath::StringType process_type;
 | 
			
		||||
| 
						 | 
				
			
			@ -199,8 +208,7 @@ node::Environment* NodeBindings::CreateEnvironment(
 | 
			
		|||
      resources_path.Append(FILE_PATH_LITERAL("electron.asar"))
 | 
			
		||||
                    .Append(process_type)
 | 
			
		||||
                    .Append(FILE_PATH_LITERAL("init.js"));
 | 
			
		||||
  std::string script_path_str = script_path.AsUTF8Unsafe();
 | 
			
		||||
  args.insert(args.begin() + 1, script_path_str.c_str());
 | 
			
		||||
  args.insert(args.begin() + 1, script_path.AsUTF8Unsafe());
 | 
			
		||||
 | 
			
		||||
  std::unique_ptr<const char*[]> c_argv = StringVectorToArgArray(args);
 | 
			
		||||
  node::Environment* env = node::CreateEnvironment(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,7 +32,7 @@ the hostname and the port number 'hostname:port'.
 | 
			
		|||
  * `redirect` String (optional) - The redirect mode for this request. Should be
 | 
			
		||||
one of `follow`, `error` or `manual`. Defaults to `follow`. When mode is `error`,
 | 
			
		||||
any redirection will be aborted. When mode is `manual` the redirection will be
 | 
			
		||||
deferred until [`request.followRedirect`](#requestfollowRedirect) is invoked. Listen for the [`redirect`](#event-redirect) event in
 | 
			
		||||
deferred until [`request.followRedirect`](#requestfollowredirect) is invoked. Listen for the [`redirect`](#event-redirect) event in
 | 
			
		||||
this mode to get more details about the redirect request.
 | 
			
		||||
 | 
			
		||||
`options` properties such as `protocol`, `host`, `hostname`, `port` and `path`
 | 
			
		||||
| 
						 | 
				
			
			@ -137,7 +137,7 @@ Returns:
 | 
			
		|||
* `responseHeaders` Object
 | 
			
		||||
 | 
			
		||||
Emitted when there is redirection and the mode is `manual`. Calling
 | 
			
		||||
[`request.followRedirect`](#requestfollowRedirect) will continue with the redirection.
 | 
			
		||||
[`request.followRedirect`](#requestfollowredirect) will continue with the redirection.
 | 
			
		||||
 | 
			
		||||
### Instance Properties
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -291,7 +291,7 @@ Calling `event.preventDefault` will prevent the page `keydown`/`keyup` events
 | 
			
		|||
and the menu shortcuts.
 | 
			
		||||
 | 
			
		||||
To only prevent the menu shortcuts, use
 | 
			
		||||
[`setIgnoreMenuShortcuts`](#contentssetignoremenushortcuts):
 | 
			
		||||
[`setIgnoreMenuShortcuts`](#contentssetignoremenushortcutsignore-experimental):
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
const {BrowserWindow} = require('electron')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -528,7 +528,7 @@ can be obtained by subscribing to [`found-in-page`](webview-tag.md#event-found-i
 | 
			
		|||
### `<webview>.stopFindInPage(action)`
 | 
			
		||||
 | 
			
		||||
* `action` String - Specifies the action to take place when ending
 | 
			
		||||
  [`<webview>.findInPage`](webview-tag.md#webviewtagfindinpage) request.
 | 
			
		||||
  [`<webview>.findInPage`](#webviewfindinpagetext-options) request.
 | 
			
		||||
  * `clearSelection` - Clear the selection.
 | 
			
		||||
  * `keepSelection` - Translate the selection into a normal selection.
 | 
			
		||||
  * `activateSelection` - Focus and click the selection node.
 | 
			
		||||
| 
						 | 
				
			
			@ -579,7 +579,7 @@ Send an asynchronous message to renderer process via `channel`, you can also
 | 
			
		|||
send arbitrary arguments. The renderer process can handle the message by
 | 
			
		||||
listening to the `channel` event with the [`ipcRenderer`](ipc-renderer.md) module.
 | 
			
		||||
 | 
			
		||||
See [webContents.send](web-contents.md#webcontentssendchannel-args) for
 | 
			
		||||
See [webContents.send](web-contents.md#contentssendchannel-arg1-arg2-) for
 | 
			
		||||
examples.
 | 
			
		||||
 | 
			
		||||
### `<webview>.sendInputEvent(event)`
 | 
			
		||||
| 
						 | 
				
			
			@ -588,7 +588,7 @@ examples.
 | 
			
		|||
 | 
			
		||||
Sends an input `event` to the page.
 | 
			
		||||
 | 
			
		||||
See [webContents.sendInputEvent](web-contents.md#webcontentssendinputeventevent)
 | 
			
		||||
See [webContents.sendInputEvent](web-contents.md#contentssendinputeventevent)
 | 
			
		||||
for detailed description of `event` object.
 | 
			
		||||
 | 
			
		||||
### `<webview>.setZoomFactor(factor)`
 | 
			
		||||
| 
						 | 
				
			
			@ -752,7 +752,7 @@ Returns:
 | 
			
		|||
  * `finalUpdate` Boolean
 | 
			
		||||
 | 
			
		||||
Fired when a result is available for
 | 
			
		||||
[`webview.findInPage`](webview-tag.md#webviewtagfindinpage) request.
 | 
			
		||||
[`webview.findInPage`](#webviewfindinpagetext-options) request.
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
const webview = document.querySelector('webview')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ To ensure that your JavaScript is in compliance with the Electron coding
 | 
			
		|||
style, run `npm run lint-js`, which will run `standard` against both
 | 
			
		||||
Electron itself as well as the unit tests. If you are using an editor
 | 
			
		||||
with a plugin/addon system, you might want to use one of the many
 | 
			
		||||
[StandardJS addons](standard-addons) to be informed of coding style
 | 
			
		||||
[StandardJS addons][standard-addons] to be informed of coding style
 | 
			
		||||
violations before you ever commit them.
 | 
			
		||||
 | 
			
		||||
To run `standard` with parameters, run `npm run lint-js --` followed by
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -99,6 +99,8 @@
 | 
			
		|||
      'atom/app/atom_main_delegate.cc',
 | 
			
		||||
      'atom/app/atom_main_delegate.h',
 | 
			
		||||
      'atom/app/atom_main_delegate_mac.mm',
 | 
			
		||||
      'atom/app/command_line_args.cc',
 | 
			
		||||
      'atom/app/command_line_args.h',
 | 
			
		||||
      'atom/app/node_main.cc',
 | 
			
		||||
      'atom/app/node_main.h',
 | 
			
		||||
      'atom/app/uv_task_runner.cc',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -634,6 +634,54 @@ describe('app module', () => {
 | 
			
		|||
    })
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  describe('app launch through uri', () => {
 | 
			
		||||
    before(function () {
 | 
			
		||||
      if (process.platform !== 'win32') {
 | 
			
		||||
        this.skip()
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    it('does not launch for blacklisted argument', function (done) {
 | 
			
		||||
      const appPath = path.join(__dirname, 'fixtures', 'api', 'quit-app')
 | 
			
		||||
      // App should exit with non 123 code.
 | 
			
		||||
      const first = ChildProcess.spawn(remote.process.execPath, [appPath, 'electron-test://?', '--no-sandbox', '--gpu-launcher=cmd.exe /c start calc'])
 | 
			
		||||
      first.once('exit', (code) => {
 | 
			
		||||
        assert.notEqual(code, 123)
 | 
			
		||||
        done()
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    it('launches successfully for multiple uris in cmd args', function (done) {
 | 
			
		||||
      const appPath = path.join(__dirname, 'fixtures', 'api', 'quit-app')
 | 
			
		||||
      // App should exit with code 123.
 | 
			
		||||
      const first = ChildProcess.spawn(remote.process.execPath, [appPath, 'http://electronjs.org', 'electron-test://testdata'])
 | 
			
		||||
      first.once('exit', (code) => {
 | 
			
		||||
        assert.equal(code, 123)
 | 
			
		||||
        done()
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    it('does not launch for encoded space', function (done) {
 | 
			
		||||
      const appPath = path.join(__dirname, 'fixtures', 'api', 'quit-app')
 | 
			
		||||
      // App should exit with non 123 code.
 | 
			
		||||
      const first = ChildProcess.spawn(remote.process.execPath, [appPath, 'electron-test://?', '--no-sandbox', '--gpu-launcher%20"cmd.exe /c start calc'])
 | 
			
		||||
      first.once('exit', (code) => {
 | 
			
		||||
        assert.notEqual(code, 123)
 | 
			
		||||
        done()
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    it('launches successfully for argnames similar to blacklisted ones', function (done) {
 | 
			
		||||
      const appPath = path.join(__dirname, 'fixtures', 'api', 'quit-app')
 | 
			
		||||
      // inspect is blacklisted, but inspector should work, and app launch should succeed
 | 
			
		||||
      const first = ChildProcess.spawn(remote.process.execPath, [appPath, 'electron-test://?', '--inspector'])
 | 
			
		||||
      first.once('exit', (code) => {
 | 
			
		||||
        assert.equal(code, 123)
 | 
			
		||||
        done()
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  describe('getFileIcon() API', () => {
 | 
			
		||||
    const iconPath = path.join(__dirname, 'fixtures/assets/icon.ico')
 | 
			
		||||
    const sizes = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue