update dis shit mang
This commit is contained in:
parent
cc089b3401
commit
d31ca5b6a7
@ -1,2 +1,4 @@
|
|||||||
*.o
|
*.o
|
||||||
nntpchan
|
nntpd
|
||||||
|
nntpchan-tool
|
||||||
|
.gdb_history
|
@ -1,5 +1,7 @@
|
|||||||
|
|
||||||
EXE = nntpchan
|
EXE = nntpd
|
||||||
|
|
||||||
|
TOOL = nntpchan-tool
|
||||||
|
|
||||||
CXX = clang++
|
CXX = clang++
|
||||||
|
|
||||||
@ -9,21 +11,24 @@ SOURCES := $(wildcard $(SRC_PATH)/*.cpp)
|
|||||||
HEADERS := $(wildcard $(SRC_PATH)/*.hpp)
|
HEADERS := $(wildcard $(SRC_PATH)/*.hpp)
|
||||||
OBJECTS := $(SOURCES:.cpp=.o)
|
OBJECTS := $(SOURCES:.cpp=.o)
|
||||||
|
|
||||||
PKGS := libuv
|
PKGS := libuv libsodium
|
||||||
|
|
||||||
LD_FLAGS := $(shell pkg-config --libs $(PKGS))
|
LD_FLAGS := $(shell pkg-config --libs $(PKGS))
|
||||||
INC_FLAGS := -I $(SRC_PATH) $(shell pkg-config --cflags $(PKGS))
|
INC_FLAGS := -I $(SRC_PATH) $(shell pkg-config --cflags $(PKGS))
|
||||||
CXXFLAGS := -std=c++14 -Wall -Wextra $(INC_FLAGS)
|
CXXFLAGS := -std=c++14 -Wall -Wextra $(INC_FLAGS) -g
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
all: $(EXE)
|
all: $(EXE) $(TOOL)
|
||||||
|
|
||||||
$(EXE): $(OBJECTS)
|
$(EXE): $(OBJECTS)
|
||||||
$(CXX) -o $(EXE) $(LD_FLAGS) $(OBJECTS)
|
$(CXX) -o $(EXE) $(LD_FLAGS) $(OBJECTS) $(CXXFLAGS) nntpchan.cpp
|
||||||
|
|
||||||
|
$(TOOL): $(OBJECTS)
|
||||||
|
$(CXX) -o $(TOOL) $(LD_FLAGS) $(OBJECTS) $(CXXFLAGS) tool.cpp
|
||||||
|
|
||||||
%.o: src/%.cpp
|
%.o: src/%.cpp
|
||||||
$(CXX) $(CXXFLAGS) -c -o $@
|
$(CXX) $(CXXFLAGS) -c -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(OBJECTS) $(EXE)
|
rm -f $(OBJECTS) $(EXE) $(TOOL)
|
||||||
|
234
contrib/frontends/cpp/nntpchan-daemon/src/base64.cpp
Normal file
234
contrib/frontends/cpp/nntpchan-daemon/src/base64.cpp
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
#include "base64.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
// taken from i2pd
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace data
|
||||||
|
{
|
||||||
|
static void iT64Build(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* BASE64 Substitution Table
|
||||||
|
* -------------------------
|
||||||
|
*
|
||||||
|
* Direct Substitution Table
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const char T64[64] = {
|
||||||
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||||
|
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||||
|
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||||
|
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||||
|
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||||
|
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||||
|
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||||
|
'4', '5', '6', '7', '8', '9', '+', '/'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reverse Substitution Table (built in run time)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static char iT64[256];
|
||||||
|
static int isFirstTime = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Padding
|
||||||
|
*/
|
||||||
|
|
||||||
|
static char P64 = '=';
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* ByteStreamToBase64
|
||||||
|
* ------------------
|
||||||
|
*
|
||||||
|
* Converts binary encoded data to BASE64 format.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static size_t /* Number of bytes in the encoded buffer */
|
||||||
|
ByteStreamToBase64 (
|
||||||
|
const uint8_t * InBuffer, /* Input buffer, binary data */
|
||||||
|
size_t InCount, /* Number of bytes in the input buffer */
|
||||||
|
char * OutBuffer, /* output buffer */
|
||||||
|
size_t len /* length of output buffer */
|
||||||
|
)
|
||||||
|
|
||||||
|
{
|
||||||
|
unsigned char * ps;
|
||||||
|
unsigned char * pd;
|
||||||
|
unsigned char acc_1;
|
||||||
|
unsigned char acc_2;
|
||||||
|
int i;
|
||||||
|
int n;
|
||||||
|
int m;
|
||||||
|
size_t outCount;
|
||||||
|
|
||||||
|
ps = (unsigned char *)InBuffer;
|
||||||
|
n = InCount/3;
|
||||||
|
m = InCount%3;
|
||||||
|
if (!m)
|
||||||
|
outCount = 4*n;
|
||||||
|
else
|
||||||
|
outCount = 4*(n+1);
|
||||||
|
if (outCount > len) return 0;
|
||||||
|
pd = (unsigned char *)OutBuffer;
|
||||||
|
for ( i = 0; i<n; i++ ){
|
||||||
|
acc_1 = *ps++;
|
||||||
|
acc_2 = (acc_1<<4)&0x30;
|
||||||
|
acc_1 >>= 2; /* base64 digit #1 */
|
||||||
|
*pd++ = T64[acc_1];
|
||||||
|
acc_1 = *ps++;
|
||||||
|
acc_2 |= acc_1 >> 4; /* base64 digit #2 */
|
||||||
|
*pd++ = T64[acc_2];
|
||||||
|
acc_1 &= 0x0f;
|
||||||
|
acc_1 <<=2;
|
||||||
|
acc_2 = *ps++;
|
||||||
|
acc_1 |= acc_2>>6; /* base64 digit #3 */
|
||||||
|
*pd++ = T64[acc_1];
|
||||||
|
acc_2 &= 0x3f; /* base64 digit #4 */
|
||||||
|
*pd++ = T64[acc_2];
|
||||||
|
}
|
||||||
|
if ( m == 1 ){
|
||||||
|
acc_1 = *ps++;
|
||||||
|
acc_2 = (acc_1<<4)&0x3f; /* base64 digit #2 */
|
||||||
|
acc_1 >>= 2; /* base64 digit #1 */
|
||||||
|
*pd++ = T64[acc_1];
|
||||||
|
*pd++ = T64[acc_2];
|
||||||
|
*pd++ = P64;
|
||||||
|
*pd++ = P64;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if ( m == 2 ){
|
||||||
|
acc_1 = *ps++;
|
||||||
|
acc_2 = (acc_1<<4)&0x3f;
|
||||||
|
acc_1 >>= 2; /* base64 digit #1 */
|
||||||
|
*pd++ = T64[acc_1];
|
||||||
|
acc_1 = *ps++;
|
||||||
|
acc_2 |= acc_1 >> 4; /* base64 digit #2 */
|
||||||
|
*pd++ = T64[acc_2];
|
||||||
|
acc_1 &= 0x0f;
|
||||||
|
acc_1 <<=2; /* base64 digit #3 */
|
||||||
|
*pd++ = T64[acc_1];
|
||||||
|
*pd++ = P64;
|
||||||
|
}
|
||||||
|
|
||||||
|
return outCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Base64ToByteStream
|
||||||
|
* ------------------
|
||||||
|
*
|
||||||
|
* Converts BASE64 encoded data to binary format. If input buffer is
|
||||||
|
* not properly padded, buffer of negative length is returned
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
ssize_t /* Number of output bytes */
|
||||||
|
Base64ToByteStream (
|
||||||
|
const char * InBuffer, /* BASE64 encoded buffer */
|
||||||
|
size_t InCount, /* Number of input bytes */
|
||||||
|
uint8_t * OutBuffer, /* output buffer length */
|
||||||
|
size_t len /* length of output buffer */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
unsigned char * ps;
|
||||||
|
unsigned char * pd;
|
||||||
|
unsigned char acc_1;
|
||||||
|
unsigned char acc_2;
|
||||||
|
int i;
|
||||||
|
int n;
|
||||||
|
int m;
|
||||||
|
size_t outCount;
|
||||||
|
|
||||||
|
if (isFirstTime) iT64Build();
|
||||||
|
n = InCount/4;
|
||||||
|
m = InCount%4;
|
||||||
|
if (InCount && !m)
|
||||||
|
outCount = 3*n;
|
||||||
|
else {
|
||||||
|
outCount = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ps = (unsigned char *)(InBuffer + InCount - 1);
|
||||||
|
while ( *ps-- == P64 ) outCount--;
|
||||||
|
ps = (unsigned char *)InBuffer;
|
||||||
|
|
||||||
|
if (outCount > len) return -1;
|
||||||
|
pd = OutBuffer;
|
||||||
|
auto endOfOutBuffer = OutBuffer + outCount;
|
||||||
|
for ( i = 0; i < n; i++ ){
|
||||||
|
acc_1 = iT64[*ps++];
|
||||||
|
acc_2 = iT64[*ps++];
|
||||||
|
acc_1 <<= 2;
|
||||||
|
acc_1 |= acc_2>>4;
|
||||||
|
*pd++ = acc_1;
|
||||||
|
if (pd >= endOfOutBuffer) break;
|
||||||
|
|
||||||
|
acc_2 <<= 4;
|
||||||
|
acc_1 = iT64[*ps++];
|
||||||
|
acc_2 |= acc_1 >> 2;
|
||||||
|
*pd++ = acc_2;
|
||||||
|
if (pd >= endOfOutBuffer) break;
|
||||||
|
|
||||||
|
acc_2 = iT64[*ps++];
|
||||||
|
acc_2 |= acc_1 << 6;
|
||||||
|
*pd++ = acc_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return outCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t Base64EncodingBufferSize (const size_t input_size)
|
||||||
|
{
|
||||||
|
auto d = div (input_size, 3);
|
||||||
|
if (d.rem) d.quot++;
|
||||||
|
return 4*d.quot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* iT64
|
||||||
|
* ----
|
||||||
|
* Reverse table builder. P64 character is replaced with 0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void iT64Build()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
isFirstTime = 0;
|
||||||
|
for ( i=0; i<256; i++ ) iT64[i] = -1;
|
||||||
|
for ( i=0; i<64; i++ ) iT64[(int)T64[i]] = i;
|
||||||
|
iT64[(int)P64] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace nntpchan
|
||||||
|
{
|
||||||
|
std::string B64Encode(const uint8_t * data, const std::size_t l)
|
||||||
|
{
|
||||||
|
std::string out;
|
||||||
|
out.reserve(i2p::data::Base64EncodingBufferSize(l));
|
||||||
|
i2p::data::ByteStreamToBase64(data, l, &out[0], out.capacity());
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool B64Decode(const std::string & data, std::vector<uint8_t> & out)
|
||||||
|
{
|
||||||
|
out.resize(data.size());
|
||||||
|
if(i2p::data::Base64ToByteStream(data.c_str(), data.size(), &out[0], out.size()) == -1) return false;
|
||||||
|
out.shrink_to_fit();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
17
contrib/frontends/cpp/nntpchan-daemon/src/base64.hpp
Normal file
17
contrib/frontends/cpp/nntpchan-daemon/src/base64.hpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef NNTPCHAN_BASE64_HPP
|
||||||
|
#define NNTPCHAN_BASE64_HPP
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace nntpchan
|
||||||
|
{
|
||||||
|
/** returns base64 encoded string */
|
||||||
|
std::string B64Encode(const uint8_t * data, const std::size_t l);
|
||||||
|
|
||||||
|
/** @brief returns true if decode was successful */
|
||||||
|
bool B64Decode(const std::string & data, std::vector<uint8_t> & out);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
9
contrib/frontends/cpp/nntpchan-daemon/src/crypto.cpp
Normal file
9
contrib/frontends/cpp/nntpchan-daemon/src/crypto.cpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#include "crypto.hpp"
|
||||||
|
|
||||||
|
namespace nntpchan
|
||||||
|
{
|
||||||
|
void SHA512(const uint8_t * d, const std::size_t l, SHA512Digest & h)
|
||||||
|
{
|
||||||
|
crypto_hash(h.data(), d, l);
|
||||||
|
}
|
||||||
|
}
|
15
contrib/frontends/cpp/nntpchan-daemon/src/crypto.hpp
Normal file
15
contrib/frontends/cpp/nntpchan-daemon/src/crypto.hpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef NNTPCHAN_CRYPTO_HPP
|
||||||
|
#define NNTPCHAN_CRYPTO_HPP
|
||||||
|
|
||||||
|
#include <sodium/crypto_hash.h>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
namespace nntpchan
|
||||||
|
{
|
||||||
|
typedef std::array<uint8_t, crypto_hash_BYTES> SHA512Digest;
|
||||||
|
|
||||||
|
void SHA512(const uint8_t * d, std::size_t l, SHA512Digest & h);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
41
contrib/frontends/cpp/nntpchan-daemon/src/line.cpp
Normal file
41
contrib/frontends/cpp/nntpchan-daemon/src/line.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "line.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace nntpchan {
|
||||||
|
|
||||||
|
void LineReader::OnData(const char * d, ssize_t l)
|
||||||
|
{
|
||||||
|
if(l <= 0) return;
|
||||||
|
std::size_t idx = 0;
|
||||||
|
while(l-- > 0) {
|
||||||
|
char c = d[idx++];
|
||||||
|
if(c == '\n') {
|
||||||
|
OnLine(d, idx-2);
|
||||||
|
d += idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineReader::OnLine(const char *d, const size_t l)
|
||||||
|
{
|
||||||
|
std::string line(d, l);
|
||||||
|
HandleLine(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LineReader::HasNextLine()
|
||||||
|
{
|
||||||
|
return m_sendlines.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string LineReader::GetNextLine()
|
||||||
|
{
|
||||||
|
std::string line = m_sendlines[0];
|
||||||
|
m_sendlines.pop_front();
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineReader::QueueLine(const std::string & line)
|
||||||
|
{
|
||||||
|
m_sendlines.push_back(line);
|
||||||
|
}
|
||||||
|
}
|
35
contrib/frontends/cpp/nntpchan-daemon/src/line.hpp
Normal file
35
contrib/frontends/cpp/nntpchan-daemon/src/line.hpp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#ifndef NNTPCHAN_LINE_HPP
|
||||||
|
#define NNTPCHAN_LINE_HPP
|
||||||
|
#include <string>
|
||||||
|
#include <deque>
|
||||||
|
namespace nntpchan
|
||||||
|
{
|
||||||
|
|
||||||
|
/** @brief a buffered line reader */
|
||||||
|
class LineReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief queue inbound data from connection */
|
||||||
|
void OnData(const char * data, ssize_t s);
|
||||||
|
|
||||||
|
/** @brief do we have line to send to the client? */
|
||||||
|
bool HasNextLine();
|
||||||
|
/** @brief get the next line to send to the client, does not check if it exists */
|
||||||
|
std::string GetNextLine();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** @brief handle a line from the client */
|
||||||
|
virtual void HandleLine(const std::string & line) = 0;
|
||||||
|
/** @brief queue the next line to send to the client */
|
||||||
|
void QueueLine(const std::string & line);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void OnLine(const char * d, const size_t l);
|
||||||
|
// lines to send
|
||||||
|
std::deque<std::string> m_sendlines;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
61
contrib/frontends/cpp/nntpchan-daemon/src/nntp_auth.cpp
Normal file
61
contrib/frontends/cpp/nntpchan-daemon/src/nntp_auth.cpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include "nntp_auth.hpp"
|
||||||
|
#include "crypto.hpp"
|
||||||
|
#include "base64.hpp"
|
||||||
|
#include <array>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
namespace nntpchan
|
||||||
|
{
|
||||||
|
HashedCredDB::HashedCredDB(std::istream & i) :
|
||||||
|
m_instream(i) {}
|
||||||
|
|
||||||
|
bool HashedCredDB::CheckLogin(const std::string & user, const std::string & passwd)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m_access);
|
||||||
|
m_found = false;
|
||||||
|
m_user = user;
|
||||||
|
m_passwd = passwd;
|
||||||
|
m_instream.seekg(0, std::ios::end);
|
||||||
|
const auto l = m_instream.tellg();
|
||||||
|
m_instream.seekg(0, std::ios::beg);
|
||||||
|
char * buff = new char[l];
|
||||||
|
// read file
|
||||||
|
m_instream.read(buff, l);
|
||||||
|
OnData(buff, l);
|
||||||
|
delete [] buff;
|
||||||
|
return m_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HashedCredDB::ProcessLine(const std::string & line)
|
||||||
|
{
|
||||||
|
// strip comments
|
||||||
|
auto comment = line.find("#");
|
||||||
|
std::string part = line;
|
||||||
|
for (; comment != std::string::npos; comment = part.find("#")) {
|
||||||
|
if(comment)
|
||||||
|
part = part.substr(0, comment);
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
if(!part.size()) return false; // empty line after comments
|
||||||
|
auto idx = part.find(":");
|
||||||
|
if (idx == std::string::npos) return false; // bad format
|
||||||
|
if (m_user != part.substr(0, idx)) return false; // username mismatch
|
||||||
|
part = part.substr(idx+1);
|
||||||
|
|
||||||
|
idx = part.find(":");
|
||||||
|
if (idx == std::string::npos) return false; // bad format
|
||||||
|
std::string cred = part.substr(0, idx);
|
||||||
|
std::string salt = part.substr(idx+1);
|
||||||
|
return Hash(m_passwd, salt) == cred;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string HashedCredDB::Hash(const std::string & data, const std::string & salt)
|
||||||
|
{
|
||||||
|
SHA512Digest h;
|
||||||
|
std::string d = data + salt;
|
||||||
|
SHA512((const uint8_t*)d.c_str(), d.size(), h);
|
||||||
|
return B64Encode(h.data(), h.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
38
contrib/frontends/cpp/nntpchan-daemon/src/nntp_auth.hpp
Normal file
38
contrib/frontends/cpp/nntpchan-daemon/src/nntp_auth.hpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef NNTPCHAN_NNTP_AUTH_HPP
|
||||||
|
#define NNTPCHAN_NNTP_AUTH_HPP
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <mutex>
|
||||||
|
#include "line.hpp"
|
||||||
|
|
||||||
|
namespace nntpchan
|
||||||
|
{
|
||||||
|
/** @brief nntp credential db interface */
|
||||||
|
class NNTPCredentialDB
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** @brief return true if username password combo is correct */
|
||||||
|
virtual bool CheckLogin(const std::string & user, const std::string & passwd) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief nntp credential db using hashed+salted passwords */
|
||||||
|
class HashedCredDB : public NNTPCredentialDB, public LineReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HashedCredDB(std::istream & i);
|
||||||
|
bool CheckLogin(const std::string & user, const std::string & passwd);
|
||||||
|
protected:
|
||||||
|
std::string Hash(const std::string & data, const std::string & salt);
|
||||||
|
private:
|
||||||
|
|
||||||
|
bool ProcessLine(const std::string & line);
|
||||||
|
|
||||||
|
std::mutex m_access;
|
||||||
|
std::string m_user, m_passwd;
|
||||||
|
bool m_found;
|
||||||
|
/** return true if we have a line that matches this username / password combo */
|
||||||
|
std::istream & m_instream;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
74
contrib/frontends/cpp/nntpchan-daemon/src/nntp_handler.cpp
Normal file
74
contrib/frontends/cpp/nntpchan-daemon/src/nntp_handler.cpp
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#include "nntp_handler.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace nntpchan
|
||||||
|
{
|
||||||
|
NNTPServerHandler::NNTPServerHandler(const std::string & storage) :
|
||||||
|
m_store(storage),
|
||||||
|
m_authed(false),
|
||||||
|
m_state(eStateReadCommand)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void NNTPServerHandler::HandleLine(const std::string &line)
|
||||||
|
{
|
||||||
|
if(m_state == eStateReadCommand) {
|
||||||
|
std::deque<std::string> command;
|
||||||
|
std::istringstream s;
|
||||||
|
s.str(line);
|
||||||
|
for (std::string part; std::getline(s, part, ' '); ) {
|
||||||
|
if(part.size()) command.push_back(std::string(part));
|
||||||
|
}
|
||||||
|
if(command.size())
|
||||||
|
HandleCommand(command);
|
||||||
|
else
|
||||||
|
QueueLine("501 Syntax error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NNTPServerHandler::HandleCommand(const std::deque<std::string> & command)
|
||||||
|
{
|
||||||
|
auto cmd = command[0];
|
||||||
|
std::transform(cmd.begin(), cmd.end(), cmd.begin(),
|
||||||
|
[](unsigned char ch) { return std::toupper(ch); });
|
||||||
|
std::size_t cmdlen = command.size();
|
||||||
|
std::cerr << "handle command [" << cmd << "] " << (int) cmdlen << std::endl;
|
||||||
|
if (cmd == "QUIT") {
|
||||||
|
Quit();
|
||||||
|
return;
|
||||||
|
} else if (cmd == "MODE" ) {
|
||||||
|
if(cmdlen == 1) {
|
||||||
|
// set mode
|
||||||
|
SwitchMode(command[1]);
|
||||||
|
} else if(cmdlen) {
|
||||||
|
// too many arguments
|
||||||
|
} else {
|
||||||
|
// get mode
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// unknown command
|
||||||
|
QueueLine("500 Unknown Command");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NNTPServerHandler::SwitchMode(const std::string & mode)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void NNTPServerHandler::Quit()
|
||||||
|
{
|
||||||
|
std::cerr << "quitting" << std::endl;
|
||||||
|
m_state = eStateQuit;
|
||||||
|
QueueLine("205 quitting");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NNTPServerHandler::Done()
|
||||||
|
{
|
||||||
|
return m_state == eStateQuit;
|
||||||
|
}
|
||||||
|
}
|
45
contrib/frontends/cpp/nntpchan-daemon/src/nntp_handler.hpp
Normal file
45
contrib/frontends/cpp/nntpchan-daemon/src/nntp_handler.hpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#ifndef NNTPCHAN_NNTP_HANDLER_HPP
|
||||||
|
#define NNTPCHAN_NNTP_HANDLER_HPP
|
||||||
|
#include <deque>
|
||||||
|
#include <string>
|
||||||
|
#include "line.hpp"
|
||||||
|
#include "storage.hpp"
|
||||||
|
|
||||||
|
namespace nntpchan
|
||||||
|
{
|
||||||
|
class NNTPServerHandler : public LineReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NNTPServerHandler(const std::string & storage);
|
||||||
|
|
||||||
|
bool Done();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void HandleLine(const std::string & line);
|
||||||
|
void HandleCommand(const std::deque<std::string> & command);
|
||||||
|
private:
|
||||||
|
|
||||||
|
enum State {
|
||||||
|
eStateReadCommand,
|
||||||
|
eStateStoreArticle,
|
||||||
|
eStateQuit
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
// handle quit command, this queues a reply
|
||||||
|
void Quit();
|
||||||
|
|
||||||
|
// switch nntp modes, this queues a reply
|
||||||
|
void SwitchMode(const std::string & mode);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
ArticleStorage m_store;
|
||||||
|
std::string m_mode;
|
||||||
|
bool m_authed;
|
||||||
|
State m_state;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -39,7 +39,7 @@ namespace nntpchan
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NNTPServerConn * conn = new NNTPServerConn(m_loop, s, m_storagePath);
|
NNTPServerConn * conn = new NNTPServerConn(m_loop, s, m_storagePath);
|
||||||
conn->SendCode(200, "Posting Allowed");
|
conn->Greet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -56,6 +56,7 @@ namespace nntpchan
|
|||||||
uv_accept(s, (uv_stream_t*) &m_conn);
|
uv_accept(s, (uv_stream_t*) &m_conn);
|
||||||
uv_read_start((uv_stream_t*) &m_conn, [] (uv_handle_t * h, size_t s, uv_buf_t * b) {
|
uv_read_start((uv_stream_t*) &m_conn, [] (uv_handle_t * h, size_t s, uv_buf_t * b) {
|
||||||
NNTPServerConn * self = (NNTPServerConn*) h->data;
|
NNTPServerConn * self = (NNTPServerConn*) h->data;
|
||||||
|
if(self == nullptr) return;
|
||||||
b->base = self->m_readbuff;
|
b->base = self->m_readbuff;
|
||||||
if (s > sizeof(self->m_readbuff))
|
if (s > sizeof(self->m_readbuff))
|
||||||
b->len = sizeof(self->m_readbuff);
|
b->len = sizeof(self->m_readbuff);
|
||||||
@ -63,70 +64,56 @@ namespace nntpchan
|
|||||||
b->len = s;
|
b->len = s;
|
||||||
}, [] (uv_stream_t * s, ssize_t nread, const uv_buf_t * b) {
|
}, [] (uv_stream_t * s, ssize_t nread, const uv_buf_t * b) {
|
||||||
NNTPServerConn * self = (NNTPServerConn*) s->data;
|
NNTPServerConn * self = (NNTPServerConn*) s->data;
|
||||||
|
if(self == nullptr) return;
|
||||||
if(nread > 0) {
|
if(nread > 0) {
|
||||||
self->ProcessData(b->base, nread);
|
self->m_handler.OnData(b->base, nread);
|
||||||
self->SendNextReply();
|
self->SendNextReply();
|
||||||
|
if(self->m_handler.Done())
|
||||||
|
self->Close();
|
||||||
} else {
|
} else {
|
||||||
if (nread != UV_EOF) {
|
if (nread != UV_EOF) {
|
||||||
std::cerr << "error in nntp server conn alloc: ";
|
std::cerr << "error in nntp server conn alloc: ";
|
||||||
std::cerr << uv_strerror(nread);
|
std::cerr << uv_strerror(nread);
|
||||||
std::cerr << std::endl;
|
std::cerr << std::endl;
|
||||||
}
|
}
|
||||||
|
// got eof or error
|
||||||
delete self;
|
self->Close();
|
||||||
s->data = nullptr;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
NNTPServerConn::~NNTPServerConn()
|
|
||||||
{
|
|
||||||
uv_close((uv_handle_t*)&m_conn, [] (uv_handle_t *) {});
|
|
||||||
}
|
|
||||||
|
|
||||||
void NNTPServerConn::ProcessData(const char *d, ssize_t l)
|
|
||||||
{
|
|
||||||
m_handler.OnData(d, l);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NNTPServerConn::SendNextReply()
|
void NNTPServerConn::SendNextReply()
|
||||||
{
|
{
|
||||||
if(m_handler.HasNextLine()) {
|
if(m_handler.HasNextLine()) {
|
||||||
auto line = m_handler.GetNextLine();
|
auto line = m_handler.GetNextLine();
|
||||||
SendLine(line);
|
SendString(line+"\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NNTPServerConn::SendCode(const int code, const std::string & msg)
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << code << " " << msg << std::endl;
|
|
||||||
SendString(ss.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void NNTPServerConn::SendString(const std::string & line)
|
|
||||||
{
|
|
||||||
WriteBuffer * b = new WriteBuffer(line);
|
|
||||||
uv_write(&b->w, *this, &b->b, 1, [](uv_write_t * w, int status) {
|
|
||||||
WriteBuffer * wb = (WriteBuffer *) w->data;
|
|
||||||
delete wb;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
NNTPServerHandler::NNTPServerHandler(const std::string & storagepath) :
|
void NNTPServerConn::Greet()
|
||||||
m_state(eNNTPStateGreet)
|
|
||||||
{
|
|
||||||
m_storage.SetPath(storagepath);
|
|
||||||
}
|
|
||||||
|
|
||||||
NNTPServerHandler::~NNTPServerHandler()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void NNTPServerHandler::OnData(const char * d, ssize_t l)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NNTPServerConn::SendString(const std::string & str)
|
||||||
|
{
|
||||||
|
WriteBuffer * b = new WriteBuffer(str);
|
||||||
|
uv_write(&b->w, *this, &b->b, 1, [](uv_write_t * w, int status) {
|
||||||
|
(void) status;
|
||||||
|
WriteBuffer * wb = (WriteBuffer *) w->data;
|
||||||
|
if(wb)
|
||||||
|
delete wb;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void NNTPServerConn::Close()
|
||||||
|
{
|
||||||
|
uv_close((uv_handle_t*)&m_conn, [] (uv_handle_t * s) {
|
||||||
|
NNTPServerConn * self = (NNTPServerConn*) s->data;
|
||||||
|
if(self)
|
||||||
|
delete self;
|
||||||
|
s->data = nullptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,14 @@
|
|||||||
#define NNTPCHAN_NNTP_SERVER_HPP
|
#define NNTPCHAN_NNTP_SERVER_HPP
|
||||||
#include <uv.h>
|
#include <uv.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <deque>
|
||||||
#include "storage.hpp"
|
#include "storage.hpp"
|
||||||
|
#include "nntp_auth.hpp"
|
||||||
|
#include "nntp_handler.hpp"
|
||||||
|
|
||||||
namespace nntpchan
|
namespace nntpchan
|
||||||
{
|
{
|
||||||
|
|
||||||
class NNTPServerConn;
|
class NNTPServerConn;
|
||||||
|
|
||||||
class NNTPServer
|
class NNTPServer
|
||||||
@ -31,58 +33,24 @@ namespace nntpchan
|
|||||||
uv_tcp_t m_server;
|
uv_tcp_t m_server;
|
||||||
uv_loop_t * m_loop;
|
uv_loop_t * m_loop;
|
||||||
|
|
||||||
std::vector<NNTPServerConn *> m_conns;
|
std::deque<NNTPServerConn *> m_conns;
|
||||||
|
|
||||||
std::string m_storagePath;
|
std::string m_storagePath;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class NNTPServerHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum State {
|
|
||||||
eNNTPStateGreet,
|
|
||||||
eNNTPStateHandshake,
|
|
||||||
eNNTPStateReader,
|
|
||||||
eNNTPStateStream,
|
|
||||||
eNNTPStateTAKETHIS,
|
|
||||||
eNNTPStateIHAVE,
|
|
||||||
eNNTPStateARTICLE,
|
|
||||||
eNNTPStatePOST
|
|
||||||
};
|
|
||||||
|
|
||||||
NNTPServerHandler(const std::string & storagepath);
|
|
||||||
~NNTPServerHandler();
|
|
||||||
|
|
||||||
void OnData(const char * data, ssize_t s);
|
|
||||||
|
|
||||||
bool HasNextLine();
|
|
||||||
std::string GetNextLine();
|
|
||||||
|
|
||||||
private:
|
|
||||||
State m_state;
|
|
||||||
ArticleStorage m_storage;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
virtual ~NNTPServerConn();
|
|
||||||
|
|
||||||
|
/** @brief close connection, this connection cannot be used after calling this */
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
void Quit();
|
|
||||||
|
|
||||||
void SendLine(const std::string & line);
|
|
||||||
void SendCode(const int code, const std::string & message);
|
|
||||||
|
|
||||||
void ProcessData(const char * d, ssize_t l);
|
|
||||||
|
|
||||||
|
/** @brief send next queued reply */
|
||||||
void SendNextReply();
|
void SendNextReply();
|
||||||
|
|
||||||
|
void Greet();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -94,8 +62,10 @@ namespace nntpchan
|
|||||||
uv_tcp_t m_conn;
|
uv_tcp_t m_conn;
|
||||||
|
|
||||||
NNTPServerHandler m_handler;
|
NNTPServerHandler m_handler;
|
||||||
|
|
||||||
|
NNTPCredentialDB * m_logindb;
|
||||||
|
|
||||||
char m_readbuff[1024];
|
char m_readbuff[1028];
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,10 @@ namespace nntpchan
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArticleStorage::ArticleStorage(const std::string & fpath) {
|
||||||
|
SetPath(fpath);
|
||||||
|
}
|
||||||
|
|
||||||
ArticleStorage::~ArticleStorage()
|
ArticleStorage::~ArticleStorage()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ namespace nntpchan
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ArticleStorage();
|
ArticleStorage();
|
||||||
|
ArticleStorage(const std::string & fpath);
|
||||||
~ArticleStorage();
|
~ArticleStorage();
|
||||||
|
|
||||||
void SetPath(const std::string & fpath);
|
void SetPath(const std::string & fpath);
|
||||||
|
18
contrib/frontends/cpp/nntpchan-daemon/tool.cpp
Normal file
18
contrib/frontends/cpp/nntpchan-daemon/tool.cpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include "base64.hpp"
|
||||||
|
#include "crypto.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
static void print_help(const std::string & exename)
|
||||||
|
{
|
||||||
|
std::cout << "usage: " << exename << " [help|passwd|genconf]" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char * argv[])
|
||||||
|
{
|
||||||
|
if(argc == 1) {
|
||||||
|
print_help(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user