mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-01-20 20:31:46 -05:00
7642216912
Deprecate unsafe costructor, substituted by fromBufferUnsafe which explicitely marked suggest the caller to pay attention. Use enum class for id types instead of constants Make size constants more private Use internal Id_t alias to avoid huge template lines Remove and deprecate oguly names in favor of consistent names
339 lines
11 KiB
C++
339 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 RsPpgFingerprint = 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 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) = RsPpgFingerprint;
|