]> WPIA git - cassiopeia.git/blob - src/util.cpp
9e24b378d834c6e3ad6a356b3f9a48b533fb1751
[cassiopeia.git] / src / util.cpp
1 #include "util.h"
2
3 #include <sys/stat.h>
4
5 #include <fstream>
6 #include <iostream>
7 #include <sstream>
8 #include <time.h>
9 #include <stdexcept>
10
11 void writeFile( const std::string& name, const std::string& content ) {
12     std::ofstream file;
13
14     file.open( name );
15     file << content;
16     file.close();
17
18     //! \FIXME: Error checking
19 }
20
21 std::string readFile( const std::string& name ) {
22     std::ifstream t( name );
23     std::string res = std::string( std::istreambuf_iterator<char>( t ), std::istreambuf_iterator<char>() );
24     t.close();
25
26     return res;
27 }
28
29 std::string writeBackFile( const std::string& serial, const std::string& cert, const std::string& keydir ) {
30     errno = 0;
31
32     std::string filename = keydir;
33
34     if( 0 != mkdir( filename.c_str(), 0755 ) ) {
35         if( EEXIST != errno ) {
36             return "";
37         }
38
39         //! \FIXME: Check this is a directory
40     }
41
42     filename += "/crt";
43
44     if( 0 != mkdir( filename.c_str(), 0755 ) ) {
45         if( EEXIST != errno ) {
46             return "";
47         }
48
49         //! \FIXME: Check this is a directory
50     }
51
52     std::string first;
53
54     if( serial.length() < 3 ) {
55         first = "0";
56     } else {
57         first = serial.substr( 0, serial.length() - 3 );
58     }
59
60     filename += "/" + first;
61
62     if( 0 != mkdir( filename.c_str(), 0755 ) ) {
63         if( EEXIST != errno ) {
64             return "";
65         }
66
67         //! \FIXME: Check this is a directory
68     }
69
70     filename += "/" + serial + ".crt";
71     writeFile( filename, cert );
72
73     return filename;
74 }
75
76 bool isDigit( char c ) {
77     return ( c >= '0' ) && ( c <= '9' );
78 }
79
80 std::pair<bool, time_t> parseDate( const std::string& date ) {
81     if( date.size() != 10 || date[4] != '-' || date[7] != '-' ) {
82         return std::pair<bool, time_t>( false, 0 );
83     }
84
85     if( !isDigit( date[0] )
86             || !isDigit( date[1] )
87             || !isDigit( date[2] )
88             || !isDigit( date[3] )
89             || !isDigit( date[5] )
90             || !isDigit( date[6] )
91             || !isDigit( date[8] )
92             || !isDigit( date[9] ) ) {
93         return std::pair<bool, time_t>( false, 0 );
94     }
95
96     std::tm t;
97     t.tm_sec = 0;
98     t.tm_min = 0;
99     t.tm_hour = 0;
100     t.tm_year = std::stoi( date.substr( 0, 4 ) ) - 1900;
101     t.tm_mon = std::stoi( date.substr( 5, 2 ) ) - 1;
102     t.tm_mday = std::stoi( date.substr( 8, 2 ) );
103     setenv( "TZ", "UTC", 1 );
104     tzset();
105     std::time_t res = mktime( &t );
106     char check[11];
107     std::size_t siz = strftime( check, 11, "%Y-%m-%d", &t );
108
109     if( siz != 10 ) {
110         return std::pair<bool, time_t>( false, 0 ); // NO-COVERAGE (by contract of strftime)
111     }
112
113     std::string checkS( check, siz );
114
115     if( checkS != date ) {
116         return std::pair<bool, time_t>( false, 0 );
117     }
118
119     return std::pair<bool, time_t>( true, res );
120 }
121
122 std::pair<bool, time_t> addMonths( std::time_t t, int32_t count ) {
123     std::tm* parsed = gmtime( &t );
124
125     if( !parsed || count <= 0 || count > 24 ) { // FIXED MAX-Validity-Length
126         return std::pair<bool, time_t>( false, 0 );
127     }
128
129     parsed->tm_mon += count;
130     int oldday = parsed->tm_mday;
131     setenv( "TZ", "UTC", 1 );
132     tzset();
133     std::time_t res = mktime( parsed );
134
135     if( parsed->tm_mday != oldday ) {
136         parsed->tm_mday = 0;
137         res = mktime( parsed );
138     }
139
140     return std::pair<bool, time_t>( true, res );
141 }
142
143 std::pair<bool, time_t> parseMonthInterval( std::time_t t, const std::string& date ) {
144     if( date[date.size() - 1] != 'm' ) {
145         return  std::pair<bool, time_t>( false, 0 );
146     }
147
148     try {
149         size_t end = 0;
150         int num = std::stoi( date.substr( 0, date.size() - 1 ) , &end );
151
152         if( end != date.size() - 1 ) {
153             return  std::pair<bool, time_t>( false, 0 );
154         }
155
156         return addMonths( t, num );
157     } catch( const std::invalid_argument& a ) {
158         return std::pair<bool, time_t>( false, 0 );
159     } catch( const std::out_of_range& a ) {
160         return std::pair<bool, time_t>( false, 0 );
161     }
162 }
163
164 std::pair<bool, time_t> parseYearInterval( std::time_t t, const std::string& date ) {
165     if( date[date.size() - 1] != 'y' ) {
166         return  std::pair<bool, time_t>( false, 0 );
167     }
168
169     try {
170         size_t end = 0;
171         int num = std::stoi( date.substr( 0, date.size() - 1 ), &end );
172
173         if( end != date.size() - 1 ) {
174             return  std::pair<bool, time_t>( false, 0 );
175         }
176
177         return addMonths( t, num * 12 );
178     } catch( std::invalid_argument& a ) {
179         return std::pair<bool, time_t>( false, 0 );
180     } catch( std::out_of_range& a ) {
181         return std::pair<bool, time_t>( false, 0 );
182     }
183 }
184
185 std::shared_ptr<std::ofstream> openLogfile( const std::string name ) {
186     struct stat buffer;
187     std::string tname = name;
188     int ctr = 2;
189
190     while( stat( tname.c_str(), &buffer ) == 0 ) {
191         tname = name + "_" + std::to_string( ctr++ );
192     }
193
194     auto res = std::shared_ptr<std::ofstream>( new std::ofstream( tname ),
195         []( std::ofstream * p ) {
196             p->close();
197             delete p;
198         } );
199
200     if( ! res->good() ) {
201         throw std::string( "Failed to open file for logging: " ) + name;
202     }
203
204     return res;
205 }