updates
This commit is contained in:
parent
d31ca5b6a7
commit
9ae0b0ef5b
@ -53,6 +53,10 @@ int main(int argc, char * argv[]) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nntpconf.find("authdb") != nntpconf.end()) {
|
||||||
|
nntp.SetLoginDB(nntpconf["authdb"]);
|
||||||
|
}
|
||||||
|
|
||||||
auto & a = nntpconf["bind"];
|
auto & a = nntpconf["bind"];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[nntp]
|
[nntp]
|
||||||
bind = [::]:1199
|
bind = [::]:1199
|
||||||
|
authdb=auth.txt
|
||||||
|
|
||||||
[storage]
|
[storage]
|
||||||
path = ./storage/
|
path = ./storage/
|
@ -219,8 +219,8 @@ namespace nntpchan
|
|||||||
std::string B64Encode(const uint8_t * data, const std::size_t l)
|
std::string B64Encode(const uint8_t * data, const std::size_t l)
|
||||||
{
|
{
|
||||||
std::string out;
|
std::string out;
|
||||||
out.reserve(i2p::data::Base64EncodingBufferSize(l));
|
out.resize(i2p::data::Base64EncodingBufferSize(l));
|
||||||
i2p::data::ByteStreamToBase64(data, l, &out[0], out.capacity());
|
i2p::data::ByteStreamToBase64(data, l, &out[0], out.size());
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,9 @@ namespace nntpchan {
|
|||||||
if(c == '\n') {
|
if(c == '\n') {
|
||||||
OnLine(d, idx-2);
|
OnLine(d, idx-2);
|
||||||
d += idx;
|
d += idx;
|
||||||
|
} else if (c == '\r' && d[idx] == '\n') {
|
||||||
|
OnLine(d, idx-2);
|
||||||
|
d += idx + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,21 +7,18 @@
|
|||||||
|
|
||||||
namespace nntpchan
|
namespace nntpchan
|
||||||
{
|
{
|
||||||
HashedCredDB::HashedCredDB(std::istream & i) :
|
|
||||||
m_instream(i) {}
|
|
||||||
|
|
||||||
bool HashedCredDB::CheckLogin(const std::string & user, const std::string & passwd)
|
bool HashedCredDB::CheckLogin(const std::string & user, const std::string & passwd)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(m_access);
|
std::unique_lock<std::mutex> lock(m_access);
|
||||||
m_found = false;
|
m_found = false;
|
||||||
m_user = user;
|
m_user = user;
|
||||||
m_passwd = passwd;
|
m_passwd = passwd;
|
||||||
m_instream.seekg(0, std::ios::end);
|
m_instream->seekg(0, std::ios::end);
|
||||||
const auto l = m_instream.tellg();
|
const auto l = m_instream->tellg();
|
||||||
m_instream.seekg(0, std::ios::beg);
|
m_instream->seekg(0, std::ios::beg);
|
||||||
char * buff = new char[l];
|
char * buff = new char[l];
|
||||||
// read file
|
// read file
|
||||||
m_instream.read(buff, l);
|
m_instream->read(buff, l);
|
||||||
OnData(buff, l);
|
OnData(buff, l);
|
||||||
delete [] buff;
|
delete [] buff;
|
||||||
return m_found;
|
return m_found;
|
||||||
@ -50,6 +47,18 @@ namespace nntpchan
|
|||||||
return Hash(m_passwd, salt) == cred;
|
return Hash(m_passwd, salt) == cred;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HashedCredDB::HandleLine(const std::string &line)
|
||||||
|
{
|
||||||
|
if(m_found) return;
|
||||||
|
if(ProcessLine(line))
|
||||||
|
m_found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HashedCredDB::SetStream(std::istream * s)
|
||||||
|
{
|
||||||
|
m_instream = s;
|
||||||
|
}
|
||||||
|
|
||||||
std::string HashedCredDB::Hash(const std::string & data, const std::string & salt)
|
std::string HashedCredDB::Hash(const std::string & data, const std::string & salt)
|
||||||
{
|
{
|
||||||
SHA512Digest h;
|
SHA512Digest h;
|
||||||
@ -57,5 +66,33 @@ namespace nntpchan
|
|||||||
SHA512((const uint8_t*)d.c_str(), d.size(), h);
|
SHA512((const uint8_t*)d.c_str(), d.size(), h);
|
||||||
return B64Encode(h.data(), h.size());
|
return B64Encode(h.data(), h.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HashedFileDB::HashedFileDB(const std::string & fname) :
|
||||||
|
m_fname(fname),
|
||||||
|
f(nullptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
HashedFileDB::~HashedFileDB()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void HashedFileDB::Close()
|
||||||
|
{
|
||||||
|
if(f.is_open())
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HashedFileDB::Open()
|
||||||
|
{
|
||||||
|
if(!f.is_open())
|
||||||
|
f.open(m_fname);
|
||||||
|
if(f.is_open()) {
|
||||||
|
SetStream(&f);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define NNTPCHAN_NNTP_AUTH_HPP
|
#define NNTPCHAN_NNTP_AUTH_HPP
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include "line.hpp"
|
#include "line.hpp"
|
||||||
|
|
||||||
@ -11,27 +12,45 @@ namespace nntpchan
|
|||||||
class NNTPCredentialDB
|
class NNTPCredentialDB
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/** @brief open connection to database, return false on error otherwise return true */
|
||||||
|
virtual bool Open() = 0;
|
||||||
|
/** @brief close connection to database */
|
||||||
|
virtual void Close() = 0;
|
||||||
/** @brief return true if username password combo is correct */
|
/** @brief return true if username password combo is correct */
|
||||||
virtual bool CheckLogin(const std::string & user, const std::string & passwd) = 0;
|
virtual bool CheckLogin(const std::string & user, const std::string & passwd) = 0;
|
||||||
|
virtual ~NNTPCredentialDB() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @brief nntp credential db using hashed+salted passwords */
|
/** @brief nntp credential db using hashed+salted passwords */
|
||||||
class HashedCredDB : public NNTPCredentialDB, public LineReader
|
class HashedCredDB : public NNTPCredentialDB, public LineReader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HashedCredDB(std::istream & i);
|
|
||||||
bool CheckLogin(const std::string & user, const std::string & passwd);
|
bool CheckLogin(const std::string & user, const std::string & passwd);
|
||||||
protected:
|
protected:
|
||||||
std::string Hash(const std::string & data, const std::string & salt);
|
void SetStream(std::istream * i);
|
||||||
private:
|
|
||||||
|
|
||||||
|
std::string Hash(const std::string & data, const std::string & salt);
|
||||||
|
void HandleLine(const std::string & line);
|
||||||
|
private:
|
||||||
bool ProcessLine(const std::string & line);
|
bool ProcessLine(const std::string & line);
|
||||||
|
|
||||||
std::mutex m_access;
|
std::mutex m_access;
|
||||||
std::string m_user, m_passwd;
|
std::string m_user, m_passwd;
|
||||||
bool m_found;
|
bool m_found;
|
||||||
/** return true if we have a line that matches this username / password combo */
|
/** return true if we have a line that matches this username / password combo */
|
||||||
std::istream & m_instream;
|
std::istream * m_instream;
|
||||||
|
};
|
||||||
|
|
||||||
|
class HashedFileDB : public HashedCredDB
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HashedFileDB(const std::string & fname);
|
||||||
|
~HashedFileDB();
|
||||||
|
bool Open();
|
||||||
|
void Close();
|
||||||
|
private:
|
||||||
|
std::string m_fname;
|
||||||
|
std::ifstream f;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,12 +8,18 @@
|
|||||||
namespace nntpchan
|
namespace nntpchan
|
||||||
{
|
{
|
||||||
NNTPServerHandler::NNTPServerHandler(const std::string & storage) :
|
NNTPServerHandler::NNTPServerHandler(const std::string & storage) :
|
||||||
|
m_auth(nullptr),
|
||||||
m_store(storage),
|
m_store(storage),
|
||||||
m_authed(false),
|
m_authed(false),
|
||||||
m_state(eStateReadCommand)
|
m_state(eStateReadCommand)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NNTPServerHandler::~NNTPServerHandler()
|
||||||
|
{
|
||||||
|
if(m_auth) delete m_auth;
|
||||||
|
}
|
||||||
|
|
||||||
void NNTPServerHandler::HandleLine(const std::string &line)
|
void NNTPServerHandler::HandleLine(const std::string &line)
|
||||||
{
|
{
|
||||||
if(m_state == eStateReadCommand) {
|
if(m_state == eStateReadCommand) {
|
||||||
@ -58,6 +64,7 @@ namespace nntpchan
|
|||||||
|
|
||||||
void NNTPServerHandler::SwitchMode(const std::string & mode)
|
void NNTPServerHandler::SwitchMode(const std::string & mode)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NNTPServerHandler::Quit()
|
void NNTPServerHandler::Quit()
|
||||||
@ -71,4 +78,23 @@ namespace nntpchan
|
|||||||
{
|
{
|
||||||
return m_state == eStateQuit;
|
return m_state == eStateQuit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NNTPServerHandler::PostingAllowed()
|
||||||
|
{
|
||||||
|
return m_authed || m_auth == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NNTPServerHandler::Greet()
|
||||||
|
{
|
||||||
|
if(PostingAllowed())
|
||||||
|
QueueLine("200 Posting allowed");
|
||||||
|
else
|
||||||
|
QueueLine("201 Posting not allowed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void NNTPServerHandler::SetAuth(NNTPCredentialDB *creds)
|
||||||
|
{
|
||||||
|
if(m_auth) delete m_auth;
|
||||||
|
m_auth = creds;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <deque>
|
#include <deque>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "line.hpp"
|
#include "line.hpp"
|
||||||
|
#include "nntp_auth.hpp"
|
||||||
#include "storage.hpp"
|
#include "storage.hpp"
|
||||||
|
|
||||||
namespace nntpchan
|
namespace nntpchan
|
||||||
@ -11,9 +12,14 @@ namespace nntpchan
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NNTPServerHandler(const std::string & storage);
|
NNTPServerHandler(const std::string & storage);
|
||||||
|
~NNTPServerHandler();
|
||||||
|
|
||||||
bool Done();
|
bool Done();
|
||||||
|
|
||||||
|
void SetAuth(NNTPCredentialDB * creds);
|
||||||
|
|
||||||
|
void Greet();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void HandleLine(const std::string & line);
|
void HandleLine(const std::string & line);
|
||||||
void HandleCommand(const std::deque<std::string> & command);
|
void HandleCommand(const std::deque<std::string> & command);
|
||||||
@ -32,8 +38,10 @@ namespace nntpchan
|
|||||||
// switch nntp modes, this queues a reply
|
// switch nntp modes, this queues a reply
|
||||||
void SwitchMode(const std::string & mode);
|
void SwitchMode(const std::string & mode);
|
||||||
|
|
||||||
private:
|
bool PostingAllowed();
|
||||||
|
|
||||||
|
private:
|
||||||
|
NNTPCredentialDB * m_auth;
|
||||||
ArticleStorage m_store;
|
ArticleStorage m_store;
|
||||||
std::string m_mode;
|
std::string m_mode;
|
||||||
bool m_authed;
|
bool m_authed;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "buffer.hpp"
|
#include "buffer.hpp"
|
||||||
#include "nntp_server.hpp"
|
#include "nntp_server.hpp"
|
||||||
|
#include "nntp_auth.hpp"
|
||||||
#include "net.hpp"
|
#include "net.hpp"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -38,19 +39,32 @@ namespace nntpchan
|
|||||||
std::cerr << "nntp server OnAccept fail: " << uv_strerror(status) << std::endl;
|
std::cerr << "nntp server OnAccept fail: " << uv_strerror(status) << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NNTPServerConn * conn = new NNTPServerConn(m_loop, s, m_storagePath);
|
NNTPCredentialDB * creds = nullptr;
|
||||||
|
|
||||||
|
std::ifstream i;
|
||||||
|
i.open(m_logindbpath);
|
||||||
|
if(i.is_open()) creds = new HashedFileDB(m_logindbpath);
|
||||||
|
|
||||||
|
NNTPServerConn * conn = new NNTPServerConn(m_loop, s, m_storagePath, creds);
|
||||||
conn->Greet();
|
conn->Greet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NNTPServer::SetLoginDB(const std::string path)
|
||||||
|
{
|
||||||
|
m_logindbpath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void NNTPServer::SetStoragePath(const std::string & path)
|
void NNTPServer::SetStoragePath(const std::string & path)
|
||||||
{
|
{
|
||||||
m_storagePath = path;
|
m_storagePath = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
NNTPServerConn::NNTPServerConn(uv_loop_t * l, uv_stream_t * s, const std::string & storage) :
|
NNTPServerConn::NNTPServerConn(uv_loop_t * l, uv_stream_t * s, const std::string & storage, NNTPCredentialDB * creds) :
|
||||||
m_handler(storage)
|
m_handler(storage)
|
||||||
{
|
{
|
||||||
|
m_handler.SetAuth(creds);
|
||||||
uv_tcp_init(l, &m_conn);
|
uv_tcp_init(l, &m_conn);
|
||||||
m_conn.data = this;
|
m_conn.data = this;
|
||||||
uv_accept(s, (uv_stream_t*) &m_conn);
|
uv_accept(s, (uv_stream_t*) &m_conn);
|
||||||
@ -93,7 +107,8 @@ namespace nntpchan
|
|||||||
|
|
||||||
void NNTPServerConn::Greet()
|
void NNTPServerConn::Greet()
|
||||||
{
|
{
|
||||||
|
m_handler.Greet();
|
||||||
|
SendNextReply();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NNTPServerConn::SendString(const std::string & str)
|
void NNTPServerConn::SendString(const std::string & str)
|
||||||
|
@ -24,6 +24,8 @@ namespace nntpchan
|
|||||||
|
|
||||||
void SetStoragePath(const std::string & path);
|
void SetStoragePath(const std::string & path);
|
||||||
|
|
||||||
|
void SetLoginDB(const std::string path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
operator uv_handle_t * () { return (uv_handle_t*) &m_server; }
|
operator uv_handle_t * () { return (uv_handle_t*) &m_server; }
|
||||||
@ -35,6 +37,7 @@ namespace nntpchan
|
|||||||
|
|
||||||
std::deque<NNTPServerConn *> m_conns;
|
std::deque<NNTPServerConn *> m_conns;
|
||||||
|
|
||||||
|
std::string m_logindbpath;
|
||||||
std::string m_storagePath;
|
std::string m_storagePath;
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -42,8 +45,7 @@ namespace nntpchan
|
|||||||
class NNTPServerConn
|
class NNTPServerConn
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NNTPServerConn(uv_loop_t * l, uv_stream_t * s, const std::string & storage);
|
NNTPServerConn(uv_loop_t * l, uv_stream_t * s, const std::string & storage, NNTPCredentialDB * creds);
|
||||||
|
|
||||||
/** @brief close connection, this connection cannot be used after calling this */
|
/** @brief close connection, this connection cannot be used after calling this */
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
@ -63,8 +65,6 @@ namespace nntpchan
|
|||||||
|
|
||||||
NNTPServerHandler m_handler;
|
NNTPServerHandler m_handler;
|
||||||
|
|
||||||
NNTPCredentialDB * m_logindb;
|
|
||||||
|
|
||||||
char m_readbuff[1028];
|
char m_readbuff[1028];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1,18 +1,91 @@
|
|||||||
#include "base64.hpp"
|
#include "base64.hpp"
|
||||||
#include "crypto.hpp"
|
#include "crypto.hpp"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sodium.h>
|
||||||
|
|
||||||
static void print_help(const std::string & exename)
|
static void print_help(const std::string & exename)
|
||||||
{
|
{
|
||||||
std::cout << "usage: " << exename << " [help|passwd|genconf]" << std::endl;
|
std::cout << "usage: " << exename << " [help|gencred|checkcred]" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_long_help() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_passwd(const std::string & username, const std::string & passwd)
|
||||||
|
{
|
||||||
|
std::array<uint8_t, 8> random;
|
||||||
|
randombytes_buf(random.data(), random.size());
|
||||||
|
std::string salt = nntpchan::B64Encode(random.data(), random.size());
|
||||||
|
std::string cred = passwd + salt;
|
||||||
|
nntpchan::SHA512Digest d;
|
||||||
|
nntpchan::SHA512((const uint8_t *)cred.c_str(), cred.size(), d);
|
||||||
|
std::string hash = nntpchan::B64Encode(d.data(), d.size());
|
||||||
|
std::cout << username << ":" << hash << ":" << salt << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool check_cred(const std::string & cred, const std::string & passwd)
|
||||||
|
{
|
||||||
|
auto idx = cred.find(":");
|
||||||
|
if(idx == std::string::npos || idx == 0) return false;
|
||||||
|
std::string part = cred.substr(idx+1);
|
||||||
|
idx = part.find(":");
|
||||||
|
if(idx == std::string::npos || idx == 0) return false;
|
||||||
|
std::string salt = part.substr(idx+1);
|
||||||
|
std::string hash = part.substr(0, idx);
|
||||||
|
std::vector<uint8_t> h;
|
||||||
|
if(!nntpchan::B64Decode(hash, h)) return false;
|
||||||
|
nntpchan::SHA512Digest d;
|
||||||
|
std::string l = passwd + salt;
|
||||||
|
nntpchan::SHA512((const uint8_t*)l.data(), l.size(), d);
|
||||||
|
return std::memcmp(h.data(), d.data(), d.size()) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char * argv[])
|
int main(int argc, char * argv[])
|
||||||
{
|
{
|
||||||
|
assert(sodium_init() == 0);
|
||||||
if(argc == 1) {
|
if(argc == 1) {
|
||||||
print_help(argv[0]);
|
print_help(argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
std::string cmd(argv[1]);
|
||||||
|
if (cmd == "help") {
|
||||||
|
print_long_help();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (cmd == "gencred") {
|
||||||
|
if(argc == 4) {
|
||||||
|
gen_passwd(argv[2], argv[3]);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
std::cout << "usage: " << argv[0] << " passwd username password" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(cmd == "checkcred" ) {
|
||||||
|
std::string cred;
|
||||||
|
std::cout << "credential: " ;
|
||||||
|
if(!std::getline(std::cin, cred)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
std::string passwd;
|
||||||
|
std::cout << "password: ";
|
||||||
|
if(!std::getline(std::cin, passwd)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(check_cred(cred, passwd)) {
|
||||||
|
std::cout << "okay" << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
std::cout << "bad login" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_help(argv[0]);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user