Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
e3f1db4
Update file upload extension to be compatible with current XEP
pwetrifork Apr 7, 2025
0ec523a
Fix out of band data extension to inject full URLs into outgoing mess…
pwetrifork Apr 7, 2025
74c121c
Implement in-band account registration request in registration module
pwetrifork Jun 5, 2025
8b8ec5e
Implement SCE envelope content manipulation helpers
pwetrifork Jul 23, 2025
0228959
Implement SCE affix element helpers
pwetrifork Jul 23, 2025
4593500
Define stanza content encryption handling module API
pwetrifork Jul 23, 2025
d49f93a
Implement encrypted message sending method
pwetrifork Jul 23, 2025
fb33d44
Implement incoming encrypted message handling
pwetrifork Jul 23, 2025
460e91f
Fix unused local variable warning
pwetrifork Jul 23, 2025
68372f8
Remove message parameter from encryption completion callback
pwetrifork Jul 23, 2025
68db709
Add comments to clarify how encryption profile implementation may han…
pwetrifork Jul 23, 2025
7f15c3c
Fix type of elements returned from envelope creation helper
pwetrifork Jul 24, 2025
811088a
Apply review feedback: fix sensitive element classification bug
pwetrifork Jul 24, 2025
ca4fdd7
Apply review feedback: require exactly one element to be present when…
pwetrifork Jul 24, 2025
e608d7f
Apply review feedback: do not require synchronous module code invocation
pwetrifork Jul 24, 2025
f564ec6
Apply review feedback: API improvements
pwetrifork Jul 24, 2025
2d66918
Apply review feedback: add comments with specification links
pwetrifork Jul 24, 2025
a98f364
Apply review feedback: refactor affix verification implementation
pwetrifork Jul 24, 2025
fb6c7a6
Merge pull request #1 from trifork/feature/stanza-content-encryption
pwetrifork Jul 24, 2025
a7a1db0
Adjust message sending API to be more flexible
pwetrifork Jul 25, 2025
2e95c2a
Merge branch 'feature/stanza-content-encryption' into release/4.1.0+t…
pwetrifork Jul 25, 2025
cded637
Make server-processed element list customisable
pwetrifork Jul 28, 2025
303194b
Merge branch 'feature/stanza-content-encryption' into release/4.1.0+t…
pwetrifork Jul 29, 2025
29425ab
Fix module delegate invocations
pwetrifork Aug 19, 2025
beb45e8
Merge branch 'feature/stanza-content-encryption' into release/4.1.0+t…
pwetrifork Aug 19, 2025
b4582b0
Include stanza errors in default list of server processed elements
pwetrifork Aug 29, 2025
8a9ee56
Merge branch 'feature/stanza-content-encryption' into release/4.1.0+t…
pwetrifork Aug 29, 2025
e5fb01a
Modernize iq stanza for publishing bundle for device
wnatrifork Sep 10, 2025
13ea066
Modernize iq stanza for manually fetching deviceIds list
wnatrifork Sep 10, 2025
858a442
Modernize iq stanza for publishing your device ids
wnatrifork Sep 10, 2025
cdb3f51
Add access model to iq stanza for publishing bundle for device
wnatrifork Sep 10, 2025
605c5aa
Modernize parsing code for iq stanza that lists devices
wnatrifork Sep 11, 2025
00eaa65
Modernize iq stanza for fetching remote bundle
wnatrifork Sep 12, 2025
3591a3a
Modernize parsing code for iq stanza for bundle
wnatrifork Sep 12, 2025
e78dde6
Apply feedback: remove namespace attribute from methods migrated to O…
wnatrifork Sep 23, 2025
19b0eae
Apply feedback: add signatures for deprecated methods to document whi…
wnatrifork Sep 23, 2025
a317ed0
Apply feedback: Fix OMEMOElementTests
wnatrifork Sep 23, 2025
5d6ea5e
Apply feedback: Fix OMEMOModuleTests
wnatrifork Sep 23, 2025
a8c6365
Apply feedback: revert unneeded changes in omemo_* methods
wnatrifork Sep 24, 2025
6c4e702
Apply feedback: remove unneeded change from -omemo_deviceListFromItem…
wnatrifork Sep 24, 2025
10514c7
Fix testRequestSlot test
wnatrifork Sep 24, 2025
eba06ab
Apply feedback: bring back -omemo_deviceListFromIqResponse: implement…
wnatrifork Sep 24, 2025
2e5b815
Apply feedback: mark xmlnsOMEMO:, xmlnsOMEMODeviceList:, xmlnsOMEMOBu…
wnatrifork Sep 24, 2025
579d889
Apply feedback: remove dead code
wnatrifork Sep 24, 2025
54389ee
Apply feedback: fix XMPPCapabilitiesDelegate implementation
wnatrifork Sep 24, 2025
2af8ada
Apply feedback: remove deprecated functions and use new versions wher…
wnatrifork Sep 24, 2025
f51c548
Apply feedback: remove ns argument from -omemo_deviceListFromPEPUpdate:
wnatrifork Sep 24, 2025
8561a02
Merge pull request #4 from trifork/feature/key-bundle-distribution/bu…
wnatrifork Sep 24, 2025
30004c0
Add callback to inform delegate when outgoing message processing is a…
pwetrifork Oct 1, 2025
e14d4e0
Merge branch 'feature/stanza-content-encryption' into release/4.1.0+t…
pwetrifork Oct 1, 2025
0cb5acf
Add encryption profile configuration hook
pwetrifork Oct 2, 2025
2888043
Merge branch 'feature/stanza-content-encryption' into release/4.1.0+t…
pwetrifork Oct 2, 2025
a5abde6
Abort crypto processing if module is deactivated
pwetrifork Jan 9, 2026
61634f4
Track number of processed message envelopes
pwetrifork Jan 9, 2026
7b0588b
Notify delegate when crypto processing finishes upon deactivation
pwetrifork Jan 9, 2026
0df6a3d
Merge pull request #7 from trifork/feature/stanza-content-encryption
pwetrifork Jan 15, 2026
d7872d7
Add missing XMPPMessageArchiving's XMPPStreamDelegate conformance dec…
wnatrifork Mar 31, 2026
36c2122
Merge pull request #9 from trifork/feature/enable-carbon-copies
wnatrifork Mar 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions Extensions/OMEMO/NSXMLElement+OMEMO.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,9 @@ NS_ASSUME_NONNULL_BEGIN


/** Extracts device list from PEP <items> element */
- (nullable NSArray<NSNumber *>*)omemo_deviceListFromItems:(OMEMOModuleNamespace)ns;
- (nullable NSArray<NSNumber *>*)omemo_deviceListFromItems;
/** Extracts device list from PEP iq respnse */
- (nullable NSArray<NSNumber *>*)omemo_deviceListFromIqResponse:(OMEMOModuleNamespace)ns;

- (nullable NSArray<NSNumber *>*)omemo_deviceListFromIqResponse;

@end
NS_ASSUME_NONNULL_END
30 changes: 15 additions & 15 deletions Extensions/OMEMO/NSXMLElement+OMEMO.m
Original file line number Diff line number Diff line change
Expand Up @@ -110,27 +110,27 @@ + (NSXMLElement*) omemo_keyTransportElementWithKeyData:(NSArray<OMEMOKeyData*>*)
}

/*
<iq xmlns="jabber:client" id="AEA43C1D-DA7D-448F-8F41-268D1A14FF3F" type="result" to="[email protected]/b9038fb3-0575-47bf-b8bb-cd1073f972c6" from="[email protected]">
<pubsub xmlns="http://jabber.org/protocol/pubsub">
<items node="eu.siacs.conversations.axolotl.devicelist">
<item id="1">
<list xmlns="eu.siacs.conversations.axolotl">
<device id="1259777401"/>
</list>
</item>
</items>
</pubsub>
<iq from="[email protected]" id="AEA43C1D-DA7D-448F-8F41-268D1A14FF3F" to="[email protected]/b9038fb3-0575-47bf-b8bb-cd1073f972c6" type="result" xmlns="jabber:client">
<pubsub xmlns="http://jabber.org/protocol/pubsub">
<items node="urn:xmpp:omemo:2:devices">
<item id="current">
<devices xmlns="urn:xmpp:omemo:2">
<device id="1259777401"/>
</devices>
</item>
</items>
</pubsub>
</iq>
*/
- (nullable NSArray<NSNumber *>*)omemo_deviceListFromIqResponse:(OMEMOModuleNamespace)ns {
- (nullable NSArray<NSNumber *>*)omemo_deviceListFromIqResponse {
NSXMLElement *pubsub = [self elementForName:@"pubsub" xmlns:XMLNS_PUBSUB];
NSXMLElement *items = [pubsub elementForName:@"items"];
return [items omemo_deviceListFromItems:ns];
return [items omemo_deviceListFromItems];
}

- (nullable NSArray<NSNumber *>*)omemo_deviceListFromItems:(OMEMOModuleNamespace)ns {
if ([[self attributeStringValueForName:@"node"] isEqualToString:[OMEMOModule xmlnsOMEMODeviceList:ns]]) {
NSXMLElement * devicesList = [[self elementForName:@"item"] elementForName:@"list" xmlns:[OMEMOModule xmlnsOMEMO:ns]];
- (nullable NSArray<NSNumber *>*)omemo_deviceListFromItems {
if ([[self attributeStringValueForName:@"node"] isEqualToString:[OMEMOModule xmlnsOMEMODeviceList]]) {
NSXMLElement * devicesList = [[self elementForName:@"item"] elementForName:@"devices" xmlns:[OMEMOModule xmlnsOMEMO]];
if (devicesList) {
NSArray *children = [devicesList children];
NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:children.count];
Expand Down
11 changes: 6 additions & 5 deletions Extensions/OMEMO/OMEMOModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,12 @@ typedef NS_ENUM(NSUInteger, OMEMOModuleNamespace) {

#pragma mark Namespace methods

+ (NSString*) xmlnsOMEMO:(OMEMOModuleNamespace)ns;
+ (NSString*) xmlnsOMEMODeviceList:(OMEMOModuleNamespace)ns;
+ (NSString*) xmlnsOMEMODeviceListNotify:(OMEMOModuleNamespace)ns;
+ (NSString*) xmlnsOMEMOBundles:(OMEMOModuleNamespace)ns;
+ (NSString*) xmlnsOMEMOBundles:(OMEMOModuleNamespace)ns deviceId:(uint32_t)deviceId;
+ (NSString*) xmlnsOMEMO;
+ (NSString*) xmlnsOMEMODeviceList;
+ (NSString*) xmlnsOMEMODeviceListNotify;
+ (NSString*) xmlnsOMEMOBundles;

+ (NSString*) xmlnsOMEMO:(OMEMOModuleNamespace)ns __attribute__((deprecated("Use xmlnsOMEMO instead")));

@end

Expand Down
59 changes: 25 additions & 34 deletions Extensions/OMEMO/OMEMOModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ - (void) publishDeviceIds:(NSArray<NSNumber*>*)deviceIds elementId:(nullable NSS
__weak id weakMulticast = multicastDelegate;
[self performBlock:^{
NSString *eid = [self fixElementId:elementId];
XMPPIQ *iq = [XMPPIQ omemo_iqPublishDeviceIds:deviceIds elementId:eid xmlNamespace:self.xmlNamespace];
XMPPIQ *iq = [XMPPIQ omemo_iqPublishDeviceIds:deviceIds elementId:eid];
[self.tracker addElement:iq block:^(XMPPIQ *responseIq, id<XMPPTrackingInfo> info) {
__typeof__(self) strongSelf = weakSelf;
if (!strongSelf) { return; }
Expand Down Expand Up @@ -119,7 +119,7 @@ - (void) fetchDeviceIdsForJID:(XMPPJID*)jid
return;
}

NSArray<NSNumber *> *devices = [responseIq omemo_deviceListFromIqResponse:self.xmlNamespace];
NSArray<NSNumber *> *devices = [responseIq omemo_deviceListFromIqResponse];
if (!devices) {
devices = @[];
XMPPLogWarn(@"Missing devices from element: %@ %@", info.element, responseIq);
Expand All @@ -141,7 +141,7 @@ - (void) fetchDeviceIdsForJID:(nonnull XMPPJID*)jid
completion:(void (^_Nonnull)(XMPPIQ *responseIq, id<XMPPTrackingInfo> info))completion {
[self performBlock:^{
NSString *eid = [self fixElementId:elementId];
XMPPIQ *iq = [XMPPIQ omemo_iqFetchDeviceIdsForJID:jid elementId:eid xmlNamespace:self.xmlNamespace];
XMPPIQ *iq = [XMPPIQ omemo_iqFetchDeviceIdsForJID:jid elementId:eid];
[self.tracker addElement:iq block:completion timeout:30];
[self->xmppStream sendElement:iq];
}];
Expand All @@ -155,7 +155,7 @@ - (void) publishBundle:(OMEMOBundle*)bundle
__weak id weakMulticast = multicastDelegate;
[self performBlock:^{
NSString *eid = [self fixElementId:elementId];
XMPPIQ *iq = [XMPPIQ omemo_iqPublishBundle:bundle elementId:eid xmlNamespace:self.xmlNamespace];
XMPPIQ *iq = [XMPPIQ omemo_iqPublishBundle:bundle elementId:eid];
[self.tracker addElement:iq block:^(XMPPIQ *responseIq, id<XMPPTrackingInfo> info) {
__typeof__(self) strongSelf = weakSelf;
if (!strongSelf) { return; }
Expand All @@ -181,7 +181,7 @@ - (void) fetchBundleForDeviceId:(uint32_t)deviceId
__weak id weakMulticast = multicastDelegate;
[self performBlock:^{
NSString *eid = [self fixElementId:elementId];
XMPPIQ *iq = [XMPPIQ omemo_iqFetchBundleForDeviceId:deviceId jid:jid.bareJID elementId:eid xmlNamespace:self.xmlNamespace];
XMPPIQ *iq = [XMPPIQ omemo_iqFetchBundleForDeviceId:deviceId jid:jid.bareJID elementId:eid];
[self.tracker addElement:iq block:^(XMPPIQ *responseIq, id<XMPPTrackingInfo> info) {
__typeof__(self) strongSelf = weakSelf;
if (!strongSelf) { return; }
Expand All @@ -191,7 +191,7 @@ - (void) fetchBundleForDeviceId:(uint32_t)deviceId
[weakMulticast omemo:strongSelf failedToFetchBundleForDeviceId:deviceId fromJID:jid errorIq:responseIq outgoingIq:iq];
return;
}
OMEMOBundle *bundle = [responseIq omemo_bundle:strongSelf.xmlNamespace];
OMEMOBundle *bundle = [responseIq omemo_bundle];
if (bundle) {
[weakMulticast omemo:strongSelf fetchedBundle:bundle fromJID:jid responseIq:responseIq outgoingIq:iq];
} else {
Expand All @@ -218,7 +218,7 @@ - (void) removeDeviceIds:(NSArray<NSNumber*>*)deviceIds elementId:(NSString *)el
return;
}

NSArray<NSNumber *> *devices = [responseIq omemo_deviceListFromIqResponse:strongSelf.xmlNamespace];
NSArray<NSNumber *> *devices = [responseIq omemo_deviceListFromIqResponse];
NSIndexSet *indexSet = [devices indexesOfObjectsPassingTest:^BOOL(NSNumber * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
return [deviceIds containsObject:obj];
}];
Expand Down Expand Up @@ -277,7 +277,7 @@ - (void) receiveMessage:(XMPPMessage*)message forJID:(XMPPJID*)forJID isIncoming
return;
}
// Check for incoming device list updates
NSArray<NSNumber *> *deviceIds = [message omemo_deviceListFromPEPUpdate:self.xmlNamespace];
NSArray<NSNumber *> *deviceIds = [message omemo_deviceListFromPEPUpdate];
XMPPJID *bareJID = forJID.bareJID;
if (deviceIds && message == originalMessage) {
[multicastDelegate omemo:self deviceListUpdate:deviceIds fromJID:bareJID incomingElement:message];
Expand All @@ -301,37 +301,28 @@ - (void) receiveMessage:(XMPPMessage*)message forJID:(XMPPJID*)forJID isIncoming

#pragma mark Namespace methods

+ (NSString*) xmlnsOMEMO:(OMEMOModuleNamespace)ns {
if (ns == OMEMOModuleNamespaceOMEMO) {
return @"urn:xmpp:omemo:0";
} else { // OMEMOModuleNamespaceConversationsLegacy
return @"eu.siacs.conversations.axolotl";
}
+ (NSString*) xmlnsOMEMO {
return @"urn:xmpp:omemo:2";
}
+ (NSString*) xmlnsOMEMODeviceList:(OMEMOModuleNamespace)ns {
NSString *xmlns = [self xmlnsOMEMO:ns];
if (ns == OMEMOModuleNamespaceOMEMO) {
return [NSString stringWithFormat:@"%@:devicelist", xmlns];
} else { // OMEMOModuleNamespaceConversationsLegacy
return [NSString stringWithFormat:@"%@.devicelist", xmlns];
}

+ (NSString*) xmlnsOMEMODeviceList {
return [NSString stringWithFormat:@"%@:devices", [self xmlnsOMEMO]];
}
+ (NSString*) xmlnsOMEMODeviceListNotify:(OMEMOModuleNamespace)ns {
return [NSString stringWithFormat:@"%@+notify", [self xmlnsOMEMODeviceList:ns]];

+ (NSString*) xmlnsOMEMODeviceListNotify {
return [NSString stringWithFormat:@"%@+notify", [self xmlnsOMEMODeviceList]];
}

+ (NSString*) xmlnsOMEMOBundles {
return [NSString stringWithFormat:@"%@:bundles", [self xmlnsOMEMO]];
}
+ (NSString*) xmlnsOMEMOBundles:(OMEMOModuleNamespace)ns {
NSString *xmlns = [self xmlnsOMEMO:ns];

+ (NSString*) xmlnsOMEMO:(OMEMOModuleNamespace)ns {
if (ns == OMEMOModuleNamespaceOMEMO) {
xmlns = [NSString stringWithFormat:@"%@:bundles", xmlns];
return @"urn:xmpp:omemo:0";
} else { // OMEMOModuleNamespaceConversationsLegacy
xmlns = [NSString stringWithFormat:@"%@.bundles", xmlns];
return @"eu.siacs.conversations.axolotl";
}
NSParameterAssert(xmlns != nil);
return xmlns;
}

+ (NSString*) xmlnsOMEMOBundles:(OMEMOModuleNamespace)ns deviceId:(uint32_t)deviceId {
return [NSString stringWithFormat:@"%@:%d", [self xmlnsOMEMOBundles:ns], (int)deviceId];
}

#pragma mark XMPPStreamDelegate methods
Expand Down Expand Up @@ -395,7 +386,7 @@ - (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq {
#pragma mark XMPPCapabilitiesDelegate methods

- (NSArray<NSString*>*) myFeaturesForXMPPCapabilities:(XMPPCapabilities *)sender {
return @[[[self class] xmlnsOMEMODeviceList:self.xmlNamespace], [[self class] xmlnsOMEMODeviceListNotify:self.xmlNamespace]];
return @[[[self class] xmlnsOMEMODeviceList], [[self class] xmlnsOMEMODeviceListNotify]];
}

#pragma mark Utility
Expand Down
14 changes: 5 additions & 9 deletions Extensions/OMEMO/XMPPIQ+OMEMO.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,23 @@ NS_ASSUME_NONNULL_BEGIN

/** iq stanza for manually fetching deviceIds list. This should be handled automatically by PEP. */
+ (XMPPIQ*) omemo_iqFetchDeviceIdsForJID:(XMPPJID*)jid
elementId:(nullable NSString*)elementId
xmlNamespace:(OMEMOModuleNamespace)xmlNamespace;
elementId:(nullable NSString*)elementId;

/** iq stanza for publishing your device ids. The Device IDs are integers between 1 and 2^31 - 1 */
+ (XMPPIQ*) omemo_iqPublishDeviceIds:(NSArray<NSNumber*>*)deviceIds
elementId:(nullable NSString*)elementId
xmlNamespace:(OMEMOModuleNamespace)xmlNamespace;
elementId:(nullable NSString*)elementId;

/** iq stanza for publishing bundle for device */
+ (XMPPIQ*) omemo_iqPublishBundle:(OMEMOBundle*)bundle
elementId:(nullable NSString*)elementId
xmlNamespace:(OMEMOModuleNamespace)xmlNamespace;
elementId:(nullable NSString*)elementId;

/** iq stanza for fetching remote bundle */
+ (XMPPIQ*) omemo_iqFetchBundleForDeviceId:(uint32_t)deviceId
jid:(XMPPJID*)jid
elementId:(nullable NSString*)elementId
xmlNamespace:(OMEMOModuleNamespace)xmlNamespace;
elementId:(nullable NSString*)elementId;

/** Serialize bundle from IQ */
- (nullable OMEMOBundle*) omemo_bundle:(OMEMOModuleNamespace)ns;
- (nullable OMEMOBundle*) omemo_bundle;

@end
NS_ASSUME_NONNULL_END
Loading