From 593e59e093b9b9720c2de000fe2131098cea01f3 Mon Sep 17 00:00:00 2001 From: Pavan Koushik Nellore Date: Wed, 18 Mar 2026 15:29:22 -0400 Subject: [PATCH] proxy: add pushType field and propagate through proxy notifications --- include/opendht/value.h | 15 +++++++- src/dht_proxy_server.cpp | 7 +++- src/value.cpp | 8 ++++- tests/test_value.cpp | 78 ++++++++++++++++++++++++++++++++++++++++ tests/test_value.h | 6 ++++ 5 files changed, 111 insertions(+), 3 deletions(-) diff --git a/include/opendht/value.h b/include/opendht/value.h index 5599aa9e..2111cac4 100644 --- a/include/opendht/value.h +++ b/include/opendht/value.h @@ -31,6 +31,7 @@ using namespace std::literals; static constexpr auto VALUE_KEY_ID("id"); static const std::string VALUE_KEY_DAT("dat"); static const std::string VALUE_KEY_PRIO("p"); +static const std::string VALUE_KEY_PUSHTYPE("pt"); static const std::string VALUE_KEY_SIGNATURE("sig"); static const std::string VALUE_KEY_SEQ("seq"); @@ -451,6 +452,7 @@ struct OPENDHT_PUBLIC Value , signature(std::move(o.signature)) , cypher(std::move(o.cypher)) , priority(o.priority) + , pushType(std::move(o.pushType)) {} template @@ -574,7 +576,7 @@ struct OPENDHT_PUBLIC Value template void msgpack_pack(Packer& pk) const { - pk.pack_map(2 + (priority ? 1 : 0)); + pk.pack_map(2 + (priority ? 1 : 0) + (!pushType.empty() ? 1 : 0)); pk.pack(VALUE_KEY_ID); pk.pack(id); pk.pack(VALUE_KEY_DAT); @@ -583,6 +585,10 @@ struct OPENDHT_PUBLIC Value pk.pack(VALUE_KEY_PRIO); pk.pack(priority); } + if (!pushType.empty()) { + pk.pack(VALUE_KEY_PUSHTYPE); + pk.pack(pushType); + } } template @@ -672,6 +678,13 @@ struct OPENDHT_PUBLIC Value */ unsigned priority {0}; + /** + * Push notification type — set by the sender so that the proxy server + * can include it in the FCM/APNs payload without decrypting the value. + * Example: "audioCall", "videoCall" + */ + std::string pushType {}; + inline bool isSignatureChecked() const { return signatureChecked; } inline bool isDecrypted() const { return decrypted; } bool checkSignature(); diff --git a/src/dht_proxy_server.cpp b/src/dht_proxy_server.cpp index 8c01ec05..3a60d381 100644 --- a/src/dht_proxy_server.cpp +++ b/src/dht_proxy_server.cpp @@ -1158,12 +1158,17 @@ DhtProxyServer::handlePushListen(const InfoHash& infoHash, // Build a comma-separated list of ids from the values. This is intended to be used when // streaming from the iOS notification extension in order to filter out unwanted values. std::string ids; + std::string pushTypes; for (const auto& value : values) { - if (!ids.empty()) + if (!ids.empty()) { ids += ","; + pushTypes += ","; + } + pushTypes += value->pushType; ids += std::to_string(value->id); } json["ids"] = ids; + json["pt"] = pushTypes; // If message is expired copy the value ID to the `exp` field. // This is presumably used by the Android notification system. diff --git a/src/value.cpp b/src/value.cpp index 6f5f8ad4..9a088515 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -85,7 +85,7 @@ ValueType::DEFAULT_STORE_POLICY(InfoHash, const std::shared_ptr& v, const size_t Value::size() const { - return cypher.size() + data.size() + signature.size() + user_type.size(); + return cypher.size() + data.size() + signature.size() + user_type.size() + pushType.size(); } void @@ -104,9 +104,14 @@ Value::msgpack_unpack(const msgpack::object& o) } else throw msgpack::type_error(); + priority = 0; + pushType.clear(); if (auto rprio = findMapValue(o, VALUE_KEY_PRIO)) { priority = rprio->as(); } + if (auto rpt = findMapValue(o, VALUE_KEY_PUSHTYPE)) { + pushType = rpt->as(); + } } void @@ -261,6 +266,7 @@ Value::encrypt(const crypto::PrivateKey& from, const crypto::PublicKey& to) sign(from); Value nv {id}; nv.priority = priority; + nv.pushType = pushType; nv.setCypher(to.encrypt(getToEncrypt())); return nv; } diff --git a/tests/test_value.cpp b/tests/test_value.cpp index d3548ca7..e8bff4cf 100644 --- a/tests/test_value.cpp +++ b/tests/test_value.cpp @@ -8,6 +8,8 @@ // opendht #include "opendht/value.h" +#include "opendht/crypto.h" +#include namespace test { CPPUNIT_TEST_SUITE_REGISTRATION(ValueTester); @@ -59,4 +61,80 @@ ValueTester::testFilter() void ValueTester::tearDown() {} + +void +ValueTester::testPushTypeMsgpackRoundTrip() +{ + dht::Value original {(const uint8_t*) "hello", 5}; + original.id = 42; + original.priority = 3; + original.pushType = "audioCall"; + + msgpack::sbuffer buffer; + msgpack::packer pk(&buffer); + original.msgpack_pack(pk); + + msgpack::unpacked msg; + msgpack::unpack(msg, buffer.data(), buffer.size()); + dht::Value restored(msg.get()); + + CPPUNIT_ASSERT_EQUAL(original.id, restored.id); + CPPUNIT_ASSERT_EQUAL(original.priority, restored.priority); + CPPUNIT_ASSERT_EQUAL(original.pushType, restored.pushType); +} + +void +ValueTester::testPushTypeAbsentAfterUnpack() +{ + dht::Value withPt {(const uint8_t*) "data", 4}; + withPt.id = 1; + withPt.pushType = "videoCall"; + withPt.priority = 2; + + msgpack::sbuffer buf1; + msgpack::packer pk1(&buf1); + withPt.msgpack_pack(pk1); + + msgpack::unpacked msg1; + msgpack::unpack(msg1, buf1.data(), buf1.size()); + + dht::Value reused; + reused.msgpack_unpack(msg1.get()); + CPPUNIT_ASSERT_EQUAL(std::string("videoCall"), reused.pushType); + CPPUNIT_ASSERT_EQUAL(2u, reused.priority); + + dht::Value plain {(const uint8_t*) "data", 4}; + plain.id = 2; + + msgpack::sbuffer buf2; + msgpack::packer pk2(&buf2); + plain.msgpack_pack(pk2); + + msgpack::unpacked msg2; + msgpack::unpack(msg2, buf2.data(), buf2.size()); + + reused.msgpack_unpack(msg2.get()); + CPPUNIT_ASSERT_EQUAL(std::string(), reused.pushType); + CPPUNIT_ASSERT_EQUAL(0u, reused.priority); +} + +void +ValueTester::testPushTypePreservedAfterEncrypt() +{ + auto key = dht::crypto::PrivateKey::generate(); + const auto& pubkey = key.getPublicKey(); + + dht::Value original {(const uint8_t*) "secret", 6}; + original.id = 99; + original.priority = 1; + original.pushType = "audioCall"; + + auto encrypted = original.encrypt(key, pubkey); + + CPPUNIT_ASSERT_EQUAL(original.pushType, encrypted.pushType); + CPPUNIT_ASSERT_EQUAL(original.priority, encrypted.priority); + CPPUNIT_ASSERT_EQUAL(original.id, encrypted.id); + CPPUNIT_ASSERT(encrypted.isEncrypted()); +} + } // namespace test diff --git a/tests/test_value.h b/tests/test_value.h index 69070e70..cbfb009b 100644 --- a/tests/test_value.h +++ b/tests/test_value.h @@ -13,6 +13,9 @@ class ValueTester : public CppUnit::TestFixture CPPUNIT_TEST_SUITE(ValueTester); CPPUNIT_TEST(testConstructors); CPPUNIT_TEST(testFilter); + CPPUNIT_TEST(testPushTypeMsgpackRoundTrip); + CPPUNIT_TEST(testPushTypeAbsentAfterUnpack); + CPPUNIT_TEST(testPushTypePreservedAfterEncrypt); CPPUNIT_TEST_SUITE_END(); public: @@ -32,6 +35,9 @@ public: * Test compare operators */ void testFilter(); + void testPushTypeMsgpackRoundTrip(); + void testPushTypeAbsentAfterUnpack(); + void testPushTypePreservedAfterEncrypt(); }; } // namespace test