· 6 years ago · Oct 09, 2019, 11:36 AM
1//
2// Created by alst on 26.07.18.
3//
4
5#ifndef CURL_EMAIL_VEDA_MAIL_H
6#define CURL_EMAIL_VEDA_MAIL_H
7
8#include <string>
9#include <vedatypes.h>
10#include <openssl/bio.h>
11#include <openssl/ssl.h>
12#include <openssl/err.h>
13
14#ifdef WINDOWS
15
16#include <winsock2.h>
17#include <ws2tcpip.h>
18//#include <arpa/inet.h>
19#endif
20
21const int READ_BUF_SIZE = 5000;
22const int VERIFICATION_KEY_LENGTH = 6;
23
24/*!
25 \file
26 \brief API-функции для работы по отправке сообщений ферификации по почте
27 \details Заголовочный файл для использования библиотеки по отправки сообшений верификации по почте
28 \author Veda team
29 \version 1.0
30 \date Июль 2018 года
31*/
32class veda_email
33{
34public:
35 /*!
36 \brief constructor veda_mail
37 \param [in] UID user login for authorization
38 \param [in] PWD user password for authorization
39 \param [in] smtp_server_url server adress to connect
40 \param [in] domain_name domain_name for check connection
41 \code
42
43 const std::string UID = "sener@ymail.com"; //- от него отправляется письмо
44 const std::string PWD = "some_password"; //- его пароль
45 const std::string smtp_server_url = "smtp.mail.com";
46 const std::string domain_name = "smtps.mail.com";
47 veda_mail sender(UID, PWD, smtp_server_url, domain_name);
48
49 \endcode
50*/
51 veda_email(std::string UID, std::string PWD, std::string smtp_server_url, std::string domain_name);
52 /*!
53 \brief send verification key to email address
54 \param [in] to_adress user enail adress for sending key
55 \param [in] key generated by generate_verification_key()
56 \return error EXIT_FAILURE or EXIT_SUCCESS
57 \code
58
59 std::string key = veda_mail::generate_verification_key();
60 std::string addres = "rcvr@mail.com";
61 sender.send_key(addres, key);
62
63 \endcode
64*/
65 int send_key(std::string to_adress, std::string key);
66/*!
67 \brief generate 6th length random code
68 \return 6th length generated code
69 \code
70
71 std::string key = veda_mail::generate_verification_key();
72
73 \endcode
74*/
75 static std::string generate_verification_key();
76/*!
77 \brief Для отправки письма в службу поддержки
78 \param [in] to_adress - кому отправить письмо
79 \param [in] user_uid - идентификатор пользователя, который запросил поддержку
80 \return error EXIT_FAILURE or EXIT_SUCCESS
81 \code
82
83 std::string key = veda_mail::generate_verification_key();
84 std::string addres = "rcvr@mail.com";
85 std::string user_uid = "user@mail.com";
86 sender.send_key(addres, user_uid, key);
87
88 \endcode
89*/
90 int send_letter(std::string to_adress, std::string user_uid, std::string write_letter);
91private:
92/*!
93 \brief generate random sting
94 \param [in] len length of output string
95 \return len generated code
96 \code
97 \endcode
98*/
99 static std::string random_string(size_t len);
100/*!
101 \brief generate mail header
102 \param [in] from sender mail adress
103 \param [in] to receiver mail adress
104 \param [in] subject the subject of the email
105 \param [in] mime_type type of the email
106 \param [in] charset coding information
107 \return len generated code
108 \code
109 \endcode
110*/
111 std::string mail_header(std::string from, std::string to, std::string subject, std::string mime_type,
112 std::string charset) ;
113/*!
114 \brief generate ip_adress from readable format
115 \param [in] server_address server adress in readable format
116 \return ip_address
117 \code
118 \endcode
119*/
120 const char* get_ip_adress(const char *server_address);
121/*!
122 \brief connect to server
123 \param [in] server_address server addres in readable format
124 \return socket handler
125 \code
126 \endcode
127*/
128 int connect_to_server(const char *server_address);
129/*!
130 \brief write message to server and print its answer
131 \param [in] server_address write line to server
132 \return error EXIT_FAILURE or EXIT_SUCCESS
133
134 \code
135 \endcode
136*/
137 int write_and_log(std::string write_str);
138/*!
139 \brief check connection to server
140 \return error EXIT_FAILURE or EXIT_SUCCESS
141
142 \code
143 \endcode
144*/
145 int check_connection();
146
147private:
148 SSL *ssl_;
149
150 std::string UID_;
151 std::string PWD_;
152 const std::string smtp_server_url_;
153 const std::string domain_name_;
154 char read_buffer_[READ_BUF_SIZE];
155};
156
157#endif //CURL_EMAIL_VEDA_MAIL_H
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173#include <stdio.h>
174#include <stdlib.h>
175#ifndef WINDOWS
176#include <sys/socket.h>
177#include <netinet/in.h>
178#include <netdb.h>
179#include <arpa/inet.h>
180#endif
181#include <cstring>
182#include <ctime>
183
184#ifdef WINDOWS
185#include <vedatypes.h>
186#endif
187
188#include <iostream>
189#include <algorithm>
190
191#include "base64.h"
192
193#include "veda_email.h"
194
195veda_email::veda_email(std::string UID, std::string PWD, std::string smtp_server_url, std::string domain_name)
196: ssl_{NULL},
197 UID_{UID},
198 PWD_{PWD},
199 smtp_server_url_{smtp_server_url},
200 domain_name_{domain_name},
201 read_buffer_{0}
202{
203 ;
204}
205
206int veda_email::check_connection(){
207 if( SSL_read(ssl_, read_buffer_, sizeof(read_buffer_)) <= 0)
208 return EXIT_FAILURE;
209 std::cout << read_buffer_ << std::endl;
210 return EXIT_SUCCESS;
211}
212
213int veda_email::write_and_log(std::string write_str){
214 int write = SSL_write(ssl_, write_str.c_str(), write_str.length());
215 if (write <= 0) {
216 std::cout << "write error" << std::endl;
217 return EXIT_FAILURE;
218 }
219
220 int read = SSL_read(ssl_, read_buffer_, sizeof (read_buffer_));
221 if (read <= 0){
222 std::cout << "read error" << std::endl;
223 return EXIT_FAILURE;
224 }
225
226 std::cout << read_buffer_ << std::endl;
227 memset(read_buffer_, 0x0, sizeof(read_buffer_));
228 return EXIT_SUCCESS;
229}
230
231int veda_email::send_key(std::string to_adress, std::string key){
232 OpenSSL_add_all_algorithms();
233 ERR_load_crypto_strings();
234 SSL_load_error_strings();
235
236 const SSL_METHOD *method{NULL};
237 SSL_CTX *ctx{NULL};
238 std::string buffer_str("");
239
240 const std::string MAIL_HEADER_FROM = "Veda_platform<" + UID_ + ">" ;
241 const std::string MAIL_HEADER_TO = "User<" + to_adress + ">";
242 //!формирование сообщения письма
243 std::string write_letter =
244 "Here is your verification code:\n"
245 "\n" +
246 key + "\n"
247 "\n"
248 "If you are not suppose to receive the code, please ignore this email. It is possible that another user entered their information incorrectly.\n"
249 "\n"
250 "(c)Veda platform.\n"
251 "All rights reserved. All trademarks are property of their respective owners in the US and other countries.\n";
252
253 //
254
255 if (SSL_library_init() < 0) {
256 std::cout << "OpenSSL not initialized" << std::endl;
257 return EXIT_FAILURE;
258 }
259
260 method = SSLv23_client_method();
261 ctx = SSL_CTX_new(method);
262 if (ctx == NULL) {
263 std::cout << "OpenSSL context not initialized" << std::endl;
264 SSL_CTX_free(ctx);
265 return EXIT_FAILURE;
266 }
267
268 SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
269 ssl_ = SSL_new(ctx);
270
271 int connceted_fd = connect_to_server(smtp_server_url_.c_str());
272 if (connceted_fd == 0) {
273 std::cout << "Connected unsuccessfully" << std::endl;
274 SSL_CTX_free(ctx);
275 SSL_free(ssl_);
276 return EXIT_FAILURE;
277 }
278
279 SSL_set_fd(ssl_, connceted_fd);
280 if (SSL_connect(ssl_) != 1) {
281 std::cout << "SSL session not created" << std::endl;
282 SSL_CTX_free(ctx);
283 SSL_free(ssl_);
284 return EXIT_FAILURE;
285 }
286
287 check_connection();
288
289 buffer_str = "HELO " + domain_name_ + "\r\n";
290 write_and_log(buffer_str);
291
292 buffer_str = "AUTH LOGIN\r\n";
293 write_and_log(buffer_str);
294
295 char *uid_base64 = (char*) malloc (2 * UID_.length());
296 if(uid_base64 == NULL){
297 SSL_CTX_free(ctx);
298 SSL_free(ssl_);
299 return EXIT_FAILURE;
300 }
301 memset(uid_base64, 0x0, 2 * UID_.length());
302
303 Base64encode(uid_base64, UID_.c_str(), UID_.length());
304 buffer_str = std::string(uid_base64 ) + std::string("\r\n");
305 write_and_log(buffer_str);
306
307
308 char *pwd_base64 = (char*) malloc (2 * PWD_.length());
309 if(pwd_base64 == NULL){
310 SSL_CTX_free(ctx);
311 SSL_free(ssl_);
312 free(uid_base64);
313 return EXIT_FAILURE;
314 }
315 memset(pwd_base64, 0x0, 2 * PWD_.length());
316
317
318 Base64encode(pwd_base64, PWD_.c_str(), PWD_.length());
319 buffer_str = std::string(pwd_base64 ) + std::string("\r\n");
320 write_and_log(buffer_str);
321
322 buffer_str = "MAIL FROM: " + UID_ + "\r\n";
323 write_and_log(buffer_str);
324
325 buffer_str = "RCPT TO: " + to_adress + "\r\n";
326 write_and_log(buffer_str);
327
328 buffer_str = "DATA\r\n";
329 write_and_log(buffer_str);
330
331 buffer_str = mail_header(MAIL_HEADER_FROM, MAIL_HEADER_TO, "Veda platform verification code",
332 "text/plain", "US-ASCII");
333 buffer_str += write_letter + "\r\n.\r\n";
334 write_and_log(buffer_str);
335
336
337 buffer_str = "QUIT\r\n";
338 write_and_log(buffer_str);
339
340 SSL_free(ssl_);
341 SSL_CTX_free(ctx);
342
343 free(uid_base64);
344 free(pwd_base64);
345
346 if (connceted_fd) {
347 shutdown(connceted_fd, 1);
348 closesocket(connceted_fd);
349 }
350 return EXIT_SUCCESS;
351}
352
353int veda_email::send_letter(std::string to_adress, std::string user_uid, std::string write_letter){
354 OpenSSL_add_all_algorithms();
355 ERR_load_crypto_strings();
356 SSL_load_error_strings();
357
358 const SSL_METHOD *method{NULL};
359 SSL_CTX *ctx{NULL};
360 std::string buffer_str("");
361
362 const std::string MAIL_HEADER_FROM = "Veda_wallet<" + UID_ + ">" ;
363 const std::string MAIL_HEADER_TO = "Support<" + to_adress + ">";
364
365 if (SSL_library_init() < 0) {
366 std::cout << "OpenSSL not initialized" << std::endl;
367 return EXIT_FAILURE;
368 }
369
370 method = SSLv23_client_method();
371 ctx = SSL_CTX_new(method);
372 if (ctx == NULL) {
373 std::cout << "OpenSSL context not initialized" << std::endl;
374 SSL_CTX_free(ctx);
375 return EXIT_FAILURE;
376 }
377
378 SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
379 ssl_ = SSL_new(ctx);
380
381 int connceted_fd = connect_to_server(smtp_server_url_.c_str());
382 if (connceted_fd == 0) {
383 std::cout << "Connected unsuccessfully" << std::endl;
384 SSL_CTX_free(ctx);
385 SSL_free(ssl_);
386 return EXIT_FAILURE;
387 }
388
389 SSL_set_fd(ssl_, connceted_fd);
390 if (SSL_connect(ssl_) != 1) {
391 std::cout << "SSL session not created" << std::endl;
392 SSL_CTX_free(ctx);
393 SSL_free(ssl_);
394 return EXIT_FAILURE;
395 }
396
397 check_connection();
398
399 buffer_str = "HELO " + domain_name_ + "\r\n";
400 write_and_log(buffer_str);
401
402 buffer_str = "AUTH LOGIN\r\n";
403 write_and_log(buffer_str);
404
405 char *uid_base64 = (char*) malloc (2 * UID_.length());
406 if(uid_base64 == NULL){
407 SSL_CTX_free(ctx);
408 SSL_free(ssl_);
409 return EXIT_FAILURE;
410 }
411 memset(uid_base64, 0x0, 2 * UID_.length());
412
413 Base64encode(uid_base64, UID_.c_str(), UID_.length());
414 buffer_str = std::string(uid_base64 ) + std::string("\r\n");
415 write_and_log(buffer_str);
416
417
418 char *pwd_base64 = (char*) malloc (2 * PWD_.length());
419 if(pwd_base64 == NULL){
420 SSL_CTX_free(ctx);
421 SSL_free(ssl_);
422 free(uid_base64);
423 return EXIT_FAILURE;
424 }
425 memset(pwd_base64, 0x0, 2 * PWD_.length());
426
427
428 Base64encode(pwd_base64, PWD_.c_str(), PWD_.length());
429 buffer_str = std::string(pwd_base64 ) + std::string("\r\n");
430 write_and_log(buffer_str);
431
432 buffer_str = "MAIL FROM: " + UID_ + "\r\n";
433 write_and_log(buffer_str);
434
435 buffer_str = "RCPT TO: " + to_adress + "\r\n";
436 write_and_log(buffer_str);
437
438 buffer_str = "DATA\r\n";
439 write_and_log(buffer_str);
440
441 buffer_str = mail_header(MAIL_HEADER_FROM, MAIL_HEADER_TO, "request from " + user_uid,
442 "text/plain", "US-ASCII");
443 buffer_str += write_letter + "\r\n.\r\n";
444 write_and_log(buffer_str);
445
446
447 buffer_str = "QUIT\r\n";
448 write_and_log(buffer_str);
449
450 SSL_free(ssl_);
451 SSL_CTX_free(ctx);
452
453 free(uid_base64);
454 free(pwd_base64);
455
456 return EXIT_SUCCESS;
457}
458std::string veda_email::random_string( size_t len )
459{
460 return "random_string";
461}
462
463std::string veda_email::generate_verification_key()
464{
465 return random_string(VERIFICATION_KEY_LENGTH);
466}
467
468std::string veda_email::mail_header(std::string from, std::string to, std::string subject, std::string mime_type,
469 std::string charset) {
470 time_t rawtime;
471 time(&rawtime);
472 struct tm *timeinfo = localtime(&rawtime);
473 const uint8_t MAX_SIZE = 80;
474 char date_buff[MAX_SIZE]{0};
475 strftime(date_buff, MAX_SIZE, "%a , %d %b %Y %H:%M:%S", timeinfo);
476
477 std::string app_brand = "veda platform";
478 std::string branding = "DATE: " + std::string(date_buff) + "\r\nX-Mailer: " + app_brand + "\r\n";
479 std::string sender = "FROM: " + from + "\r\n";
480 std::string recip = "To: " + to + "\r\n";
481 std::string subject_letter = "Subject: " + subject + "\r\n";
482 std::string mime_data =std::string("MIME-Version: 1.0\r\nContent-type: ") + mime_type + " ; charset=" + charset +"\r\n\r\n";
483
484 std::string mail_header = branding + sender + recip + subject_letter + mime_data;
485
486 return mail_header;
487}
488
489
490const char* veda_email::get_ip_adress(const char *server_address) {
491 const char* target_ip = NULL;
492 //struct in_addr *host_address;
493 struct hostent *raw_list = gethostbyname(server_address);
494 if(raw_list == NULL){
495 return NULL;
496 }
497// int i = 0;
498// for (i; raw_list->h_addr_list[i] != 0; i++) {
499// //host_address = (in_addr*)raw_list->h_addr_list[i];
500// target_ip = inet_ntoa(*((in_addr*)raw_list->h_addr_list[i]));
501// }
502 int nAdapter = 0;
503 while ( raw_list->h_addr_list[nAdapter] ){
504 target_ip = inet_ntoa(*((in_addr*)raw_list->h_addr_list[nAdapter]));
505 nAdapter++;
506 }
507
508 return target_ip;
509}
510
511#ifdef WINDOWS
512int inet_pton(int af, const char *src, void *dst)
513{
514 struct sockaddr_storage ss;
515 int size = sizeof(ss);
516 char src_copy[INET6_ADDRSTRLEN+1];
517
518 ZeroMemory(&ss, sizeof(ss));
519 /* stupid non-const API */
520 strncpy (src_copy, src, INET6_ADDRSTRLEN+1);
521 src_copy[INET6_ADDRSTRLEN] = 0;
522
523 if (WSAStringToAddress((LPWSTR)src_copy, af, NULL, (struct sockaddr *)&ss, &size) == 0) {
524 switch(af) {
525 case AF_INET:
526 *(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr;
527 return 1;
528 case AF_INET6:
529 *(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr;
530 return 1;
531 }
532 }
533 return 0;
534}
535
536const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
537{
538 struct sockaddr_storage ss;
539 unsigned long s = size;
540
541 ZeroMemory(&ss, sizeof(ss));
542 ss.ss_family = af;
543
544 switch(af) {
545 case AF_INET:
546 ((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src;
547 break;
548 case AF_INET6:
549 ((struct sockaddr_in6 *)&ss)->sin6_addr = *(struct in6_addr *)src;
550 break;
551 default:
552 return NULL;
553 }
554 /* cannot direclty use &size because of strict aliasing rules */
555 return (WSAAddressToString((struct sockaddr *)&ss, sizeof(ss), NULL, (LPWSTR)dst, &s) == 0)?
556 dst : NULL;
557}
558#endif
559
560int veda_email::connect_to_server(const char *server_address) {
561 int socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
562 struct sockaddr_in addr;
563 const char* ipadress = NULL;
564 memset(&addr, 0, sizeof (addr));
565 addr.sin_family = AF_INET;
566 addr.sin_port = htons(465);
567 if(NULL == (ipadress = get_ip_adress(server_address))){
568 return 0;
569 }
570 if (inet_pton(AF_INET, get_ip_adress(server_address), &addr.sin_addr) == 1) {
571
572 connect(socket_fd, (struct sockaddr *) &addr, sizeof (addr));
573 }
574 return socket_fd;
575}