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

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

Issue 118328: chrome.exe --package-extension (Closed)
Patch Set: final Created 11 years, 6 months 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/extension_creator.h"
6
7 #include <vector>
8 #include <string>
9
10 #include "base/crypto/rsa_private_key.h"
11 #include "base/crypto/signature_creator.h"
12 #include "base/file_util.h"
13 #include "base/scoped_handle.h"
14 #include "base/string_util.h"
15 #include "chrome/browser/extensions/extensions_service.h"
16 #include "chrome/common/extensions/extension.h"
17 #include "chrome/common/extensions/extension_error_reporter.h"
18 #include "chrome/common/chrome_switches.h"
19 #include "chrome/common/extensions/extension.h"
20 #include "chrome/common/json_value_serializer.h"
21 #include "chrome/common/zip.h"
22 #include "net/base/base64.h"
23
24 namespace {
25 const int kRSAKeySize = 1024;
26 };
27
28 DictionaryValue* ExtensionCreator::InitializeInput(
29 const FilePath& extension_dir,
30 const FilePath& private_key_path,
31 const FilePath& private_key_output_path) {
32 // Validate input |extension_dir|.
33 if (extension_dir.value().empty() ||
34 !file_util::DirectoryExists(extension_dir)) {
35 error_message_ = "Input directory must exist.";
36 return false;
37 }
38
39 // Validate input |private_key| (if provided).
40 if (!private_key_path.value().empty() &&
41 !file_util::PathExists(private_key_path)) {
42 error_message_ = "Input value for private key must be a valid path.";
43 return false;
44 }
45
46 // If an |output_private_key| path is given, make sure it doesn't over-write
47 // an existing private key.
48 if (private_key_path.value().empty() &&
49 !private_key_output_path.value().empty() &&
50 file_util::PathExists(private_key_output_path)) {
51 error_message_ = "Private key exists next to input directory. Try using "
52 "--pack-extension-key";
53 return false;
54 }
55
56 // Read the manifest.
57 FilePath manifest_path = extension_dir.AppendASCII(
58 Extension::kManifestFilename);
59 if (!file_util::PathExists(manifest_path)) {
60 error_message_ = "Extension must contain '";
61 error_message_.append(Extension::kManifestFilename);
62 error_message_.append("'.");
63 return false;
64 }
65
66 JSONFileValueSerializer serializer(manifest_path);
67 std::string serialization_error;
68 Value* input_manifest = (serializer.Deserialize(&serialization_error));
69 if (!input_manifest) {
70 error_message_ = "Invalid manifest.json: ";
71 error_message_.append(serialization_error);
72 return false;
73 }
74
75 if (!input_manifest->IsType(Value::TYPE_DICTIONARY)) {
76 error_message_ = "Invalid manifest.json";
77 return false;
78 }
79
80 return static_cast<DictionaryValue*>(input_manifest);
81 }
82
83 base::RSAPrivateKey* ExtensionCreator::ReadInputKey(const FilePath&
84 private_key_path) {
85 if (!file_util::PathExists(private_key_path)) {
86 error_message_ = "Input value for private key must exist.";
87 return false;
88 }
89
90 std::string private_key_contents;
91 if (!file_util::ReadFileToString(private_key_path,
92 &private_key_contents)) {
93 error_message_ = "Failed to read private key.";
94 return false;
95 }
96
97 std::string private_key_bytes;
98 if (!Extension::ParsePEMKeyBytes(private_key_contents,
99 &private_key_bytes)) {
100 error_message_ = "Invalid private key.";
101 return false;
102 }
103
104 return base::RSAPrivateKey::CreateFromPrivateKeyInfo(
105 std::vector<uint8>(private_key_bytes.begin(), private_key_bytes.end()));
106 }
107
108 base::RSAPrivateKey* ExtensionCreator::GenerateKey(const FilePath&
109 output_private_key_path) {
110 scoped_ptr<base::RSAPrivateKey> key_pair(
111 base::RSAPrivateKey::Create(kRSAKeySize));
112 if (!key_pair.get()) {
113 error_message_ = "Yikes! Failed to generate random RSA private key.";
114 return NULL;
115 }
116
117 std::vector<uint8> private_key_vector;
118 if (!key_pair->ExportPrivateKey(&private_key_vector)) {
119 error_message_ = "Failed to export private key.";
120 return NULL;
121 }
122 std::string private_key_bytes(private_key_vector.begin(),
123 private_key_vector.end());
124
125 std::string private_key;
126 if (!Extension::ProducePEM(private_key_bytes, &private_key)) {
127 error_message_ = "Failed to output private key.";
128 return NULL;
129 }
130 std::string pem_output;
131 if (!Extension::FormatPEMForFileOutput(private_key, &pem_output,
132 false)) {
133 error_message_ = "Failed to output private key.";
134 return NULL;
135 }
136
137 if (!output_private_key_path.empty()) {
138 if (-1 == file_util::WriteFile(output_private_key_path,
139 pem_output.c_str(), pem_output.size())) {
140 error_message_ = "Failed to write private key.";
141 return NULL;
142 }
143 }
144
145 return key_pair.release();
146 }
147
148 bool ExtensionCreator::CreateAndSignZip(const FilePath& extension_dir,
149 base::RSAPrivateKey *key_pair,
150 FilePath* zip_path,
151 std::string* signature) {
152 file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("chrome_"), zip_path);
153 *zip_path = zip_path->Append(FILE_PATH_LITERAL("extension.zip"));
154
155 if (!Zip(extension_dir, *zip_path)) {
156 error_message_ = "Failed to create temporary zip file during packaging.";
157 return false;
158 }
159
160 scoped_ptr<base::SignatureCreator> signature_creator(
161 base::SignatureCreator::Create(key_pair));
162 ScopedStdioHandle zip_handle(file_util::OpenFile(*zip_path, "rb"));
163 uint8 buffer[1 << 16];
164 int bytes_read = -1;
165 while ((bytes_read = fread(buffer, 1, sizeof(buffer),
166 zip_handle.get())) > 0) {
167 if (!signature_creator->Update(buffer, bytes_read)) {
168 error_message_ = "Error while signing extension.";
169 return false;
170 }
171 }
172 zip_handle.Close();
173
174 std::vector<uint8> signature_vector;
175 signature_creator->Final(&signature_vector);
176 std::string signature_bytes(signature_vector.begin(), signature_vector.end());
177 bool result = net::Base64Encode(signature_bytes, signature);
178 DCHECK(result);
179 return true;
180 }
181
182 bool ExtensionCreator::PrepareManifestForExport(base::RSAPrivateKey *key_pair,
183 const std::string& signature,
184 DictionaryValue* manifest) {
185 std::vector<uint8> public_key_vector;
186 if (!key_pair->ExportPublicKey(&public_key_vector)) {
187 error_message_ = "Failed to export public key.";
188 return false;
189 }
190
191 std::string public_key_bytes(public_key_vector.begin(),
192 public_key_vector.end());
193 std::string public_key;
194 if (!net::Base64Encode(public_key_bytes, &public_key)) {
195 error_message_ = "Error while signing extension.";
196 return false;
197 }
198
199 manifest->SetString(Extension::kSignatureKey, signature);
200 manifest->SetString(Extension::kPublicKeyKey, public_key);
201
202 return true;
203 }
204
205 bool ExtensionCreator::WriteCRX(const FilePath& crx_path,
206 DictionaryValue* manifest,
207 const FilePath& zip_path) {
208 std::string manifest_string;
209 JSONStringValueSerializer serializer(&manifest_string);
210 if (!serializer.Serialize(*manifest)) {
211 error_message_ = "Failed to write crx.";
212 return false;
213 }
214
215 if (file_util::PathExists(crx_path))
216 file_util::Delete(crx_path, false);
217 ScopedStdioHandle crx_handle(file_util::OpenFile(crx_path, "wb"));
218
219 ExtensionsService::ExtensionHeader header;
220 memcpy(&header.magic, ExtensionsService::kExtensionFileMagic,
221 sizeof(ExtensionsService::kExtensionFileMagic));
222 header.version = 1; // kExpectedVersion
223 header.header_size = sizeof(ExtensionsService::ExtensionHeader);
224 header.manifest_size = manifest_string.size();
225
226 fwrite(&header, sizeof(ExtensionsService::ExtensionHeader), 1,
227 crx_handle.get());
228 fwrite(manifest_string.c_str(), sizeof(char), manifest_string.size(),
229 crx_handle.get());
230
231 uint8 buffer[1 << 16];
232 int bytes_read = -1;
233 ScopedStdioHandle zip_handle(file_util::OpenFile(zip_path, "rb"));
234 while ((bytes_read = fread(buffer, 1, sizeof(buffer),
235 zip_handle.get())) > 0) {
236 fwrite(buffer, sizeof(char), bytes_read, crx_handle.get());
237 }
238
239 return true;
240 }
241
242 bool ExtensionCreator::Run(const FilePath& extension_dir,
243 const FilePath& crx_path,
244 const FilePath& private_key_path,
245 const FilePath& output_private_key_path) {
246 // Check input diretory and read manifest.
247 scoped_ptr<DictionaryValue> manifest(InitializeInput(extension_dir,
248 private_key_path, output_private_key_path));
249 if (!manifest.get())
250 return false;
251
252 // Initialize Key Pair
253 scoped_ptr<base::RSAPrivateKey> key_pair;
254 if (!private_key_path.value().empty())
255 key_pair.reset(ReadInputKey(private_key_path));
256 else
257 key_pair.reset(GenerateKey(output_private_key_path));
258 if (!key_pair.get())
259 return false;
260
261 // Zip up the extension.
262 FilePath zip_path;
263 std::string signature;
264 if (!CreateAndSignZip(extension_dir, key_pair.get(), &zip_path, &signature))
265 return false;
266
267 if (!PrepareManifestForExport(key_pair.get(), signature, manifest.get()))
268 return false;
269
270 // Write the final crx out to disk.
271 if (!WriteCRX(crx_path, manifest.get(), zip_path))
272 return false;
273
274 return true;
275 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_creator.h ('k') | chrome/browser/extensions/extensions_service.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698