1 // Copyright 2018 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef IOS_WEB_JS_MESSAGING_WEB_FRAME_IMPL_H_ 6 #define IOS_WEB_JS_MESSAGING_WEB_FRAME_IMPL_H_ 7 8 #include "ios/web/public/js_messaging/web_frame.h" 9 10 #include <map> 11 #include <string> 12 13 #include "base/cancelable_callback.h" 14 #include "base/macros.h" 15 #include "base/memory/weak_ptr.h" 16 #include "base/values.h" 17 #include "crypto/symmetric_key.h" 18 #import "ios/web/public/web_state.h" 19 #include "ios/web/public/web_state_observer.h" 20 #include "url/gurl.h" 21 22 namespace web { 23 24 class WebFrameImpl : public WebFrame, public web::WebStateObserver { 25 public: 26 // Creates a new WebFrame. |initial_message_id| will be used as the message ID 27 // of the next message sent to the frame with the |CallJavaScriptFunction| 28 // API. 29 WebFrameImpl(const std::string& frame_id, 30 bool is_main_frame, 31 GURL security_origin, 32 web::WebState* web_state); 33 ~WebFrameImpl() override; 34 35 // Sets the value to use for the next message ID. 36 void SetNextMessageId(int message_id); 37 // Sets the key to use for message encryption. 38 void SetEncryptionKey(std::unique_ptr<crypto::SymmetricKey> frame_key); 39 // The associated web state. 40 WebState* GetWebState(); 41 42 // WebFrame implementation 43 std::string GetFrameId() const override; 44 bool IsMainFrame() const override; 45 GURL GetSecurityOrigin() const override; 46 bool CanCallJavaScriptFunction() const override; 47 48 bool CallJavaScriptFunction( 49 const std::string& name, 50 const std::vector<base::Value>& parameters) override; 51 bool CallJavaScriptFunction( 52 const std::string& name, 53 const std::vector<base::Value>& parameters, 54 base::OnceCallback<void(const base::Value*)> callback, 55 base::TimeDelta timeout) override; 56 57 // WebStateObserver implementation 58 void WebStateDestroyed(web::WebState* web_state) override; 59 60 private: 61 // Calls the JavaScript function |name| in the frame context in the same 62 // manner as the inherited CallJavaScriptFunction functions. If 63 // |reply_with_result| is true, the return value of executing the function 64 // will be sent back to the receiver and handled by |OnJavaScriptReply|. 65 bool CallJavaScriptFunction(const std::string& name, 66 const std::vector<base::Value>& parameters, 67 bool reply_with_result); 68 69 // Detaches the receiver from the associated WebState. 70 void DetachFromWebState(); 71 // Returns the script command name to use for this WebFrame. 72 const std::string GetScriptCommandPrefix(); 73 // Encrypts |payload| and returns a JSON string of a dictionary containing 74 // the encrypted metadata and its initialization vector. If encryption fails, 75 // an empty string will be returned. 76 const std::string EncryptPayload(base::DictionaryValue payload, 77 const std::string& additiona_data); 78 79 // A structure to store the callbacks associated with the 80 // |CallJavaScriptFunction| requests. 81 typedef base::CancelableOnceCallback<void(void)> TimeoutCallback; 82 struct RequestCallbacks { 83 RequestCallbacks(base::OnceCallback<void(const base::Value*)> completion, 84 std::unique_ptr<TimeoutCallback>); 85 ~RequestCallbacks(); 86 base::OnceCallback<void(const base::Value*)> completion; 87 std::unique_ptr<TimeoutCallback> timeout_callback; 88 }; 89 90 // Calls the JavaScript function |name| in the web state (main frame). If 91 // |reply_with_result| is true, the return value of executing the function 92 // will be sent back to the receiver. This function is only used if the 93 // receiver does not have an encryption key. The JavaScript function is called 94 // directly and thus only works on the main frame. (Encryption is not required 95 // to securely communicate with the main frame because evaluating JavaScript 96 // on the WebState is already secure.) 97 bool ExecuteJavaScriptFunction(const std::string& name, 98 const std::vector<base::Value>& parameters, 99 int message_id, 100 bool reply_with_result); 101 102 // Runs the request associated with the message with id |message_id|. The 103 // completion callback, if any, associated with |message_id| will be called 104 // with |result|. 105 void CompleteRequest(int message_id, const base::Value* result); 106 // Calls the completion block of |request_callbacks| with |result| value and 107 // removes the callbacks from |pending_requests|. 108 void CompleteRequest(std::unique_ptr<RequestCallbacks> request_callbacks, 109 const base::Value* result); 110 111 // Cancels the request associated with the message with id |message_id|. The 112 // completion callback, if any, associated with |message_id| will be called 113 // with a null result value. Note that the JavaScript will still run to 114 // completion, but any future response will be ignored. 115 void CancelRequest(int message_id); 116 // Performs |CancelRequest| on all outstanding request callbacks in 117 // |pending_requests_|. 118 void CancelPendingRequests(); 119 120 // Handles message from JavaScript with result of executing the function 121 // specified in CallJavaScriptFunction. 122 void OnJavaScriptReply(web::WebState* web_state, 123 const base::DictionaryValue& command, 124 const GURL& page_url, 125 bool interacting, 126 WebFrame* sender_frame); 127 128 // The JavaScript requests awating a reply. 129 std::map<uint32_t, std::unique_ptr<struct RequestCallbacks>> 130 pending_requests_; 131 132 // The frame identifier which uniquely identifies this frame across the 133 // application's lifetime. 134 std::string frame_id_; 135 // The symmetric encryption key used to encrypt messages addressed to the 136 // frame. Stored in a base64 encoded string. 137 std::unique_ptr<crypto::SymmetricKey> frame_key_; 138 // The message ID of the next JavaScript message to be sent. 139 int next_message_id_ = 0; 140 // Whether or not the receiver represents the main frame. 141 bool is_main_frame_ = false; 142 // The security origin associated with this frame. 143 GURL security_origin_; 144 // The associated web state. 145 web::WebState* web_state_ = nullptr; 146 // Subscription for JS message. 147 std::unique_ptr<web::WebState::ScriptCommandSubscription> subscription_; 148 149 base::WeakPtrFactory<WebFrameImpl> weak_ptr_factory_; 150 151 DISALLOW_COPY_AND_ASSIGN(WebFrameImpl); 152 }; 153 154 } // namespace web 155 156 #endif // IOS_WEB_JS_MESSAGING_WEB_FRAME_IMPL_H_ 157