@ -55,6 +55,7 @@ import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid ;
import eu.siacs.conversations.xmpp.pep.PublishOptions ;
import eu.siacs.conversations.xmpp.stanzas.IqPacket ;
import eu.siacs.conversations.xmpp.stanzas.MessagePacket ;
public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
@ -77,11 +78,12 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
private final Map < Jid , Set < Integer > > deviceIds ;
private final Map < String , XmppAxolotlMessage > messageCache ;
private final FetchStatusMap fetchStatusMap ;
private final HashMap < Jid , List < OnDeviceIdsFetched > > fetchDeviceIdsMap = new HashMap < > ( ) ;
private final HashMap < Jid , List < OnDeviceIdsFetched > > fetchDeviceIdsMap = new HashMap < > ( ) ;
private final SerialSingleThreadExecutor executor ;
private int numPublishTriesOnEmptyPep = 0 ;
private boolean pepBroken = false ;
private int lastDeviceListNotificationHash = 0 ;
private Set < XmppAxolotlSession > postponedSessions = new HashSet < > ( ) ; / / sessions stored here will receive after mam catchup treatment
private AtomicBoolean changeAccessMode = new AtomicBoolean ( false ) ;
@ -92,12 +94,12 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
& & account . getXmppConnection ( ) . getFeatures ( ) . pep ( ) ) {
publishBundlesIfNeeded ( true , false ) ;
} else {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : skipping OMEMO initialization " ) ;
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : skipping OMEMO initialization " ) ;
}
}
public boolean fetchMapHasErrors ( List < Jid > jids ) {
for ( Jid jid : jids ) {
for ( Jid jid : jids ) {
if ( deviceIds . get ( jid ) ! = null ) {
for ( Integer foreignId : this . deviceIds . get ( jid ) ) {
SignalProtocolAddress address = new SignalProtocolAddress ( jid . toPreppedString ( ) , foreignId ) ;
@ -119,7 +121,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
}
public boolean hasVerifiedKeys ( String name ) {
for ( XmppAxolotlSession session : this . sessions . getAll ( name ) . values ( ) ) {
for ( XmppAxolotlSession session : this . sessions . getAll ( name ) . values ( ) ) {
if ( session . getTrust ( ) . isVerified ( ) ) {
return true ;
}
@ -194,14 +196,14 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
for ( Integer deviceId : deviceIds ) {
SignalProtocolAddress axolotlAddress = new SignalProtocolAddress ( bareJid , deviceId ) ;
IdentityKey identityKey = store . loadSession ( axolotlAddress ) . getSessionState ( ) . getRemoteIdentityKey ( ) ;
if ( Config . X509_VERIFICATION ) {
if ( Config . X509_VERIFICATION ) {
X509Certificate certificate = store . getFingerprintCertificate ( CryptoHelper . bytesToHex ( identityKey . getPublicKey ( ) . serialize ( ) ) ) ;
if ( certificate ! = null ) {
Bundle information = CryptoHelper . extractCertificateInformation ( certificate ) ;
try {
final String cn = information . getString ( " subject_cn " ) ;
final Jid jid = Jid . fromString ( bareJid ) ;
Log . d ( Config . LOGTAG , " setting common name for " + jid + " to " + cn ) ;
Log . d ( Config . LOGTAG , " setting common name for " + jid + " to " + cn ) ;
account . getRoster ( ) . getContact ( jid ) . setCommonName ( cn ) ;
} catch ( final InvalidJidException ignored ) {
/ / ignored
@ -215,7 +217,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
private void fillMap ( SQLiteAxolotlStore store ) {
List < Integer > deviceIds = store . getSubDeviceSessions ( account . getJid ( ) . toBareJid ( ) . toPreppedString ( ) ) ;
putDevicesForJid ( account . getJid ( ) . toBareJid ( ) . toPreppedString ( ) , deviceIds , store ) ;
for ( String address : store . getKnownAddresses ( ) ) {
for ( String address : store . getKnownAddresses ( ) ) {
deviceIds = store . getSubDeviceSessions ( address ) ;
putDevicesForJid ( address , deviceIds , store ) ;
}
@ -249,9 +251,9 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
if ( devices = = null ) {
return ;
}
for ( Map . Entry < Integer , FetchStatus > entry : devices . entrySet ( ) ) {
for ( Map . Entry < Integer , FetchStatus > entry : devices . entrySet ( ) ) {
if ( entry . getValue ( ) = = FetchStatus . ERROR ) {
Log . d ( Config . LOGTAG , " resetting error for " + jid . toBareJid ( ) + " ( " + entry . getKey ( ) + " ) " ) ;
Log . d ( Config . LOGTAG , " resetting error for " + jid . toBareJid ( ) + " ( " + entry . getKey ( ) + " ) " ) ;
entry . setValue ( FetchStatus . TIMEOUT ) ;
}
}
@ -294,7 +296,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
public Set < IdentityKey > getKeysWithTrust ( FingerprintStatus status , List < Jid > jids ) {
Set < IdentityKey > keys = new HashSet < > ( ) ;
for ( Jid jid : jids ) {
for ( Jid jid : jids ) {
keys . addAll ( axolotlStore . getContactKeysWithTrust ( jid . toPreppedString ( ) , status ) ) ;
}
return keys ;
@ -305,7 +307,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
}
public boolean anyTargetHasNoTrustedKeys ( List < Jid > jids ) {
for ( Jid jid : jids ) {
for ( Jid jid : jids ) {
if ( axolotlStore . getContactNumTrustedKeys ( jid . toBareJid ( ) . toPreppedString ( ) ) = = 0 ) {
return true ;
}
@ -325,7 +327,6 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
}
public Collection < XmppAxolotlSession > findSessionsForContact ( Contact contact ) {
SignalProtocolAddress contactAddress = getAddressForJid ( contact . getJid ( ) ) ;
ArrayList < XmppAxolotlSession > s = new ArrayList < > ( this . sessions . getAll ( contactAddress . getName ( ) ) . values ( ) ) ;
@ -335,7 +336,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
private Set < XmppAxolotlSession > findSessionsForConversation ( Conversation conversation ) {
HashSet < XmppAxolotlSession > sessions = new HashSet < > ( ) ;
for ( Jid jid : conversation . getAcceptedCryptoTargets ( ) ) {
for ( Jid jid : conversation . getAcceptedCryptoTargets ( ) ) {
sessions . addAll ( this . sessions . getAll ( getAddressForJid ( jid ) . getName ( ) ) . values ( ) ) ;
}
return sessions ;
@ -368,13 +369,13 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
}
public void destroy ( ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : destroying old axolotl service. no longer in use " ) ;
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : destroying old axolotl service. no longer in use " ) ;
mXmppConnectionService . databaseBackend . wipeAxolotlDb ( account ) ;
}
public AxolotlService makeNew ( ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : make new axolotl service " ) ;
return new AxolotlService ( this . account , this . mXmppConnectionService ) ;
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : make new axolotl service " ) ;
return new AxolotlService ( this . account , this . mXmppConnectionService ) ;
}
public int getOwnDeviceId ( ) {
@ -382,7 +383,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
}
public SignalProtocolAddress getOwnAxolotlAddress ( ) {
return new SignalProtocolAddress ( account . getJid ( ) . toBareJid ( ) . toPreppedString ( ) , getOwnDeviceId ( ) ) ;
return new SignalProtocolAddress ( account . getJid ( ) . toBareJid ( ) . toPreppedString ( ) , getOwnDeviceId ( ) ) ;
}
public Set < Integer > getOwnDeviceIds ( ) {
@ -420,7 +421,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
XmppAxolotlSession session = sessions . get ( address ) ;
if ( session ! = null & & session . getFingerprint ( ) ! = null ) {
if ( ! session . getTrust ( ) . isActive ( ) ) {
Log . d ( Config . LOGTAG , " reactivating device with fingerprint " + session . getFingerprint ( ) ) ;
Log . d ( Config . LOGTAG , " reactivating device with fingerprint " + session . getFingerprint ( ) ) ;
session . setTrust ( session . getTrust ( ) . toActive ( ) ) ;
}
}
@ -462,7 +463,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
public void distrustFingerprint ( final String fingerprint ) {
final String fp = fingerprint . replaceAll ( " \\ s " , " " ) ;
final FingerprintStatus fingerprintStatus = axolotlStore . getFingerprintStatus ( fp ) ;
axolotlStore . setFingerprintStatus ( fp , fingerprintStatus . toUntrusted ( ) ) ;
axolotlStore . setFingerprintStatus ( fp , fingerprintStatus . toUntrusted ( ) ) ;
}
public void publishOwnDeviceIdIfNeeded ( ) {
@ -479,8 +480,8 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
} else {
Element item = mXmppConnectionService . getIqParser ( ) . getItem ( packet ) ;
Set < Integer > deviceIds = mXmppConnectionService . getIqParser ( ) . deviceIds ( item ) ;
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : retrieved own device list: " + deviceIds ) ;
registerDevices ( account . getJid ( ) . toBareJid ( ) , deviceIds ) ;
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : retrieved own device list: " + deviceIds ) ;
registerDevices ( account . getJid ( ) . toBareJid ( ) , deviceIds ) ;
}
}
} ) ;
@ -488,18 +489,18 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
private Set < Integer > getExpiredDevices ( ) {
Set < Integer > devices = new HashSet < > ( ) ;
for ( XmppAxolotlSession session : findOwnSessions ( ) ) {
for ( XmppAxolotlSession session : findOwnSessions ( ) ) {
if ( session . getTrust ( ) . isActive ( ) ) {
long diff = System . currentTimeMillis ( ) - session . getTrust ( ) . getLastActivation ( ) ;
if ( diff > Config . OMEMO_AUTO_EXPIRY ) {
long lastMessageDiff = System . currentTimeMillis ( ) - mXmppConnectionService . databaseBackend . getLastTimeFingerprintUsed ( account , session . getFingerprint ( ) ) ;
long hours = Math . round ( lastMessageDiff / ( 1000 * 60 . 0 * 60 . 0 ) ) ;
long lastMessageDiff = System . currentTimeMillis ( ) - mXmppConnectionService . databaseBackend . getLastTimeFingerprintUsed ( account , session . getFingerprint ( ) ) ;
long hours = Math . round ( lastMessageDiff / ( 1000 * 60 . 0 * 60 . 0 ) ) ;
if ( lastMessageDiff > Config . OMEMO_AUTO_EXPIRY ) {
devices . add ( session . getRemoteAddress ( ) . getDeviceId ( ) ) ;
session . setTrust ( session . getTrust ( ) . toInactive ( ) ) ;
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : added own device " + session . getFingerprint ( ) + " to list of expired devices. Last message received " + hours + " hours ago " ) ;
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : added own device " + session . getFingerprint ( ) + " to list of expired devices. Last message received " + hours + " hours ago " ) ;
} else {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : own device " + session . getFingerprint ( ) + " was active " + hours + " hours ago " ) ;
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : own device " + session . getFingerprint ( ) + " was active " + hours + " hours ago " ) ;
}
}
}
@ -527,7 +528,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
}
private void publishDeviceIdsAndRefineAccessModel ( Set < Integer > ids ) {
publishDeviceIdsAndRefineAccessModel ( ids , true ) ;
publishDeviceIdsAndRefineAccessModel ( ids , true ) ;
}
private void publishDeviceIdsAndRefineAccessModel ( final Set < Integer > ids , final boolean firstAttempt ) {
@ -537,8 +538,8 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
Element error = packet . getType ( ) = = IqPacket . TYPE . ERROR ? packet . findChild ( " error " ) : null ;
if ( firstAttempt & & error ! = null & & error . hasChild ( " precondition-not-met " , Namespace . PUBSUB_ERROR ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : precondition wasn't met for device list. pushing node configuration " ) ;
if ( firstAttempt & & error ! = null & & error . hasChild ( " precondition-not-met " , Namespace . PUBSUB_ERROR ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : precondition wasn't met for device list. pushing node configuration " ) ;
mXmppConnectionService . pushNodeConfiguration ( account , AxolotlService . PEP_DEVICE_LIST , publishOptions , new XmppConnectionService . OnConfigurationPushed ( ) {
@Override
public void onPushSucceeded ( ) {
@ -551,9 +552,9 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
}
} ) ;
} else {
if ( AxolotlService . this . changeAccessMode . compareAndSet ( true , false ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : done changing access mode " ) ;
account . setOption ( Account . OPTION_REQUIRES_ACCESS_MODE_CHANGE , false ) ;
if ( AxolotlService . this . changeAccessMode . compareAndSet ( true , false ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : done changing access mode " ) ;
account . setOption ( Account . OPTION_REQUIRES_ACCESS_MODE_CHANGE , false ) ;
mXmppConnectionService . databaseBackend . updateAccount ( account ) ;
}
if ( packet . getType ( ) = = IqPacket . TYPE . ERROR ) {
@ -566,39 +567,39 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
}
public void publishDeviceVerificationAndBundle ( final SignedPreKeyRecord signedPreKeyRecord ,
final Set < PreKeyRecord > preKeyRecords ,
final boolean announceAfter ,
final boolean wipe ) {
final Set < PreKeyRecord > preKeyRecords ,
final boolean announceAfter ,
final boolean wipe ) {
try {
IdentityKey axolotlPublicKey = axolotlStore . getIdentityKeyPair ( ) . getPublicKey ( ) ;
PrivateKey x509PrivateKey = KeyChain . getPrivateKey ( mXmppConnectionService , account . getPrivateKeyAlias ( ) ) ;
X509Certificate [ ] chain = KeyChain . getCertificateChain ( mXmppConnectionService , account . getPrivateKeyAlias ( ) ) ;
Signature verifier = Signature . getInstance ( " sha256WithRSA " ) ;
verifier . initSign ( x509PrivateKey , mXmppConnectionService . getRNG ( ) ) ;
verifier . initSign ( x509PrivateKey , mXmppConnectionService . getRNG ( ) ) ;
verifier . update ( axolotlPublicKey . serialize ( ) ) ;
byte [ ] signature = verifier . sign ( ) ;
IqPacket packet = mXmppConnectionService . getIqGenerator ( ) . publishVerification ( signature , chain , getOwnDeviceId ( ) ) ;
Log . d ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " : publish verification for device " + getOwnDeviceId ( ) ) ;
Log . d ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " : publish verification for device " + getOwnDeviceId ( ) ) ;
mXmppConnectionService . sendIqPacket ( account , packet , new OnIqPacketReceived ( ) {
@Override
public void onIqPacketReceived ( final Account account , IqPacket packet ) {
String node = AxolotlService . PEP_VERIFICATION + " : " + getOwnDeviceId ( ) ;
String node = AxolotlService . PEP_VERIFICATION + " : " + getOwnDeviceId ( ) ;
mXmppConnectionService . pushNodeConfiguration ( account , node , PublishOptions . openAccess ( ) , new XmppConnectionService . OnConfigurationPushed ( ) {
@Override
public void onPushSucceeded ( ) {
Log . d ( Config . LOGTAG , getLogprefix ( account ) + " configured verification node to be world readable " ) ;
Log . d ( Config . LOGTAG , getLogprefix ( account ) + " configured verification node to be world readable " ) ;
publishDeviceBundle ( signedPreKeyRecord , preKeyRecords , announceAfter , wipe ) ;
}
@Override
public void onPushFailed ( ) {
Log . d ( Config . LOGTAG , getLogprefix ( account ) + " unable to set access model on verification node " ) ;
Log . d ( Config . LOGTAG , getLogprefix ( account ) + " unable to set access model on verification node " ) ;
publishDeviceBundle ( signedPreKeyRecord , preKeyRecords , announceAfter , wipe ) ;
}
} ) ;
}
} ) ;
} catch ( Exception e ) {
} catch ( Exception e ) {
e . printStackTrace ( ) ;
}
}
@ -612,7 +613,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
if ( account . getXmppConnection ( ) . getFeatures ( ) . pepPublishOptions ( ) ) {
this . changeAccessMode . set ( account . isOptionSet ( Account . OPTION_REQUIRES_ACCESS_MODE_CHANGE ) ) ;
} else {
if ( account . setOption ( Account . OPTION_REQUIRES_ACCESS_MODE_CHANGE , true ) ) {
if ( account . setOption ( Account . OPTION_REQUIRES_ACCESS_MODE_CHANGE , true ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : server doesn’ t support publish-options. setting for later access mode change " ) ;
mXmppConnectionService . databaseBackend . updateAccount ( account ) ;
}
@ -728,38 +729,38 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
}
private void publishDeviceBundle ( SignedPreKeyRecord signedPreKeyRecord ,
Set < PreKeyRecord > preKeyRecords ,
final boolean announceAfter ,
final boolean wipe ) {
publishDeviceBundle ( signedPreKeyRecord , preKeyRecords , announceAfter , wipe , true ) ;
Set < PreKeyRecord > preKeyRecords ,
final boolean announceAfter ,
final boolean wipe ) {
publishDeviceBundle ( signedPreKeyRecord , preKeyRecords , announceAfter , wipe , true ) ;
}
private void publishDeviceBundle ( final SignedPreKeyRecord signedPreKeyRecord ,
final Set < PreKeyRecord > preKeyRecords ,
final boolean announceAfter ,
final boolean wipe ,
final boolean firstAttempt ) {
final Set < PreKeyRecord > preKeyRecords ,
final boolean announceAfter ,
final boolean wipe ,
final boolean firstAttempt ) {
final Bundle publishOptions = account . getXmppConnection ( ) . getFeatures ( ) . pepPublishOptions ( ) ? PublishOptions . openAccess ( ) : null ;
IqPacket publish = mXmppConnectionService . getIqGenerator ( ) . publishBundles (
signedPreKeyRecord , axolotlStore . getIdentityKeyPair ( ) . getPublicKey ( ) ,
preKeyRecords , getOwnDeviceId ( ) , publishOptions ) ;
preKeyRecords , getOwnDeviceId ( ) , publishOptions ) ;
Log . d ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " : Bundle " + getOwnDeviceId ( ) + " in PEP not current. Publishing... " ) ;
mXmppConnectionService . sendIqPacket ( account , publish , new OnIqPacketReceived ( ) {
@Override
public void onIqPacketReceived ( final Account account , IqPacket packet ) {
Element error = packet . getType ( ) = = IqPacket . TYPE . ERROR ? packet . findChild ( " error " ) : null ;
if ( firstAttempt & & error ! = null & & error . hasChild ( " precondition-not-met " , Namespace . PUBSUB_ERROR ) ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : precondition wasn't met for bundle. pushing node configuration " ) ;
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : precondition wasn't met for bundle. pushing node configuration " ) ;
final String node = AxolotlService . PEP_BUNDLES + " : " + getOwnDeviceId ( ) ;
mXmppConnectionService . pushNodeConfiguration ( account , node , publishOptions , new XmppConnectionService . OnConfigurationPushed ( ) {
@Override
public void onPushSucceeded ( ) {
publishDeviceBundle ( signedPreKeyRecord , preKeyRecords , announceAfter , wipe , false ) ;
publishDeviceBundle ( signedPreKeyRecord , preKeyRecords , announceAfter , wipe , false ) ;
}
@Override
public void onPushFailed ( ) {
publishDeviceBundle ( signedPreKeyRecord , preKeyRecords , announceAfter , wipe , false ) ;
publishDeviceBundle ( signedPreKeyRecord , preKeyRecords , announceAfter , wipe , false ) ;
}
} ) ;
} else if ( packet . getType ( ) = = IqPacket . TYPE . RESULT ) {
@ -790,16 +791,16 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
return conversation . getMode ( ) = = Conversation . MODE_SINGLE | | ( conversation . getMucOptions ( ) . nonanonymous ( ) & & conversation . getMucOptions ( ) . membersOnly ( ) ) ;
}
public Pair < AxolotlCapability , Jid > isConversationAxolotlCapableDetailed ( Conversation conversation ) {
public Pair < AxolotlCapability , Jid > isConversationAxolotlCapableDetailed ( Conversation conversation ) {
if ( conversation . getMode ( ) = = Conversation . MODE_SINGLE
| | ( conversation . getMucOptions ( ) . membersOnly ( ) & & conversation . getMucOptions ( ) . nonanonymous ( ) ) ) {
final List < Jid > jids = getCryptoTargets ( conversation ) ;
for ( Jid jid : jids ) {
for ( Jid jid : jids ) {
if ( ! hasAny ( jid ) & & ( ! deviceIds . containsKey ( jid ) | | deviceIds . get ( jid ) . isEmpty ( ) ) ) {
if ( conversation . getAccount ( ) . getRoster ( ) . getContact ( jid ) . mutualPresenceSubscription ( ) ) {
return new Pair < > ( AxolotlCapability . MISSING_KEYS , jid ) ;
return new Pair < > ( AxolotlCapability . MISSING_KEYS , jid ) ;
} else {
return new Pair < > ( AxolotlCapability . MISSING_PRESENCE , jid ) ;
return new Pair < > ( AxolotlCapability . MISSING_PRESENCE , jid ) ;
}
}
}
@ -845,7 +846,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
mXmppConnectionService . sendIqPacket ( account , packet , new OnIqPacketReceived ( ) {
@Override
public void onIqPacketReceived ( Account account , IqPacket packet ) {
Pair < X509Certificate [ ] , byte [ ] > verification = mXmppConnectionService . getIqParser ( ) . verification ( packet ) ;
Pair < X509Certificate [ ] , byte [ ] > verification = mXmppConnectionService . getIqParser ( ) . verification ( packet ) ;
if ( verification ! = null ) {
try {
Signature verifier = Signature . getInstance ( " sha256WithRSA " ) ;
@ -855,7 +856,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
try {
mXmppConnectionService . getMemorizingTrustManager ( ) . getNonInteractive ( ) . checkClientTrusted ( verification . first , " RSA " ) ;
String fingerprint = session . getFingerprint ( ) ;
Log . d ( Config . LOGTAG , " verified session with x.509 signature. fingerprint was: " + fingerprint ) ;
Log . d ( Config . LOGTAG , " verified session with x.509 signature. fingerprint was: " + fingerprint ) ;
setFingerprintTrust ( fingerprint , FingerprintStatus . createActiveVerified ( true ) ) ;
axolotlStore . setFingerprintCertificate ( fingerprint , verification . first [ 0 ] ) ;
fetchStatusMap . put ( address , FetchStatus . SUCCESS_VERIFIED ) ;
@ -863,7 +864,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
try {
final String cn = information . getString ( " subject_cn " ) ;
final Jid jid = Jid . fromString ( address . getName ( ) ) ;
Log . d ( Config . LOGTAG , " setting common name for " + jid + " to " + cn ) ;
Log . d ( Config . LOGTAG , " setting common name for " + jid + " to " + cn ) ;
account . getRoster ( ) . getContact ( jid ) . setCommonName ( cn ) ;
} catch ( final InvalidJidException ignored ) {
/ / ignored
@ -871,14 +872,14 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
finishBuildingSessionsFromPEP ( address ) ;
return ;
} catch ( Exception e ) {
Log . d ( Config . LOGTAG , " could not verify certificate " ) ;
Log . d ( Config . LOGTAG , " could not verify certificate " ) ;
}
}
} catch ( Exception e ) {
Log . d ( Config . LOGTAG , " error during verification " + e . getMessage ( ) ) ;
}
} else {
Log . d ( Config . LOGTAG , " no verification found " ) ;
Log . d ( Config . LOGTAG , " no verification found " ) ;
}
fetchStatusMap . put ( address , FetchStatus . SUCCESS ) ;
finishBuildingSessionsFromPEP ( address ) ;
@ -938,7 +939,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
}
public void fetchDeviceIds ( final Jid jid ) {
fetchDeviceIds ( jid , null ) ;
fetchDeviceIds ( jid , null ) ;
}
public void fetchDeviceIds ( final Jid jid , OnDeviceIdsFetched callback ) {
@ -948,14 +949,14 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
if ( callback ! = null ) {
callbacks . add ( callback ) ;
}
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : fetching device ids for " + jid + " already running. adding callback " ) ;
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : fetching device ids for " + jid + " already running. adding callback " ) ;
} else {
callbacks = new ArrayList < > ( ) ;
if ( callback ! = null ) {
callbacks . add ( callback ) ;
}
this . fetchDeviceIdsMap . put ( jid , callbacks ) ;
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : fetching device ids for " + jid ) ;
this . fetchDeviceIdsMap . put ( jid , callbacks ) ;
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : fetching device ids for " + jid ) ;
IqPacket packet = mXmppConnectionService . getIqGenerator ( ) . retrieveDeviceIds ( jid ) ;
mXmppConnectionService . sendIqPacket ( account , packet , new OnIqPacketReceived ( ) {
@Override
@ -967,14 +968,14 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
Set < Integer > deviceIds = mXmppConnectionService . getIqParser ( ) . deviceIds ( item ) ;
registerDevices ( jid , deviceIds ) ;
if ( callbacks ! = null ) {
for ( OnDeviceIdsFetched callback : callbacks ) {
for ( OnDeviceIdsFetched callback : callbacks ) {
callback . fetched ( jid , deviceIds ) ;
}
}
} else {
Log . d ( Config . LOGTAG , packet . toString ( ) ) ;
if ( callbacks ! = null ) {
for ( OnDeviceIdsFetched callback : callbacks ) {
for ( OnDeviceIdsFetched callback : callbacks ) {
callback . fetched ( jid , null ) ;
}
}
@ -1086,7 +1087,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
public Set < SignalProtocolAddress > findDevicesWithoutSession ( final Conversation conversation ) {
Set < SignalProtocolAddress > addresses = new HashSet < > ( ) ;
for ( Jid jid : getCryptoTargets ( conversation ) ) {
for ( Jid jid : getCryptoTargets ( conversation ) ) {
Log . d ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " Finding devices without session for " + jid ) ;
if ( deviceIds . get ( jid ) ! = null ) {
for ( Integer foreignId : this . deviceIds . get ( jid ) ) {
@ -1126,7 +1127,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
if ( fetchStatusMap . get ( address ) ! = FetchStatus . ERROR ) {
addresses . add ( address ) ;
} else {
Log . d ( Config . LOGTAG , getLogprefix ( account ) + " skipping over " + address + " because it's broken " ) ;
Log . d ( Config . LOGTAG , getLogprefix ( account ) + " skipping over " + address + " because it's broken " ) ;
}
}
}
@ -1138,13 +1139,13 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
public boolean createSessionsIfNeeded ( final Conversation conversation ) {
final List < Jid > jidsWithEmptyDeviceList = getCryptoTargets ( conversation ) ;
for ( Iterator < Jid > iterator = jidsWithEmptyDeviceList . iterator ( ) ; iterator . hasNext ( ) ; ) {
for ( Iterator < Jid > iterator = jidsWithEmptyDeviceList . iterator ( ) ; iterator . hasNext ( ) ; ) {
final Jid jid = iterator . next ( ) ;
if ( ! hasEmptyDeviceList ( jid ) ) {
iterator . remove ( ) ;
}
}
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : createSessionsIfNeeded() - jids with empty device list: " + jidsWithEmptyDeviceList ) ;
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : createSessionsIfNeeded() - jids with empty device list: " + jidsWithEmptyDeviceList ) ;
if ( jidsWithEmptyDeviceList . size ( ) > 0 ) {
fetchDeviceIds ( jidsWithEmptyDeviceList , new OnMultipleDeviceIdFetched ( ) {
@Override
@ -1183,7 +1184,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
Set < XmppAxolotlSession > sessions = findSessionsForConversation ( conversation ) ;
sessions . addAll ( findOwnSessions ( ) ) ;
boolean verified = false ;
for ( XmppAxolotlSession session : sessions ) {
for ( XmppAxolotlSession session : sessions ) {
if ( session . getTrust ( ) . isTrustedAndActive ( ) ) {
if ( session . getTrust ( ) . getTrust ( ) = = FingerprintStatus . Trust . VERIFIED_X509 ) {
verified = true ;
@ -1243,7 +1244,8 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
Log . w ( Config . LOGTAG , getLogprefix ( account ) + " Failed to encrypt message: " + e . getMessage ( ) ) ;
return null ;
}
if ( ! buildHeader ( axolotlMessage , message . getConversation ( ) ) ) {
/ / TODO : fix this for MUC PMs - Don ' t encrypt to all participants
if ( ! buildHeader ( axolotlMessage , message . getConversation ( ) ) ) {
return null ;
}
@ -1272,7 +1274,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
@Override
public void run ( ) {
final XmppAxolotlMessage axolotlMessage = new XmppAxolotlMessage ( account . getJid ( ) . toBareJid ( ) , getOwnDeviceId ( ) ) ;
if ( buildHeader ( axolotlMessage , conversation ) ) {
if ( buildHeader ( axolotlMessage , conversation ) ) {
onMessageCreatedCallback . run ( axolotlMessage ) ;
} else {
onMessageCreatedCallback . run ( null ) ;
@ -1324,7 +1326,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
postPreKeyMessageHandling ( session , preKeyId , postponePreKeyMessageHandling ) ;
}
} catch ( CryptoFailedException e ) {
Log . w ( Config . LOGTAG , getLogprefix ( account ) + " Failed to decrypt message from " + message . getFrom ( ) + " : " + e . getMessage ( ) ) ;
Log . w ( Config . LOGTAG , getLogprefix ( account ) + " Failed to decrypt message from " + message . getFrom ( ) + " : " + e . getMessage ( ) ) ;
}
if ( session . isFresh ( ) & & plaintextMessage ! = null ) {
@ -1335,11 +1337,39 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
}
private void postPreKeyMessageHandling ( final XmppAxolotlSession session , int preKeyId , final boolean postpone ) {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : postPreKeyMessageHandling() preKeyId= " + preKeyId + " , postpone= " + Boolean . toString ( postpone ) ) ;
/ / TODO : do not republish if we already removed this preKeyId
publishBundlesIfNeeded ( false , false ) ;
if ( postpone ) {
postponedSessions . add ( session ) ;
} else {
/ / TODO : do not republish if we already removed this preKeyId
publishBundlesIfNeeded ( false , false ) ;
completeSession ( session ) ;
}
}
public void processPostponed ( ) {
if ( postponedSessions . size ( ) > 0 ) {
publishBundlesIfNeeded ( false , false ) ;
}
Iterator < XmppAxolotlSession > iterator = postponedSessions . iterator ( ) ;
while ( iterator . hasNext ( ) ) {
completeSession ( iterator . next ( ) ) ;
iterator . remove ( ) ;
}
}
private void completeSession ( XmppAxolotlSession session ) {
final XmppAxolotlMessage axolotlMessage = new XmppAxolotlMessage ( account . getJid ( ) . toBareJid ( ) , getOwnDeviceId ( ) ) ;
axolotlMessage . addDevice ( session ) ;
try {
Jid jid = Jid . fromString ( session . getRemoteAddress ( ) . getName ( ) ) ;
MessagePacket packet = mXmppConnectionService . getMessageGenerator ( ) . generateKeyTransportMessage ( jid , axolotlMessage ) ;
mXmppConnectionService . sendMessagePacket ( account , packet ) ;
} catch ( InvalidJidException e ) {
throw new Error ( " Remote addresses are created from jid and should convert back to jid " , e ) ;
}
}
public XmppAxolotlMessage . XmppAxolotlKeyTransportMessage processReceivingKeyTransportMessage ( XmppAxolotlMessage message , final boolean postponePreKeyMessageHandling ) {
XmppAxolotlMessage . XmppAxolotlKeyTransportMessage keyTransportMessage ;
@ -1351,7 +1381,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
postPreKeyMessageHandling ( session , preKeyId , postponePreKeyMessageHandling ) ;
}
} catch ( CryptoFailedException e ) {
Log . d ( Config . LOGTAG , " could not decrypt keyTransport message " + e . getMessage ( ) ) ;
Log . d ( Config . LOGTAG , " could not decrypt keyTransport message " + e . getMessage ( ) ) ;
keyTransportMessage = null ;
}
@ -1363,13 +1393,13 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
}
private void putFreshSession ( XmppAxolotlSession session ) {
Log . d ( Config . LOGTAG , " put fresh session " ) ;
Log . d ( Config . LOGTAG , " put fresh session " ) ;
sessions . put ( session ) ;
if ( Config . X509_VERIFICATION ) {
if ( session . getIdentityKey ( ) ! = null ) {
verifySessionWithPEP ( session ) ;
} else {
Log . e ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : identity key was empty after reloading for x509 verification " ) ;
Log . e ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : identity key was empty after reloading for x509 verification " ) ;
}
}
}