Loading src/import.cpp +63 −9 Changes for src/import.cpp: 63 added lines, 9 removed lines. Original line number Diff line number Diff line Loading @@ -29,6 +29,9 @@ #include <vector> #include <string> #include <set> #include <utility> #include <netplus/crypto/base64.h> #include <uuidp.h> Loading @@ -38,6 +41,26 @@ namespace fenrirds { namespace { struct ImportRecord { AuthData::Record rec; std::vector<char> data; }; /* dirname of a stored DirectoryObject, empty if it has none */ std::string storedDirName(AuthBackend &backend, const uuid::uuid &guid) { AuthData dat(guid); if (!backend.getRecord(dat, DataType::DirectoryObject)) return ""; for (const AuthData *c = &dat; c; c = c->next()) { if (c->Data.type == DataType::DirectoryObject && strcmp(c->Data.fieldname, "dirname") == 0 && c->Data.datasize) return std::string(c->Data.data, strnlen(c->Data.data, c->Data.datasize)); } return ""; } } int Import::fromJson(AuthBackend &backend, json_object *jroot) { AuthBackend::Guard guard(backend); if (!jroot) Loading @@ -47,7 +70,7 @@ namespace fenrirds { if (!jrecords || !json_object_is_type(jrecords, json_type_array)) throw AuthBackendError("import: missing or invalid 'records' array!"); int count = 0; std::vector<ImportRecord> records; size_t len = json_object_array_length(jrecords); for (size_t i = 0; i < len; ++i) { Loading @@ -65,7 +88,8 @@ namespace fenrirds { continue; // Build the record AuthData::Record rec{}; ImportRecord ir{}; AuthData::Record &rec = ir.rec; rec.start = 0xFE; // Parse ruid Loading @@ -84,30 +108,60 @@ namespace fenrirds { strncpy(rec.fieldname, json_object_get_string(jfieldname), sizeof(rec.fieldname) - 1); // Base64 decode the data std::vector<char> rawdata; if (jdata) { const char *b64str = json_object_get_string(jdata); if (b64str && strlen(b64str) > 0) { netplus::base64 b64; b64.setEncodedData(std::string(b64str)); b64 >> rawdata; b64 >> ir.data; } } if (!rawdata.empty()) { rec.datasize = rawdata.size(); if (!ir.data.empty()) { rec.datasize = ir.data.size(); } else if (jdatasize) { rec.datasize = static_cast<size_t>(json_object_get_int64(jdatasize)); } else { rec.datasize = 0; } records.push_back(std::move(ir)); } // The import is authoritative: drop existing objects it would // duplicate -- same uuid/type, or a directory object at the same DN // (the well-known objects a new domain provisions with fresh GUIDs). std::set<std::pair<std::string, int>> keys; std::set<std::string> dirnames; for (const auto &ir : records) { keys.emplace(uuid::uuid(ir.rec.ruid).c_str(), ir.rec.type); if (ir.rec.type == DataType::DirectoryObject && strcmp(ir.rec.fieldname, "dirname") == 0 && !ir.data.empty()) dirnames.emplace(ir.data.data(), strnlen(ir.data.data(), ir.data.size())); } RecordIndex &idx = backend.getIndex(); if (!idx.valid() || idx.revision() != backend.getRevesion()) idx.build(backend); std::vector<uuid::uuid> existing; idx.listByType(DataType::DirectoryObject, existing); for (const auto &guid : existing) { if (keys.count({guid.c_str(), DataType::DirectoryObject})) continue; if (dirnames.count(storedDirName(backend, guid))) backend.delRecord(guid, DataType::DirectoryObject); } for (const auto &key : keys) backend.delRecord(uuid::uuid(key.first.c_str()), key.second); int count = 0; for (const auto &ir : records) { // Write record to backend size_t wd = backend.end(); backend.setPos(wd); backend.write(reinterpret_cast<unsigned char*>(&rec), sizeof(AuthData::Record)); if (!rawdata.empty()) { backend.write(reinterpret_cast<unsigned char*>(rawdata.data()), rawdata.size()); backend.write(reinterpret_cast<const unsigned char*>(&ir.rec), sizeof(AuthData::Record)); if (!ir.data.empty()) { backend.write(reinterpret_cast<const unsigned char*>(ir.data.data()), ir.data.size()); } ++count; Loading Loading
src/import.cpp +63 −9 Changes for src/import.cpp: 63 added lines, 9 removed lines. Original line number Diff line number Diff line Loading @@ -29,6 +29,9 @@ #include <vector> #include <string> #include <set> #include <utility> #include <netplus/crypto/base64.h> #include <uuidp.h> Loading @@ -38,6 +41,26 @@ namespace fenrirds { namespace { struct ImportRecord { AuthData::Record rec; std::vector<char> data; }; /* dirname of a stored DirectoryObject, empty if it has none */ std::string storedDirName(AuthBackend &backend, const uuid::uuid &guid) { AuthData dat(guid); if (!backend.getRecord(dat, DataType::DirectoryObject)) return ""; for (const AuthData *c = &dat; c; c = c->next()) { if (c->Data.type == DataType::DirectoryObject && strcmp(c->Data.fieldname, "dirname") == 0 && c->Data.datasize) return std::string(c->Data.data, strnlen(c->Data.data, c->Data.datasize)); } return ""; } } int Import::fromJson(AuthBackend &backend, json_object *jroot) { AuthBackend::Guard guard(backend); if (!jroot) Loading @@ -47,7 +70,7 @@ namespace fenrirds { if (!jrecords || !json_object_is_type(jrecords, json_type_array)) throw AuthBackendError("import: missing or invalid 'records' array!"); int count = 0; std::vector<ImportRecord> records; size_t len = json_object_array_length(jrecords); for (size_t i = 0; i < len; ++i) { Loading @@ -65,7 +88,8 @@ namespace fenrirds { continue; // Build the record AuthData::Record rec{}; ImportRecord ir{}; AuthData::Record &rec = ir.rec; rec.start = 0xFE; // Parse ruid Loading @@ -84,30 +108,60 @@ namespace fenrirds { strncpy(rec.fieldname, json_object_get_string(jfieldname), sizeof(rec.fieldname) - 1); // Base64 decode the data std::vector<char> rawdata; if (jdata) { const char *b64str = json_object_get_string(jdata); if (b64str && strlen(b64str) > 0) { netplus::base64 b64; b64.setEncodedData(std::string(b64str)); b64 >> rawdata; b64 >> ir.data; } } if (!rawdata.empty()) { rec.datasize = rawdata.size(); if (!ir.data.empty()) { rec.datasize = ir.data.size(); } else if (jdatasize) { rec.datasize = static_cast<size_t>(json_object_get_int64(jdatasize)); } else { rec.datasize = 0; } records.push_back(std::move(ir)); } // The import is authoritative: drop existing objects it would // duplicate -- same uuid/type, or a directory object at the same DN // (the well-known objects a new domain provisions with fresh GUIDs). std::set<std::pair<std::string, int>> keys; std::set<std::string> dirnames; for (const auto &ir : records) { keys.emplace(uuid::uuid(ir.rec.ruid).c_str(), ir.rec.type); if (ir.rec.type == DataType::DirectoryObject && strcmp(ir.rec.fieldname, "dirname") == 0 && !ir.data.empty()) dirnames.emplace(ir.data.data(), strnlen(ir.data.data(), ir.data.size())); } RecordIndex &idx = backend.getIndex(); if (!idx.valid() || idx.revision() != backend.getRevesion()) idx.build(backend); std::vector<uuid::uuid> existing; idx.listByType(DataType::DirectoryObject, existing); for (const auto &guid : existing) { if (keys.count({guid.c_str(), DataType::DirectoryObject})) continue; if (dirnames.count(storedDirName(backend, guid))) backend.delRecord(guid, DataType::DirectoryObject); } for (const auto &key : keys) backend.delRecord(uuid::uuid(key.first.c_str()), key.second); int count = 0; for (const auto &ir : records) { // Write record to backend size_t wd = backend.end(); backend.setPos(wd); backend.write(reinterpret_cast<unsigned char*>(&rec), sizeof(AuthData::Record)); if (!rawdata.empty()) { backend.write(reinterpret_cast<unsigned char*>(rawdata.data()), rawdata.size()); backend.write(reinterpret_cast<const unsigned char*>(&ir.rec), sizeof(AuthData::Record)); if (!ir.data.empty()) { backend.write(reinterpret_cast<const unsigned char*>(ir.data.data()), ir.data.size()); } ++count; Loading