7684972a |
/* Copyright (C) CJ Affiliate
*
* You may use, distribute and modify this code under the
|
bef74c28 |
* terms of the GNU General Public License version 2 or
|
7684972a |
* later.
*
* You should have received a copy of the license with this
* file. If not, you will find a copy in the "LICENSE" file
* at https://github.com/cjdev/dual-control.
*/
|
55259c47 |
#include <string>
#include <vector>
#include <memory>
|
4bf199d2 |
#include <fstream>
|
af3a4cd4 |
#include <iostream>
#include <functional>
|
1c7f8bf0 |
|
bef74c28 |
#include "token.h"
#include "user.h"
|
43889d2c |
#include "base32.h"
|
215ea751 |
#include "sys_fstream.h"
|
4a6aca25 |
#include "random_source.h"
|
bef74c28 |
namespace
{
|
e064ffa9 |
class tokens_impl : public tokens_ifc
|
0e218820 |
{
private:
|
215ea751 |
fstreams fstreams_;
|
194e6869 |
totp_generator generator_;
|
b6eb15ba |
random_source rand_;
|
0e218820 |
public:
|
8adb1737 |
tokens_impl (const fstreams &fstreams, const totp_generator generator,
const random_source rand) :
|
b6eb15ba |
fstreams_ (fstreams), generator_ (generator), rand_ (rand) {}
|
af3a4cd4 |
std::string token (const user &user) const override
|
0e218820 |
{
|
43889d2c |
// Get key
|
8c62e61c |
std::string line = read_key (user);
|
3f7d4dd6 |
if (line == "") {
return "";
}
base32 codec;
|
8c62e61c |
std::vector<uint8_t> key = codec.decode (line);
|
3f7d4dd6 |
|
40fd6c82 |
return generator_.generate_token (key);
|
3f7d4dd6 |
}
private:
|
8c62e61c |
std::string get_key_path (const user &user) const
{
|
3f7d4dd6 |
return user.home_directory() + "/.dual_control";
}
|
8c62e61c |
bool key_exists (const user &user) const
{
|
3f7d4dd6 |
// check if file exists
|
8c62e61c |
std::string file_path = get_key_path (user);
fstreams::pstream stream (fstreams_.open_fstream (file_path));
|
3f7d4dd6 |
return stream->good();
}
|
8c62e61c |
std::string read_key (const user &user) const
{
std::string file_path = get_key_path (user);
|
43889d2c |
fstreams::pstream stream (fstreams_.open_fstream (file_path));
|
4bf199d2 |
|
8c62e61c |
std::vector<char> line_v (16);
stream->read (line_v.data(), line_v.size());
|
4bf199d2 |
|
43889d2c |
if (stream->fail()) {
return "";
}
|
4bf199d2 |
|
8c62e61c |
std::string line (line_v.begin(), line_v.end());
|
3f7d4dd6 |
return line;
}
public:
|
b6eb15ba |
std::string generate_key() const override
{
base32 codec;
// get randomness
int length = 10;
|
8adb1737 |
std::vector<uint8_t> random_bytes (rand_.get_random_bytes (length));
|
b6eb15ba |
// base32encode it
std::string key = codec.encode (random_bytes);
return key;
}
|
8c62e61c |
std::string ensure_key (const user &user) const override
{
if (!key_exists (user)) {
|
3f7d4dd6 |
std::string key = generate_key();
|
8c62e61c |
save (user, key);
|
3f7d4dd6 |
return key;
} else {
|
8c62e61c |
return read_key (user);
|
3f7d4dd6 |
}
|
0e218820 |
}
|
3f7d4dd6 |
|
b6eb15ba |
void save (const user &user, const std::string &key) const override
|
d10906ee |
{
|
8c62e61c |
std::string file_path = get_key_path (user);
|
d10906ee |
fstreams::postream stream (fstreams_.open_ofstream (file_path,
std::ios_base::trunc));
|
b6eb15ba |
*stream << key<< std::endl;
|
af3a4cd4 |
}
|
0e218820 |
};
|
bef74c28 |
}
|
194e6869 |
|
8c62e61c |
tokens tokens::create (const fstreams &fstreams,
|
b6eb15ba |
const totp_generator &generator,
const random_source &rand)
|
bef74c28 |
{
|
e064ffa9 |
return tokens (tokens::delegate
|
b6eb15ba |
(new tokens_impl (fstreams, generator, rand)));
|
bef74c28 |
}
|
0d8b9a17 |
|