electron_permission_manager.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. // Copyright (c) 2016 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 "shell/browser/electron_permission_manager.h"
  5. #include <memory>
  6. #include <utility>
  7. #include <vector>
  8. #include "base/values.h"
  9. #include "content/browser/permissions/permission_util.h" // nogncheck
  10. #include "content/public/browser/child_process_security_policy.h"
  11. #include "content/public/browser/global_routing_id.h"
  12. #include "content/public/browser/permission_controller.h"
  13. #include "content/public/browser/render_frame_host.h"
  14. #include "content/public/browser/render_process_host.h"
  15. #include "content/public/browser/render_view_host.h"
  16. #include "content/public/browser/web_contents.h"
  17. #include "gin/data_object_builder.h"
  18. #include "shell/browser/api/electron_api_web_contents.h"
  19. #include "shell/browser/electron_browser_client.h"
  20. #include "shell/browser/electron_browser_main_parts.h"
  21. #include "shell/browser/web_contents_permission_helper.h"
  22. #include "shell/browser/web_contents_preferences.h"
  23. #include "shell/common/gin_converters/content_converter.h"
  24. #include "shell/common/gin_converters/frame_converter.h"
  25. #include "shell/common/gin_converters/usb_protected_classes_converter.h"
  26. #include "shell/common/gin_converters/value_converter.h"
  27. #include "shell/common/gin_helper/event_emitter_caller.h"
  28. #include "third_party/blink/public/common/permissions/permission_utils.h"
  29. namespace electron {
  30. namespace {
  31. bool WebContentsDestroyed(content::RenderFrameHost* rfh) {
  32. content::WebContents* web_contents =
  33. content::WebContents::FromRenderFrameHost(rfh);
  34. if (!web_contents)
  35. return true;
  36. return web_contents->IsBeingDestroyed();
  37. }
  38. void PermissionRequestResponseCallbackWrapper(
  39. ElectronPermissionManager::StatusCallback callback,
  40. const std::vector<blink::mojom::PermissionStatus>& vector) {
  41. std::move(callback).Run(vector[0]);
  42. }
  43. } // namespace
  44. class ElectronPermissionManager::PendingRequest {
  45. public:
  46. PendingRequest(content::RenderFrameHost* render_frame_host,
  47. const std::vector<blink::PermissionType>& permissions,
  48. StatusesCallback callback)
  49. : render_frame_host_id_(render_frame_host->GetGlobalId()),
  50. callback_(std::move(callback)),
  51. permissions_(permissions),
  52. results_(permissions.size(), blink::mojom::PermissionStatus::DENIED),
  53. remaining_results_(permissions.size()) {}
  54. void SetPermissionStatus(int permission_id,
  55. blink::mojom::PermissionStatus status) {
  56. DCHECK(!IsComplete());
  57. if (status == blink::mojom::PermissionStatus::GRANTED) {
  58. const auto permission = permissions_[permission_id];
  59. if (permission == blink::PermissionType::MIDI_SYSEX) {
  60. content::ChildProcessSecurityPolicy::GetInstance()
  61. ->GrantSendMidiSysExMessage(render_frame_host_id_.child_id);
  62. } else if (permission == blink::PermissionType::GEOLOCATION) {
  63. ElectronBrowserMainParts::Get()
  64. ->GetGeolocationControl()
  65. ->UserDidOptIntoLocationServices();
  66. }
  67. }
  68. results_[permission_id] = status;
  69. --remaining_results_;
  70. }
  71. content::RenderFrameHost* GetRenderFrameHost() {
  72. return content::RenderFrameHost::FromID(render_frame_host_id_);
  73. }
  74. bool IsComplete() const { return remaining_results_ == 0; }
  75. void RunCallback() {
  76. if (!callback_.is_null()) {
  77. std::move(callback_).Run(results_);
  78. }
  79. }
  80. private:
  81. content::GlobalRenderFrameHostId render_frame_host_id_;
  82. StatusesCallback callback_;
  83. std::vector<blink::PermissionType> permissions_;
  84. std::vector<blink::mojom::PermissionStatus> results_;
  85. size_t remaining_results_;
  86. };
  87. ElectronPermissionManager::ElectronPermissionManager() = default;
  88. ElectronPermissionManager::~ElectronPermissionManager() = default;
  89. void ElectronPermissionManager::SetPermissionRequestHandler(
  90. const RequestHandler& handler) {
  91. if (handler.is_null() && !pending_requests_.IsEmpty()) {
  92. for (PendingRequestsMap::iterator iter(&pending_requests_); !iter.IsAtEnd();
  93. iter.Advance()) {
  94. auto* request = iter.GetCurrentValue();
  95. if (!WebContentsDestroyed(request->GetRenderFrameHost()))
  96. request->RunCallback();
  97. }
  98. pending_requests_.Clear();
  99. }
  100. request_handler_ = handler;
  101. }
  102. void ElectronPermissionManager::SetPermissionCheckHandler(
  103. const CheckHandler& handler) {
  104. check_handler_ = handler;
  105. }
  106. void ElectronPermissionManager::SetDevicePermissionHandler(
  107. const DeviceCheckHandler& handler) {
  108. device_permission_handler_ = handler;
  109. }
  110. void ElectronPermissionManager::SetProtectedUSBHandler(
  111. const ProtectedUSBHandler& handler) {
  112. protected_usb_handler_ = handler;
  113. }
  114. void ElectronPermissionManager::SetBluetoothPairingHandler(
  115. const BluetoothPairingHandler& handler) {
  116. bluetooth_pairing_handler_ = handler;
  117. }
  118. void ElectronPermissionManager::RequestPermission(
  119. blink::PermissionType permission,
  120. content::RenderFrameHost* render_frame_host,
  121. const GURL& requesting_origin,
  122. bool user_gesture,
  123. StatusCallback callback) {
  124. if (render_frame_host->IsNestedWithinFencedFrame()) {
  125. std::move(callback).Run(blink::mojom::PermissionStatus::DENIED);
  126. return;
  127. }
  128. RequestPermissionWithDetails(permission, render_frame_host, requesting_origin,
  129. user_gesture, {}, std::move(callback));
  130. }
  131. void ElectronPermissionManager::RequestPermissionWithDetails(
  132. blink::PermissionType permission,
  133. content::RenderFrameHost* render_frame_host,
  134. const GURL& requesting_origin,
  135. bool user_gesture,
  136. base::Value::Dict details,
  137. StatusCallback response_callback) {
  138. RequestPermissionsWithDetails(
  139. std::vector<blink::PermissionType>(1, permission), render_frame_host,
  140. user_gesture, std::move(details),
  141. base::BindOnce(PermissionRequestResponseCallbackWrapper,
  142. std::move(response_callback)));
  143. }
  144. void ElectronPermissionManager::RequestPermissions(
  145. const std::vector<blink::PermissionType>& permissions,
  146. content::RenderFrameHost* render_frame_host,
  147. const GURL& requesting_origin,
  148. bool user_gesture,
  149. StatusesCallback callback) {
  150. if (render_frame_host->IsNestedWithinFencedFrame()) {
  151. std::move(callback).Run(std::vector<blink::mojom::PermissionStatus>(
  152. permissions.size(), blink::mojom::PermissionStatus::DENIED));
  153. return;
  154. }
  155. RequestPermissionsWithDetails(permissions, render_frame_host, user_gesture,
  156. {}, std::move(callback));
  157. }
  158. void ElectronPermissionManager::RequestPermissionsWithDetails(
  159. const std::vector<blink::PermissionType>& permissions,
  160. content::RenderFrameHost* render_frame_host,
  161. bool user_gesture,
  162. base::Value::Dict details,
  163. StatusesCallback response_callback) {
  164. if (permissions.empty()) {
  165. std::move(response_callback).Run({});
  166. return;
  167. }
  168. if (request_handler_.is_null()) {
  169. std::vector<blink::mojom::PermissionStatus> statuses;
  170. for (auto permission : permissions) {
  171. if (permission == blink::PermissionType::MIDI_SYSEX) {
  172. content::ChildProcessSecurityPolicy::GetInstance()
  173. ->GrantSendMidiSysExMessage(
  174. render_frame_host->GetProcess()->GetID());
  175. } else if (permission == blink::PermissionType::GEOLOCATION) {
  176. ElectronBrowserMainParts::Get()
  177. ->GetGeolocationControl()
  178. ->UserDidOptIntoLocationServices();
  179. }
  180. statuses.push_back(blink::mojom::PermissionStatus::GRANTED);
  181. }
  182. std::move(response_callback).Run(statuses);
  183. return;
  184. }
  185. auto* web_contents =
  186. content::WebContents::FromRenderFrameHost(render_frame_host);
  187. int request_id = pending_requests_.Add(std::make_unique<PendingRequest>(
  188. render_frame_host, permissions, std::move(response_callback)));
  189. details.Set("requestingUrl", render_frame_host->GetLastCommittedURL().spec());
  190. details.Set("isMainFrame", render_frame_host->GetParent() == nullptr);
  191. base::Value dict_value(std::move(details));
  192. for (size_t i = 0; i < permissions.size(); ++i) {
  193. auto permission = permissions[i];
  194. const auto callback =
  195. base::BindRepeating(&ElectronPermissionManager::OnPermissionResponse,
  196. base::Unretained(this), request_id, i);
  197. request_handler_.Run(web_contents, permission, callback, dict_value);
  198. }
  199. }
  200. void ElectronPermissionManager::OnPermissionResponse(
  201. int request_id,
  202. int permission_id,
  203. blink::mojom::PermissionStatus status) {
  204. auto* pending_request = pending_requests_.Lookup(request_id);
  205. if (!pending_request)
  206. return;
  207. pending_request->SetPermissionStatus(permission_id, status);
  208. if (pending_request->IsComplete()) {
  209. pending_request->RunCallback();
  210. pending_requests_.Remove(request_id);
  211. }
  212. }
  213. void ElectronPermissionManager::ResetPermission(
  214. blink::PermissionType permission,
  215. const GURL& requesting_origin,
  216. const GURL& embedding_origin) {}
  217. void ElectronPermissionManager::RequestPermissionsFromCurrentDocument(
  218. const std::vector<blink::PermissionType>& permissions,
  219. content::RenderFrameHost* render_frame_host,
  220. bool user_gesture,
  221. base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus>&)>
  222. callback) {
  223. if (render_frame_host->IsNestedWithinFencedFrame()) {
  224. std::move(callback).Run(std::vector<blink::mojom::PermissionStatus>(
  225. permissions.size(), blink::mojom::PermissionStatus::DENIED));
  226. return;
  227. }
  228. RequestPermissionsWithDetails(permissions, render_frame_host, user_gesture,
  229. {}, std::move(callback));
  230. }
  231. blink::mojom::PermissionStatus ElectronPermissionManager::GetPermissionStatus(
  232. blink::PermissionType permission,
  233. const GURL& requesting_origin,
  234. const GURL& embedding_origin) {
  235. base::Value::Dict details;
  236. details.Set("embeddingOrigin", embedding_origin.spec());
  237. bool granted = CheckPermissionWithDetails(permission, {}, requesting_origin,
  238. std::move(details));
  239. return granted ? blink::mojom::PermissionStatus::GRANTED
  240. : blink::mojom::PermissionStatus::DENIED;
  241. }
  242. content::PermissionResult
  243. ElectronPermissionManager::GetPermissionResultForOriginWithoutContext(
  244. blink::PermissionType permission,
  245. const url::Origin& requesting_origin,
  246. const url::Origin& embedding_origin) {
  247. blink::mojom::PermissionStatus status = GetPermissionStatus(
  248. permission, requesting_origin.GetURL(), embedding_origin.GetURL());
  249. return content::PermissionResult(
  250. status, content::PermissionStatusSource::UNSPECIFIED);
  251. }
  252. void ElectronPermissionManager::CheckBluetoothDevicePair(
  253. gin_helper::Dictionary details,
  254. PairCallback pair_callback) const {
  255. if (bluetooth_pairing_handler_.is_null()) {
  256. base::Value::Dict response;
  257. response.Set("confirmed", false);
  258. std::move(pair_callback).Run(std::move(response));
  259. } else {
  260. bluetooth_pairing_handler_.Run(details, std::move(pair_callback));
  261. }
  262. }
  263. bool ElectronPermissionManager::CheckPermissionWithDetails(
  264. blink::PermissionType permission,
  265. content::RenderFrameHost* render_frame_host,
  266. const GURL& requesting_origin,
  267. base::Value::Dict details) const {
  268. if (check_handler_.is_null())
  269. return true;
  270. auto* web_contents =
  271. render_frame_host
  272. ? content::WebContents::FromRenderFrameHost(render_frame_host)
  273. : nullptr;
  274. if (render_frame_host) {
  275. details.Set("requestingUrl",
  276. render_frame_host->GetLastCommittedURL().spec());
  277. }
  278. details.Set("isMainFrame",
  279. render_frame_host && render_frame_host->GetParent() == nullptr);
  280. switch (permission) {
  281. case blink::PermissionType::AUDIO_CAPTURE:
  282. details.Set("mediaType", "audio");
  283. break;
  284. case blink::PermissionType::VIDEO_CAPTURE:
  285. details.Set("mediaType", "video");
  286. break;
  287. default:
  288. break;
  289. }
  290. return check_handler_.Run(web_contents, permission, requesting_origin,
  291. base::Value(std::move(details)));
  292. }
  293. bool ElectronPermissionManager::CheckDevicePermission(
  294. blink::PermissionType permission,
  295. const url::Origin& origin,
  296. const base::Value& device,
  297. ElectronBrowserContext* browser_context) const {
  298. if (device_permission_handler_.is_null())
  299. return browser_context->CheckDevicePermission(origin, device, permission);
  300. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  301. v8::HandleScope scope(isolate);
  302. v8::Local<v8::Object> details = gin::DataObjectBuilder(isolate)
  303. .Set("deviceType", permission)
  304. .Set("origin", origin.Serialize())
  305. .Set("device", device.Clone())
  306. .Build();
  307. return device_permission_handler_.Run(details);
  308. }
  309. void ElectronPermissionManager::GrantDevicePermission(
  310. blink::PermissionType permission,
  311. const url::Origin& origin,
  312. const base::Value& device,
  313. ElectronBrowserContext* browser_context) const {
  314. if (device_permission_handler_.is_null()) {
  315. browser_context->GrantDevicePermission(origin, device, permission);
  316. }
  317. }
  318. void ElectronPermissionManager::RevokeDevicePermission(
  319. blink::PermissionType permission,
  320. const url::Origin& origin,
  321. const base::Value& device,
  322. ElectronBrowserContext* browser_context) const {
  323. browser_context->RevokeDevicePermission(origin, device, permission);
  324. }
  325. ElectronPermissionManager::USBProtectedClasses
  326. ElectronPermissionManager::CheckProtectedUSBClasses(
  327. const USBProtectedClasses& classes) const {
  328. if (protected_usb_handler_.is_null())
  329. return classes;
  330. v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
  331. v8::HandleScope scope(isolate);
  332. v8::Local<v8::Object> details =
  333. gin::DataObjectBuilder(isolate).Set("protectedClasses", classes).Build();
  334. return protected_usb_handler_.Run(details);
  335. }
  336. blink::mojom::PermissionStatus
  337. ElectronPermissionManager::GetPermissionStatusForCurrentDocument(
  338. blink::PermissionType permission,
  339. content::RenderFrameHost* render_frame_host) {
  340. if (render_frame_host->IsNestedWithinFencedFrame())
  341. return blink::mojom::PermissionStatus::DENIED;
  342. base::Value::Dict details;
  343. details.Set("embeddingOrigin",
  344. content::PermissionUtil::GetLastCommittedOriginAsURL(
  345. render_frame_host->GetMainFrame())
  346. .spec());
  347. bool granted = CheckPermissionWithDetails(
  348. permission, render_frame_host,
  349. render_frame_host->GetLastCommittedOrigin().GetURL(), std::move(details));
  350. return granted ? blink::mojom::PermissionStatus::GRANTED
  351. : blink::mojom::PermissionStatus::DENIED;
  352. }
  353. blink::mojom::PermissionStatus
  354. ElectronPermissionManager::GetPermissionStatusForWorker(
  355. blink::PermissionType permission,
  356. content::RenderProcessHost* render_process_host,
  357. const GURL& worker_origin) {
  358. return GetPermissionStatus(permission, worker_origin, worker_origin);
  359. }
  360. blink::mojom::PermissionStatus
  361. ElectronPermissionManager::GetPermissionStatusForEmbeddedRequester(
  362. blink::PermissionType permission,
  363. content::RenderFrameHost* render_frame_host,
  364. const url::Origin& overridden_origin) {
  365. if (render_frame_host->IsNestedWithinFencedFrame())
  366. return blink::mojom::PermissionStatus::DENIED;
  367. return GetPermissionStatus(
  368. permission, overridden_origin.GetURL(),
  369. render_frame_host->GetLastCommittedOrigin().GetURL());
  370. }
  371. ElectronPermissionManager::SubscriptionId
  372. ElectronPermissionManager::SubscribePermissionStatusChange(
  373. blink::PermissionType permission,
  374. content::RenderProcessHost* render_process_host,
  375. content::RenderFrameHost* render_frame_host,
  376. const GURL& requesting_origin,
  377. base::RepeatingCallback<void(blink::mojom::PermissionStatus)> callback) {
  378. return SubscriptionId();
  379. }
  380. void ElectronPermissionManager::UnsubscribePermissionStatusChange(
  381. SubscriptionId id) {}
  382. } // namespace electron