user_script.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. // Copyright 2013 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/common/user_script.h"
  5. #include <stddef.h>
  6. #include <stdint.h>
  7. #include <memory>
  8. #include <utility>
  9. #include "base/atomic_sequence_num.h"
  10. #include "base/command_line.h"
  11. #include "base/pickle.h"
  12. #include "base/strings/pattern.h"
  13. #include "base/strings/string_number_conversions.h"
  14. #include "base/strings/string_util.h"
  15. #include "extensions/common/switches.h"
  16. namespace {
  17. // This cannot be a plain int or int64_t because we need to generate unique IDs
  18. // from multiple threads.
  19. base::AtomicSequenceNumber g_user_script_id_generator;
  20. bool UrlMatchesGlobs(const std::vector<std::string>* globs,
  21. const GURL& url) {
  22. for (auto glob = globs->cbegin(); glob != globs->cend(); ++glob) {
  23. if (base::MatchPattern(url.spec(), *glob))
  24. return true;
  25. }
  26. return false;
  27. }
  28. } // namespace
  29. namespace extensions {
  30. // The bitmask for valid user script injectable schemes used by URLPattern.
  31. enum {
  32. kValidUserScriptSchemes = URLPattern::SCHEME_CHROMEUI |
  33. URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS |
  34. URLPattern::SCHEME_FILE | URLPattern::SCHEME_FTP |
  35. URLPattern::SCHEME_UUID_IN_PACKAGE
  36. };
  37. // static
  38. const char UserScript::kFileExtension[] = ".user.js";
  39. // static
  40. const char UserScript::kGeneratedIDPrefix = '_';
  41. // static
  42. std::string UserScript::GenerateUserScriptID() {
  43. // This could just as easily use a GUID. The actual value of the id is not
  44. // important as long a unique id is generated for each UserScript.
  45. return "_" + base::NumberToString(g_user_script_id_generator.GetNext());
  46. }
  47. bool UserScript::IsURLUserScript(const GURL& url,
  48. const std::string& mime_type) {
  49. return base::EndsWith(url.ExtractFileName(), kFileExtension,
  50. base::CompareCase::INSENSITIVE_ASCII) &&
  51. mime_type != "text/html";
  52. }
  53. // static
  54. int UserScript::ValidUserScriptSchemes(bool can_execute_script_everywhere) {
  55. if (can_execute_script_everywhere)
  56. return URLPattern::SCHEME_ALL;
  57. int valid_schemes = kValidUserScriptSchemes;
  58. if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
  59. switches::kExtensionsOnChromeURLs)) {
  60. valid_schemes &= ~URLPattern::SCHEME_CHROMEUI;
  61. }
  62. return valid_schemes;
  63. }
  64. // static
  65. bool UserScript::IsIDGenerated(const std::string& id) {
  66. return !id.empty() && id[0] == kGeneratedIDPrefix;
  67. }
  68. UserScript::File::File(const base::FilePath& extension_root,
  69. const base::FilePath& relative_path,
  70. const GURL& url)
  71. : extension_root_(extension_root),
  72. relative_path_(relative_path),
  73. url_(url) {
  74. }
  75. UserScript::File::File() {}
  76. // File content is not copied.
  77. UserScript::File::File(const File& other)
  78. : extension_root_(other.extension_root_),
  79. relative_path_(other.relative_path_),
  80. url_(other.url_) {}
  81. UserScript::File::~File() {}
  82. UserScript::UserScript() = default;
  83. UserScript::~UserScript() = default;
  84. // static.
  85. std::unique_ptr<UserScript> UserScript::CopyMetadataFrom(
  86. const UserScript& other) {
  87. std::unique_ptr<UserScript> script(new UserScript());
  88. script->run_location_ = other.run_location_;
  89. script->name_space_ = other.name_space_;
  90. script->name_ = other.name_;
  91. script->description_ = other.description_;
  92. script->version_ = other.version_;
  93. script->globs_ = other.globs_;
  94. script->exclude_globs_ = other.exclude_globs_;
  95. script->url_set_ = other.url_set_.Clone();
  96. script->exclude_url_set_ = other.exclude_url_set_.Clone();
  97. // Note: File content is not copied.
  98. for (const std::unique_ptr<File>& file : other.js_scripts()) {
  99. std::unique_ptr<File> file_copy(new File(*file));
  100. script->js_scripts_.push_back(std::move(file_copy));
  101. }
  102. for (const std::unique_ptr<File>& file : other.css_scripts()) {
  103. std::unique_ptr<File> file_copy(new File(*file));
  104. script->css_scripts_.push_back(std::move(file_copy));
  105. }
  106. script->host_id_ = other.host_id_;
  107. script->consumer_instance_type_ = other.consumer_instance_type_;
  108. script->user_script_id_ = other.user_script_id_;
  109. script->emulate_greasemonkey_ = other.emulate_greasemonkey_;
  110. script->match_all_frames_ = other.match_all_frames_;
  111. script->match_origin_as_fallback_ = other.match_origin_as_fallback_;
  112. script->incognito_enabled_ = other.incognito_enabled_;
  113. script->execution_world_ = other.execution_world_;
  114. return script;
  115. }
  116. void UserScript::add_url_pattern(const URLPattern& pattern) {
  117. url_set_.AddPattern(pattern);
  118. }
  119. void UserScript::add_exclude_url_pattern(const URLPattern& pattern) {
  120. exclude_url_set_.AddPattern(pattern);
  121. }
  122. bool UserScript::MatchesURL(const GURL& url) const {
  123. if (!url_set_.is_empty()) {
  124. if (!url_set_.MatchesURL(url))
  125. return false;
  126. }
  127. if (!exclude_url_set_.is_empty()) {
  128. if (exclude_url_set_.MatchesURL(url))
  129. return false;
  130. }
  131. if (!globs_.empty()) {
  132. if (!UrlMatchesGlobs(&globs_, url))
  133. return false;
  134. }
  135. if (!exclude_globs_.empty()) {
  136. if (UrlMatchesGlobs(&exclude_globs_, url))
  137. return false;
  138. }
  139. return true;
  140. }
  141. bool UserScript::MatchesDocument(const GURL& effective_document_url,
  142. bool is_subframe) const {
  143. if (is_subframe && !match_all_frames())
  144. return false;
  145. return MatchesURL(effective_document_url);
  146. }
  147. void UserScript::File::Pickle(base::Pickle* pickle) const {
  148. pickle->WriteString(url_.spec());
  149. // Do not write path. It's not needed in the renderer.
  150. // Do not write content. It will be serialized by other means.
  151. }
  152. void UserScript::File::Unpickle(const base::Pickle& pickle,
  153. base::PickleIterator* iter) {
  154. // Read the url from the pickle.
  155. std::string url;
  156. CHECK(iter->ReadString(&url));
  157. set_url(GURL(url));
  158. }
  159. void UserScript::Pickle(base::Pickle* pickle) const {
  160. // Write the simple types to the pickle.
  161. pickle->WriteInt(static_cast<int>(run_location()));
  162. pickle->WriteString(user_script_id_);
  163. pickle->WriteBool(emulate_greasemonkey());
  164. pickle->WriteBool(match_all_frames());
  165. pickle->WriteInt(static_cast<int>(match_origin_as_fallback()));
  166. pickle->WriteBool(is_incognito_enabled());
  167. pickle->WriteInt(static_cast<int>(execution_world()));
  168. PickleHostID(pickle, host_id_);
  169. pickle->WriteInt(consumer_instance_type());
  170. PickleGlobs(pickle, globs_);
  171. PickleGlobs(pickle, exclude_globs_);
  172. PickleURLPatternSet(pickle, url_set_);
  173. PickleURLPatternSet(pickle, exclude_url_set_);
  174. PickleScripts(pickle, js_scripts_);
  175. PickleScripts(pickle, css_scripts_);
  176. }
  177. void UserScript::PickleGlobs(base::Pickle* pickle,
  178. const std::vector<std::string>& globs) const {
  179. pickle->WriteUInt32(globs.size());
  180. for (auto glob = globs.cbegin(); glob != globs.cend(); ++glob) {
  181. pickle->WriteString(*glob);
  182. }
  183. }
  184. void UserScript::PickleHostID(base::Pickle* pickle,
  185. const mojom::HostID& host_id) const {
  186. pickle->WriteInt(static_cast<int>(host_id.type));
  187. pickle->WriteString(host_id.id);
  188. }
  189. void UserScript::PickleURLPatternSet(base::Pickle* pickle,
  190. const URLPatternSet& pattern_list) const {
  191. pickle->WriteUInt32(pattern_list.patterns().size());
  192. for (auto pattern = pattern_list.begin(); pattern != pattern_list.end();
  193. ++pattern) {
  194. pickle->WriteInt(pattern->valid_schemes());
  195. pickle->WriteString(pattern->GetAsString());
  196. }
  197. }
  198. void UserScript::PickleScripts(base::Pickle* pickle,
  199. const FileList& scripts) const {
  200. pickle->WriteUInt32(scripts.size());
  201. for (const std::unique_ptr<File>& file : scripts)
  202. file->Pickle(pickle);
  203. }
  204. void UserScript::Unpickle(const base::Pickle& pickle,
  205. base::PickleIterator* iter) {
  206. // Read the run location.
  207. int run_location = 0;
  208. CHECK(iter->ReadInt(&run_location));
  209. CHECK(run_location >= static_cast<int>(mojom::RunLocation::kUndefined) &&
  210. run_location <= static_cast<int>(mojom::RunLocation::kMaxValue));
  211. run_location_ = static_cast<mojom::RunLocation>(run_location);
  212. CHECK(iter->ReadString(&user_script_id_));
  213. CHECK(iter->ReadBool(&emulate_greasemonkey_));
  214. CHECK(iter->ReadBool(&match_all_frames_));
  215. int match_origin_as_fallback_int = 0;
  216. CHECK(iter->ReadInt(&match_origin_as_fallback_int));
  217. match_origin_as_fallback_ =
  218. static_cast<MatchOriginAsFallbackBehavior>(match_origin_as_fallback_int);
  219. CHECK(iter->ReadBool(&incognito_enabled_));
  220. // Read the execution world.
  221. int execution_world = 0;
  222. CHECK(iter->ReadInt(&execution_world));
  223. CHECK(execution_world >= static_cast<int>(mojom::ExecutionWorld::kIsolated) &&
  224. execution_world <= static_cast<int>(mojom::ExecutionWorld::kMaxValue));
  225. execution_world_ = static_cast<mojom::ExecutionWorld>(execution_world);
  226. UnpickleHostID(pickle, iter, &host_id_);
  227. int consumer_instance_type = 0;
  228. CHECK(iter->ReadInt(&consumer_instance_type));
  229. consumer_instance_type_ =
  230. static_cast<ConsumerInstanceType>(consumer_instance_type);
  231. UnpickleGlobs(pickle, iter, &globs_);
  232. UnpickleGlobs(pickle, iter, &exclude_globs_);
  233. UnpickleURLPatternSet(pickle, iter, &url_set_);
  234. UnpickleURLPatternSet(pickle, iter, &exclude_url_set_);
  235. UnpickleScripts(pickle, iter, &js_scripts_);
  236. UnpickleScripts(pickle, iter, &css_scripts_);
  237. }
  238. bool UserScript::IsIDGenerated() const {
  239. CHECK(!user_script_id_.empty());
  240. return IsIDGenerated(user_script_id_);
  241. }
  242. void UserScript::UnpickleGlobs(const base::Pickle& pickle,
  243. base::PickleIterator* iter,
  244. std::vector<std::string>* globs) {
  245. uint32_t num_globs = 0;
  246. CHECK(iter->ReadUInt32(&num_globs));
  247. globs->clear();
  248. for (uint32_t i = 0; i < num_globs; ++i) {
  249. std::string glob;
  250. CHECK(iter->ReadString(&glob));
  251. globs->push_back(glob);
  252. }
  253. }
  254. void UserScript::UnpickleHostID(const base::Pickle& pickle,
  255. base::PickleIterator* iter,
  256. mojom::HostID* host_id) {
  257. int type = 0;
  258. std::string id;
  259. CHECK(iter->ReadInt(&type));
  260. CHECK(iter->ReadString(&id));
  261. *host_id = mojom::HostID(static_cast<mojom::HostID::HostType>(type), id);
  262. }
  263. void UserScript::UnpickleURLPatternSet(const base::Pickle& pickle,
  264. base::PickleIterator* iter,
  265. URLPatternSet* pattern_list) {
  266. uint32_t num_patterns = 0;
  267. CHECK(iter->ReadUInt32(&num_patterns));
  268. pattern_list->ClearPatterns();
  269. for (uint32_t i = 0; i < num_patterns; ++i) {
  270. int valid_schemes;
  271. CHECK(iter->ReadInt(&valid_schemes));
  272. std::string pattern_str;
  273. CHECK(iter->ReadString(&pattern_str));
  274. URLPattern pattern(kValidUserScriptSchemes);
  275. URLPattern::ParseResult result = pattern.Parse(pattern_str);
  276. CHECK(URLPattern::ParseResult::kSuccess == result)
  277. << URLPattern::GetParseResultString(result) << " "
  278. << pattern_str.c_str();
  279. pattern.SetValidSchemes(valid_schemes);
  280. pattern_list->AddPattern(pattern);
  281. }
  282. }
  283. void UserScript::UnpickleScripts(const base::Pickle& pickle,
  284. base::PickleIterator* iter,
  285. FileList* scripts) {
  286. uint32_t num_files = 0;
  287. CHECK(iter->ReadUInt32(&num_files));
  288. scripts->clear();
  289. for (uint32_t i = 0; i < num_files; ++i) {
  290. std::unique_ptr<File> file(new File());
  291. file->Unpickle(pickle, iter);
  292. scripts->push_back(std::move(file));
  293. }
  294. }
  295. } // namespace extensions