Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(137)

Side by Side Diff: chrome/browser/extensions/convert_user_script.cc

Issue 340057: Add first-class support for user scripts (Closed)
Patch Set: newness Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2009 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 #include "chrome/browser/extensions/convert_user_script.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/file_path.h"
11 #include "base/file_util.h"
12 #include "base/scoped_temp_dir.h"
13 #include "base/sha2.h"
14 #include "base/string_util.h"
15 #include "chrome/browser/extensions/user_script_master.h"
16 #include "chrome/common/extensions/extension.h"
17 #include "chrome/common/extensions/extension_constants.h"
18 #include "chrome/common/extensions/user_script.h"
19 #include "chrome/common/json_value_serializer.h"
20 #include "googleurl/src/gurl.h"
21 #include "net/base/base64.h"
22
23 namespace keys = extension_manifest_keys;
24
25 Extension* ConvertUserScriptToExtension(const FilePath& user_script_path,
26 const GURL& original_url,
27 std::string* error){
28 std::string content;
29 if (!file_util::ReadFileToString(user_script_path, &content)) {
30 *error = "Could not read source file: " +
31 WideToASCII(user_script_path.ToWStringHack());
32 return NULL;
33 }
34
35 UserScript script;
36 if (!UserScriptMaster::ScriptReloader::ParseMetadataHeader(content,
37 &script)) {
38 *error = "Invalid script header.";
39 return NULL;
40 }
41
42 ScopedTempDir temp_dir;
43 if (!temp_dir.CreateUniqueTempDir()) {
44 *error = "Could not create temporary directory.";
45 return NULL;
46 }
47
48 // Create the manifest
49 scoped_ptr<DictionaryValue> root(new DictionaryValue);
50 std::string script_name;
51 if (!script.name().empty() && !script.name_space().empty())
52 script_name = script.name_space() + "/" + script.name();
53 else
54 script_name = original_url.spec();
55
56 // Create the public key.
57 // User scripts are not signed, but the public key for an extension doubles as
58 // its unique identity, and we need one of those. A user script's unique
59 // identity is its namespace+name, so we hash that to create a public key.
60 // There will be no corresponding private key, which means user scripts cannot
61 // be auto-updated, or claimed in the gallery.
62 char raw[base::SHA256_LENGTH] = {0};
63 std::string key;
64 base::SHA256HashString(script_name, raw, base::SHA256_LENGTH);
65 net::Base64Encode(raw, &key);
66
67 // The script may not have a name field, but we need one for an extension. If
68 // it is missing, use the filename of the original URL.
69 if (!script.name().empty())
70 root->SetString(keys::kName, script.name());
71 else
72 root->SetString(keys::kName, original_url.ExtractFileName());
73
74 root->SetString(keys::kDescription, script.description());
75 root->SetString(keys::kVersion, "1.0");
76 root->SetString(keys::kPublicKey, key);
77 root->SetBoolean(keys::kConvertedFromUserScript, true);
78
79 ListValue* js_files = new ListValue();
80 js_files->Append(Value::CreateStringValue("script.js"));
81
82 // If the script provides its own match patterns, we use those. Otherwise, we
83 // generate some using the include globs.
84 ListValue* matches = new ListValue();
85 if (!script.url_patterns().empty()) {
86 for (size_t i = 0; i < script.url_patterns().size(); ++i) {
87 matches->Append(Value::CreateStringValue(
88 script.url_patterns()[i].GetAsString()));
89 }
90 } else {
91 // TODO(aa): Derive tighter matches where possible.
92 matches->Append(Value::CreateStringValue("http://*/*"));
93 matches->Append(Value::CreateStringValue("https://*/*"));
94 }
95
96 ListValue* includes = new ListValue();
97 for (size_t i = 0; i < script.globs().size(); ++i)
98 includes->Append(Value::CreateStringValue(script.globs().at(i)));
99
100 ListValue* excludes = new ListValue();
101 for (size_t i = 0; i < script.exclude_globs().size(); ++i)
102 excludes->Append(Value::CreateStringValue(script.exclude_globs().at(i)));
103
104 DictionaryValue* content_script = new DictionaryValue();
105 content_script->Set(keys::kMatches, matches);
106 content_script->Set(keys::kIncludeGlobs, includes);
107 content_script->Set(keys::kExcludeGlobs, excludes);
108 content_script->Set(keys::kJs, js_files);
109
110 ListValue* content_scripts = new ListValue();
111 content_scripts->Append(content_script);
112
113 root->Set(keys::kContentScripts, content_scripts);
114
115 FilePath manifest_path = temp_dir.path().AppendASCII(
116 Extension::kManifestFilename);
117 JSONFileValueSerializer serializer(manifest_path);
118 if (!serializer.Serialize(*root)) {
119 *error = "Could not write JSON.";
120 return NULL;
121 }
122
123 // Write the script file.
124 if (!file_util::CopyFile(user_script_path,
125 temp_dir.path().AppendASCII("script.js"))) {
126 *error = "Could not copy script file.";
127 return NULL;
128 }
129
130 scoped_ptr<Extension> extension(new Extension(temp_dir.path()));
131 if (!extension->InitFromValue(*root, false, error)) {
132 NOTREACHED() << "Could not init extension " << *error;
133 return NULL;
134 }
135
136 temp_dir.Take(); // The caller takes ownership of the directory.
137 return extension.release();
138 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698