atom_api_app.cc 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112
  1. // Copyright (c) 2013 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "atom/browser/api/atom_api_app.h"
  5. #include <string>
  6. #include <vector>
  7. #include "atom/browser/api/atom_api_menu.h"
  8. #include "atom/browser/api/atom_api_session.h"
  9. #include "atom/browser/api/atom_api_web_contents.h"
  10. #include "atom/browser/atom_browser_context.h"
  11. #include "atom/browser/atom_browser_main_parts.h"
  12. #include "atom/browser/login_handler.h"
  13. #include "atom/browser/relauncher.h"
  14. #include "atom/common/atom_command_line.h"
  15. #include "atom/common/native_mate_converters/callback.h"
  16. #include "atom/common/native_mate_converters/file_path_converter.h"
  17. #include "atom/common/native_mate_converters/gurl_converter.h"
  18. #include "atom/common/native_mate_converters/image_converter.h"
  19. #include "atom/common/native_mate_converters/net_converter.h"
  20. #include "atom/common/native_mate_converters/value_converter.h"
  21. #include "atom/common/node_includes.h"
  22. #include "atom/common/options_switches.h"
  23. #include "base/command_line.h"
  24. #include "base/environment.h"
  25. #include "base/files/file_path.h"
  26. #include "base/files/file_util.h"
  27. #include "base/path_service.h"
  28. #include "base/strings/string_util.h"
  29. #include "brightray/browser/brightray_paths.h"
  30. #include "chrome/browser/browser_process.h"
  31. #include "chrome/browser/icon_manager.h"
  32. #include "chrome/common/chrome_paths.h"
  33. #include "content/public/browser/browser_accessibility_state.h"
  34. #include "content/public/browser/browser_child_process_host.h"
  35. #include "content/public/browser/client_certificate_delegate.h"
  36. #include "content/public/browser/gpu_data_manager.h"
  37. #include "content/public/browser/render_frame_host.h"
  38. #include "content/public/common/content_switches.h"
  39. #include "media/audio/audio_manager.h"
  40. #include "native_mate/object_template_builder.h"
  41. #include "net/ssl/ssl_cert_request_info.h"
  42. #include "ui/base/l10n/l10n_util.h"
  43. #include "ui/gfx/image/image.h"
  44. #if defined(OS_WIN)
  45. #include "atom/browser/ui/win/jump_list.h"
  46. #include "base/strings/utf_string_conversions.h"
  47. #endif
  48. using atom::Browser;
  49. namespace mate {
  50. #if defined(OS_WIN)
  51. template<>
  52. struct Converter<Browser::UserTask> {
  53. static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
  54. Browser::UserTask* out) {
  55. mate::Dictionary dict;
  56. if (!ConvertFromV8(isolate, val, &dict))
  57. return false;
  58. if (!dict.Get("program", &(out->program)) ||
  59. !dict.Get("title", &(out->title)))
  60. return false;
  61. if (dict.Get("iconPath", &(out->icon_path)) &&
  62. !dict.Get("iconIndex", &(out->icon_index)))
  63. return false;
  64. dict.Get("arguments", &(out->arguments));
  65. dict.Get("description", &(out->description));
  66. return true;
  67. }
  68. };
  69. using atom::JumpListItem;
  70. using atom::JumpListCategory;
  71. using atom::JumpListResult;
  72. template<>
  73. struct Converter<JumpListItem::Type> {
  74. static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
  75. JumpListItem::Type* out) {
  76. std::string item_type;
  77. if (!ConvertFromV8(isolate, val, &item_type))
  78. return false;
  79. if (item_type == "task")
  80. *out = JumpListItem::Type::TASK;
  81. else if (item_type == "separator")
  82. *out = JumpListItem::Type::SEPARATOR;
  83. else if (item_type == "file")
  84. *out = JumpListItem::Type::FILE;
  85. else
  86. return false;
  87. return true;
  88. }
  89. static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
  90. JumpListItem::Type val) {
  91. std::string item_type;
  92. switch (val) {
  93. case JumpListItem::Type::TASK:
  94. item_type = "task";
  95. break;
  96. case JumpListItem::Type::SEPARATOR:
  97. item_type = "separator";
  98. break;
  99. case JumpListItem::Type::FILE:
  100. item_type = "file";
  101. break;
  102. }
  103. return mate::ConvertToV8(isolate, item_type);
  104. }
  105. };
  106. template<>
  107. struct Converter<JumpListItem> {
  108. static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
  109. JumpListItem* out) {
  110. mate::Dictionary dict;
  111. if (!ConvertFromV8(isolate, val, &dict))
  112. return false;
  113. if (!dict.Get("type", &(out->type)))
  114. return false;
  115. switch (out->type) {
  116. case JumpListItem::Type::TASK:
  117. if (!dict.Get("program", &(out->path)) ||
  118. !dict.Get("title", &(out->title)))
  119. return false;
  120. if (dict.Get("iconPath", &(out->icon_path)) &&
  121. !dict.Get("iconIndex", &(out->icon_index)))
  122. return false;
  123. dict.Get("args", &(out->arguments));
  124. dict.Get("description", &(out->description));
  125. return true;
  126. case JumpListItem::Type::SEPARATOR:
  127. return true;
  128. case JumpListItem::Type::FILE:
  129. return dict.Get("path", &(out->path));
  130. }
  131. assert(false);
  132. return false;
  133. }
  134. static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
  135. const JumpListItem& val) {
  136. mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
  137. dict.Set("type", val.type);
  138. switch (val.type) {
  139. case JumpListItem::Type::TASK:
  140. dict.Set("program", val.path);
  141. dict.Set("args", val.arguments);
  142. dict.Set("title", val.title);
  143. dict.Set("iconPath", val.icon_path);
  144. dict.Set("iconIndex", val.icon_index);
  145. dict.Set("description", val.description);
  146. break;
  147. case JumpListItem::Type::SEPARATOR:
  148. break;
  149. case JumpListItem::Type::FILE:
  150. dict.Set("path", val.path);
  151. break;
  152. }
  153. return dict.GetHandle();
  154. }
  155. };
  156. template<>
  157. struct Converter<JumpListCategory::Type> {
  158. static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
  159. JumpListCategory::Type* out) {
  160. std::string category_type;
  161. if (!ConvertFromV8(isolate, val, &category_type))
  162. return false;
  163. if (category_type == "tasks")
  164. *out = JumpListCategory::Type::TASKS;
  165. else if (category_type == "frequent")
  166. *out = JumpListCategory::Type::FREQUENT;
  167. else if (category_type == "recent")
  168. *out = JumpListCategory::Type::RECENT;
  169. else if (category_type == "custom")
  170. *out = JumpListCategory::Type::CUSTOM;
  171. else
  172. return false;
  173. return true;
  174. }
  175. static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
  176. JumpListCategory::Type val) {
  177. std::string category_type;
  178. switch (val) {
  179. case JumpListCategory::Type::TASKS:
  180. category_type = "tasks";
  181. break;
  182. case JumpListCategory::Type::FREQUENT:
  183. category_type = "frequent";
  184. break;
  185. case JumpListCategory::Type::RECENT:
  186. category_type = "recent";
  187. break;
  188. case JumpListCategory::Type::CUSTOM:
  189. category_type = "custom";
  190. break;
  191. }
  192. return mate::ConvertToV8(isolate, category_type);
  193. }
  194. };
  195. template<>
  196. struct Converter<JumpListCategory> {
  197. static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
  198. JumpListCategory* out) {
  199. mate::Dictionary dict;
  200. if (!ConvertFromV8(isolate, val, &dict))
  201. return false;
  202. if (dict.Get("name", &(out->name)) && out->name.empty())
  203. return false;
  204. if (!dict.Get("type", &(out->type))) {
  205. if (out->name.empty())
  206. out->type = JumpListCategory::Type::TASKS;
  207. else
  208. out->type = JumpListCategory::Type::CUSTOM;
  209. }
  210. if ((out->type == JumpListCategory::Type::TASKS) ||
  211. (out->type == JumpListCategory::Type::CUSTOM)) {
  212. if (!dict.Get("items", &(out->items)))
  213. return false;
  214. }
  215. return true;
  216. }
  217. };
  218. // static
  219. template<>
  220. struct Converter<JumpListResult> {
  221. static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, JumpListResult val) {
  222. std::string result_code;
  223. switch (val) {
  224. case JumpListResult::SUCCESS:
  225. result_code = "ok";
  226. break;
  227. case JumpListResult::ARGUMENT_ERROR:
  228. result_code = "argumentError";
  229. break;
  230. case JumpListResult::GENERIC_ERROR:
  231. result_code = "error";
  232. break;
  233. case JumpListResult::CUSTOM_CATEGORY_SEPARATOR_ERROR:
  234. result_code = "invalidSeparatorError";
  235. break;
  236. case JumpListResult::MISSING_FILE_TYPE_REGISTRATION_ERROR:
  237. result_code = "fileTypeRegistrationError";
  238. break;
  239. case JumpListResult::CUSTOM_CATEGORY_ACCESS_DENIED_ERROR:
  240. result_code = "customCategoryAccessDeniedError";
  241. break;
  242. }
  243. return ConvertToV8(isolate, result_code);
  244. }
  245. };
  246. #endif
  247. template<>
  248. struct Converter<Browser::LoginItemSettings> {
  249. static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
  250. Browser::LoginItemSettings* out) {
  251. mate::Dictionary dict;
  252. if (!ConvertFromV8(isolate, val, &dict))
  253. return false;
  254. dict.Get("openAtLogin", &(out->open_at_login));
  255. dict.Get("openAsHidden", &(out->open_as_hidden));
  256. dict.Get("path", &(out->path));
  257. dict.Get("args", &(out->args));
  258. return true;
  259. }
  260. static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
  261. Browser::LoginItemSettings val) {
  262. mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
  263. dict.Set("openAtLogin", val.open_at_login);
  264. dict.Set("openAsHidden", val.open_as_hidden);
  265. dict.Set("restoreState", val.restore_state);
  266. dict.Set("wasOpenedAtLogin", val.opened_at_login);
  267. dict.Set("wasOpenedAsHidden", val.opened_as_hidden);
  268. return dict.GetHandle();
  269. }
  270. };
  271. template<>
  272. struct Converter<content::CertificateRequestResultType> {
  273. static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
  274. content::CertificateRequestResultType* out) {
  275. bool b;
  276. if (!ConvertFromV8(isolate, val, &b))
  277. return false;
  278. *out = b ? content::CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE :
  279. content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL;
  280. return true;
  281. }
  282. };
  283. } // namespace mate
  284. namespace atom {
  285. namespace api {
  286. namespace {
  287. class AppIdProcessIterator : public base::ProcessIterator {
  288. public:
  289. AppIdProcessIterator() : base::ProcessIterator(nullptr) {}
  290. protected:
  291. bool IncludeEntry() override {
  292. return (entry().parent_pid() == base::GetCurrentProcId() ||
  293. entry().pid() == base::GetCurrentProcId());
  294. }
  295. };
  296. IconLoader::IconSize GetIconSizeByString(const std::string& size) {
  297. if (size == "small") {
  298. return IconLoader::IconSize::SMALL;
  299. } else if (size == "large") {
  300. return IconLoader::IconSize::LARGE;
  301. }
  302. return IconLoader::IconSize::NORMAL;
  303. }
  304. // Return the path constant from string.
  305. int GetPathConstant(const std::string& name) {
  306. if (name == "appData")
  307. return brightray::DIR_APP_DATA;
  308. else if (name == "userData")
  309. return brightray::DIR_USER_DATA;
  310. else if (name == "cache")
  311. return brightray::DIR_CACHE;
  312. else if (name == "userCache")
  313. return brightray::DIR_USER_CACHE;
  314. else if (name == "home")
  315. return base::DIR_HOME;
  316. else if (name == "temp")
  317. return base::DIR_TEMP;
  318. else if (name == "userDesktop" || name == "desktop")
  319. return base::DIR_USER_DESKTOP;
  320. else if (name == "exe")
  321. return base::FILE_EXE;
  322. else if (name == "module")
  323. return base::FILE_MODULE;
  324. else if (name == "documents")
  325. return chrome::DIR_USER_DOCUMENTS;
  326. else if (name == "downloads")
  327. return chrome::DIR_DEFAULT_DOWNLOADS;
  328. else if (name == "music")
  329. return chrome::DIR_USER_MUSIC;
  330. else if (name == "pictures")
  331. return chrome::DIR_USER_PICTURES;
  332. else if (name == "videos")
  333. return chrome::DIR_USER_VIDEOS;
  334. else if (name == "pepperFlashSystemPlugin")
  335. return chrome::FILE_PEPPER_FLASH_SYSTEM_PLUGIN;
  336. else
  337. return -1;
  338. }
  339. bool NotificationCallbackWrapper(
  340. const ProcessSingleton::NotificationCallback& callback,
  341. const base::CommandLine::StringVector& cmd,
  342. const base::FilePath& cwd) {
  343. // Make sure the callback is called after app gets ready.
  344. if (Browser::Get()->is_ready()) {
  345. callback.Run(cmd, cwd);
  346. } else {
  347. scoped_refptr<base::SingleThreadTaskRunner> task_runner(
  348. base::ThreadTaskRunnerHandle::Get());
  349. task_runner->PostTask(
  350. FROM_HERE, base::Bind(base::IgnoreResult(callback), cmd, cwd));
  351. }
  352. // ProcessSingleton needs to know whether current process is quiting.
  353. return !Browser::Get()->is_shutting_down();
  354. }
  355. void OnClientCertificateSelected(
  356. v8::Isolate* isolate,
  357. std::shared_ptr<content::ClientCertificateDelegate> delegate,
  358. mate::Arguments* args) {
  359. if (args->Length() == 2) {
  360. delegate->ContinueWithCertificate(nullptr);
  361. return;
  362. }
  363. v8::Local<v8::Value> val;
  364. args->GetNext(&val);
  365. if (val->IsNull()) {
  366. delegate->ContinueWithCertificate(nullptr);
  367. return;
  368. }
  369. mate::Dictionary cert_data;
  370. if (!mate::ConvertFromV8(isolate, val, &cert_data)) {
  371. args->ThrowError("Must pass valid certificate object.");
  372. return;
  373. }
  374. std::string data;
  375. if (!cert_data.Get("data", &data))
  376. return;
  377. auto certs = net::X509Certificate::CreateCertificateListFromBytes(
  378. data.c_str(), data.length(), net::X509Certificate::FORMAT_AUTO);
  379. if (!certs.empty())
  380. delegate->ContinueWithCertificate(certs[0].get());
  381. }
  382. void PassLoginInformation(scoped_refptr<LoginHandler> login_handler,
  383. mate::Arguments* args) {
  384. base::string16 username, password;
  385. if (args->GetNext(&username) && args->GetNext(&password))
  386. login_handler->Login(username, password);
  387. else
  388. login_handler->CancelAuth();
  389. }
  390. #if defined(USE_NSS_CERTS)
  391. int ImportIntoCertStore(
  392. CertificateManagerModel* model,
  393. const base::DictionaryValue& options) {
  394. std::string file_data, cert_path;
  395. base::string16 password;
  396. net::CertificateList imported_certs;
  397. int rv = -1;
  398. options.GetString("certificate", &cert_path);
  399. options.GetString("password", &password);
  400. if (!cert_path.empty()) {
  401. if (base::ReadFileToString(base::FilePath(cert_path), &file_data)) {
  402. auto module = model->cert_db()->GetPublicModule();
  403. rv = model->ImportFromPKCS12(module,
  404. file_data,
  405. password,
  406. true,
  407. &imported_certs);
  408. if (imported_certs.size() > 1) {
  409. auto it = imported_certs.begin();
  410. ++it; // skip first which would be the client certificate.
  411. for (; it != imported_certs.end(); ++it)
  412. rv &= model->SetCertTrust(it->get(),
  413. net::CA_CERT,
  414. net::NSSCertDatabase::TRUSTED_SSL);
  415. }
  416. }
  417. }
  418. return rv;
  419. }
  420. #endif
  421. void OnIconDataAvailable(v8::Isolate* isolate,
  422. const App::FileIconCallback& callback,
  423. gfx::Image* icon) {
  424. v8::Locker locker(isolate);
  425. v8::HandleScope handle_scope(isolate);
  426. if (icon && !icon->IsEmpty()) {
  427. callback.Run(v8::Null(isolate), *icon);
  428. } else {
  429. v8::Local<v8::String> error_message =
  430. v8::String::NewFromUtf8(isolate, "Failed to get file icon.");
  431. callback.Run(v8::Exception::Error(error_message), gfx::Image());
  432. }
  433. }
  434. } // namespace
  435. App::App(v8::Isolate* isolate) {
  436. static_cast<AtomBrowserClient*>(AtomBrowserClient::Get())->set_delegate(this);
  437. Browser::Get()->AddObserver(this);
  438. content::GpuDataManager::GetInstance()->AddObserver(this);
  439. Init(isolate);
  440. }
  441. App::~App() {
  442. static_cast<AtomBrowserClient*>(AtomBrowserClient::Get())->set_delegate(
  443. nullptr);
  444. Browser::Get()->RemoveObserver(this);
  445. content::GpuDataManager::GetInstance()->RemoveObserver(this);
  446. }
  447. void App::OnBeforeQuit(bool* prevent_default) {
  448. *prevent_default = Emit("before-quit");
  449. }
  450. void App::OnWillQuit(bool* prevent_default) {
  451. *prevent_default = Emit("will-quit");
  452. }
  453. void App::OnWindowAllClosed() {
  454. Emit("window-all-closed");
  455. }
  456. void App::OnQuit() {
  457. int exitCode = AtomBrowserMainParts::Get()->GetExitCode();
  458. Emit("quit", exitCode);
  459. if (process_singleton_) {
  460. process_singleton_->Cleanup();
  461. process_singleton_.reset();
  462. }
  463. }
  464. void App::OnOpenFile(bool* prevent_default, const std::string& file_path) {
  465. *prevent_default = Emit("open-file", file_path);
  466. }
  467. void App::OnOpenURL(const std::string& url) {
  468. Emit("open-url", url);
  469. }
  470. void App::OnActivate(bool has_visible_windows) {
  471. Emit("activate", has_visible_windows);
  472. }
  473. void App::OnWillFinishLaunching() {
  474. Emit("will-finish-launching");
  475. }
  476. void App::OnFinishLaunching(const base::DictionaryValue& launch_info) {
  477. #if defined(OS_LINUX)
  478. // Set the application name for audio streams shown in external
  479. // applications. Only affects pulseaudio currently.
  480. media::AudioManager::SetGlobalAppName(Browser::Get()->GetName());
  481. #endif
  482. Emit("ready", launch_info);
  483. }
  484. void App::OnAccessibilitySupportChanged() {
  485. Emit("accessibility-support-changed", IsAccessibilitySupportEnabled());
  486. }
  487. #if defined(OS_MACOSX)
  488. void App::OnContinueUserActivity(
  489. bool* prevent_default,
  490. const std::string& type,
  491. const base::DictionaryValue& user_info) {
  492. *prevent_default = Emit("continue-activity", type, user_info);
  493. }
  494. #endif
  495. void App::OnLogin(LoginHandler* login_handler,
  496. const base::DictionaryValue& request_details) {
  497. v8::Locker locker(isolate());
  498. v8::HandleScope handle_scope(isolate());
  499. bool prevent_default = Emit(
  500. "login",
  501. WebContents::CreateFrom(isolate(), login_handler->GetWebContents()),
  502. request_details,
  503. login_handler->auth_info(),
  504. base::Bind(&PassLoginInformation, make_scoped_refptr(login_handler)));
  505. // Default behavior is to always cancel the auth.
  506. if (!prevent_default)
  507. login_handler->CancelAuth();
  508. }
  509. void App::OnCreateWindow(
  510. const GURL& target_url,
  511. const std::string& frame_name,
  512. WindowOpenDisposition disposition,
  513. const std::vector<std::string>& features,
  514. const scoped_refptr<content::ResourceRequestBodyImpl>& body,
  515. int render_process_id,
  516. int render_frame_id) {
  517. v8::Locker locker(isolate());
  518. v8::HandleScope handle_scope(isolate());
  519. content::RenderFrameHost* rfh =
  520. content::RenderFrameHost::FromID(render_process_id, render_frame_id);
  521. content::WebContents* web_contents =
  522. content::WebContents::FromRenderFrameHost(rfh);
  523. if (web_contents) {
  524. auto api_web_contents = WebContents::CreateFrom(isolate(), web_contents);
  525. api_web_contents->OnCreateWindow(target_url,
  526. frame_name,
  527. disposition,
  528. features,
  529. body);
  530. }
  531. }
  532. void App::AllowCertificateError(
  533. content::WebContents* web_contents,
  534. int cert_error,
  535. const net::SSLInfo& ssl_info,
  536. const GURL& request_url,
  537. content::ResourceType resource_type,
  538. bool overridable,
  539. bool strict_enforcement,
  540. bool expired_previous_decision,
  541. const base::Callback<void(content::CertificateRequestResultType)>&
  542. callback) {
  543. v8::Locker locker(isolate());
  544. v8::HandleScope handle_scope(isolate());
  545. bool prevent_default = Emit("certificate-error",
  546. WebContents::CreateFrom(isolate(), web_contents),
  547. request_url,
  548. net::ErrorToString(cert_error),
  549. ssl_info.cert,
  550. callback);
  551. // Deny the certificate by default.
  552. if (!prevent_default)
  553. callback.Run(content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY);
  554. }
  555. void App::SelectClientCertificate(
  556. content::WebContents* web_contents,
  557. net::SSLCertRequestInfo* cert_request_info,
  558. std::unique_ptr<content::ClientCertificateDelegate> delegate) {
  559. std::shared_ptr<content::ClientCertificateDelegate>
  560. shared_delegate(delegate.release());
  561. bool prevent_default =
  562. Emit("select-client-certificate",
  563. WebContents::CreateFrom(isolate(), web_contents),
  564. cert_request_info->host_and_port.ToString(),
  565. cert_request_info->client_certs,
  566. base::Bind(&OnClientCertificateSelected,
  567. isolate(),
  568. shared_delegate));
  569. // Default to first certificate from the platform store.
  570. if (!prevent_default)
  571. shared_delegate->ContinueWithCertificate(
  572. cert_request_info->client_certs[0].get());
  573. }
  574. void App::OnGpuProcessCrashed(base::TerminationStatus status) {
  575. Emit("gpu-process-crashed",
  576. status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED);
  577. }
  578. base::FilePath App::GetAppPath() const {
  579. return app_path_;
  580. }
  581. void App::SetAppPath(const base::FilePath& app_path) {
  582. app_path_ = app_path;
  583. }
  584. base::FilePath App::GetPath(mate::Arguments* args, const std::string& name) {
  585. bool succeed = false;
  586. base::FilePath path;
  587. int key = GetPathConstant(name);
  588. if (key >= 0)
  589. succeed = PathService::Get(key, &path);
  590. if (!succeed)
  591. args->ThrowError("Failed to get '" + name + "' path");
  592. return path;
  593. }
  594. void App::SetPath(mate::Arguments* args,
  595. const std::string& name,
  596. const base::FilePath& path) {
  597. if (!path.IsAbsolute()) {
  598. args->ThrowError("Path must be absolute");
  599. return;
  600. }
  601. bool succeed = false;
  602. int key = GetPathConstant(name);
  603. if (key >= 0)
  604. succeed = PathService::OverrideAndCreateIfNeeded(key, path, true, false);
  605. if (!succeed)
  606. args->ThrowError("Failed to set path");
  607. }
  608. void App::SetDesktopName(const std::string& desktop_name) {
  609. #if defined(OS_LINUX)
  610. std::unique_ptr<base::Environment> env(base::Environment::Create());
  611. env->SetVar("CHROME_DESKTOP", desktop_name);
  612. #endif
  613. }
  614. std::string App::GetLocale() {
  615. return l10n_util::GetApplicationLocale("");
  616. }
  617. bool App::MakeSingleInstance(
  618. const ProcessSingleton::NotificationCallback& callback) {
  619. if (process_singleton_)
  620. return false;
  621. base::FilePath user_dir;
  622. PathService::Get(brightray::DIR_USER_DATA, &user_dir);
  623. process_singleton_.reset(new ProcessSingleton(
  624. user_dir, base::Bind(NotificationCallbackWrapper, callback)));
  625. switch (process_singleton_->NotifyOtherProcessOrCreate()) {
  626. case ProcessSingleton::NotifyResult::LOCK_ERROR:
  627. case ProcessSingleton::NotifyResult::PROFILE_IN_USE:
  628. case ProcessSingleton::NotifyResult::PROCESS_NOTIFIED:
  629. process_singleton_.reset();
  630. return true;
  631. case ProcessSingleton::NotifyResult::PROCESS_NONE:
  632. default: // Shouldn't be needed, but VS warns if it is not there.
  633. return false;
  634. }
  635. }
  636. void App::ReleaseSingleInstance() {
  637. if (process_singleton_) {
  638. process_singleton_->Cleanup();
  639. process_singleton_.reset();
  640. }
  641. }
  642. bool App::Relaunch(mate::Arguments* js_args) {
  643. // Parse parameters.
  644. bool override_argv = false;
  645. base::FilePath exec_path;
  646. relauncher::StringVector args;
  647. mate::Dictionary options;
  648. if (js_args->GetNext(&options)) {
  649. if (options.Get("execPath", &exec_path) | options.Get("args", &args))
  650. override_argv = true;
  651. }
  652. if (!override_argv) {
  653. const relauncher::StringVector& argv = atom::AtomCommandLine::argv();
  654. return relauncher::RelaunchApp(argv);
  655. }
  656. relauncher::StringVector argv;
  657. argv.reserve(1 + args.size());
  658. if (exec_path.empty()) {
  659. base::FilePath current_exe_path;
  660. PathService::Get(base::FILE_EXE, &current_exe_path);
  661. argv.push_back(current_exe_path.value());
  662. } else {
  663. argv.push_back(exec_path.value());
  664. }
  665. argv.insert(argv.end(), args.begin(), args.end());
  666. return relauncher::RelaunchApp(argv);
  667. }
  668. void App::DisableHardwareAcceleration(mate::Arguments* args) {
  669. if (Browser::Get()->is_ready()) {
  670. args->ThrowError("app.disableHardwareAcceleration() can only be called "
  671. "before app is ready");
  672. return;
  673. }
  674. content::GpuDataManager::GetInstance()->DisableHardwareAcceleration();
  675. }
  676. bool App::IsAccessibilitySupportEnabled() {
  677. auto ax_state = content::BrowserAccessibilityState::GetInstance();
  678. return ax_state->IsAccessibleBrowser();
  679. }
  680. Browser::LoginItemSettings App::GetLoginItemSettings(mate::Arguments* args) {
  681. Browser::LoginItemSettings options;
  682. args->GetNext(&options);
  683. return Browser::Get()->GetLoginItemSettings(options);
  684. }
  685. #if defined(USE_NSS_CERTS)
  686. void App::ImportCertificate(
  687. const base::DictionaryValue& options,
  688. const net::CompletionCallback& callback) {
  689. auto browser_context = AtomBrowserContext::From("", false);
  690. if (!certificate_manager_model_) {
  691. std::unique_ptr<base::DictionaryValue> copy = options.CreateDeepCopy();
  692. CertificateManagerModel::Create(
  693. browser_context.get(),
  694. base::Bind(&App::OnCertificateManagerModelCreated,
  695. base::Unretained(this),
  696. base::Passed(&copy),
  697. callback));
  698. return;
  699. }
  700. int rv = ImportIntoCertStore(certificate_manager_model_.get(), options);
  701. callback.Run(rv);
  702. }
  703. void App::OnCertificateManagerModelCreated(
  704. std::unique_ptr<base::DictionaryValue> options,
  705. const net::CompletionCallback& callback,
  706. std::unique_ptr<CertificateManagerModel> model) {
  707. certificate_manager_model_ = std::move(model);
  708. int rv = ImportIntoCertStore(certificate_manager_model_.get(),
  709. *(options.get()));
  710. callback.Run(rv);
  711. }
  712. #endif
  713. #if defined(OS_WIN)
  714. v8::Local<v8::Value> App::GetJumpListSettings() {
  715. JumpList jump_list(Browser::Get()->GetAppUserModelID());
  716. int min_items = 10;
  717. std::vector<JumpListItem> removed_items;
  718. if (jump_list.Begin(&min_items, &removed_items)) {
  719. // We don't actually want to change anything, so abort the transaction.
  720. jump_list.Abort();
  721. } else {
  722. LOG(ERROR) << "Failed to begin Jump List transaction.";
  723. }
  724. auto dict = mate::Dictionary::CreateEmpty(isolate());
  725. dict.Set("minItems", min_items);
  726. dict.Set("removedItems", mate::ConvertToV8(isolate(), removed_items));
  727. return dict.GetHandle();
  728. }
  729. JumpListResult App::SetJumpList(v8::Local<v8::Value> val,
  730. mate::Arguments* args) {
  731. std::vector<JumpListCategory> categories;
  732. bool delete_jump_list = val->IsNull();
  733. if (!delete_jump_list &&
  734. !mate::ConvertFromV8(args->isolate(), val, &categories)) {
  735. args->ThrowError("Argument must be null or an array of categories");
  736. return JumpListResult::ARGUMENT_ERROR;
  737. }
  738. JumpList jump_list(Browser::Get()->GetAppUserModelID());
  739. if (delete_jump_list) {
  740. return jump_list.Delete()
  741. ? JumpListResult::SUCCESS
  742. : JumpListResult::GENERIC_ERROR;
  743. }
  744. // Start a transaction that updates the JumpList of this application.
  745. if (!jump_list.Begin())
  746. return JumpListResult::GENERIC_ERROR;
  747. JumpListResult result = jump_list.AppendCategories(categories);
  748. // AppendCategories may have failed to add some categories, but it's better
  749. // to have something than nothing so try to commit the changes anyway.
  750. if (!jump_list.Commit()) {
  751. LOG(ERROR) << "Failed to commit changes to custom Jump List.";
  752. // It's more useful to return the earlier error code that might give
  753. // some indication as to why the transaction actually failed, so don't
  754. // overwrite it with a "generic error" code here.
  755. if (result == JumpListResult::SUCCESS)
  756. result = JumpListResult::GENERIC_ERROR;
  757. }
  758. return result;
  759. }
  760. #endif // defined(OS_WIN)
  761. void App::GetFileIcon(const base::FilePath& path,
  762. mate::Arguments* args) {
  763. mate::Dictionary options;
  764. IconLoader::IconSize icon_size;
  765. FileIconCallback callback;
  766. v8::Locker locker(isolate());
  767. v8::HandleScope handle_scope(isolate());
  768. base::FilePath normalized_path = path.NormalizePathSeparators();
  769. if (!args->GetNext(&options)) {
  770. icon_size = IconLoader::IconSize::NORMAL;
  771. } else {
  772. std::string icon_size_string;
  773. options.Get("size", &icon_size_string);
  774. icon_size = GetIconSizeByString(icon_size_string);
  775. }
  776. if (!args->GetNext(&callback)) {
  777. args->ThrowError("Missing required callback function");
  778. return;
  779. }
  780. auto icon_manager = g_browser_process->GetIconManager();
  781. gfx::Image* icon =
  782. icon_manager->LookupIconFromFilepath(normalized_path, icon_size);
  783. if (icon) {
  784. callback.Run(v8::Null(isolate()), *icon);
  785. } else {
  786. icon_manager->LoadIcon(
  787. normalized_path, icon_size,
  788. base::Bind(&OnIconDataAvailable, isolate(), callback),
  789. &cancelable_task_tracker_);
  790. }
  791. }
  792. std::vector<mate::Dictionary> App::GetAppMemoryInfo(v8::Isolate* isolate) {
  793. AppIdProcessIterator process_iterator;
  794. auto process_entry = process_iterator.NextProcessEntry();
  795. std::vector<mate::Dictionary> result;
  796. while (process_entry != nullptr) {
  797. int64_t pid = process_entry->pid();
  798. auto process = base::Process::OpenWithExtraPrivileges(pid);
  799. #if defined(OS_MACOSX)
  800. std::unique_ptr<base::ProcessMetrics> metrics(
  801. base::ProcessMetrics::CreateProcessMetrics(
  802. process.Handle(), content::BrowserChildProcessHost::GetPortProvider()));
  803. #else
  804. std::unique_ptr<base::ProcessMetrics> metrics(
  805. base::ProcessMetrics::CreateProcessMetrics(process.Handle()));
  806. #endif
  807. mate::Dictionary pid_dict = mate::Dictionary::CreateEmpty(isolate);
  808. mate::Dictionary memory_dict = mate::Dictionary::CreateEmpty(isolate);
  809. memory_dict.Set("workingSetSize",
  810. static_cast<double>(metrics->GetWorkingSetSize() >> 10));
  811. memory_dict.Set("peakWorkingSetSize",
  812. static_cast<double>(metrics->GetPeakWorkingSetSize() >> 10));
  813. size_t private_bytes, shared_bytes;
  814. if (metrics->GetMemoryBytes(&private_bytes, &shared_bytes)) {
  815. memory_dict.Set("privateBytes", static_cast<double>(private_bytes >> 10));
  816. memory_dict.Set("sharedBytes", static_cast<double>(shared_bytes >> 10));
  817. }
  818. pid_dict.Set("memory", memory_dict);
  819. pid_dict.Set("pid", pid);
  820. result.push_back(pid_dict);
  821. process_entry = process_iterator.NextProcessEntry();
  822. }
  823. return result;
  824. }
  825. // static
  826. mate::Handle<App> App::Create(v8::Isolate* isolate) {
  827. return mate::CreateHandle(isolate, new App(isolate));
  828. }
  829. // static
  830. void App::BuildPrototype(
  831. v8::Isolate* isolate, v8::Local<v8::FunctionTemplate> prototype) {
  832. prototype->SetClassName(mate::StringToV8(isolate, "App"));
  833. auto browser = base::Unretained(Browser::Get());
  834. mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
  835. .SetMethod("quit", base::Bind(&Browser::Quit, browser))
  836. .SetMethod("exit", base::Bind(&Browser::Exit, browser))
  837. .SetMethod("focus", base::Bind(&Browser::Focus, browser))
  838. .SetMethod("getVersion", base::Bind(&Browser::GetVersion, browser))
  839. .SetMethod("setVersion", base::Bind(&Browser::SetVersion, browser))
  840. .SetMethod("getName", base::Bind(&Browser::GetName, browser))
  841. .SetMethod("setName", base::Bind(&Browser::SetName, browser))
  842. .SetMethod("isReady", base::Bind(&Browser::is_ready, browser))
  843. .SetMethod("addRecentDocument",
  844. base::Bind(&Browser::AddRecentDocument, browser))
  845. .SetMethod("clearRecentDocuments",
  846. base::Bind(&Browser::ClearRecentDocuments, browser))
  847. .SetMethod("setAppUserModelId",
  848. base::Bind(&Browser::SetAppUserModelID, browser))
  849. .SetMethod("isDefaultProtocolClient",
  850. base::Bind(&Browser::IsDefaultProtocolClient, browser))
  851. .SetMethod("setAsDefaultProtocolClient",
  852. base::Bind(&Browser::SetAsDefaultProtocolClient, browser))
  853. .SetMethod("removeAsDefaultProtocolClient",
  854. base::Bind(&Browser::RemoveAsDefaultProtocolClient, browser))
  855. .SetMethod("setBadgeCount", base::Bind(&Browser::SetBadgeCount, browser))
  856. .SetMethod("getBadgeCount", base::Bind(&Browser::GetBadgeCount, browser))
  857. .SetMethod("getLoginItemSettings", &App::GetLoginItemSettings)
  858. .SetMethod("setLoginItemSettings",
  859. base::Bind(&Browser::SetLoginItemSettings, browser))
  860. #if defined(OS_MACOSX)
  861. .SetMethod("hide", base::Bind(&Browser::Hide, browser))
  862. .SetMethod("show", base::Bind(&Browser::Show, browser))
  863. .SetMethod("setUserActivity",
  864. base::Bind(&Browser::SetUserActivity, browser))
  865. .SetMethod("getCurrentActivityType",
  866. base::Bind(&Browser::GetCurrentActivityType, browser))
  867. .SetMethod("setAboutPanelOptions",
  868. base::Bind(&Browser::SetAboutPanelOptions, browser))
  869. #endif
  870. #if defined(OS_WIN)
  871. .SetMethod("setUserTasks", base::Bind(&Browser::SetUserTasks, browser))
  872. .SetMethod("getJumpListSettings", &App::GetJumpListSettings)
  873. .SetMethod("setJumpList", &App::SetJumpList)
  874. #endif
  875. #if defined(OS_LINUX)
  876. .SetMethod("isUnityRunning",
  877. base::Bind(&Browser::IsUnityRunning, browser))
  878. #endif
  879. .SetMethod("setAppPath", &App::SetAppPath)
  880. .SetMethod("getAppPath", &App::GetAppPath)
  881. .SetMethod("setPath", &App::SetPath)
  882. .SetMethod("getPath", &App::GetPath)
  883. .SetMethod("setDesktopName", &App::SetDesktopName)
  884. .SetMethod("getLocale", &App::GetLocale)
  885. #if defined(USE_NSS_CERTS)
  886. .SetMethod("importCertificate", &App::ImportCertificate)
  887. #endif
  888. .SetMethod("makeSingleInstance", &App::MakeSingleInstance)
  889. .SetMethod("releaseSingleInstance", &App::ReleaseSingleInstance)
  890. .SetMethod("relaunch", &App::Relaunch)
  891. .SetMethod("isAccessibilitySupportEnabled",
  892. &App::IsAccessibilitySupportEnabled)
  893. .SetMethod("disableHardwareAcceleration",
  894. &App::DisableHardwareAcceleration)
  895. .SetMethod("getFileIcon", &App::GetFileIcon)
  896. .SetMethod("getAppMemoryInfo", &App::GetAppMemoryInfo);
  897. }
  898. } // namespace api
  899. } // namespace atom
  900. namespace {
  901. void AppendSwitch(const std::string& switch_string, mate::Arguments* args) {
  902. auto command_line = base::CommandLine::ForCurrentProcess();
  903. if (base::EndsWith(switch_string, "-path",
  904. base::CompareCase::INSENSITIVE_ASCII) ||
  905. switch_string == switches::kLogNetLog) {
  906. base::FilePath path;
  907. args->GetNext(&path);
  908. command_line->AppendSwitchPath(switch_string, path);
  909. return;
  910. }
  911. std::string value;
  912. if (args->GetNext(&value))
  913. command_line->AppendSwitchASCII(switch_string, value);
  914. else
  915. command_line->AppendSwitch(switch_string);
  916. }
  917. #if defined(OS_MACOSX)
  918. int DockBounce(const std::string& type) {
  919. int request_id = -1;
  920. if (type == "critical")
  921. request_id = Browser::Get()->DockBounce(Browser::BOUNCE_CRITICAL);
  922. else if (type == "informational")
  923. request_id = Browser::Get()->DockBounce(Browser::BOUNCE_INFORMATIONAL);
  924. return request_id;
  925. }
  926. void DockSetMenu(atom::api::Menu* menu) {
  927. Browser::Get()->DockSetMenu(menu->model());
  928. }
  929. #endif
  930. void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
  931. v8::Local<v8::Context> context, void* priv) {
  932. v8::Isolate* isolate = context->GetIsolate();
  933. auto command_line = base::CommandLine::ForCurrentProcess();
  934. mate::Dictionary dict(isolate, exports);
  935. dict.Set("App", atom::api::App::GetConstructor(isolate)->GetFunction());
  936. dict.Set("app", atom::api::App::Create(isolate));
  937. dict.SetMethod("appendSwitch", &AppendSwitch);
  938. dict.SetMethod("appendArgument",
  939. base::Bind(&base::CommandLine::AppendArg,
  940. base::Unretained(command_line)));
  941. #if defined(OS_MACOSX)
  942. auto browser = base::Unretained(Browser::Get());
  943. dict.SetMethod("dockBounce", &DockBounce);
  944. dict.SetMethod("dockCancelBounce",
  945. base::Bind(&Browser::DockCancelBounce, browser));
  946. dict.SetMethod("dockDownloadFinished",
  947. base::Bind(&Browser::DockDownloadFinished, browser));
  948. dict.SetMethod("dockSetBadgeText",
  949. base::Bind(&Browser::DockSetBadgeText, browser));
  950. dict.SetMethod("dockGetBadgeText",
  951. base::Bind(&Browser::DockGetBadgeText, browser));
  952. dict.SetMethod("dockHide", base::Bind(&Browser::DockHide, browser));
  953. dict.SetMethod("dockShow", base::Bind(&Browser::DockShow, browser));
  954. dict.SetMethod("dockIsVisible", base::Bind(&Browser::DockIsVisible, browser));
  955. dict.SetMethod("dockSetMenu", &DockSetMenu);
  956. dict.SetMethod("dockSetIcon", base::Bind(&Browser::DockSetIcon, browser));
  957. #endif
  958. }
  959. } // namespace
  960. NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_app, Initialize)