Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2012 Emweb bv, Herent, Belgium. |
3 | | * |
4 | | * See the LICENSE file for terms of use. |
5 | | */ |
6 | | |
7 | | #include <vector> |
8 | | #include <iterator> |
9 | | |
10 | | #include <string.h> |
11 | | |
12 | | #include "Wt/WConfig.h" // WT_WIN32 |
13 | | // for htonl(): |
14 | | #ifndef WT_WIN32 |
15 | | #include <arpa/inet.h> |
16 | | #else |
17 | | #include <winsock2.h> |
18 | | #endif |
19 | | |
20 | | #include "Wt/WLogger.h" |
21 | | #include "Wt/Utils.h" |
22 | | #include "DomElement.h" |
23 | | #include "md5.h" |
24 | | #include "base32.h" |
25 | | #include "base64.h" |
26 | | #include "ImageUtils.h" |
27 | | #include "StringUtils.h" |
28 | | |
29 | | |
30 | | #include <cstring> |
31 | | |
32 | | extern "C" { |
33 | | #include "sha1.h" |
34 | | } |
35 | | |
36 | | namespace Wt { |
37 | | |
38 | | LOGGER("Utils"); |
39 | | |
40 | | namespace Utils { |
41 | | |
42 | | namespace { |
43 | | |
44 | | unsigned char fromHex(char b) |
45 | 0 | { |
46 | 0 | if (b <= '9') |
47 | 0 | return b - '0'; |
48 | 0 | else if (b <= 'F') |
49 | 0 | return (b - 'A') + 0x0A; |
50 | 0 | else |
51 | 0 | return (b - 'a') + 0x0A; |
52 | 0 | } |
53 | | |
54 | | unsigned char fromHex(char msb, char lsb) |
55 | 0 | { |
56 | 0 | return (fromHex(msb) << 4) + fromHex(lsb); |
57 | 0 | } |
58 | | |
59 | | char toHex(unsigned char b) |
60 | 0 | { |
61 | 0 | if (b < 0xA) |
62 | 0 | return '0' + b; |
63 | 0 | else |
64 | 0 | return 'a' + (b - 0xA); |
65 | 0 | } |
66 | | |
67 | | void toHex(unsigned char b, char& msb, char& lsb) |
68 | 0 | { |
69 | 0 | lsb = toHex(b & 0x0F); |
70 | 0 | msb = toHex(b >> 4); |
71 | 0 | } |
72 | | |
73 | | } |
74 | | |
75 | | std::string md5(const std::string& text) |
76 | 0 | { |
77 | 0 | md5_state_t c; |
78 | 0 | wt_md5_init(&c); |
79 | |
|
80 | 0 | wt_md5_append(&c, (const md5_byte_t *)text.c_str(), text.length()); |
81 | |
|
82 | 0 | unsigned char buf[16]; |
83 | 0 | wt_md5_finish(&c, buf); |
84 | |
|
85 | 0 | return std::string((const char *)buf, 16); |
86 | 0 | } |
87 | | |
88 | | std::string sha1(const std::string& text) |
89 | 0 | { |
90 | 0 | SHA1Context sha; |
91 | |
|
92 | 0 | wt_SHA1Reset(&sha); |
93 | 0 | wt_SHA1Input(&sha, (unsigned char *)text.c_str(), text.length()); |
94 | |
|
95 | 0 | if (!wt_SHA1Result(&sha)) { |
96 | 0 | LOG_ERROR("Error computing sha1 hash"); |
97 | 0 | return std::string(); |
98 | 0 | } else { |
99 | 0 | const unsigned SHA1_LENGTH = 20; |
100 | 0 | unsigned char hash[SHA1_LENGTH]; |
101 | |
|
102 | 0 | for (unsigned i = 0; i < 5; ++i) { |
103 | 0 | unsigned v = htonl(sha.Message_Digest[i]); |
104 | 0 | memcpy(hash + (i*4), &v, 4); |
105 | 0 | } |
106 | |
|
107 | 0 | return std::string(hash, hash + SHA1_LENGTH); |
108 | 0 | } |
109 | 0 | } |
110 | | |
111 | | std::string base32Encode(const std::string& data, bool crlf) |
112 | 0 | { |
113 | 0 | std::vector<char> v; |
114 | | |
115 | | // base32 encoded value will be 8/5 larger than original value |
116 | 0 | v.reserve(static_cast<std::size_t>(data.size() * 1.6)); |
117 | |
|
118 | 0 | base32::encode(data.begin(), data.end(), std::back_inserter(v), crlf); |
119 | |
|
120 | 0 | return std::string(v.begin(), v.end()); |
121 | 0 | } |
122 | | |
123 | | std::string base32Decode(const std::string& data) |
124 | 0 | { |
125 | 0 | std::vector<char> v; |
126 | | |
127 | | // decoded value will be 5/8 smaller than encoded value |
128 | 0 | v.reserve((std::size_t)(data.size() * 0.625)); |
129 | |
|
130 | 0 | base32::decode(data.begin(), data.end(), std::back_inserter(v)); |
131 | |
|
132 | 0 | return std::string(v.begin(), v.end()); |
133 | 0 | } |
134 | | |
135 | | std::string base64Encode(const std::string& data, bool crlf) |
136 | 0 | { |
137 | 0 | std::vector<char> v; |
138 | | |
139 | | // base64 encoded value will be 4/3 larger than original value |
140 | 0 | v.reserve((std::size_t)(data.size() * 1.35)); |
141 | |
|
142 | 0 | base64::encode(data.begin(), data.end(), std::back_inserter(v), crlf); |
143 | |
|
144 | 0 | return std::string(v.begin(), v.end()); |
145 | 0 | } |
146 | | |
147 | | std::string base64Decode(const std::string& data) |
148 | 0 | { |
149 | 0 | std::vector<char> v; |
150 | | |
151 | | // decoded value will be 3/4 smaller than encoded value |
152 | 0 | v.reserve((std::size_t)(data.size() * 0.8)); |
153 | |
|
154 | 0 | base64::decode(data.begin(), data.end(), std::back_inserter(v)); |
155 | |
|
156 | 0 | return std::string(v.begin(), v.end()); |
157 | 0 | } |
158 | | |
159 | | std::string hexEncode(const std::string& data) |
160 | 0 | { |
161 | 0 | std::string result(data.length() * 2, '-'); |
162 | |
|
163 | 0 | for (unsigned i = 0; i < data.length(); ++i) |
164 | 0 | toHex(data[i], result[2 * i], result[2 * i + 1]); |
165 | |
|
166 | 0 | return result; |
167 | 0 | } |
168 | | |
169 | | std::string hexDecode(const std::string& data) |
170 | 0 | { |
171 | 0 | std::string result(data.length() / 2, '-'); |
172 | |
|
173 | 0 | for (unsigned i = 0; i < result.length(); ++i) |
174 | 0 | result[i] = fromHex(data[2 * i], data[2 * i + 1]); |
175 | |
|
176 | 0 | return result; |
177 | 0 | } |
178 | | |
179 | | std::string htmlEncode(const std::string& text, WFlags<HtmlEncodingFlag> flags) |
180 | 0 | { |
181 | 0 | std::string result = text; |
182 | 0 | WWebWidget::escapeText(result, |
183 | 0 | (flags.test(HtmlEncodingFlag::EncodeNewLines)) ? |
184 | 0 | true : false); |
185 | 0 | return result; |
186 | 0 | } |
187 | | |
188 | | WString htmlEncode(const WString& text, WFlags<HtmlEncodingFlag> flags) |
189 | 0 | { |
190 | 0 | return WString::fromUTF8(htmlEncode(text.toUTF8(), flags)); |
191 | 0 | } |
192 | | |
193 | | std::string htmlAttributeValue(const std::string& text) |
194 | 0 | { |
195 | 0 | Wt::WStringStream ss; |
196 | 0 | DomElement::htmlAttributeValue(ss, text); |
197 | 0 | return ss.str(); |
198 | 0 | } |
199 | | |
200 | | std::string urlEncode(const std::string& text) |
201 | 0 | { |
202 | 0 | return DomElement::urlEncodeS(text); |
203 | 0 | } |
204 | | |
205 | | std::string urlDecode(const std::string &text) |
206 | 179 | { |
207 | 179 | WStringStream result; |
208 | | |
209 | 86.4k | for (unsigned i = 0; i < text.length(); ++i) { |
210 | 86.3k | char c = text[i]; |
211 | | |
212 | 86.3k | if (c == '+') { |
213 | 2.40k | result << ' '; |
214 | 83.9k | } else if (c == '%' && i + 2 < text.length()) { |
215 | 2.44k | std::string h = text.substr(i + 1, 2); |
216 | 2.44k | char *e = nullptr; |
217 | 2.44k | int hval = std::strtol(h.c_str(), &e, 16); |
218 | | |
219 | 2.44k | if (*e == 0) { |
220 | 661 | result << (char)hval; |
221 | 661 | i += 2; |
222 | 661 | } else |
223 | | // not a proper %XX with XX hexadecimal format |
224 | 1.78k | result << c; |
225 | 2.44k | } else |
226 | 81.4k | result << c; |
227 | 86.3k | } |
228 | | |
229 | 179 | return result.str(); |
230 | 179 | } |
231 | | |
232 | | bool removeScript(WString& text) |
233 | 0 | { |
234 | 0 | return WWebWidget::removeScript(text); |
235 | 0 | } |
236 | | |
237 | | std::string guessImageMimeTypeData(const std::vector<unsigned char>& header) |
238 | 0 | { |
239 | 0 | return Wt::ImageUtils::identifyMimeType(header); |
240 | 0 | } |
241 | | std::string guessImageMimeType(const std::string& file) |
242 | 0 | { |
243 | 0 | return Wt::ImageUtils::identifyMimeType(file); |
244 | 0 | } |
245 | | |
246 | | |
247 | 0 | std::string createDataUrl(std::vector<unsigned char>& data, std::string mimeType){ |
248 | 0 | std::string url = "data:"+mimeType+";"+"base64,"; |
249 | 0 | std::string datab64 = base64Encode(std::string(data.begin(), data.end())); |
250 | 0 | return url+datab64; |
251 | 0 | } |
252 | | |
253 | | std::string hmac(const std::string& text, |
254 | | const std::string& key, |
255 | | std::string (*hashfunction)(const std::string&), |
256 | | size_t blocksize, |
257 | | size_t keysize) |
258 | 0 | { |
259 | 0 | unsigned char ipad[256]; |
260 | 0 | unsigned char opad[256]; |
261 | |
|
262 | 0 | std::memset(ipad, 0, sizeof(unsigned char) * blocksize); |
263 | |
|
264 | 0 | if (key.size() > blocksize) { |
265 | 0 | std::memcpy(ipad, (unsigned char*) hashfunction(key).c_str(), keysize); |
266 | 0 | } |
267 | 0 | else { |
268 | 0 | keysize = key.size(); |
269 | 0 | std::memcpy(ipad, (unsigned char*) key.c_str(), keysize); |
270 | 0 | } |
271 | 0 | std::memcpy(opad, ipad, blocksize); |
272 | |
|
273 | 0 | for (size_t i=0; i<blocksize; ++i) { |
274 | 0 | ipad[i] ^= 0x36; |
275 | 0 | opad[i] ^= 0x5c; |
276 | 0 | } |
277 | |
|
278 | 0 | return hashfunction(std::string((char*) opad,blocksize) |
279 | 0 | + hashfunction(std::string((char*) ipad,blocksize) + text)); |
280 | 0 | } |
281 | | |
282 | | std::string hmac_md5(const std::string& text, const std::string& key) |
283 | 0 | { |
284 | 0 | return hmac(text, |
285 | 0 | key, |
286 | 0 | &md5, |
287 | 0 | 64, |
288 | 0 | 16); |
289 | 0 | } |
290 | | |
291 | | std::string hmac_sha1(const std::string& text, const std::string& key) |
292 | 0 | { |
293 | 0 | return hmac(text, |
294 | 0 | key, |
295 | 0 | &sha1, |
296 | 0 | 64, |
297 | 0 | 20); |
298 | 0 | } |
299 | | |
300 | | std::vector<std::string> getWidgetStyleClasses(WWidget* widget) |
301 | 0 | { |
302 | 0 | std::string styleClass = widget->styleClass().toUTF8(); |
303 | 0 | std::vector<std::string> styleClassVec; |
304 | 0 | SplitSet styleClassSet; |
305 | |
|
306 | 0 | split(styleClassSet, styleClass, " ", false); |
307 | |
|
308 | 0 | for (const auto& entry : styleClassSet) { |
309 | 0 | styleClassVec.push_back(splitEntryToString(entry)); |
310 | 0 | } |
311 | 0 | return styleClassVec; |
312 | 0 | } |
313 | | |
314 | | |
315 | | } |
316 | | |
317 | | } |