tpk/wgt backend will run as system session
[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(current, error_code);
92     if (error_code)
93       return false;
94     if (is_sym)
95       continue;  // TODO(p.sikorski) is it enough?
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   // TODO(p.sikorski) check if it is Preloaded
138   int ret;
139   if (context_->request_mode.get() == common_installer::RequestMode::GLOBAL)
140     ret = wae_encrypt_global_web_application(
141             context_->pkgid.get().c_str(),
142             context_->is_preload_request.get() ?
143             true : false,
144             reinterpret_cast<const unsigned char*>(input_buffer),
145             length,
146             &encrypted_data,
147             &enc_data_len);
148   else
149     ret = wae_encrypt_web_application(
150             context_->uid.get(),
151             context_->pkgid.get().c_str(),
152             reinterpret_cast<const unsigned char*>(input_buffer),
153             length,
154             &encrypted_data,
155             &enc_data_len);
156   delete []input_buffer;
157   if (WAE_ERROR_NONE != ret) {
158     switch (ret) {
159     case WAE_ERROR_INVALID_PARAMETER:
160       LOG(ERROR) << "Error during encrypting: WAE_ERROR_INVALID_PARAMETER";
161       break;
162     case WAE_ERROR_PERMISSION_DENIED:
163       LOG(ERROR) << "Error during encrypting: WAE_ERROR_PERMISSION_DENIED";
164       break;
165     case WAE_ERROR_NO_KEY:
166       LOG(ERROR) << "Error during encrypting: WAE_ERROR_NO_KEY";
167       break;
168     case WAE_ERROR_KEY_MANAGER:
169       LOG(ERROR) << "Error during encrypting: WAE_ERROR_KEY_MANAGER";
170       break;
171     case WAE_ERROR_CRYPTO:
172       LOG(ERROR) << "Error during encrypting: WAE_ERROR_CRYPTO";
173       break;
174     case WAE_ERROR_UNKNOWN:
175       LOG(ERROR) << "Error during encrypting: WAE_ERROR_UNKNOWN";
176       break;
177     default:
178       LOG(ERROR) << "Error during encrypting: UNKNOWN";
179       break;
180     }
181     return false;
182   }
183
184   // original file is treated as destination!
185   FILE *output = fopen(src.string().c_str(), "wb");
186   if (!output) {
187     LOG(ERROR) << "Cannot create encrypted file: " << src;
188     free(encrypted_data);
189     return false;
190   }
191
192   if (enc_data_len != fwrite(reinterpret_cast<const char*>(encrypted_data),
193                              sizeof(char),
194                              enc_data_len,
195                              output)) {
196     LOG(ERROR) << "Write error, file: " << src;
197     free(encrypted_data);
198     fclose(output);
199     return false;
200   }
201
202
203   fclose(output);
204   free(encrypted_data);
205   return true;
206 }
207
208 void StepEncryptResources::SetEncryptionRoot() {
209   input_ = context_->unpacked_dir_path.get();
210 }
211
212 bool StepEncryptResources::ToBeEncrypted(const bf::path &file) {
213   size_t found_key = file.string().rfind(".");
214   if (std::string::npos != found_key) {
215     std::string mimeType = file.string().substr(found_key);
216     std::transform(mimeType.begin(), mimeType.end(), mimeType.begin(),
217                    ::tolower);
218     return encryptSet.count(mimeType) > 0;
219   }
220   return false;
221 }
222
223 }  // namespace encryption
224 }  // namespace wgt