mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-12-29 01:16:20 -05:00
Added core code for pgphash calculations.
- Reworked GxsIdGroup members... moved IdType -> groupFlags, so Hash & Sign are only ones. - Reworked GroupServiceString storage. - Added core processing functions - yet to test! git-svn-id: http://svn.code.sf.net/p/retroshare/code/branches/v0.5-gxs-b1@5777 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
parent
e803b2c447
commit
17e42f1ceb
@ -37,6 +37,12 @@
|
||||
class RsIdentity;
|
||||
extern RsIdentity *rsIdentity;
|
||||
|
||||
|
||||
// GroupFlags: Only one so far:
|
||||
#define RSGXSID_GROUPFLAG_REALID 0x0001
|
||||
|
||||
|
||||
// THESE ARE FLAGS FOR INTERFACE.
|
||||
#define RSID_TYPE_MASK 0xff00
|
||||
#define RSID_RELATION_MASK 0x00ff
|
||||
|
||||
@ -61,8 +67,7 @@ class RsGxsIdGroup
|
||||
// In GroupMetaData.
|
||||
//std::string mNickname; (mGroupName)
|
||||
//std::string mKeyId; (mGroupId)
|
||||
|
||||
uint32_t mIdType;
|
||||
//uint32_t mIdType; (mGroupFlags)
|
||||
|
||||
// SHA(KeyId + Gpg Fingerprint) -> can only be IDed if GPG known.
|
||||
// The length of the input must be long enough to make brute force search implausible.
|
||||
@ -70,14 +75,11 @@ class RsGxsIdGroup
|
||||
// Easy to do 1e9 SHA-1 hash computations per second on a GPU.
|
||||
// We will need a minimum of 256 bits, ideally 1024 bits or 2048 bits.
|
||||
|
||||
std::string mGpgIdHash;
|
||||
// Actually PgpIdHash is SHA1(.mMeta.mGroupId + PGPHandler->GpgFingerprint(ownId))
|
||||
// ??? 160 bits.
|
||||
|
||||
// NOTE: These cannot be transmitted as part of underlying messages....
|
||||
// Must use ServiceString.
|
||||
bool mGpgIdKnown; // if GpgIdHash has been identified.
|
||||
std::string mGpgId; // if known.
|
||||
std::string mGpgName; // if known.
|
||||
std::string mGpgEmail; // if known.
|
||||
std::string mPgpIdHash;
|
||||
std::string mPgpIdSign; // Need a signature as proof - otherwise anyone could add others Hashes.
|
||||
};
|
||||
|
||||
|
||||
|
@ -120,14 +120,8 @@ RsItem* RsGxsIdSerialiser::deserialise(void* data, uint32_t* size)
|
||||
|
||||
void RsGxsIdGroupItem::clear()
|
||||
{
|
||||
group.mGpgIdHash.clear();
|
||||
group.mIdType = 0;
|
||||
|
||||
// Others that aren't serialised. - but should be cleared anyway
|
||||
group.mGpgIdKnown = false;
|
||||
group.mGpgId.clear();
|
||||
group.mGpgName.clear();
|
||||
group.mGpgEmail.clear();
|
||||
group.mPgpIdHash.clear();
|
||||
group.mPgpIdSign.clear();
|
||||
}
|
||||
|
||||
std::ostream& RsGxsIdGroupItem::print(std::ostream& out, uint16_t indent)
|
||||
@ -136,9 +130,9 @@ std::ostream& RsGxsIdGroupItem::print(std::ostream& out, uint16_t indent)
|
||||
uint16_t int_Indent = indent + 2;
|
||||
|
||||
printIndent(out, int_Indent);
|
||||
out << "IdType: " << group.mIdType << std::endl;
|
||||
out << "PgpIdHash: " << group.mPgpIdHash << std::endl;
|
||||
printIndent(out, int_Indent);
|
||||
out << "GpgIdHash: " << group.mGpgIdHash << std::endl;
|
||||
out << "PgpIdSign: " << group.mPgpIdSign << std::endl;
|
||||
|
||||
printRsItemEnd(out ,"RsGxsIdGroupItem", indent);
|
||||
return out;
|
||||
@ -151,8 +145,8 @@ uint32_t RsGxsIdSerialiser::sizeGxsIdGroupItem(RsGxsIdGroupItem *item)
|
||||
const RsGxsIdGroup& group = item->group;
|
||||
uint32_t s = 8; // header
|
||||
|
||||
s += 4; // mIdType.
|
||||
s += GetTlvStringSize(group.mGpgIdHash);
|
||||
s += GetTlvStringSize(group.mPgpIdHash);
|
||||
s += GetTlvStringSize(group.mPgpIdSign);
|
||||
|
||||
return s;
|
||||
}
|
||||
@ -185,8 +179,8 @@ bool RsGxsIdSerialiser::serialiseGxsIdGroupItem(RsGxsIdGroupItem *item, void *da
|
||||
offset += 8;
|
||||
|
||||
/* GxsIdGroupItem */
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, item->group.mIdType);
|
||||
ok &= SetTlvString(data, tlvsize, &offset, 1, item->group.mGpgIdHash);
|
||||
ok &= SetTlvString(data, tlvsize, &offset, 1, item->group.mPgpIdHash);
|
||||
ok &= SetTlvString(data, tlvsize, &offset, 1, item->group.mPgpIdSign);
|
||||
|
||||
if(offset != tlvsize)
|
||||
{
|
||||
@ -246,8 +240,8 @@ RsGxsIdGroupItem* RsGxsIdSerialiser::deserialiseGxsIdGroupItem(void *data, uint3
|
||||
/* skip the header */
|
||||
offset += 8;
|
||||
|
||||
ok &= getRawUInt32(data, rssize, &offset, &(item->group.mIdType));
|
||||
ok &= GetTlvString(data, rssize, &offset, 1, item->group.mGpgIdHash);
|
||||
ok &= GetTlvString(data, rssize, &offset, 1, item->group.mPgpIdHash);
|
||||
ok &= GetTlvString(data, rssize, &offset, 1, item->group.mPgpIdSign);
|
||||
|
||||
if (offset != rssize)
|
||||
{
|
||||
|
@ -27,6 +27,10 @@
|
||||
#include "serialiser/rsgxsiditems.h"
|
||||
|
||||
#include "util/rsrandom.h"
|
||||
#include "util/rsstring.h"
|
||||
|
||||
#include "pqi/authgpg.h"
|
||||
|
||||
#include <retroshare/rspeers.h>
|
||||
|
||||
#include <sstream>
|
||||
@ -44,6 +48,24 @@
|
||||
RsIdentity *rsIdentity = NULL;
|
||||
|
||||
|
||||
/******
|
||||
* Some notes:
|
||||
* Identity tasks:
|
||||
* - Provide keys for signing / validating author signatures.
|
||||
* - Reputations
|
||||
* - Identify Known Friend's IDs.
|
||||
* - Provide details to other services (nicknames, reputations, gpg ids, etc)
|
||||
*
|
||||
* Background services:
|
||||
* - Lookup and cache keys / details of identities.
|
||||
* - Check GPGHashes.
|
||||
* - Calculate Reputations.
|
||||
*
|
||||
* We have a lot of information to store in Service Strings.
|
||||
* - GPGId or last check ts.
|
||||
* - Reputation stuff.
|
||||
*/
|
||||
|
||||
#define RSGXSID_MAX_SERVICE_STRING 1024
|
||||
|
||||
/********************************************************************************/
|
||||
@ -272,6 +294,176 @@ bool p3IdService::createMsg(uint32_t& token, RsGxsIdOpinion &opinion)
|
||||
/************************************************************************************/
|
||||
/************************************************************************************/
|
||||
|
||||
/* Encoding / Decoding Group Service String stuff
|
||||
*
|
||||
* Pgp stuff.
|
||||
*
|
||||
* If flagged as pgp id....
|
||||
* then we need to know if its been matched, or when we last tried to match.
|
||||
*
|
||||
*/
|
||||
|
||||
bool SSGxsIdPgp::load(const std::string &input)
|
||||
{
|
||||
char pgpline[RSGXSID_MAX_SERVICE_STRING];
|
||||
int timestamp = 0;
|
||||
if (1 == sscanf(input.c_str(), "K:1 I:%[^)]", pgpline))
|
||||
{
|
||||
idKnown = true;
|
||||
pgpId = pgpline;
|
||||
}
|
||||
else if (1 == sscanf(input.c_str(), "K:0 T:%d", ×tamp))
|
||||
{
|
||||
lastCheckTs = timestamp;
|
||||
idKnown = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string SSGxsIdPgp::save() const
|
||||
{
|
||||
std::string output;
|
||||
if (idKnown)
|
||||
{
|
||||
output += "K:1 I:";
|
||||
output += pgpId;
|
||||
}
|
||||
else
|
||||
{
|
||||
rs_sprintf(output, "K:0 T:%d", lastCheckTs);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
bool SSGxsIdScore::load(const std::string &input)
|
||||
{
|
||||
return (1 == sscanf(input.c_str(), "%d", &score));
|
||||
}
|
||||
|
||||
std::string SSGxsIdScore::save() const
|
||||
{
|
||||
std::string output;
|
||||
rs_sprintf(output, "%d", score);
|
||||
return output;
|
||||
}
|
||||
|
||||
bool SSGxsIdCumulator::load(const std::string &input)
|
||||
{
|
||||
return (4 == sscanf(input.c_str(), "%d %d %lf %lf", &count, &nullcount, &sum, &sumsq));
|
||||
}
|
||||
|
||||
std::string SSGxsIdCumulator::save() const
|
||||
{
|
||||
std::string output;
|
||||
rs_sprintf(output, "%d %d %lf %lf", count, nullcount, sum, sumsq);
|
||||
return output;
|
||||
}
|
||||
|
||||
bool SSGxsIdGroup::load(const std::string &input)
|
||||
{
|
||||
char pgpstr[RSGXSID_MAX_SERVICE_STRING];
|
||||
char scorestr[RSGXSID_MAX_SERVICE_STRING];
|
||||
char opinionstr[RSGXSID_MAX_SERVICE_STRING];
|
||||
char repstr[RSGXSID_MAX_SERVICE_STRING];
|
||||
|
||||
// split into two parts.
|
||||
if (4 != sscanf(input.c_str(), "v1 {%[^}]} {%[^}]} {%[^}]} {%[^}]}", pgpstr, scorestr, opinionstr, repstr))
|
||||
{
|
||||
std::cerr << "SSGxsIdGroup::load() Failed to extract 4 Parts";
|
||||
std::cerr << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
if (0 == strncmp(pgpstr, "P:", 2))
|
||||
{
|
||||
std::cerr << "SSGxsIdGroup::load() pgpstr: " << pgpstr;
|
||||
std::cerr << std::endl;
|
||||
ok &= pgp.load(pgpstr);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "SSGxsIdGroup::load() Invalid pgpstr: " << pgpstr;
|
||||
std::cerr << std::endl;
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (0 == strncmp(scorestr, "Y:", 2))
|
||||
{
|
||||
std::cerr << "SSGxsIdGroup::load() scorestr: " << scorestr;
|
||||
std::cerr << std::endl;
|
||||
ok &= score.load(scorestr);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "SSGxsIdGroup::load() Invalid scorestr: " << scorestr;
|
||||
std::cerr << std::endl;
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (0 == strncmp(opinionstr, "O:", 2))
|
||||
{
|
||||
std::cerr << "SSGxsIdGroup::load() opinionstr: " << opinionstr;
|
||||
std::cerr << std::endl;
|
||||
ok &= opinion.load(opinionstr);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "SSGxsIdGroup::load() Invalid opinionstr: " << opinionstr;
|
||||
std::cerr << std::endl;
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (0 == strncmp(repstr, "R:", 2))
|
||||
{
|
||||
std::cerr << "SSGxsIdGroup::load() repstr: " << repstr;
|
||||
std::cerr << std::endl;
|
||||
ok &= reputation.load(repstr);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "SSGxsIdGroup::load() Invalid repstr: " << repstr;
|
||||
std::cerr << std::endl;
|
||||
ok = false;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
std::string SSGxsIdGroup::save() const
|
||||
{
|
||||
std::string output = "v1 ";
|
||||
|
||||
output += "{P:";
|
||||
output += pgp.save();
|
||||
output += "}";
|
||||
|
||||
output += "{Y:";
|
||||
output += score.save();
|
||||
output += "}";
|
||||
|
||||
output += "{O:";
|
||||
output += opinion.save();
|
||||
output += "}";
|
||||
|
||||
output += "{R:";
|
||||
output += reputation.save();
|
||||
output += "}";
|
||||
|
||||
std::cerr << "SSGxsIdGroup::save() output: " << output;
|
||||
std::cerr << std::endl;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/************************************************************************************/
|
||||
/************************************************************************************/
|
||||
/************************************************************************************/
|
||||
|
||||
/* Cache of recently used keys
|
||||
*
|
||||
* It is expensive to fetch the keys, so we want to keep them around if possible.
|
||||
@ -727,6 +919,403 @@ bool p3IdService::cachetest_request()
|
||||
return true;
|
||||
}
|
||||
|
||||
/************************************************************************************/
|
||||
/************************************************************************************/
|
||||
/************************************************************************************/
|
||||
|
||||
/* Task to determine GPGHash matches
|
||||
*
|
||||
* Info to be stored in GroupServiceString + Cache.
|
||||
*
|
||||
* Actually - it must be a Signature here - otherwise, you could
|
||||
* put in a hash from someone else!
|
||||
*
|
||||
* Don't think that we need to match very often - maybe once a day?
|
||||
* Actually - we should scale the matching based on number of keys we have.
|
||||
*
|
||||
* imagine - 10^6 rsa keys + 10^3 gpg keys => 10^9 combinations.
|
||||
* -- far too many to check all quickly.
|
||||
*
|
||||
* Need to grab and cache data we need... then check over slowly.
|
||||
*
|
||||
* maybe grab a list of all gpgids - that we know of: store id list.
|
||||
* then big GroupRequest, and iterate through these.
|
||||
**/
|
||||
|
||||
//const int SHA_DIGEST_LENGTH = 20;
|
||||
|
||||
typedef t_RsGenericIdType<SHA_DIGEST_LENGTH> GxsIdPgpHash;
|
||||
|
||||
static void calcPGPHash(const RsGxsId &id, const PGPFingerprintType &pgp, GxsIdPgpHash &hash);
|
||||
|
||||
|
||||
void p3IdService::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& keySet)
|
||||
{
|
||||
RsGxsIdGroupItem *item = dynamic_cast<RsGxsIdGroupItem *>(grpItem);
|
||||
if (!item)
|
||||
{
|
||||
std::cerr << "p3IdService::service_CreateGroup() ERROR invalid cast";
|
||||
std::cerr << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::cerr << "p3IdService::service_CreateGroup() for : " << item->group.mMeta.mGroupId;
|
||||
std::cerr << std::endl;
|
||||
|
||||
if (item->group.mMeta.mGroupFlags & RSGXSID_GROUPFLAG_REALID)
|
||||
{
|
||||
/* create the hash */
|
||||
GxsIdPgpHash hash;
|
||||
|
||||
/* */
|
||||
PGPFingerprintType ownFinger;
|
||||
PGPIdType ownId(AuthGPG::getAuthGPG()->getGPGOwnId());
|
||||
|
||||
if (!AuthGPG::getAuthGPG()->getKeyFingerprint(ownId,ownFinger))
|
||||
{
|
||||
std::cerr << "p3IdService::service_CreateGroup() ERROR Own Finger is stuck";
|
||||
std::cerr << std::endl;
|
||||
return; // abandon attempt!
|
||||
}
|
||||
|
||||
calcPGPHash(item->group.mMeta.mGroupId, ownFinger, hash);
|
||||
item->group.mPgpIdHash = hash.toStdString();
|
||||
|
||||
/* do signature */
|
||||
|
||||
#define MAX_SIGN_SIZE 2048
|
||||
uint8_t signarray[MAX_SIGN_SIZE];
|
||||
unsigned int sign_size = MAX_SIGN_SIZE;
|
||||
if (!AuthGPG::getAuthGPG()->SignDataBin((void *) hash.toByteArray(), hash.SIZE_IN_BYTES, signarray, &sign_size))
|
||||
{
|
||||
/* error */
|
||||
std::cerr << "p3IdService::service_CreateGroup() ERROR Signing stuff";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* push binary into string -> really bad! */
|
||||
item->group.mPgpIdSign = "";
|
||||
for(unsigned int i = 0; i < sign_size; i++)
|
||||
{
|
||||
item->group.mPgpIdSign += signarray[i];
|
||||
}
|
||||
}
|
||||
/* done! */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool p3IdService::pgphash_tick()
|
||||
{
|
||||
/* every minute - run a background check */
|
||||
time_t now = time(NULL);
|
||||
bool doHash = false;
|
||||
{
|
||||
RsStackMutex stack(mIdMtx); /********** STACK LOCKED MTX ******/
|
||||
if (now - mHashPgp_LastTs > TEST_PERIOD)
|
||||
{
|
||||
doHash = true;
|
||||
mHashPgp_LastTs = now;
|
||||
}
|
||||
}
|
||||
|
||||
if (doHash)
|
||||
{
|
||||
std::cerr << "p3IdService::pgphash_tick() starting";
|
||||
std::cerr << std::endl;
|
||||
pgphash_getlist();
|
||||
}
|
||||
|
||||
pgphash_request();
|
||||
pgphash_process();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool p3IdService::pgphash_getlist()
|
||||
{
|
||||
|
||||
{
|
||||
RsStackMutex stack(mIdMtx); /********** STACK LOCKED MTX ******/
|
||||
if (mHashPgp_Active)
|
||||
{
|
||||
std::cerr << "p3IdService::cachetest_getlist() Already active";
|
||||
std::cerr << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr << "p3IdService::cachetest_getlist() making request";
|
||||
std::cerr << std::endl;
|
||||
|
||||
uint32_t ansType = RS_TOKREQ_ANSTYPE_SUMMARY;
|
||||
RsTokReqOptions opts;
|
||||
opts.mReqType = GXS_REQUEST_TYPE_GROUP_META;
|
||||
uint32_t token = 0;
|
||||
|
||||
RsGenExchange::getTokenService()->requestGroupInfo(token, ansType, opts);
|
||||
|
||||
{
|
||||
RsStackMutex stack(mIdMtx); /********** STACK LOCKED MTX ******/
|
||||
mHashPgp_Token = token;
|
||||
mHashPgp_Active = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool p3IdService::pgphash_request()
|
||||
{
|
||||
uint32_t token = 0;
|
||||
{
|
||||
RsStackMutex stack(mIdMtx); /********** STACK LOCKED MTX ******/
|
||||
if (!mHashPgp_Active)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
token = mHashPgp_Token;
|
||||
}
|
||||
|
||||
std::cerr << "p3IdService::pgphash_request() checking request";
|
||||
std::cerr << std::endl;
|
||||
|
||||
uint32_t status = RsGenExchange::getTokenService()->requestStatus(token);
|
||||
|
||||
if (status == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE)
|
||||
{
|
||||
std::cerr << "p3IdService::pgphash_request() token ready: " << token;
|
||||
std::cerr << std::endl;
|
||||
|
||||
// We need full data - for access to Hash & Signature.
|
||||
// Perhaps we will change this to an initial pass through Meta,
|
||||
// and use this to discard lots of things.
|
||||
|
||||
// Even better - we can set flags in the Meta Data, (IdType),
|
||||
// And use GXS to filter out all the AnonIds, and only have to process
|
||||
// Proper Ids.
|
||||
|
||||
// We Will do this later!
|
||||
|
||||
std::vector<RsGxsIdGroup> groups;
|
||||
std::vector<RsGxsIdGroup> groupsToProcess;
|
||||
bool ok = getGroupData(token, groups);
|
||||
|
||||
{
|
||||
RsStackMutex stack(mIdMtx); /********** STACK LOCKED MTX ******/
|
||||
mHashPgp_Active = false;
|
||||
}
|
||||
|
||||
if(ok)
|
||||
{
|
||||
std::vector<RsGxsIdGroup>::iterator vit;
|
||||
for(vit = groups.begin(); vit != groups.end(); vit++)
|
||||
{
|
||||
/* Filter based on IdType */
|
||||
if (!(vit->mMeta.mGroupFlags & RSGXSID_GROUPFLAG_REALID))
|
||||
{
|
||||
std::cerr << "p3IdService::pgphash_request() discarding AnonID";
|
||||
std::cerr << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* now we need to decode the Service String - see what is saved there */
|
||||
SSGxsIdGroup ssdata;
|
||||
if (ssdata.load(vit->mMeta.mServiceString))
|
||||
{
|
||||
if (ssdata.pgp.idKnown)
|
||||
{
|
||||
std::cerr << "p3IdService::pgphash_request() discarding Already Known";
|
||||
std::cerr << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Have a linear attempt policy -
|
||||
* if zero checks - try now.
|
||||
* if 1 check, at least a day.
|
||||
* if 2 checks: 2days, etc.
|
||||
*/
|
||||
|
||||
#define SECS_PER_DAY (3600 * 24)
|
||||
time_t age = time(NULL) - ssdata.pgp.lastCheckTs;
|
||||
time_t wait_period = ssdata.pgp.checkAttempts * SECS_PER_DAY;
|
||||
if (wait_period > 30 * SECS_PER_DAY)
|
||||
{
|
||||
wait_period = 30 * SECS_PER_DAY;
|
||||
}
|
||||
|
||||
if (age < wait_period)
|
||||
{
|
||||
std::cerr << "p3IdService::pgphash_request() discarding Recently Check";
|
||||
std::cerr << std::endl;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we get here -> then its to be processed */
|
||||
std::cerr << "p3IdService::cachetest_request() Requested Key Id: " << *vit;
|
||||
std::cerr << std::endl;
|
||||
|
||||
mGroupsToProcess.push_back(*vit);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool p3IdService::pgphash_process()
|
||||
{
|
||||
/* each time this is called - process one Id from mGroupsToProcess */
|
||||
if (mGroupsToProcess.empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
RsGxsIdGroup pg = mGroupsToProcess.front();
|
||||
mGroupsToProcess.pop_front();
|
||||
|
||||
SSGxsIdGroup ssdata;
|
||||
ssdata.load(pg.mMeta.mServiceString); // attempt load - okay if fails.
|
||||
|
||||
PGPIdType pgpId;
|
||||
|
||||
if (checkId(pg, pgpId))
|
||||
{
|
||||
/* found a match - update everything */
|
||||
/* Consistency issues here - what if Reputation was recently updated? */
|
||||
|
||||
|
||||
/* update */
|
||||
ssdata.pgp.idKnown = true;
|
||||
ssdata.pgp.pgpId = pgpId.toStdString();
|
||||
|
||||
// SHOULD BE PUSHED TO CACHE!
|
||||
#if 0
|
||||
id.mGpgIdKnown = true;
|
||||
|
||||
id.mGpgId = *it;
|
||||
id.mGpgName = details.name;
|
||||
id.mGpgEmail = details.email;
|
||||
|
||||
if (*it == ownId)
|
||||
{
|
||||
id.mIdType |= RSID_RELATION_YOURSELF;
|
||||
}
|
||||
else if (rsPeers->isGPGAccepted(*it))
|
||||
{
|
||||
id.mIdType |= RSID_RELATION_FRIEND;
|
||||
}
|
||||
else
|
||||
{
|
||||
id.mIdType |= RSID_RELATION_OTHER;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
ssdata.pgp.lastCheckTs = time(NULL);
|
||||
ssdata.pgp.checkAttempts++;
|
||||
}
|
||||
|
||||
/* set new Group ServiceString */
|
||||
uint32_t dummyToken = 0;
|
||||
std::string serviceString = ssdata.save();
|
||||
setGroupServiceString(dummyToken, pg.mMeta.mGroupId, serviceString);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool p3IdService::checkId(const RsGxsIdGroup &grp, PGPIdType &pgpId)
|
||||
{
|
||||
std::cerr << "p3IdService::checkId() Starting Match Check for RsGxsId: ";
|
||||
std::cerr << grp.mMeta.mGroupId;
|
||||
std::cerr << std::endl;
|
||||
|
||||
/* iterate through and check hash */
|
||||
GxsIdPgpHash ans(grp.mPgpIdHash);
|
||||
|
||||
std::map<PGPIdType, PGPFingerprintType>::iterator mit;
|
||||
for(mit = mPgpFingerprintMap.begin(); mit != mPgpFingerprintMap.end(); mit++)
|
||||
{
|
||||
GxsIdPgpHash hash;
|
||||
calcPGPHash(grp.mMeta.mGroupId, mit->second, hash);
|
||||
if (ans == hash)
|
||||
{
|
||||
std::cerr << "p3IdService::checkId() HASH MATCH!";
|
||||
std::cerr << std::endl;
|
||||
|
||||
/* miracle match! */
|
||||
/* check signature too */
|
||||
if (AuthGPG::getAuthGPG()->VerifySignBin((void *) hash.toByteArray(), hash.SIZE_IN_BYTES,
|
||||
(unsigned char *) grp.mPgpIdSign.c_str(), grp.mPgpIdSign.length(),
|
||||
mit->second.toStdString()))
|
||||
{
|
||||
std::cerr << "p3IdService::checkId() Signature Okay too!";
|
||||
std::cerr << std::endl;
|
||||
|
||||
pgpId = mit->first;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* error */
|
||||
std::cerr << "p3IdService::checkId() ERROR Signature Failed";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr << "p3IdService::checkId() Checked " << mPgpFingerprintMap.size() << " Hashes without Match";
|
||||
std::cerr << std::endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* worker functions */
|
||||
void p3IdService::getPgpIdList()
|
||||
{
|
||||
std::cerr << "p3IdService::getPgpIdList() Starting....";
|
||||
std::cerr << std::endl;
|
||||
|
||||
std::list<std::string> list;
|
||||
AuthGPG::getAuthGPG()->getGPGFilteredList(list);
|
||||
|
||||
std::list<std::string>::iterator it;
|
||||
for(it = list.begin(); it != list.end(); it++)
|
||||
{
|
||||
PGPIdType pgpId(*it);
|
||||
PGPFingerprintType fp;
|
||||
AuthGPG::getAuthGPG()->getKeyFingerprint(pgpId, fp);
|
||||
|
||||
mPgpFingerprintMap[pgpId] = fp;
|
||||
}
|
||||
|
||||
std::cerr << "p3IdService::getPgpIdList() Items: " << mPgpFingerprintMap.size();
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void calcPGPHash(const RsGxsId &id, const PGPFingerprintType &pgp, GxsIdPgpHash &hash)
|
||||
{
|
||||
unsigned char signature[SHA_DIGEST_LENGTH];
|
||||
/* hash id + pubkey => pgphash */
|
||||
SHA_CTX *sha_ctx = new SHA_CTX;
|
||||
SHA1_Init(sha_ctx);
|
||||
|
||||
SHA1_Update(sha_ctx, id.c_str(), id.length()); // TO FIX ONE DAY.
|
||||
SHA1_Update(sha_ctx, pgp.toByteArray(), pgp.SIZE_IN_BYTES);
|
||||
SHA1_Final(signature, sha_ctx);
|
||||
hash = GxsIdPgpHash(signature);
|
||||
|
||||
delete sha_ctx;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************/
|
||||
/************************************************************************************/
|
||||
@ -773,8 +1362,9 @@ void p3IdService::generateDummyData()
|
||||
|
||||
//id.mKeyId = genRandomId();
|
||||
id.mMeta.mGroupId = genRandomId();
|
||||
id.mIdType = RSID_TYPE_REALID;
|
||||
id.mGpgIdHash = genRandomId();
|
||||
id.mMeta.mGroupFlags = RSGXSID_GROUPFLAG_REALID;
|
||||
id.mPgpIdHash = genRandomId();
|
||||
id.mPgpIdSign = genRandomId();
|
||||
|
||||
if (rsPeers->getPeerDetails(*it, details))
|
||||
{
|
||||
@ -783,36 +1373,16 @@ void p3IdService::generateDummyData()
|
||||
|
||||
//id.mNickname = out.str();
|
||||
id.mMeta.mGroupName = out.str();
|
||||
|
||||
id.mGpgIdKnown = true;
|
||||
|
||||
id.mGpgId = *it;
|
||||
id.mGpgName = details.name;
|
||||
id.mGpgEmail = details.email;
|
||||
|
||||
if (*it == ownId)
|
||||
{
|
||||
id.mIdType |= RSID_RELATION_YOURSELF;
|
||||
}
|
||||
else if (rsPeers->isGPGAccepted(*it))
|
||||
{
|
||||
id.mIdType |= RSID_RELATION_FRIEND;
|
||||
}
|
||||
else
|
||||
{
|
||||
id.mIdType |= RSID_RELATION_OTHER;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "p3IdService::generateDummyData() missing" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
|
||||
id.mIdType |= RSID_RELATION_OTHER;
|
||||
//id.mNickname = genRandomId();
|
||||
id.mMeta.mGroupName = genRandomId();
|
||||
id.mGpgIdKnown = false;
|
||||
}
|
||||
|
||||
uint32_t dummyToken = 0;
|
||||
@ -841,22 +1411,13 @@ void p3IdService::generateDummyData()
|
||||
|
||||
RsPeerDetails details;
|
||||
|
||||
//id.mKeyId = genRandomId();
|
||||
id.mMeta.mGroupId = genRandomId();
|
||||
id.mIdType = RSID_TYPE_REALID;
|
||||
id.mGpgIdHash = genRandomId();
|
||||
|
||||
id.mIdType |= RSID_RELATION_OTHER;
|
||||
//id.mNickname = genRandomId();
|
||||
id.mMeta.mGroupName = genRandomId();
|
||||
id.mGpgIdKnown = false;
|
||||
id.mGpgId = "";
|
||||
id.mGpgName = "";
|
||||
id.mGpgEmail = "";
|
||||
|
||||
//mIds[id.mKeyId] = id;
|
||||
//mIdProxy->addGroup(id);
|
||||
// STORE
|
||||
id.mMeta.mGroupId = genRandomId();
|
||||
id.mMeta.mGroupFlags = RSGXSID_GROUPFLAG_REALID;
|
||||
id.mPgpIdHash = genRandomId();
|
||||
id.mPgpIdSign = genRandomId();
|
||||
|
||||
uint32_t dummyToken = 0;
|
||||
createGroup(dummyToken, id);
|
||||
}
|
||||
@ -868,21 +1429,14 @@ void p3IdService::generateDummyData()
|
||||
|
||||
RsPeerDetails details;
|
||||
|
||||
//id.mKeyId = genRandomId();
|
||||
id.mMeta.mGroupId = genRandomId();
|
||||
id.mIdType = RSID_TYPE_PSEUDONYM;
|
||||
id.mGpgIdHash = "";
|
||||
|
||||
//id.mNickname = genRandomId();
|
||||
id.mMeta.mGroupName = genRandomId();
|
||||
id.mGpgIdKnown = false;
|
||||
id.mGpgId = "";
|
||||
id.mGpgName = "";
|
||||
id.mGpgEmail = "";
|
||||
|
||||
//mIds[id.mKeyId] = id;
|
||||
//mIdProxy->addGroup(id);
|
||||
// STORE
|
||||
id.mMeta.mGroupId = genRandomId();
|
||||
id.mMeta.mGroupFlags = 0;
|
||||
id.mPgpIdHash = "";
|
||||
id.mPgpIdSign = "";
|
||||
|
||||
|
||||
uint32_t dummyToken = 0;
|
||||
createGroup(dummyToken, id);
|
||||
}
|
||||
@ -1291,10 +1845,8 @@ bool p3IdService::background_processNewMessages()
|
||||
|
||||
mit->second.mGroupStatus |= ID_LOCAL_STATUS_INC_CALC_FLAG;
|
||||
|
||||
std::string serviceString;
|
||||
IdGroupServiceStrData ssData;
|
||||
|
||||
if (!extractIdGroupCache(serviceString, ssData))
|
||||
SSGxsIdGroup ssdata;
|
||||
if (!ssdata.load(mit->second.mServiceString))
|
||||
{
|
||||
/* error */
|
||||
std::cerr << "p3IdService::background_processNewMessages() ERROR Extracting";
|
||||
@ -1308,8 +1860,9 @@ bool p3IdService::background_processNewMessages()
|
||||
/* store it back in */
|
||||
std::cerr << "p3IdService::background_processNewMessages() Stored: ";
|
||||
std::cerr << std::endl;
|
||||
|
||||
if (!encodeIdGroupCache(serviceString, ssData))
|
||||
|
||||
std::string serviceString = ssdata.save();
|
||||
if (0)
|
||||
{
|
||||
/* error */
|
||||
std::cerr << "p3IdService::background_processNewMessages() ERROR Storing";
|
||||
@ -1365,75 +1918,6 @@ bool p3IdService::background_processNewMessages()
|
||||
}
|
||||
|
||||
|
||||
bool p3IdService::encodeIdGroupCache(std::string &str, const IdGroupServiceStrData &data)
|
||||
{
|
||||
char line[RSGXSID_MAX_SERVICE_STRING];
|
||||
|
||||
snprintf(line, RSGXSID_MAX_SERVICE_STRING, "v1 {%s} {Y:%d O:%d %d %f %f R:%d %d %f %f}",
|
||||
data.pgpId.c_str(), data.ownScore,
|
||||
data.opinion.count, data.opinion.nullcount, data.opinion.sum, data.opinion.sumsq,
|
||||
data.reputation.count, data.reputation.nullcount, data.reputation.sum, data.reputation.sumsq);
|
||||
|
||||
str = line;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool p3IdService::extractIdGroupCache(std::string &str, IdGroupServiceStrData &data)
|
||||
{
|
||||
char pgpline[RSGXSID_MAX_SERVICE_STRING];
|
||||
char scoreline[RSGXSID_MAX_SERVICE_STRING];
|
||||
|
||||
uint32_t iOwnScore;
|
||||
IdRepCumulScore iOpin;
|
||||
IdRepCumulScore iRep;
|
||||
|
||||
// split into two parts.
|
||||
if (2 != sscanf(str.c_str(), "v1 {%[^}]} {%[^}]", pgpline, scoreline))
|
||||
{
|
||||
std::cerr << "p3IdService::extractIdGroupCache() Failed to extract Two Parts";
|
||||
std::cerr << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cerr << "p3IdService::extractIdGroupCache() pgpline: " << pgpline;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "p3IdService::extractIdGroupCache() scoreline: " << scoreline;
|
||||
std::cerr << std::endl;
|
||||
|
||||
std::string pgptmp = pgpline;
|
||||
if (pgptmp.length() > 5)
|
||||
{
|
||||
std::cerr << "p3IdService::extractIdGroupCache() Believe to have pgpId: " << pgptmp;
|
||||
std::cerr << std::endl;
|
||||
data.pgpIdKnown = true;
|
||||
data.pgpId = pgptmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "p3IdService::extractIdGroupCache() Think pgpId Invalid";
|
||||
std::cerr << std::endl;
|
||||
data.pgpIdKnown = false;
|
||||
}
|
||||
|
||||
|
||||
if (9 == sscanf(scoreline, " Y:%d O:%d %d %lf %lf R:%d %d %lf %lf", &iOwnScore,
|
||||
&(iOpin.count), &(iOpin.nullcount), &(iOpin.sum), &(iOpin.sumsq),
|
||||
&(iRep.count), &(iRep.nullcount), &(iRep.sum), &(iRep.sumsq)))
|
||||
{
|
||||
data.ownScore = iOwnScore;
|
||||
data.opinion = iOpin;
|
||||
data.reputation = iRep;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::cerr << "p3IdService::extractIdGroupCache() Failed to extract scores";
|
||||
std::cerr << std::endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool p3IdService::background_FullCalcRequest()
|
||||
{
|
||||
@ -1583,23 +2067,14 @@ bool p3IdService::background_processFullCalc()
|
||||
|
||||
if (validmsgs)
|
||||
{
|
||||
std::string serviceString;
|
||||
IdGroupServiceStrData ssData;
|
||||
|
||||
|
||||
if (!encodeIdGroupCache(serviceString, ssData))
|
||||
{
|
||||
std::cerr << "p3IdService::background_updateVoteCounts() Failed to encode Votes";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "p3IdService::background_updateVoteCounts() Encoded String: " << serviceString;
|
||||
std::cerr << std::endl;
|
||||
/* store new result */
|
||||
uint32_t dummyToken = 0;
|
||||
setGroupServiceString(dummyToken, groupId, serviceString);
|
||||
}
|
||||
SSGxsIdGroup ssdata;
|
||||
std::string serviceString = ssdata.save();
|
||||
|
||||
std::cerr << "p3IdService::background_updateVoteCounts() Encoded String: " << serviceString;
|
||||
std::cerr << std::endl;
|
||||
/* store new result */
|
||||
uint32_t dummyToken = 0;
|
||||
setGroupServiceString(dummyToken, groupId, serviceString);
|
||||
}
|
||||
|
||||
{
|
||||
@ -1633,9 +2108,8 @@ bool p3IdService::background_cleanup()
|
||||
std::ostream &operator<<(std::ostream &out, const RsGxsIdGroup &grp)
|
||||
{
|
||||
out << "RsGxsIdGroup: Meta: " << grp.mMeta;
|
||||
out << " IdType: " << grp.mIdType << " GpgIdHash: " << grp.mGpgIdHash;
|
||||
out << "(((Unusable: ( GpgIdKnown: " << grp.mGpgIdKnown << " GpgId: " << grp.mGpgId;
|
||||
out << " GpgName: " << grp.mGpgName << " GpgEmail: " << grp.mGpgEmail << ") )))";
|
||||
out << " PgpIdHash: " << grp.mPgpIdHash;
|
||||
out << " PgpIdSign: [binary]"; // << grp.mPgpIdSign;
|
||||
out << std::endl;
|
||||
|
||||
return out;
|
||||
|
@ -36,6 +36,8 @@
|
||||
|
||||
#include "util/rsmemcache.h"
|
||||
|
||||
#include "pqi/authgpg.h"
|
||||
|
||||
/*
|
||||
* Identity Service
|
||||
*
|
||||
@ -43,9 +45,52 @@
|
||||
|
||||
// INTERNAL DATA TYPES.
|
||||
// Describes data stored in GroupServiceString.
|
||||
class IdRepCumulScore
|
||||
|
||||
class SSBit
|
||||
{
|
||||
public:
|
||||
virtual bool load(const std::string &input) = 0;
|
||||
virtual std::string save() const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class SSGxsIdPgp: public SSBit
|
||||
{
|
||||
public:
|
||||
SSGxsIdPgp()
|
||||
:idKnown(false), lastCheckTs(0), checkAttempts(0) { return; }
|
||||
|
||||
virtual bool load(const std::string &input);
|
||||
virtual std::string save() const;
|
||||
|
||||
bool idKnown;
|
||||
time_t lastCheckTs;
|
||||
uint32_t checkAttempts;
|
||||
std::string pgpId;
|
||||
};
|
||||
|
||||
class SSGxsIdScore: public SSBit
|
||||
{
|
||||
public:
|
||||
SSGxsIdScore()
|
||||
:score(0) { return; }
|
||||
|
||||
virtual bool load(const std::string &input);
|
||||
virtual std::string save() const;
|
||||
|
||||
int score;
|
||||
};
|
||||
|
||||
class SSGxsIdCumulator: public SSBit
|
||||
{
|
||||
public:
|
||||
SSGxsIdCumulator()
|
||||
:count(0), nullcount(0), sum(0), sumsq(0) { return; }
|
||||
|
||||
virtual bool load(const std::string &input);
|
||||
virtual std::string save() const;
|
||||
|
||||
uint32_t count;
|
||||
uint32_t nullcount;
|
||||
double sum;
|
||||
@ -54,17 +99,21 @@ public:
|
||||
// derived parameters:
|
||||
};
|
||||
|
||||
|
||||
class IdGroupServiceStrData
|
||||
class SSGxsIdGroup: public SSBit
|
||||
{
|
||||
public:
|
||||
IdGroupServiceStrData() { pgpIdKnown = false; }
|
||||
bool pgpIdKnown;
|
||||
std::string pgpId;
|
||||
|
||||
uint32_t ownScore;
|
||||
IdRepCumulScore opinion;
|
||||
IdRepCumulScore reputation;
|
||||
SSGxsIdGroup() { return; }
|
||||
|
||||
virtual bool load(const std::string &input);
|
||||
virtual std::string save() const;
|
||||
|
||||
// pgphash status
|
||||
SSGxsIdPgp pgp;
|
||||
|
||||
// reputation score.
|
||||
SSGxsIdScore score;
|
||||
SSGxsIdCumulator opinion;
|
||||
SSGxsIdCumulator reputation;
|
||||
|
||||
};
|
||||
|
||||
@ -72,7 +121,6 @@ public:
|
||||
#define ID_LOCAL_STATUS_INC_CALC_FLAG 0x00020000
|
||||
|
||||
|
||||
|
||||
#define MAX_CACHE_SIZE 100 // Small for testing..
|
||||
//#define MAX_CACHE_SIZE 10000 // More useful size
|
||||
|
||||
@ -104,9 +152,7 @@ class LruData
|
||||
// Not sure exactly what should be inherited here?
|
||||
// Chris - please correct as necessary.
|
||||
|
||||
class p3IdService:
|
||||
public RsGxsIdExchange,
|
||||
public RsIdentity
|
||||
class p3IdService: public RsGxsIdExchange, public RsIdentity
|
||||
{
|
||||
public:
|
||||
p3IdService(RsGeneralDataService* gds, RsNetworkExchangeService* nes);
|
||||
@ -164,8 +210,11 @@ virtual bool getReputation(const RsGxsId &id, const GixsReputation &rep);
|
||||
|
||||
protected:
|
||||
|
||||
/** Notifications **/
|
||||
virtual void notifyChanges(std::vector<RsGxsNotify*>& changes);
|
||||
/** Notifications **/
|
||||
virtual void notifyChanges(std::vector<RsGxsNotify*>& changes);
|
||||
|
||||
/** Overloaded to add PgpIdHash to Group Definition **/
|
||||
virtual void service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& keySet);
|
||||
|
||||
private:
|
||||
|
||||
@ -175,14 +224,6 @@ virtual bool getReputation(const RsGxsId &id, const GixsReputation &rep);
|
||||
*/
|
||||
int cache_tick();
|
||||
|
||||
|
||||
//bool cache_is_loaded(const RsGxsId &id);
|
||||
//bool cache_fetch(const RsGxsId &key, RsGxsIdCache &data);
|
||||
|
||||
//bool cache_store(const RsGxsIdGroup &group);
|
||||
//bool cache_resize();
|
||||
//bool cache_discard_LRU(int count_to_clear);
|
||||
|
||||
bool cache_request_load(const RsGxsId &id);
|
||||
bool cache_start_load();
|
||||
bool cache_check_loading();
|
||||
@ -190,12 +231,6 @@ virtual bool getReputation(const RsGxsId &id, const GixsReputation &rep);
|
||||
|
||||
bool cache_store(const RsGxsIdGroupItem *item);
|
||||
|
||||
/* MUTEX PROTECTED DATA (mIdMtx - maybe should use a 2nd?) */
|
||||
//bool locked_cache_update_lrumap(const RsGxsId &key, time_t old_ts, time_t new_ts);
|
||||
//std::map<RsGxsId, RsGxsIdCache> mCacheDataMap;
|
||||
//std::multimap<time_t, LruData> mCacheLruMap;
|
||||
//uint32_t mCacheDataCount;
|
||||
|
||||
time_t mCacheLoad_LastCycle;
|
||||
int mCacheLoad_Status;
|
||||
std::list<RsGxsId> mCacheLoad_ToCache;
|
||||
@ -220,6 +255,26 @@ virtual bool getReputation(const RsGxsId &id, const GixsReputation &rep);
|
||||
bool mCacheTest_Active;
|
||||
uint32_t mCacheTest_Token;
|
||||
|
||||
/************************************************************************
|
||||
* pgphash processing.
|
||||
*
|
||||
*/
|
||||
bool pgphash_tick();
|
||||
bool pgphash_getlist();
|
||||
bool pgphash_request();
|
||||
bool pgphash_process();
|
||||
|
||||
bool checkId(const RsGxsIdGroup &grp, PGPIdType &pgp_id);
|
||||
void getPgpIdList();
|
||||
/* MUTEX PROTECTED DATA (mIdMtx - maybe should use a 2nd?) */
|
||||
|
||||
time_t mHashPgp_LastTs;
|
||||
bool mHashPgp_Active;
|
||||
uint32_t mHashPgp_Token;
|
||||
|
||||
std::map<PGPIdType, PGPFingerprintType> mPgpFingerprintMap;
|
||||
std::list<RsGxsIdGroup> mGroupsToProcess;
|
||||
|
||||
/************************************************************************
|
||||
* Below is the background task for processing opinions => reputations
|
||||
*
|
||||
@ -239,9 +294,6 @@ std::string genRandomId();
|
||||
|
||||
bool background_cleanup();
|
||||
|
||||
bool encodeIdGroupCache(std::string &str, const IdGroupServiceStrData &data);
|
||||
bool extractIdGroupCache(std::string &str, IdGroupServiceStrData &data);
|
||||
|
||||
RsMutex mIdMtx;
|
||||
|
||||
/***** below here is locked *****/
|
||||
|
@ -25,6 +25,9 @@
|
||||
// Warning: never store references to a t_RsGenericIdType accross threads, since the
|
||||
// cached string convertion is not thread safe.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
@ -60,6 +63,14 @@ template<uint32_t ID_SIZE_IN_BYTES> class t_RsGenericIdType
|
||||
return !operator==(fp) ;
|
||||
}
|
||||
|
||||
bool operator<(const t_RsGenericIdType<ID_SIZE_IN_BYTES>& fp) const
|
||||
{
|
||||
for(uint32_t i=0;i<ID_SIZE_IN_BYTES;++i)
|
||||
if(fp.bytes[i] != bytes[i])
|
||||
return (bytes[i] < fp.bytes[i]);
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned char bytes[ID_SIZE_IN_BYTES] ;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user