storage_area.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. // Copyright 2017 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. #include "extensions/renderer/storage_area.h"
  5. #include "base/strings/stringprintf.h"
  6. #include "extensions/common/api/storage.h"
  7. #include "extensions/renderer/bindings/api_binding_util.h"
  8. #include "extensions/renderer/bindings/api_event_handler.h"
  9. #include "extensions/renderer/bindings/api_invocation_errors.h"
  10. #include "extensions/renderer/bindings/api_request_handler.h"
  11. #include "extensions/renderer/bindings/api_signature.h"
  12. #include "extensions/renderer/bindings/api_type_reference_map.h"
  13. #include "extensions/renderer/bindings/binding_access_checker.h"
  14. #include "gin/arguments.h"
  15. #include "gin/handle.h"
  16. #include "gin/object_template_builder.h"
  17. #include "gin/wrappable.h"
  18. #include "v8/include/v8-object.h"
  19. #include "v8/include/v8-primitive.h"
  20. namespace extensions {
  21. namespace {
  22. #define DEFINE_STORAGE_AREA_HANDLERS() \
  23. const char* GetTypeName() override { return "StorageArea"; } \
  24. void Get(gin::Arguments* arguments) { \
  25. storage_area_.HandleFunctionCall("get", arguments); \
  26. } \
  27. void Set(gin::Arguments* arguments) { \
  28. storage_area_.HandleFunctionCall("set", arguments); \
  29. } \
  30. void Remove(gin::Arguments* arguments) { \
  31. storage_area_.HandleFunctionCall("remove", arguments); \
  32. } \
  33. void Clear(gin::Arguments* arguments) { \
  34. storage_area_.HandleFunctionCall("clear", arguments); \
  35. } \
  36. void GetBytesInUse(gin::Arguments* arguments) { \
  37. storage_area_.HandleFunctionCall("getBytesInUse", arguments); \
  38. } \
  39. v8::Local<v8::Value> GetOnChangedEvent(gin::Arguments* arguments) { \
  40. v8::Isolate* isolate = arguments->isolate(); \
  41. v8::Local<v8::Context> context = arguments->GetHolderCreationContext(); \
  42. v8::Local<v8::Object> wrapper = GetWrapper(isolate).ToLocalChecked(); \
  43. return storage_area_.GetOnChangedEvent(isolate, context, wrapper); \
  44. }
  45. // gin::Wrappables for each of the storage areas. Since each has slightly
  46. // different properties, and the object template is shared between all
  47. // instances, this is a little verbose.
  48. class LocalStorageArea final : public gin::Wrappable<LocalStorageArea> {
  49. public:
  50. LocalStorageArea(APIRequestHandler* request_handler,
  51. APIEventHandler* event_handler,
  52. const APITypeReferenceMap* type_refs,
  53. const BindingAccessChecker* access_checker)
  54. : storage_area_(request_handler,
  55. event_handler,
  56. type_refs,
  57. "local",
  58. access_checker) {}
  59. LocalStorageArea(const LocalStorageArea&) = delete;
  60. LocalStorageArea& operator=(const LocalStorageArea&) = delete;
  61. ~LocalStorageArea() override = default;
  62. static gin::WrapperInfo kWrapperInfo;
  63. gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
  64. v8::Isolate* isolate) override {
  65. return Wrappable<LocalStorageArea>::GetObjectTemplateBuilder(isolate)
  66. .SetMethod("get", &LocalStorageArea::Get)
  67. .SetMethod("set", &LocalStorageArea::Set)
  68. .SetMethod("remove", &LocalStorageArea::Remove)
  69. .SetMethod("clear", &LocalStorageArea::Clear)
  70. .SetMethod("getBytesInUse", &LocalStorageArea::GetBytesInUse)
  71. .SetProperty("onChanged", &LocalStorageArea::GetOnChangedEvent)
  72. .SetValue("QUOTA_BYTES", api::storage::local::QUOTA_BYTES);
  73. }
  74. private:
  75. DEFINE_STORAGE_AREA_HANDLERS()
  76. StorageArea storage_area_;
  77. };
  78. gin::WrapperInfo LocalStorageArea::kWrapperInfo = {gin::kEmbedderNativeGin};
  79. class SyncStorageArea final : public gin::Wrappable<SyncStorageArea> {
  80. public:
  81. SyncStorageArea(APIRequestHandler* request_handler,
  82. APIEventHandler* event_handler,
  83. const APITypeReferenceMap* type_refs,
  84. const BindingAccessChecker* access_checker)
  85. : storage_area_(request_handler,
  86. event_handler,
  87. type_refs,
  88. "sync",
  89. access_checker) {}
  90. SyncStorageArea(const SyncStorageArea&) = delete;
  91. SyncStorageArea& operator=(const SyncStorageArea&) = delete;
  92. ~SyncStorageArea() override = default;
  93. static gin::WrapperInfo kWrapperInfo;
  94. gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
  95. v8::Isolate* isolate) override {
  96. return Wrappable<SyncStorageArea>::GetObjectTemplateBuilder(isolate)
  97. .SetMethod("get", &SyncStorageArea::Get)
  98. .SetMethod("set", &SyncStorageArea::Set)
  99. .SetMethod("remove", &SyncStorageArea::Remove)
  100. .SetMethod("clear", &SyncStorageArea::Clear)
  101. .SetMethod("getBytesInUse", &SyncStorageArea::GetBytesInUse)
  102. .SetProperty("onChanged", &SyncStorageArea::GetOnChangedEvent)
  103. .SetValue("QUOTA_BYTES", api::storage::sync::QUOTA_BYTES)
  104. .SetValue("QUOTA_BYTES_PER_ITEM",
  105. api::storage::sync::QUOTA_BYTES_PER_ITEM)
  106. .SetValue("MAX_ITEMS", api::storage::sync::MAX_ITEMS)
  107. .SetValue("MAX_WRITE_OPERATIONS_PER_HOUR",
  108. api::storage::sync::MAX_WRITE_OPERATIONS_PER_HOUR)
  109. .SetValue("MAX_WRITE_OPERATIONS_PER_MINUTE",
  110. api::storage::sync::MAX_WRITE_OPERATIONS_PER_MINUTE)
  111. .SetValue(
  112. "MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE",
  113. api::storage::sync::MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE);
  114. }
  115. private:
  116. DEFINE_STORAGE_AREA_HANDLERS()
  117. StorageArea storage_area_;
  118. };
  119. gin::WrapperInfo SyncStorageArea::kWrapperInfo = {gin::kEmbedderNativeGin};
  120. class ManagedStorageArea final : public gin::Wrappable<ManagedStorageArea> {
  121. public:
  122. ManagedStorageArea(APIRequestHandler* request_handler,
  123. APIEventHandler* event_handler,
  124. const APITypeReferenceMap* type_refs,
  125. const BindingAccessChecker* access_checker)
  126. : storage_area_(request_handler,
  127. event_handler,
  128. type_refs,
  129. "managed",
  130. access_checker) {}
  131. ManagedStorageArea(const ManagedStorageArea&) = delete;
  132. ManagedStorageArea& operator=(const ManagedStorageArea&) = delete;
  133. ~ManagedStorageArea() override = default;
  134. static gin::WrapperInfo kWrapperInfo;
  135. gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
  136. v8::Isolate* isolate) override {
  137. return Wrappable<ManagedStorageArea>::GetObjectTemplateBuilder(isolate)
  138. .SetMethod("get", &ManagedStorageArea::Get)
  139. .SetMethod("set", &ManagedStorageArea::Set)
  140. .SetMethod("remove", &ManagedStorageArea::Remove)
  141. .SetMethod("clear", &ManagedStorageArea::Clear)
  142. .SetMethod("getBytesInUse", &ManagedStorageArea::GetBytesInUse)
  143. .SetProperty("onChanged", &ManagedStorageArea::GetOnChangedEvent);
  144. }
  145. private:
  146. DEFINE_STORAGE_AREA_HANDLERS()
  147. StorageArea storage_area_;
  148. };
  149. gin::WrapperInfo ManagedStorageArea::kWrapperInfo = {gin::kEmbedderNativeGin};
  150. class SessionStorageArea final : public gin::Wrappable<SessionStorageArea> {
  151. public:
  152. SessionStorageArea(APIRequestHandler* request_handler,
  153. APIEventHandler* event_handler,
  154. const APITypeReferenceMap* type_refs,
  155. const BindingAccessChecker* access_checker)
  156. : storage_area_(request_handler,
  157. event_handler,
  158. type_refs,
  159. "session",
  160. access_checker) {}
  161. SessionStorageArea(const SessionStorageArea&) = delete;
  162. SessionStorageArea& operator=(const SessionStorageArea&) = delete;
  163. ~SessionStorageArea() override = default;
  164. static gin::WrapperInfo kWrapperInfo;
  165. gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
  166. v8::Isolate* isolate) override {
  167. return Wrappable<SessionStorageArea>::GetObjectTemplateBuilder(isolate)
  168. .SetMethod("get", &SessionStorageArea::Get)
  169. .SetMethod("set", &SessionStorageArea::Set)
  170. .SetMethod("remove", &SessionStorageArea::Remove)
  171. .SetMethod("clear", &SessionStorageArea::Clear)
  172. .SetMethod("getBytesInUse", &SessionStorageArea::GetBytesInUse)
  173. // TODO(crbug.com/1227410): Only expose `setAccessLevel` in privileged
  174. // contexts.
  175. .SetMethod("setAccessLevel", &SessionStorageArea::SetAccessLevel)
  176. .SetProperty("onChanged", &SessionStorageArea::GetOnChangedEvent)
  177. .SetValue("QUOTA_BYTES", api::storage::session::QUOTA_BYTES);
  178. }
  179. private:
  180. DEFINE_STORAGE_AREA_HANDLERS()
  181. void SetAccessLevel(gin::Arguments* arguments) {
  182. storage_area_.HandleFunctionCall("setAccessLevel", arguments);
  183. }
  184. StorageArea storage_area_;
  185. };
  186. gin::WrapperInfo SessionStorageArea::kWrapperInfo = {gin::kEmbedderNativeGin};
  187. #undef DEFINE_STORAGE_AREA_HANDLERS
  188. } // namespace
  189. StorageArea::StorageArea(APIRequestHandler* request_handler,
  190. APIEventHandler* event_handler,
  191. const APITypeReferenceMap* type_refs,
  192. const std::string& name,
  193. const BindingAccessChecker* access_checker)
  194. : request_handler_(request_handler),
  195. event_handler_(event_handler),
  196. type_refs_(type_refs),
  197. name_(name),
  198. access_checker_(access_checker) {}
  199. StorageArea::~StorageArea() = default;
  200. // static
  201. v8::Local<v8::Object> StorageArea::CreateStorageArea(
  202. v8::Isolate* isolate,
  203. const std::string& property_name,
  204. const base::ListValue* property_values,
  205. APIRequestHandler* request_handler,
  206. APIEventHandler* event_handler,
  207. APITypeReferenceMap* type_refs,
  208. const BindingAccessChecker* access_checker) {
  209. v8::Local<v8::Object> object;
  210. if (property_name == "local") {
  211. gin::Handle<LocalStorageArea> handle = gin::CreateHandle(
  212. isolate, new LocalStorageArea(request_handler, event_handler, type_refs,
  213. access_checker));
  214. object = handle.ToV8().As<v8::Object>();
  215. } else if (property_name == "sync") {
  216. gin::Handle<SyncStorageArea> handle = gin::CreateHandle(
  217. isolate, new SyncStorageArea(request_handler, event_handler, type_refs,
  218. access_checker));
  219. object = handle.ToV8().As<v8::Object>();
  220. } else if (property_name == "session") {
  221. gin::Handle<SessionStorageArea> handle = gin::CreateHandle(
  222. isolate, new SessionStorageArea(request_handler, event_handler,
  223. type_refs, access_checker));
  224. object = handle.ToV8().As<v8::Object>();
  225. } else {
  226. CHECK_EQ("managed", property_name);
  227. gin::Handle<ManagedStorageArea> handle = gin::CreateHandle(
  228. isolate, new ManagedStorageArea(request_handler, event_handler,
  229. type_refs, access_checker));
  230. object = handle.ToV8().As<v8::Object>();
  231. }
  232. return object;
  233. }
  234. void StorageArea::HandleFunctionCall(const std::string& method_name,
  235. gin::Arguments* arguments) {
  236. v8::Isolate* isolate = arguments->isolate();
  237. v8::HandleScope handle_scope(isolate);
  238. v8::Local<v8::Context> context = arguments->GetHolderCreationContext();
  239. // The context may have been invalidated, as in the case where this could be
  240. // a reference to an object from a removed frame.
  241. if (!binding::IsContextValidOrThrowError(context))
  242. return;
  243. std::string full_method_name = "storage." + method_name;
  244. if (!access_checker_->HasAccessOrThrowError(context, full_method_name))
  245. return;
  246. std::vector<v8::Local<v8::Value>> argument_list = arguments->GetAll();
  247. const APISignature* signature = type_refs_->GetTypeMethodSignature(
  248. base::StringPrintf("%s.%s", "storage.StorageArea", method_name.c_str()));
  249. DCHECK(signature);
  250. APISignature::JSONParseResult parse_result =
  251. signature->ParseArgumentsToJSON(context, argument_list, *type_refs_);
  252. if (!parse_result.succeeded()) {
  253. arguments->ThrowTypeError(api_errors::InvocationError(
  254. full_method_name, signature->GetExpectedSignature(),
  255. *parse_result.error));
  256. return;
  257. }
  258. parse_result.arguments_list->GetList().Insert(
  259. parse_result.arguments_list->GetList().begin(), base::Value(name_));
  260. v8::Local<v8::Promise> promise = request_handler_->StartRequest(
  261. context, full_method_name, std::move(parse_result.arguments_list),
  262. parse_result.async_type, parse_result.callback, v8::Local<v8::Function>(),
  263. binding::ResultModifierFunction());
  264. if (!promise.IsEmpty())
  265. arguments->Return(promise);
  266. }
  267. v8::Local<v8::Value> StorageArea::GetOnChangedEvent(
  268. v8::Isolate* isolate,
  269. v8::Local<v8::Context> context,
  270. v8::Local<v8::Object> wrapper) {
  271. if (!binding::IsContextValidOrThrowError(context))
  272. return v8::Undefined(isolate);
  273. v8::Local<v8::Private> key = v8::Private::ForApi(
  274. isolate, gin::StringToSymbol(isolate, "onChangedEvent"));
  275. v8::Local<v8::Value> event;
  276. if (!wrapper->GetPrivate(context, key).ToLocal(&event)) {
  277. NOTREACHED();
  278. return v8::Local<v8::Value>();
  279. }
  280. DCHECK(!event.IsEmpty());
  281. if (event->IsUndefined()) {
  282. constexpr bool kSupportsFilters = false;
  283. constexpr bool kSupportsLazyListeners = true;
  284. event = event_handler_->CreateEventInstance(
  285. base::StringPrintf("storage.%s.onChanged", name_.c_str()),
  286. kSupportsFilters, kSupportsLazyListeners, binding::kNoListenerMax, true,
  287. context);
  288. v8::Maybe<bool> set_result = wrapper->SetPrivate(context, key, event);
  289. if (!set_result.IsJust() || !set_result.FromJust()) {
  290. NOTREACHED();
  291. return v8::Local<v8::Value>();
  292. }
  293. }
  294. return event;
  295. }
  296. } // namespace extensions