RetroShare/libretroshare/src/retroshare/rsids.h

340 lines
11 KiB
C++

/*******************************************************************************
* libretroshare/src/retroshare: rsids.h *
* *
* libretroshare: retroshare core library *
* *
* Copyright (C) 2013 Cyril Soler <csoler@users.sourceforge.net> *
* Copyright (C) 2019 Gioacchino Mazzurco <gio@eigenlab.org> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#pragma once
#include <stdexcept>
#include <string>
#include <iostream>
#include <ostream>
#include <string.h>
#include <cstdint>
#include <vector>
#include <list>
#include <set>
#include <memory>
#include "util/rsdebug.h"
#include "util/rsrandom.h"
#include "util/stacktrace.h"
/**
* RsGenericIdType values might be random, but must be different, in order to
* make the various IDs incompatible with each other.
*/
enum class RsGenericIdType
{
SSL,
PGP_ID,
SHA1,
PGP_FINGERPRINT,
GXS_GROUP,
GXS_ID,
GXS_MSG,
GXS_CIRCLE,
GROUTER,
GXS_TUNNEL,
DISTANT_CHAT,
NODE_GROUP,
SHA256,
BIAS_20_BYTES
};
/**
* This class aims at defining a generic ID type that is a list of bytes. It
* can be converted into a hexadecial string for printing, mainly) or for
* compatibility with old methods.
*
* To use this class, derive your own ID type from it.
* @see RsPpgFingerprint as an example.
*
* Take care to define and use a different @see RsGenericIdType for each ne type
* of ID you create, to avoid implicit conversion between subtypes, and
* therefore accidental ID mixup is impossible.
*
* ID Types with different lengths are not convertible even using explicit
* constructor and compilation would fail if that is attempted.
*
* Warning: never store references to a t_RsGenericIdType accross threads, since
* the cached string convertion is not thread safe.
*/
template<uint32_t ID_SIZE_IN_BYTES, bool UPPER_CASE, RsGenericIdType UNIQUE_IDENTIFIER>
struct t_RsGenericIdType
{
using Id_t = t_RsGenericIdType<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>;
using std_list = std::list<Id_t>;
using std_vector = std::vector<Id_t>;
using std_set = std::set<Id_t>;
/// by default, ids are set to null()
t_RsGenericIdType() { memset(bytes, 0, ID_SIZE_IN_BYTES); }
/// Explicit constructor from a hexadecimal string
explicit t_RsGenericIdType(const std::string& hex_string);
/**
* @brief Construct from a buffer of at least the size of SIZE_IN_BYTES
* This is dangerous if used without being absolutely sure of buffer size,
* nothing prevent a buffer of wrong size being passed at runtime!
* @param[in] buff pointer to the buffer
* @return empty id on failure, an id initialized from the bytes in the
* buffer
*/
static Id_t fromBufferUnsafe(const uint8_t* buff)
{
Id_t ret;
if(!buff)
{
RsErr() << __PRETTY_FUNCTION__ << " invalid paramethers buff: "
<< buff << std::endl;
print_stacktrace();
return ret;
}
memmove(ret.bytes, buff, SIZE_IN_BYTES);
return ret;
}
/**
* Explicit constructor from a different type but with same size.
*
* This is used for conversions such as
* GroupId -> CircleId
* GroupId -> GxsId
*/
template<bool UPPER_CASE2, RsGenericIdType UNIQUE_IDENTIFIER2>
explicit t_RsGenericIdType(
const t_RsGenericIdType<ID_SIZE_IN_BYTES, UPPER_CASE2, UNIQUE_IDENTIFIER2>&
id )
{ memmove(bytes, id.toByteArray(), ID_SIZE_IN_BYTES); }
/// Random initialization. Can be useful for testing and to generate new ids.
static Id_t random()
{
Id_t id;
RsRandom::random_bytes(id.bytes, ID_SIZE_IN_BYTES);
return id;
}
inline void clear() { memset(bytes, 0, SIZE_IN_BYTES); }
/// Converts to a std::string using cached value.
const uint8_t* toByteArray() const { return &bytes[0]; }
static constexpr uint32_t SIZE_IN_BYTES = ID_SIZE_IN_BYTES;
inline bool operator==(const Id_t& fp) const
{ return !memcmp(bytes, fp.bytes, ID_SIZE_IN_BYTES); }
inline bool operator!=(const Id_t& fp) const
{ return !!memcmp(bytes, fp.bytes, ID_SIZE_IN_BYTES); }
inline bool operator< (const Id_t& fp) const
{ return (memcmp(bytes, fp.bytes, ID_SIZE_IN_BYTES) < 0); }
inline Id_t operator~ () const
{
Id_t ret;
for(uint32_t i=0; i < ID_SIZE_IN_BYTES; ++i)
ret.bytes[i] = ~bytes[i];
return ret;
}
inline Id_t operator| (const Id_t& fp) const
{
Id_t ret;
for(uint32_t i=0; i < ID_SIZE_IN_BYTES; ++i)
ret.bytes[i] = bytes[i] | fp.bytes[i];
return ret;
}
inline bool isNull() const
{
for(uint32_t i=0; i < SIZE_IN_BYTES; ++i)
if(bytes[i] != 0) return false;
return true;
}
friend std::ostream& operator<<(std::ostream& out, const Id_t& id)
{
switch (UNIQUE_IDENTIFIER)
{
case RsGenericIdType::PGP_FINGERPRINT:
{
uint8_t index = 0;
for(char c : id.toStdString())
{
out << c;
if(++index % 4 == 0 && index < id.SIZE_IN_BYTES*2) out << ' ';
}
}
break;
default: out << id.toStdString(UPPER_CASE); break;
}
return out;
}
inline std::string toStdString() const { return toStdString(UPPER_CASE); }
inline static uint32_t serial_size() { return SIZE_IN_BYTES; }
bool serialise(void* data,uint32_t pktsize,uint32_t& offset) const
{
if(offset + SIZE_IN_BYTES > pktsize) return false;
memmove( &(reinterpret_cast<uint8_t*>(data))[offset],
bytes, SIZE_IN_BYTES );
offset += SIZE_IN_BYTES;
return true;
}
bool deserialise(const void* data, uint32_t pktsize, uint32_t& offset)
{
if(offset + SIZE_IN_BYTES > pktsize) return false;
memmove( bytes,
&(reinterpret_cast<const uint8_t*>(data))[offset],
SIZE_IN_BYTES );
offset += SIZE_IN_BYTES;
return true;
}
/** Explicit constructor from a byte array. The array must have size at
* least ID_SIZE_IN_BYTES
* @deprecated This is too dangerous!
* Nothing prevent a buffer of wrong size being passed at runtime!
*/
RS_DEPRECATED_FOR("fromBufferUnsafe(const uint8_t* buff)")
explicit t_RsGenericIdType(const uint8_t bytes[]);
private:
std::string toStdString(bool upper_case) const;
uint8_t bytes[ID_SIZE_IN_BYTES];
};
template<uint32_t ID_SIZE_IN_BYTES, bool UPPER_CASE, RsGenericIdType UNIQUE_IDENTIFIER>
std::string t_RsGenericIdType<ID_SIZE_IN_BYTES, UPPER_CASE, UNIQUE_IDENTIFIER>
::toStdString(bool upper_case) const
{
static const char outh[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' } ;
static const char outl[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' } ;
std::string res(ID_SIZE_IN_BYTES*2,' ') ;
for(uint32_t j = 0; j < ID_SIZE_IN_BYTES; j++)
if(upper_case)
{
res[2*j ] = outh[ (bytes[j]>>4) ] ;
res[2*j+1] = outh[ bytes[j] & 0xf ] ;
}
else
{
res[2*j ] = outl[ (bytes[j]>>4) ] ;
res[2*j+1] = outl[ bytes[j] & 0xf ] ;
}
return res ;
}
template<uint32_t ID_SIZE_IN_BYTES, bool UPPER_CASE, RsGenericIdType UNIQUE_IDENTIFIER>
t_RsGenericIdType<ID_SIZE_IN_BYTES, UPPER_CASE, UNIQUE_IDENTIFIER>
::t_RsGenericIdType(const std::string& s)
{
std::string::size_type n = 0;
if(s.length() != ID_SIZE_IN_BYTES*2)
{
if(!s.empty())
{
RsErr() << __PRETTY_FUNCTION__ << " supplied string in constructor "
<< "has wrong size. Expected ID size=" << ID_SIZE_IN_BYTES*2
<< " String=\"" << s << "\" = " << s.length() << std::endl;
print_stacktrace();
}
clear();
return;
}
for(uint32_t i = 0; i < ID_SIZE_IN_BYTES; ++i)
{
bytes[i] = 0 ;
for(int k=0;k<2;++k)
{
char b = s[n++] ;
if(b >= 'A' && b <= 'F')
bytes[i] += (b-'A'+10) << 4*(1-k) ;
else if(b >= 'a' && b <= 'f')
bytes[i] += (b-'a'+10) << 4*(1-k) ;
else if(b >= '0' && b <= '9')
bytes[i] += (b-'0') << 4*(1-k) ;
else
{
RsErr() << __PRETTY_FUNCTION__ << "supplied string is not "
<< "purely hexadecimal: s=\"" << s << "\"" << std::endl;
clear();
return;
}
}
}
}
template<uint32_t ID_SIZE_IN_BYTES, bool UPPER_CASE, RsGenericIdType UNIQUE_IDENTIFIER>
RS_DEPRECATED_FOR("t_RsGenericIdType::fromBuffer(...)")
t_RsGenericIdType<ID_SIZE_IN_BYTES, UPPER_CASE, UNIQUE_IDENTIFIER>::
t_RsGenericIdType(const uint8_t mem[]) /// @deprecated Too dangerous!
{
if(mem == nullptr) memset(bytes, 0, ID_SIZE_IN_BYTES);
else memcpy(bytes, mem, ID_SIZE_IN_BYTES);
}
/**
* This constants are meant to be used only inside this file.
* Use @see t_RsGenericIdType::SIZE_IN_BYTES in other places.
*/
namespace _RsIdSize
{
constexpr uint32_t SSL_ID = 16; // = CERT_SIGN
constexpr uint32_t CERT_SIGN = 16; // = SSL_ID
constexpr uint32_t PGP_ID = 8;
constexpr uint32_t PGP_FINGERPRINT = 20;
constexpr uint32_t SHA1 = 20;
constexpr uint32_t SHA256 = 32;
}
using RsPeerId = t_RsGenericIdType<_RsIdSize::SSL_ID , false, RsGenericIdType::SSL >;
using RsPgpId = t_RsGenericIdType<_RsIdSize::PGP_ID , true, RsGenericIdType::PGP_ID >;
using Sha1CheckSum = t_RsGenericIdType<_RsIdSize::SHA1 , false, RsGenericIdType::SHA1 >;
using Sha256CheckSum = t_RsGenericIdType<_RsIdSize::SHA256 , false, RsGenericIdType::SHA256 >;
using RsPgpFingerprint = t_RsGenericIdType<_RsIdSize::PGP_FINGERPRINT, true, RsGenericIdType::PGP_FINGERPRINT>;
using Bias20Bytes = t_RsGenericIdType<_RsIdSize::SHA1 , true, RsGenericIdType::BIAS_20_BYTES >;
using RsGxsGroupId = t_RsGenericIdType<_RsIdSize::CERT_SIGN , false, RsGenericIdType::GXS_GROUP >;
using RsGxsMessageId = t_RsGenericIdType<_RsIdSize::SHA1 , false, RsGenericIdType::GXS_MSG >;
using RsGxsId = t_RsGenericIdType<_RsIdSize::CERT_SIGN , false, RsGenericIdType::GXS_ID >;
using RsGxsCircleId = t_RsGenericIdType<_RsIdSize::CERT_SIGN , false, RsGenericIdType::GXS_CIRCLE >;
using RsGxsTunnelId = t_RsGenericIdType<_RsIdSize::SSL_ID , false, RsGenericIdType::GXS_TUNNEL >;
using DistantChatPeerId = t_RsGenericIdType<_RsIdSize::SSL_ID , false, RsGenericIdType::DISTANT_CHAT >;
using RsNodeGroupId = t_RsGenericIdType<_RsIdSize::CERT_SIGN , false, RsGenericIdType::NODE_GROUP >;
/// @deprecated Ugly name kept temporarly only because it is used in many places
using PGPFingerprintType RS_DEPRECATED_FOR(RsPpgFingerprint) = RsPgpFingerprint;