extension.cc 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870
  1. // Copyright (c) 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/extension.h"
  5. #include <stddef.h>
  6. #include <algorithm>
  7. #include <iterator>
  8. #include <memory>
  9. #include <string>
  10. #include <utility>
  11. #include "base/base64.h"
  12. #include "base/command_line.h"
  13. #include "base/files/file_path.h"
  14. #include "base/i18n/rtl.h"
  15. #include "base/json/json_writer.h"
  16. #include "base/memory/singleton.h"
  17. #include "base/strings/strcat.h"
  18. #include "base/strings/string_number_conversions.h"
  19. #include "base/strings/string_piece.h"
  20. #include "base/strings/string_util.h"
  21. #include "base/strings/utf_string_conversions.h"
  22. #include "base/timer/elapsed_timer.h"
  23. #include "base/values.h"
  24. #include "base/version.h"
  25. #include "components/crx_file/id_util.h"
  26. #include "content/public/common/url_constants.h"
  27. #include "extensions/common/constants.h"
  28. #include "extensions/common/error_utils.h"
  29. #include "extensions/common/manifest.h"
  30. #include "extensions/common/manifest_constants.h"
  31. #include "extensions/common/manifest_handler.h"
  32. #include "extensions/common/manifest_handlers/incognito_info.h"
  33. #include "extensions/common/manifest_handlers/permissions_parser.h"
  34. #include "extensions/common/permissions/permission_set.h"
  35. #include "extensions/common/permissions/permissions_data.h"
  36. #include "extensions/common/permissions/permissions_info.h"
  37. #include "extensions/common/switches.h"
  38. #include "extensions/common/url_pattern.h"
  39. #include "net/base/filename_util.h"
  40. #include "url/url_util.h"
  41. using extensions::mojom::ManifestLocation;
  42. namespace extensions {
  43. namespace keys = manifest_keys;
  44. namespace values = manifest_values;
  45. namespace errors = manifest_errors;
  46. namespace {
  47. constexpr int kMinimumSupportedManifestVersion = 2;
  48. constexpr int kMaximumSupportedManifestVersion = 3;
  49. constexpr int kPEMOutputColumns = 64;
  50. static_assert(kMaximumSupportedManifestVersion >=
  51. kMinimumSupportedManifestVersion,
  52. "The modern manifest version must be supported.");
  53. bool g_silence_deprecated_manifest_version_warnings = false;
  54. // KEY MARKERS
  55. constexpr char kKeyBeginHeaderMarker[] = "-----BEGIN";
  56. constexpr char kKeyBeginFooterMarker[] = "-----END";
  57. constexpr char kKeyInfoEndMarker[] = "KEY-----";
  58. constexpr char kPublic[] = "PUBLIC";
  59. constexpr char kPrivate[] = "PRIVATE";
  60. bool ContainsReservedCharacters(const base::FilePath& path) {
  61. // We should disallow backslash '\\' as file path separator even on Windows,
  62. // because the backslash is not regarded as file path separator on Linux/Mac.
  63. // Extensions are cross-platform.
  64. // Since FilePath uses backslash '\\' as file path separator on Windows, so we
  65. // need to check manually.
  66. if (path.value().find('\\') != path.value().npos)
  67. return true;
  68. return !net::IsSafePortableRelativePath(path);
  69. }
  70. // Returns true if the given |manifest_version| is supported for the specified
  71. // |type| of extension. Optionally populates |warning| if an InstallWarning
  72. // should be added.
  73. bool IsManifestSupported(int manifest_version,
  74. Manifest::Type type,
  75. ManifestLocation location,
  76. int creation_flags,
  77. std::string* warning) {
  78. // Supported versions are always safe.
  79. if (manifest_version >= kMinimumSupportedManifestVersion &&
  80. manifest_version <= kMaximumSupportedManifestVersion) {
  81. // Emit a warning for unpacked extensions on Manifest V2 warning that
  82. // MV2 is deprecated.
  83. if (type == Manifest::TYPE_EXTENSION && manifest_version == 2 &&
  84. Manifest::IsUnpackedLocation(location) &&
  85. !g_silence_deprecated_manifest_version_warnings) {
  86. *warning = errors::kManifestV2IsDeprecatedWarning;
  87. }
  88. return true;
  89. }
  90. if (manifest_version > kMaximumSupportedManifestVersion) {
  91. // Silence future manifest error with flag.
  92. bool allow_future_manifest_version =
  93. base::CommandLine::ForCurrentProcess()->HasSwitch(
  94. switches::kAllowFutureManifestVersion);
  95. if (!allow_future_manifest_version) {
  96. *warning = ErrorUtils::FormatErrorMessage(
  97. manifest_errors::kManifestVersionTooHighWarning,
  98. base::NumberToString(kMaximumSupportedManifestVersion),
  99. base::NumberToString(manifest_version));
  100. }
  101. return true;
  102. }
  103. // Allow an exception for extensions if a special commandline flag is present.
  104. // Note: This allows the extension to load, but it may effectively be treated
  105. // as a higher manifest version. For instance, all extension v1-specific
  106. // handling has been removed, which means they will effectively be treated as
  107. // v2s.
  108. bool allow_legacy_extensions =
  109. base::CommandLine::ForCurrentProcess()->HasSwitch(
  110. switches::kAllowLegacyExtensionManifests);
  111. if (type == Manifest::TYPE_EXTENSION && allow_legacy_extensions)
  112. return true;
  113. if ((creation_flags & Extension::REQUIRE_MODERN_MANIFEST_VERSION) != 0)
  114. return false;
  115. static constexpr int kMinimumExtensionManifestVersion = 2;
  116. if (type == Manifest::TYPE_EXTENSION)
  117. return manifest_version >= kMinimumExtensionManifestVersion;
  118. static constexpr int kMinimumPlatformAppManifestVersion = 2;
  119. if (type == Manifest::TYPE_PLATFORM_APP)
  120. return manifest_version >= kMinimumPlatformAppManifestVersion;
  121. return true;
  122. }
  123. // Computes the |extension_id| from the given parameters. On success, returns
  124. // true. On failure, populates |error| and returns false.
  125. bool ComputeExtensionID(const base::DictionaryValue& manifest,
  126. const base::FilePath& path,
  127. int creation_flags,
  128. std::u16string* error,
  129. ExtensionId* extension_id) {
  130. if (const base::Value* public_key = manifest.FindKey(keys::kPublicKey)) {
  131. std::string public_key_bytes;
  132. if (!public_key->is_string() ||
  133. !Extension::ParsePEMKeyBytes(public_key->GetString(),
  134. &public_key_bytes)) {
  135. *error = errors::kInvalidKey;
  136. return false;
  137. }
  138. *extension_id = crx_file::id_util::GenerateId(public_key_bytes);
  139. return true;
  140. }
  141. if (creation_flags & Extension::REQUIRE_KEY) {
  142. *error = errors::kInvalidKey;
  143. return false;
  144. }
  145. // If there is a path, we generate the ID from it. This is useful for
  146. // development mode, because it keeps the ID stable across restarts and
  147. // reloading the extension.
  148. *extension_id = crx_file::id_util::GenerateIdForPath(path);
  149. if (extension_id->empty()) {
  150. NOTREACHED() << "Could not create ID from path.";
  151. return false;
  152. }
  153. return true;
  154. }
  155. std::u16string InvalidManifestVersionError(const char* manifest_version_error,
  156. bool is_platform_app) {
  157. std::string valid_version;
  158. if (kMinimumSupportedManifestVersion == kMaximumSupportedManifestVersion) {
  159. valid_version = base::NumberToString(kMinimumSupportedManifestVersion);
  160. } else if (kMaximumSupportedManifestVersion -
  161. kMinimumSupportedManifestVersion ==
  162. 1) {
  163. valid_version = base::StrCat(
  164. {"either ", base::NumberToString(kMinimumSupportedManifestVersion),
  165. " or ", base::NumberToString(kMaximumSupportedManifestVersion)});
  166. } else {
  167. valid_version = base::StrCat(
  168. {"between ", base::NumberToString(kMinimumSupportedManifestVersion),
  169. " and ", base::NumberToString(kMaximumSupportedManifestVersion)});
  170. }
  171. return ErrorUtils::FormatErrorMessageUTF16(
  172. manifest_version_error, valid_version,
  173. is_platform_app ? "apps" : "extensions");
  174. }
  175. } // namespace
  176. const int Extension::kInitFromValueFlagBits = 15;
  177. const char Extension::kMimeType[] = "application/x-chrome-extension";
  178. const int Extension::kValidWebExtentSchemes =
  179. URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS;
  180. const int Extension::kValidHostPermissionSchemes =
  181. URLPattern::SCHEME_CHROMEUI | URLPattern::SCHEME_HTTP |
  182. URLPattern::SCHEME_HTTPS | URLPattern::SCHEME_FILE |
  183. URLPattern::SCHEME_FTP | URLPattern::SCHEME_WS | URLPattern::SCHEME_WSS |
  184. URLPattern::SCHEME_UUID_IN_PACKAGE;
  185. //
  186. // Extension
  187. //
  188. // static
  189. void Extension::set_silence_deprecated_manifest_version_warnings_for_testing(
  190. bool silence) {
  191. g_silence_deprecated_manifest_version_warnings = silence;
  192. }
  193. // static
  194. scoped_refptr<Extension> Extension::Create(const base::FilePath& path,
  195. ManifestLocation location,
  196. const base::DictionaryValue& value,
  197. int flags,
  198. std::string* utf8_error) {
  199. return Extension::Create(path,
  200. location,
  201. value,
  202. flags,
  203. std::string(), // ID is ignored if empty.
  204. utf8_error);
  205. }
  206. // TODO(sungguk): Continue removing std::string errors and replacing
  207. // with std::u16string. See http://crbug.com/71980.
  208. scoped_refptr<Extension> Extension::Create(const base::FilePath& path,
  209. ManifestLocation location,
  210. const base::DictionaryValue& value,
  211. int flags,
  212. const std::string& explicit_id,
  213. std::string* utf8_error) {
  214. base::ElapsedTimer timer;
  215. DCHECK(utf8_error);
  216. std::u16string error;
  217. ExtensionId extension_id;
  218. if (!explicit_id.empty()) {
  219. extension_id = explicit_id;
  220. } else if (!ComputeExtensionID(value, path, flags, &error, &extension_id)) {
  221. *utf8_error = base::UTF16ToUTF8(error);
  222. return nullptr;
  223. }
  224. if ((flags & FROM_BOOKMARK) != 0) {
  225. // Extension-based bookmark apps are no longer supported.
  226. // They have been replaced by web apps.
  227. return nullptr;
  228. }
  229. std::unique_ptr<extensions::Manifest> manifest;
  230. if (flags & FOR_LOGIN_SCREEN) {
  231. manifest = Manifest::CreateManifestForLoginScreen(
  232. location, value.CreateDeepCopy(), std::move(extension_id));
  233. } else {
  234. manifest = std::make_unique<Manifest>(location, value.CreateDeepCopy(),
  235. std::move(extension_id));
  236. }
  237. std::vector<InstallWarning> install_warnings;
  238. if (!manifest->ValidateManifest(utf8_error, &install_warnings)) {
  239. return nullptr;
  240. }
  241. scoped_refptr<Extension> extension = new Extension(path, std::move(manifest));
  242. extension->install_warnings_.swap(install_warnings);
  243. if (!extension->InitFromValue(flags, &error)) {
  244. *utf8_error = base::UTF16ToUTF8(error);
  245. return nullptr;
  246. }
  247. extension->guid_ = base::GUID::GenerateRandomV4();
  248. extension->dynamic_url_ = Extension::GetBaseURLFromExtensionId(
  249. extension->guid_.AsLowercaseString());
  250. return extension;
  251. }
  252. Manifest::Type Extension::GetType() const {
  253. return converted_from_user_script() ?
  254. Manifest::TYPE_USER_SCRIPT : manifest_->type();
  255. }
  256. // static
  257. GURL Extension::GetResourceURL(const GURL& extension_url,
  258. const std::string& relative_path) {
  259. DCHECK(extension_url.SchemeIs(kExtensionScheme));
  260. return extension_url.Resolve(relative_path);
  261. }
  262. bool Extension::ResourceMatches(const URLPatternSet& pattern_set,
  263. const std::string& resource) const {
  264. return pattern_set.MatchesURL(extension_url_.Resolve(resource));
  265. }
  266. ExtensionResource Extension::GetResource(
  267. base::StringPiece relative_path) const {
  268. // We have some legacy data where resources have leading slashes.
  269. // See: http://crbug.com/121164
  270. if (!relative_path.empty() && relative_path[0] == '/')
  271. relative_path.remove_prefix(1);
  272. base::FilePath relative_file_path =
  273. base::FilePath::FromUTF8Unsafe(relative_path);
  274. if (ContainsReservedCharacters(relative_file_path))
  275. return ExtensionResource();
  276. ExtensionResource r(id(), path(), relative_file_path);
  277. if ((creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)) {
  278. r.set_follow_symlinks_anywhere();
  279. }
  280. return r;
  281. }
  282. ExtensionResource Extension::GetResource(
  283. const base::FilePath& relative_file_path) const {
  284. if (ContainsReservedCharacters(relative_file_path))
  285. return ExtensionResource();
  286. ExtensionResource r(id(), path(), relative_file_path);
  287. if ((creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE)) {
  288. r.set_follow_symlinks_anywhere();
  289. }
  290. return r;
  291. }
  292. // TODO(rafaelw): Move ParsePEMKeyBytes, ProducePEM & FormatPEMForOutput to a
  293. // util class in base:
  294. // http://code.google.com/p/chromium/issues/detail?id=13572
  295. // static
  296. bool Extension::ParsePEMKeyBytes(const std::string& input,
  297. std::string* output) {
  298. DCHECK(output);
  299. if (!output)
  300. return false;
  301. if (input.length() == 0)
  302. return false;
  303. std::string working = input;
  304. if (base::StartsWith(working, kKeyBeginHeaderMarker,
  305. base::CompareCase::SENSITIVE)) {
  306. working = base::CollapseWhitespaceASCII(working, true);
  307. size_t header_pos = working.find(kKeyInfoEndMarker,
  308. sizeof(kKeyBeginHeaderMarker) - 1);
  309. if (header_pos == std::string::npos)
  310. return false;
  311. size_t start_pos = header_pos + sizeof(kKeyInfoEndMarker) - 1;
  312. size_t end_pos = working.rfind(kKeyBeginFooterMarker);
  313. if (end_pos == std::string::npos)
  314. return false;
  315. if (start_pos >= end_pos)
  316. return false;
  317. working = working.substr(start_pos, end_pos - start_pos);
  318. if (working.length() == 0)
  319. return false;
  320. }
  321. return base::Base64Decode(working, output);
  322. }
  323. // static
  324. bool Extension::ProducePEM(const std::string& input, std::string* output) {
  325. DCHECK(output);
  326. if (input.empty())
  327. return false;
  328. base::Base64Encode(input, output);
  329. return true;
  330. }
  331. // static
  332. bool Extension::FormatPEMForFileOutput(const std::string& input,
  333. std::string* output,
  334. bool is_public) {
  335. DCHECK(output);
  336. if (input.length() == 0)
  337. return false;
  338. *output = "";
  339. output->append(kKeyBeginHeaderMarker);
  340. output->append(" ");
  341. output->append(is_public ? kPublic : kPrivate);
  342. output->append(" ");
  343. output->append(kKeyInfoEndMarker);
  344. output->append("\n");
  345. for (size_t i = 0; i < input.length(); ) {
  346. int slice = std::min<int>(input.length() - i, kPEMOutputColumns);
  347. output->append(input.substr(i, slice));
  348. output->append("\n");
  349. i += slice;
  350. }
  351. output->append(kKeyBeginFooterMarker);
  352. output->append(" ");
  353. output->append(is_public ? kPublic : kPrivate);
  354. output->append(" ");
  355. output->append(kKeyInfoEndMarker);
  356. output->append("\n");
  357. return true;
  358. }
  359. // static
  360. GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
  361. return GURL(base::StrCat({extensions::kExtensionScheme,
  362. url::kStandardSchemeSeparator, extension_id}));
  363. }
  364. // static
  365. url::Origin Extension::CreateOriginFromExtensionId(
  366. const ExtensionId& extension_id) {
  367. // TODO(lukasza): Avoid url::Origin::Create calls in general. Sadly the call
  368. // below cannot be replaced with CreateFromNormalizedTuple, because it DCHECKs
  369. // that the `extension_id` is not a properly canonicalized hostname.
  370. return url::Origin::Create(GetBaseURLFromExtensionId(extension_id));
  371. }
  372. bool Extension::OverlapsWithOrigin(const GURL& origin) const {
  373. if (url() == origin)
  374. return true;
  375. if (web_extent().is_empty())
  376. return false;
  377. // Note: patterns and extents ignore port numbers.
  378. URLPattern origin_only_pattern(kValidWebExtentSchemes);
  379. if (!origin_only_pattern.SetScheme(origin.scheme()))
  380. return false;
  381. origin_only_pattern.SetHost(origin.host());
  382. origin_only_pattern.SetPath("/*");
  383. URLPatternSet origin_only_pattern_list;
  384. origin_only_pattern_list.AddPattern(origin_only_pattern);
  385. return web_extent().OverlapsWith(origin_only_pattern_list);
  386. }
  387. bool Extension::RequiresSortOrdinal() const {
  388. return is_app() && (display_in_launcher_ || display_in_new_tab_page_);
  389. }
  390. bool Extension::ShouldDisplayInAppLauncher() const {
  391. // Only apps should be displayed in the launcher.
  392. return is_app() && display_in_launcher_;
  393. }
  394. bool Extension::ShouldDisplayInNewTabPage() const {
  395. // Only apps should be displayed on the NTP.
  396. return is_app() && display_in_new_tab_page_;
  397. }
  398. bool Extension::ShouldExposeViaManagementAPI() const {
  399. // Hide component extensions because they are only extensions as an
  400. // implementation detail of Chrome.
  401. return !extensions::Manifest::IsComponentLocation(location());
  402. }
  403. Extension::ManifestData* Extension::GetManifestData(const std::string& key)
  404. const {
  405. DCHECK(finished_parsing_manifest_ || thread_checker_.CalledOnValidThread());
  406. auto iter = manifest_data_.find(key);
  407. if (iter != manifest_data_.end())
  408. return iter->second.get();
  409. return nullptr;
  410. }
  411. void Extension::SetManifestData(const std::string& key,
  412. std::unique_ptr<Extension::ManifestData> data) {
  413. DCHECK(!finished_parsing_manifest_ && thread_checker_.CalledOnValidThread());
  414. manifest_data_[key] = std::move(data);
  415. }
  416. void Extension::SetGUID(const ExtensionGuid& guid) {
  417. guid_ = base::GUID::ParseLowercase(guid);
  418. DCHECK(guid_.is_valid());
  419. dynamic_url_ =
  420. Extension::GetBaseURLFromExtensionId(guid_.AsLowercaseString());
  421. }
  422. const ExtensionGuid& Extension::guid() const {
  423. DCHECK(guid_.is_valid());
  424. return guid_.AsLowercaseString();
  425. }
  426. ManifestLocation Extension::location() const {
  427. return manifest_->location();
  428. }
  429. const std::string& Extension::id() const {
  430. return manifest_->extension_id();
  431. }
  432. const HashedExtensionId& Extension::hashed_id() const {
  433. return manifest_->hashed_id();
  434. }
  435. std::string Extension::VersionString() const {
  436. return version_.GetString();
  437. }
  438. std::string Extension::DifferentialFingerprint() const {
  439. // We currently support two sources of differential fingerprints:
  440. // server-provided and synthesized. Fingerprints are of the format V.FP, where
  441. // V indicates the fingerprint type (1 for SHA256 hash, 2 for app version) and
  442. // FP indicates the value. The hash-based FP from the server is more precise
  443. // (a hash of the extension CRX), so use that when available, otherwise
  444. // synthesize a 2.VERSION fingerprint for use. For more information, see
  445. // https://github.com/google/omaha/blob/master/doc/ServerProtocolV3.md#packages--fingerprints
  446. if (const std::string* fingerprint =
  447. manifest_->FindStringPath(keys::kDifferentialFingerprint))
  448. return *fingerprint;
  449. return "2." + VersionString();
  450. }
  451. std::string Extension::GetVersionForDisplay() const {
  452. if (version_name_.size() > 0)
  453. return version_name_;
  454. return VersionString();
  455. }
  456. void Extension::AddInstallWarning(InstallWarning new_warning) {
  457. install_warnings_.push_back(std::move(new_warning));
  458. }
  459. void Extension::AddInstallWarnings(std::vector<InstallWarning> new_warnings) {
  460. install_warnings_.insert(install_warnings_.end(),
  461. std::make_move_iterator(new_warnings.begin()),
  462. std::make_move_iterator(new_warnings.end()));
  463. }
  464. bool Extension::is_app() const {
  465. return manifest()->is_app();
  466. }
  467. bool Extension::is_platform_app() const {
  468. return manifest()->is_platform_app();
  469. }
  470. bool Extension::is_hosted_app() const {
  471. return manifest()->is_hosted_app();
  472. }
  473. bool Extension::is_legacy_packaged_app() const {
  474. return manifest()->is_legacy_packaged_app();
  475. }
  476. bool Extension::is_extension() const {
  477. return manifest()->is_extension();
  478. }
  479. bool Extension::is_shared_module() const {
  480. return manifest()->is_shared_module();
  481. }
  482. bool Extension::is_theme() const {
  483. return manifest()->is_theme();
  484. }
  485. bool Extension::is_login_screen_extension() const {
  486. return manifest()->is_login_screen_extension();
  487. }
  488. bool Extension::is_chromeos_system_extension() const {
  489. return manifest()->is_chromeos_system_extension();
  490. }
  491. void Extension::AddWebExtentPattern(const URLPattern& pattern) {
  492. extent_.AddPattern(pattern);
  493. }
  494. Extension::Extension(const base::FilePath& path,
  495. std::unique_ptr<extensions::Manifest> manifest)
  496. : manifest_version_(0),
  497. converted_from_user_script_(false),
  498. manifest_(manifest.release()),
  499. finished_parsing_manifest_(false),
  500. display_in_launcher_(true),
  501. display_in_new_tab_page_(true),
  502. wants_file_access_(false),
  503. creation_flags_(0) {
  504. DCHECK(path.empty() || path.IsAbsolute());
  505. path_ = crx_file::id_util::MaybeNormalizePath(path);
  506. }
  507. Extension::~Extension() {
  508. }
  509. bool Extension::InitFromValue(int flags, std::u16string* error) {
  510. DCHECK(error);
  511. creation_flags_ = flags;
  512. // Check for |converted_from_user_script| first, since it affects the type
  513. // returned by GetType(). This is needed to determine if the manifest version
  514. // is valid.
  515. converted_from_user_script_ =
  516. manifest_->FindBoolPath(keys::kConvertedFromUserScript).value_or(false);
  517. // Important to load manifest version first because many other features
  518. // depend on its value.
  519. if (!LoadManifestVersion(error))
  520. return false;
  521. if (!LoadRequiredFeatures(error))
  522. return false;
  523. if (const std::string* temp = manifest()->FindStringPath(keys::kPublicKey)) {
  524. // We don't need to validate because ComputeExtensionId() already did that.
  525. public_key_ = *temp;
  526. }
  527. extension_origin_ = Extension::CreateOriginFromExtensionId(id());
  528. extension_url_ = Extension::GetBaseURLFromExtensionId(id());
  529. // Load App settings. LoadExtent at least has to be done before
  530. // ParsePermissions(), because the valid permissions depend on what type of
  531. // package this is.
  532. if (is_app() && !LoadAppFeatures(error))
  533. return false;
  534. permissions_parser_ = std::make_unique<PermissionsParser>();
  535. if (!permissions_parser_->Parse(this, error))
  536. return false;
  537. if (!LoadSharedFeatures(error))
  538. return false;
  539. permissions_parser_->Finalize(this);
  540. permissions_parser_.reset();
  541. finished_parsing_manifest_ = true;
  542. permissions_data_ = std::make_unique<PermissionsData>(
  543. id(), GetType(), location(),
  544. PermissionsParser::GetRequiredPermissions(this).Clone());
  545. return true;
  546. }
  547. bool Extension::LoadRequiredFeatures(std::u16string* error) {
  548. if (!LoadName(error) ||
  549. !LoadVersion(error))
  550. return false;
  551. return true;
  552. }
  553. bool Extension::LoadName(std::u16string* error) {
  554. const std::string* non_localized_name_ptr =
  555. manifest_->FindStringPath(keys::kName);
  556. if (non_localized_name_ptr == nullptr) {
  557. *error = errors::kInvalidName16;
  558. return false;
  559. }
  560. non_localized_name_ = *non_localized_name_ptr;
  561. std::u16string sanitized_name =
  562. base::CollapseWhitespace(base::UTF8ToUTF16(non_localized_name_), true);
  563. base::i18n::SanitizeUserSuppliedString(&sanitized_name);
  564. display_name_ = base::UTF16ToUTF8(sanitized_name);
  565. return true;
  566. }
  567. bool Extension::LoadVersion(std::u16string* error) {
  568. const std::string* version_str = manifest_->FindStringPath(keys::kVersion);
  569. if (version_str == nullptr) {
  570. *error = errors::kInvalidVersion;
  571. return false;
  572. }
  573. version_ = base::Version(*version_str);
  574. if (!version_.IsValid() || version_.components().size() > 4) {
  575. *error = errors::kInvalidVersion;
  576. return false;
  577. }
  578. if (const base::Value* temp = manifest_->FindKey(keys::kVersionName)) {
  579. if (!temp->is_string()) {
  580. *error = errors::kInvalidVersionName;
  581. return false;
  582. }
  583. version_name_ = temp->GetString();
  584. }
  585. return true;
  586. }
  587. bool Extension::LoadAppFeatures(std::u16string* error) {
  588. if (!LoadExtent(keys::kWebURLs, &extent_,
  589. errors::kInvalidWebURLs, errors::kInvalidWebURL, error)) {
  590. return false;
  591. }
  592. if (const base::Value* temp = manifest_->FindKey(keys::kDisplayInLauncher)) {
  593. if (!temp->is_bool()) {
  594. *error = errors::kInvalidDisplayInLauncher;
  595. return false;
  596. }
  597. display_in_launcher_ = temp->GetBool();
  598. }
  599. if (const base::Value* temp =
  600. manifest_->FindKey(keys::kDisplayInNewTabPage)) {
  601. if (!temp->is_bool()) {
  602. *error = errors::kInvalidDisplayInNewTabPage;
  603. return false;
  604. }
  605. display_in_new_tab_page_ = temp->GetBool();
  606. } else {
  607. // Inherit default from display_in_launcher property.
  608. display_in_new_tab_page_ = display_in_launcher_;
  609. }
  610. return true;
  611. }
  612. bool Extension::LoadExtent(const char* key,
  613. URLPatternSet* extent,
  614. const char* list_error,
  615. const char* value_error,
  616. std::u16string* error) {
  617. const base::Value* temp_pattern_value = manifest_->FindPath(key);
  618. if (temp_pattern_value == nullptr)
  619. return true;
  620. if (!temp_pattern_value->is_list()) {
  621. *error = base::ASCIIToUTF16(list_error);
  622. return false;
  623. }
  624. const base::Value::List& pattern_list = temp_pattern_value->GetList();
  625. for (size_t i = 0; i < pattern_list.size(); ++i) {
  626. std::string pattern_string;
  627. if (pattern_list[i].is_string()) {
  628. pattern_string = pattern_list[i].GetString();
  629. } else {
  630. *error = ErrorUtils::FormatErrorMessageUTF16(
  631. value_error, base::NumberToString(i), errors::kExpectString);
  632. return false;
  633. }
  634. URLPattern pattern(kValidWebExtentSchemes);
  635. URLPattern::ParseResult parse_result = pattern.Parse(pattern_string);
  636. if (parse_result == URLPattern::ParseResult::kEmptyPath) {
  637. pattern_string += "/";
  638. parse_result = pattern.Parse(pattern_string);
  639. }
  640. if (parse_result != URLPattern::ParseResult::kSuccess) {
  641. *error = ErrorUtils::FormatErrorMessageUTF16(
  642. value_error, base::NumberToString(i),
  643. URLPattern::GetParseResultString(parse_result));
  644. return false;
  645. }
  646. // Do not allow authors to claim "<all_urls>".
  647. if (pattern.match_all_urls()) {
  648. *error = ErrorUtils::FormatErrorMessageUTF16(
  649. value_error, base::NumberToString(i),
  650. errors::kCannotClaimAllURLsInExtent);
  651. return false;
  652. }
  653. // Do not allow authors to claim "*" for host.
  654. if (pattern.host().empty()) {
  655. *error = ErrorUtils::FormatErrorMessageUTF16(
  656. value_error, base::NumberToString(i),
  657. errors::kCannotClaimAllHostsInExtent);
  658. return false;
  659. }
  660. // We do not allow authors to put wildcards in their paths. Instead, we
  661. // imply one at the end.
  662. if (pattern.path().find('*') != std::string::npos) {
  663. *error = ErrorUtils::FormatErrorMessageUTF16(
  664. value_error, base::NumberToString(i), errors::kNoWildCardsInPaths);
  665. return false;
  666. }
  667. pattern.SetPath(pattern.path() + '*');
  668. extent->AddPattern(pattern);
  669. }
  670. return true;
  671. }
  672. bool Extension::LoadSharedFeatures(std::u16string* error) {
  673. if (!LoadDescription(error) ||
  674. !ManifestHandler::ParseExtension(this, error) ||
  675. !LoadShortName(error))
  676. return false;
  677. return true;
  678. }
  679. bool Extension::LoadDescription(std::u16string* error) {
  680. if (const base::Value* temp = manifest_->FindKey(keys::kDescription)) {
  681. if (!temp->is_string()) {
  682. *error = errors::kInvalidDescription;
  683. return false;
  684. }
  685. description_ = temp->GetString();
  686. }
  687. return true;
  688. }
  689. bool Extension::LoadManifestVersion(std::u16string* error) {
  690. // Get the original value out of the dictionary so that we can validate it
  691. // more strictly.
  692. bool key_exists = false;
  693. if (const base::Value* version_value =
  694. manifest_->available_values().FindKey(keys::kManifestVersion)) {
  695. if (!version_value->is_int()) {
  696. *error = InvalidManifestVersionError(
  697. errors::kInvalidManifestVersionUnsupported, is_platform_app());
  698. return false;
  699. }
  700. key_exists = true;
  701. }
  702. manifest_version_ = manifest_->manifest_version();
  703. std::string warning;
  704. if (!IsManifestSupported(manifest_version_, GetType(), location(),
  705. creation_flags_, &warning)) {
  706. std::string json;
  707. base::JSONWriter::Write(*manifest_->value(), &json);
  708. LOG(WARNING) << "Failed to load extension. Manifest JSON: " << json;
  709. *error = InvalidManifestVersionError(
  710. key_exists ? errors::kInvalidManifestVersionUnsupported
  711. : errors::kInvalidManifestVersionMissingKey,
  712. is_platform_app());
  713. return false;
  714. }
  715. if (!warning.empty())
  716. AddInstallWarning(InstallWarning(warning, keys::kManifestVersion));
  717. return true;
  718. }
  719. bool Extension::LoadShortName(std::u16string* error) {
  720. if (const base::Value* temp = manifest_->FindKey(keys::kShortName)) {
  721. const std::string* localized_short_name_utf8 = temp->GetIfString();
  722. if (!localized_short_name_utf8 || localized_short_name_utf8->empty()) {
  723. *error = errors::kInvalidShortName;
  724. return false;
  725. }
  726. std::u16string localized_short_name =
  727. base::UTF8ToUTF16(*localized_short_name_utf8);
  728. base::i18n::AdjustStringForLocaleDirection(&localized_short_name);
  729. short_name_ = base::UTF16ToUTF8(localized_short_name);
  730. } else {
  731. short_name_ = display_name_;
  732. }
  733. return true;
  734. }
  735. ExtensionInfo::ExtensionInfo(const base::DictionaryValue* manifest,
  736. const std::string& id,
  737. const base::FilePath& path,
  738. ManifestLocation location)
  739. : extension_id(id), extension_path(path), extension_location(location) {
  740. if (manifest)
  741. extension_manifest = manifest->CreateDeepCopy();
  742. }
  743. ExtensionInfo::~ExtensionInfo() {}
  744. } // namespace extensions