23 #include <boost/algorithm/string.hpp> 29 #include <openssl/evp.h> 31 #include <CommonCrypto/CommonCryptor.h> 35 #include <boost/range/iterator_range.hpp> 40 #define DBG_CFG LOG_STREAM(debug , log_config) 41 #define ERR_CFG LOG_STREAM(err , log_config) 47 : vector<unsigned char>(
std::forward<T>(args)...)
51 std::fill(begin(), end(),
'\0');
60 : username(username), server(server), key(key)
62 login_info(
const std::string& username,
const std::string& server)
63 : username(username), server(server), key()
67 return 3 + username.size() + server.size() + key.size();
88 if(GetUserNameW(buffer, &size)) {
91 res =
unicode_cast<std::string>(boost::iterator_range<wchar_t*>(buffer, buffer + size - 1));
94 if(
char*
const login = getenv(
"USER")) {
105 for(
auto& cred : credentials) {
106 std::fill(cred.username.begin(), cred.username.end(),
'\0');
107 std::fill(cred.server.begin(), cred.server.end(),
'\0');
121 }
else if(name.size() > 2 && name.front() ==
'@' && name.back() ==
'@') {
122 name = name.substr(1, name.size() - 2);
124 ERR_CFG <<
"malformed user credentials (did you manually edit the preferences file?)" << std::endl;
134 auto login_clean =
login;
158 DBG_CFG <<
"Retrieving password for server: '" << server <<
"', login: '" << login <<
"'\n";
159 auto login_clean =
login;
163 if(!credentials.empty() && credentials[0].username == login_clean && credentials[0].server == server) {
165 return std::string(temp.begin(), temp.end());
170 auto cred = std::find_if(credentials.begin(), credentials.end(), [&](
const login_info& cred) {
171 return cred.server == server && cred.username == login_clean;
173 if(cred == credentials.end()) {
177 return std::string(temp.begin(), temp.end());
182 DBG_CFG <<
"Setting password for server: '" << server <<
"', login: '" << login <<
"'\n";
183 auto login_clean =
login;
189 credentials.emplace_back(login_clean, server,
encrypt(temp,
build_key(server, login_clean)));
192 auto cred = std::find_if(credentials.begin(), credentials.end(), [&](
const login_info& cred) {
193 return cred.server == server && cred.username == login_clean;
195 if(cred == credentials.end()) {
197 cred = credentials.emplace(credentials.end(), login_clean, server);
214 secure_buffer data((std::istreambuf_iterator<char>(*stream)), (std::istreambuf_iterator<char>()));
217 ERR_CFG <<
"Invalid data in credentials file\n";
221 std::size_t
at = elem.find_last_of(
'@');
222 std::size_t eq = elem.find_first_of(
'=', at + 1);
223 if(at != std::string::npos && eq != std::string::npos) {
225 credentials.emplace_back(elem.substr(0, at), elem.substr(at + 1, eq - at - 1),
unescape(key));
237 for(
const auto& cred : credentials) {
239 credentials_data.insert(credentials_data.end(), cred.username.begin(), cred.username.end());
240 credentials_data.push_back(
'@');
241 credentials_data.insert(credentials_data.end(), cred.server.begin(), cred.server.end());
242 credentials_data.push_back(
'=');
244 credentials_data.insert(credentials_data.end(), key_escaped.begin(), key_escaped.end());
249 credentials_file->write(reinterpret_cast<const char*>(encrypted.data()), encrypted.size());
260 secure_buffer result(std::max<std::size_t>(server.size() + login.size() + sysname.size(), 32));
262 std::generate(result.begin(), result.end(), [&
i]() {
return 'x' ^ i++;});
263 std::copy(login.begin(), login.end(), result.begin());
264 std::copy(sysname.begin(), sysname.end(), result.begin() + login.size());
265 std::copy(server.begin(), server.end(), result.begin() + login.size() + sysname.size());
276 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
279 EVP_EncryptInit_ex(ctx, EVP_rc4(), NULL, key.data(), NULL);
280 EVP_EncryptUpdate(ctx, result.data(), &outlen, text.data(), text.size());
281 EVP_EncryptFinal_ex(ctx, result.data() + outlen, &tmplen);
283 EVP_CIPHER_CTX_free(ctx);
285 size_t outWritten = 0;
286 CCCryptorStatus ccStatus = CCCrypt(kCCDecrypt,
288 kCCOptionPKCS7Padding,
298 assert(ccStatus == kCCSuccess);
299 assert(outWritten == text.size());
312 while(!buf.empty() && buf.back() == 0) {
321 unescaped.reserve(text.size());
322 bool escaping =
false;
326 unescaped.push_back(
'\xc');
327 }
else if(
c ==
'.') {
328 unescaped.push_back(
'@');
330 unescaped.push_back(
c);
333 }
else if(
c ==
'\x1') {
336 unescaped.push_back(
c);
346 escaped.reserve(text.size());
349 escaped.push_back(
'\x1');
350 escaped.push_back(
'\x1');
351 }
else if(
c ==
'\xc') {
352 escaped.push_back(
'\x1');
353 escaped.push_back(
'\xa');
354 }
else if(
c ==
'@') {
355 escaped.push_back(
'\x1');
356 escaped.push_back(
'.');
358 escaped.push_back(
c);
login_info(const std::string &username, const std::string &server)
static secure_buffer rc4_crypt(const secure_buffer &text, const secure_buffer &key)
bool delete_file(const std::string &filename)
static secure_buffer encrypt(const secure_buffer &text, const secure_buffer &key)
void set_remember_password(bool remember)
static bool file_exists(const bfs::path &fpath)
ucs4_convert_impl::enableif< TD, typename TS::value_type >::type unicode_cast(const TS &source)
filesystem::scoped_istream istream_file(const std::string &fname, bool treat_failure_as_error)
static secure_buffer unescape(const secure_buffer &text)
void set(const std::string &key, bool value)
static lg::log_domain log_config("config")
filesystem::scoped_ostream ostream_file(const std::string &fname, std::ios_base::openmode mode, bool create_directory)
static secure_buffer escape(const secure_buffer &text)
static std::string at(const std::string &file, int line)
secure_buffer(T &&... args)
std::string get(const std::string &key)
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
static void clear_credentials()
void set_login(const std::string &login)
std::unique_ptr< std::istream > scoped_istream
void set_password(const std::string &server, const std::string &login, const std::string &key)
Modify, read and display user preferences.
static const unsigned char CREDENTIAL_SEPARATOR
std::unique_ptr< std::ostream > scoped_ostream
static std::string get_system_username()
static secure_buffer decrypt(const secure_buffer &text, const secure_buffer &key)
An exception object used when an IO error occurs.
static const std::string EMPTY_LOGIN
std::string password(const std::string &server, const std::string &login)
Declarations for File-IO.
static std::vector< login_info > credentials
std::vector< std::string > split(const config_attribute_value &val)
std::string get_credentials_file()
Standard logging facilities (interface).
void trim(std::string_view &s)
login_info(const std::string &username, const std::string &server, const secure_buffer &key)
static secure_buffer build_key(const std::string &server, const std::string &login)