Skip to content

Commit 1b8b269

Browse files
committed
feat: add decryptForGroup through MultiEncrypt
1 parent 43ee42f commit 1b8b269

File tree

2 files changed

+148
-12
lines changed

2 files changed

+148
-12
lines changed

include/multi_encrypt/multi_encrypt.hpp

Lines changed: 141 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,41 @@ inline session::array_uc32 extractEd25519PrivateKeyHex(
261261
return arr;
262262
}
263263

264+
std::vector<unsigned char> extractEd25519GroupPubkeyHex(
265+
const Napi::Object& obj, const std::string& identifier) {
266+
assertIsString(obj.Get("ed25519GroupPubkeyHex"), identifier);
267+
auto ed25519GroupPubkeyHex = toCppString(obj.Get("ed25519GroupPubkeyHex"), identifier);
268+
assert_length(ed25519GroupPubkeyHex, 66, identifier);
269+
270+
auto arr = from_hex_to_vector(ed25519GroupPubkeyHex);
271+
272+
return arr;
273+
}
274+
275+
std::vector<std::vector<unsigned char>> extractGroupEncKeys(
276+
const Napi::Object& obj, const std::string& identifier) {
277+
assertIsArray(obj.Get("groupEncKeys"), identifier);
278+
279+
auto asArray = obj.Get("groupEncKeys").As<Napi::Array>();
280+
std::vector<std::vector<unsigned char>> groupEncKeys;
281+
groupEncKeys.reserve(asArray.Length());
282+
283+
for (uint32_t i = 0; i < asArray.Length(); i++) {
284+
auto itemValue = asArray.Get(i);
285+
assertIsUInt8Array(itemValue, "extractGroupEncKeys");
286+
287+
auto encKey = itemValue.As<Napi::Uint8Array>();
288+
289+
std::vector<unsigned char> cppEncKey =
290+
toCppBuffer(encKey, "extractGroupEncKeys.groupEncKey");
291+
assert_length(cppEncKey, 32, "extractGroupEncKeys.groupEncKey");
292+
293+
groupEncKeys.emplace_back(cppEncKey);
294+
}
295+
296+
return groupEncKeys;
297+
}
298+
264299
class MultiEncryptWrapper : public Napi::ObjectWrap<MultiEncryptWrapper> {
265300
public:
266301
MultiEncryptWrapper(const Napi::CallbackInfo& info) :
@@ -321,10 +356,10 @@ class MultiEncryptWrapper : public Napi::ObjectWrap<MultiEncryptWrapper> {
321356
"decryptFor1o1",
322357
static_cast<napi_property_attributes>(
323358
napi_writable | napi_configurable)),
324-
// StaticMethod<&MultiEncryptWrapper::decryptForGroup>(
325-
// "decryptForGroup",
326-
// static_cast<napi_property_attributes>(
327-
// napi_writable | napi_configurable)),
359+
StaticMethod<&MultiEncryptWrapper::decryptForGroup>(
360+
"decryptForGroup",
361+
static_cast<napi_property_attributes>(
362+
napi_writable | napi_configurable)),
328363
});
329364
}
330365

@@ -549,7 +584,8 @@ class MultiEncryptWrapper : public Napi::ObjectWrap<MultiEncryptWrapper> {
549584

550585
ready_to_send[i] = session::encode_for_1o1(
551586
extractPlaintext(obj, "encryptFor1o1.obj.plaintext"),
552-
extractSenderEd25519SeedAsVector(obj, "encryptFor1o1.obj.senderEd25519Seed"),
587+
extractSenderEd25519SeedAsVector(
588+
obj, "encryptFor1o1.obj.senderEd25519Seed"),
553589
extractSentTimestampMs(obj, "encryptFor1o1.obj.sentTimestampMs"),
554590
extractRecipientPubkeyAsArray(obj, "encryptFor1o1.obj.recipientPubkey"),
555591
extractProRotatingEd25519PrivKeyAsSpan(
@@ -898,5 +934,105 @@ class MultiEncryptWrapper : public Napi::ObjectWrap<MultiEncryptWrapper> {
898934
return ret;
899935
});
900936
};
937+
938+
static Napi::Value decryptForGroup(const Napi::CallbackInfo& info) {
939+
return wrapResult(info, [&] {
940+
// we expect two arguments that match:
941+
// first: [{
942+
// "envelopePayload": Uint8Array,
943+
// "messageHash": string,
944+
// }],
945+
// second: {
946+
// "nowMs": number,
947+
// "proBackendPubkeyHex": Hexstring,
948+
// "ed25519GroupPubkeyHex": Hexstring,
949+
// "groupEncKeys": Array<Uint8Array>,
950+
// }
951+
//
952+
953+
assertInfoLength(info, 2);
954+
assertIsArray(info[0], "decryptForGroup info[0]");
955+
assertIsObject(info[1]);
956+
957+
auto first = info[0].As<Napi::Array>();
958+
959+
if (first.IsEmpty())
960+
throw std::invalid_argument("decryptForGroup first received empty");
961+
962+
auto second = info[1].As<Napi::Object>();
963+
964+
if (second.IsEmpty())
965+
throw std::invalid_argument("decryptForGroup second received empty");
966+
967+
auto nowMs = extractNowSysMs(second, "decryptForGroup.second.nowMs");
968+
auto proBackendPubkeyHex = extractProBackendPubkeyHex(
969+
second, "decryptForGroup.second.proBackendPubkeyHex");
970+
971+
std::vector<DecodedEnvelope> decrypted;
972+
std::vector<std::string> decryptedMessageHashes;
973+
974+
DecodeEnvelopeKey keys{};
975+
auto groupPk = extractEd25519GroupPubkeyHex(
976+
second, "decryptForGroup.second.ed25519GroupPubkeyHex");
977+
978+
// this has to be vector and not spans, the memory gets freed by the function
979+
std::vector<std::vector<unsigned char>> groupEncKeysVec =
980+
extractGroupEncKeys(second, "decryptForGroup.second.groupEncKeys");
981+
982+
std::vector<std::span<const unsigned char>> span_group_enc_keys;
983+
span_group_enc_keys.reserve(span_group_enc_keys.size());
984+
for (const auto& inner : groupEncKeysVec) {
985+
span_group_enc_keys.emplace_back(inner);
986+
}
987+
988+
// Create a span of spans
989+
std::span<std::span<const unsigned char>> groupEncKeys(span_group_enc_keys);
990+
991+
keys.decrypt_keys = groupEncKeys;
992+
993+
for (uint32_t i = 0; i < first.Length(); i++) {
994+
auto itemValue = first.Get(i);
995+
if (!itemValue.IsObject()) {
996+
throw std::invalid_argument(
997+
"decryptForGroup itemValue is not an "
998+
"object");
999+
}
1000+
auto obj = itemValue.As<Napi::Object>();
1001+
1002+
try {
1003+
std::string messageHash =
1004+
extractMessageHash(obj, "decryptForGroup.obj.messageHash");
1005+
1006+
auto envelopePayload =
1007+
extractEnvelopePayload(obj, "decryptForGroup.obj.envelopePayload");
1008+
decrypted.push_back(
1009+
session::decode_envelope(
1010+
keys, envelopePayload, nowMs, proBackendPubkeyHex));
1011+
decryptedMessageHashes.push_back(messageHash);
1012+
} catch (const std::exception& e) {
1013+
log::warning(
1014+
cat,
1015+
"decryptForGroup: Failed to decrypt "
1016+
"message at index {}",
1017+
i);
1018+
}
1019+
}
1020+
1021+
auto ret = Napi::Array::New(info.Env(), decrypted.size());
1022+
uint32_t i = 0;
1023+
1024+
for (auto& d : decrypted) {
1025+
auto to_insert = Napi::Object::New(info.Env());
1026+
1027+
to_insert.Set("decodedEnvelope", toJs(info.Env(), d));
1028+
to_insert.Set("messageHash", toJs(info.Env(), decryptedMessageHashes[i]));
1029+
1030+
ret.Set(i, to_insert);
1031+
i++;
1032+
}
1033+
1034+
return ret;
1035+
});
1036+
};
9011037
};
9021038
}; // namespace session::nodeapi

types/multi_encrypt/multi_encrypt.d.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -200,10 +200,10 @@ declare module 'libsession_util_nodejs' {
200200
second: WithNowMs & WithProBackendPubkey & WithEd25519PrivateKeyHex
201201
) => Array<WithDecodedEnvelope & WithMessageHash>;
202202

203-
// decryptForGroup: (
204-
// first: Array<WithEnvelopePayload>,
205-
// second: WithNowMs & WithProBackendPubkey & WithEd25519GroupPubkeyHex & WithGroupEncryptionKeys
206-
// ) => Array<{}>;
203+
decryptForGroup: (
204+
first: Array<WithEnvelopePayload & WithMessageHash>,
205+
second: WithNowMs & WithProBackendPubkey & WithEd25519GroupPubkeyHex & WithGroupEncryptionKeys
206+
) => Array<WithDecodedEnvelope & WithMessageHash>;
207207
};
208208

209209
export type MultiEncryptActionsCalls = MakeWrapperActionCalls<MultiEncryptWrapper>;
@@ -223,7 +223,7 @@ declare module 'libsession_util_nodejs' {
223223

224224
public static decryptForCommunity: MultiEncryptWrapper['decryptForCommunity'];
225225
public static decryptFor1o1: MultiEncryptWrapper['decryptFor1o1'];
226-
// public static decryptForGroup: MultiEncryptWrapper['decryptForGroup'];
226+
public static decryptForGroup: MultiEncryptWrapper['decryptForGroup'];
227227
}
228228

229229
/**
@@ -241,6 +241,6 @@ declare module 'libsession_util_nodejs' {
241241
| MakeActionCall<MultiEncryptWrapper, 'encryptForCommunity'>
242242
| MakeActionCall<MultiEncryptWrapper, 'encryptForGroup'>
243243
| MakeActionCall<MultiEncryptWrapper, 'decryptForCommunity'>
244-
| MakeActionCall<MultiEncryptWrapper, 'decryptFor1o1'>;
245-
// | MakeActionCall<MultiEncryptWrapper, 'decryptForGroup'>;
244+
| MakeActionCall<MultiEncryptWrapper, 'decryptFor1o1'>
245+
| MakeActionCall<MultiEncryptWrapper, 'decryptForGroup'>;
246246
}

0 commit comments

Comments
 (0)