electron_permission_manager.cc 14 KB

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