ad5485f37a5e547889b1e9b62238c8920e9c5737
[platform/core/appfw/wgt-backend.git] / src / wgt / step / encryption / step_encrypt_resources.cc
1 // Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by a apache 2.0 license that can be
3 // found in the LICENSE file.
4
5 #include "wgt/step/encryption/step_encrypt_resources.h"
6
7 #include <web_app_enc.h>
8
9 #include <boost/filesystem/operations.hpp>
10 #include <boost/system/error_code.hpp>
11
12 #include <common/utils/file_util.h>
13
14 #include <manifest_parser/utils/logging.h>
15
16 #include <algorithm>
17 #include <cstdio>
18 #include <cstdlib>
19 #include <set>
20 #include <string>
21
22 namespace {
23
24 const std::set<std::string> encryptSet { ".html", ".htm", ".css", ".js"};
25
26 }  // namespace
27
28
29 namespace wgt {
30 namespace encryption {
31
32 namespace bf = boost::filesystem;
33 namespace bs = boost::system;
34
35 common_installer::Step::Status StepEncryptResources::precheck() {
36   backend_data_ = static_cast<WgtBackendData*>(context_->backend_data.get());
37   if (!backend_data_) {
38     LOG(ERROR) << "no backend data";
39     return common_installer::Step::Status::ERROR;
40   }
41
42   SetEncryptionRoot();
43
44   if (input_.empty()) {
45     LOG(ERROR) << "unpacked_dir_path attribute is empty";
46     return Step::Status::INVALID_VALUE;
47   }
48   if (!bf::exists(input_)) {
49     LOG(ERROR) << "unpacked_dir_path (" << input_ << ") path does not exist";
50     return Step::Status::INVALID_VALUE;
51   }
52
53   return common_installer::Step::Status::OK;
54 }
55
56 common_installer::Step::Status StepEncryptResources::process() {
57   if (!backend_data_->settings.get().encryption_enabled()) {
58     LOG(DEBUG) << "no encryption";
59     return common_installer::Step::Status::OK;
60   }
61   LOG(DEBUG) << "Encrypting";
62
63   if (!Encrypt(input_)) {
64     LOG(ERROR) << "Error during encryption";
65     return common_installer::Step::Status::ERROR;
66   }
67
68   return common_installer::Step::Status::OK;
69 }
70
71 bool StepEncryptResources::Encrypt(const bf::path &src) {
72   // traversing through src dir (recurrence if subdir found)
73   // for every file found, check if it should be encrypted (ToBeEncrypted)
74   // if yes, encrypt it (and replace original one)
75   // if not, leave it
76   for (bf::directory_iterator file(src);
77        file != bf::directory_iterator();
78        ++file) {
79     bs::error_code error_code;
80     bf::path current(file->path());
81
82     bool is_dir = bf::is_directory(current, error_code);
83     if (error_code)
84       return false;
85     if (is_dir) {
86       if (!Encrypt(current))
87         return false;
88       continue;
89     }
90
91     bool is_sym = bf::is_symlink(symlink_status(current, error_code));
92     if (error_code)
93       return false;
94     if (is_sym)
95       continue;
96
97     // it is regular file (not dir, not symlink)
98     if (ToBeEncrypted(current)) {
99       LOG(INFO) << "File for encryption: " << current;
100       if (!EncryptFile(current))
101         return false;
102     }
103   }
104   return true;
105 }
106
107 bool StepEncryptResources::EncryptFile(const bf::path &src) {
108   FILE *input = fopen(src.string().c_str(), "rb");
109   if (!input) {
110     LOG(ERROR) << "Cannot open file for encryption: " << src;
111     return false;
112   }
113
114   // read size
115   fseek(input , 0 , SEEK_END);
116   size_t length = ftell(input);
117
118   // don't encrypt empty files because libwebappenc doesn't support it
119   if (length == 0) {
120     fclose(input);
121     return true;
122   }
123
124   rewind(input);
125
126   char *input_buffer = new char[length];
127   if (length != fread(input_buffer, sizeof(char), length, input)) {
128     LOG(ERROR) << "Read error, file: " << src;
129     fclose(input);
130     delete []input_buffer;
131     return false;
132   }
133   fclose(input);
134
135   unsigned char* encrypted_data = nullptr;
136   size_t enc_data_len = 0;
137   int ret;
138   if (context_->request_mode.get() == common_installer::RequestMode::GLOBAL)
139     ret = wae_encrypt_global_web_application(
140             context_->pkgid.get().c_str(),
141             context_->is_preload_request.get() ?
142             true : false,
143             reinterpret_cast<const unsigned char*>(input_buffer),
144             length,
145             &encrypted_data,
146             &enc_data_len);
147   else
148     ret = wae_encrypt_web_application(
149             context_->uid.get(),
150             context_->pkgid.get().c_str(),
151             reinterpret_cast<const unsigned char*>(input_buffer),
152             length,
153             &encrypted_data,
154             &enc_data_len);
155   delete []input_buffer;
156   if (WAE_ERROR_NONE != ret) {
157     switch (ret) {
158     case WAE_ERROR_INVALID_PARAMETER:
159       LOG(ERROR) << "Error during encrypting: WAE_ERROR_INVALID_PARAMETER";
160       break;
161     case WAE_ERROR_PERMISSION_DENIED:
162       LOG(ERROR) << "Error during encrypting: WAE_ERROR_PERMISSION_DENIED";
163       break;
164     case WAE_ERROR_NO_KEY:
165       LOG(ERROR) << "Error during encrypting: WAE_ERROR_NO_KEY";
166       break;
167     case WAE_ERROR_KEY_MANAGER:
168       LOG(ERROR) << "Error during encrypting: WAE_ERROR_KEY_MANAGER";
169       break;
170     case WAE_ERROR_CRYPTO:
171       LOG(ERROR) << "Error during encrypting: WAE_ERROR_CRYPTO";
172       break;
173     case WAE_ERROR_UNKNOWN:
174       LOG(ERROR) << "Error during encrypting: WAE_ERROR_UNKNOWN";
175       break;
176     default:
177       LOG(ERROR) << "Error during encrypting: UNKNOWN";
178       break;
179     }
180     return false;
181   }
182
183   // original file is treated as destination!
184   FILE *output = fopen(src.string().c_str(), "wb");
185   if (!output) {
186     LOG(ERROR) << "Cannot create encrypted file: " << src;
187     free(encrypted_data);
188     return false;
189   }
190
191   if (enc_data_len != fwrite(reinterpret_cast<const char*>(encrypted_data),
192                              sizeof(char),
193                              enc_data_len,
194                              output)) {
195     LOG(ERROR) << "Write error, file: " << src;
196     free(encrypted_data);
197     fclose(output);
198     return false;
199   }
200
201
202   fclose(output);
203   free(encrypted_data);
204   return true;
205 }
206
207 void StepEncryptResources::SetEncryptionRoot() {
208   input_ = context_->unpacked_dir_path.get();
209 }
210
211 bool StepEncryptResources::ToBeEncrypted(const bf::path &file) {
212   size_t found_key = file.string().rfind(".");
213   if (std::string::npos != found_key) {
214     std::string mimeType = file.string().substr(found_key);
215     std::transform(mimeType.begin(), mimeType.end(), mimeType.begin(),
216                    ::tolower);
217     return encryptSet.count(mimeType) > 0;
218   }
219   return false;
220 }
221
222 }  // namespace encryption
223 }  // namespace wgt