@ -125,7 +125,7 @@ public final class OpenGroupAPI: NSObject {
)
return send ( request , using : dependencies )
. decoded ( as : responseTypes , on : OpenGroupAPI . workQueue , error : Error . parsingFailed )
. decoded ( as : responseTypes , on : OpenGroupAPI . workQueue , error : Error . parsingFailed , using : dependencies )
. map { result in
result . enumerated ( )
. reduce ( into : [ : ] ) { prev , next in
@ -156,7 +156,7 @@ public final class OpenGroupAPI: NSObject {
// TODO: H a n d l e a ` 4 1 2 ` r e s p o n s e ( i e . a r e q u i r e d c a p a b i l i t y i s n ' t s u p p o r t e d )
return send ( request , using : dependencies )
. decoded ( as : responseTypes , on : OpenGroupAPI . workQueue , error : Error . parsingFailed )
. decoded ( as : responseTypes , on : OpenGroupAPI . workQueue , error : Error . parsingFailed , using : dependencies )
. map { result in
result . enumerated ( )
. reduce ( into : [ : ] ) { prev , next in
@ -176,7 +176,7 @@ public final class OpenGroupAPI: NSObject {
// TODO: H a n d l e a ` 4 1 2 ` r e s p o n s e ( i e . a r e q u i r e d c a p a b i l i t y i s n ' t s u p p o r t e d )
return send ( request , using : dependencies )
. decoded ( as : Capabilities . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed )
. decoded ( as : Capabilities . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed , using : dependencies )
}
// MARK: - R o o m
@ -188,7 +188,7 @@ public final class OpenGroupAPI: NSObject {
)
return send ( request , using : dependencies )
. decoded ( as : [ Room ] . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed )
. decoded ( as : [ Room ] . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed , using : dependencies )
}
public static func room ( for roomToken : String , on server : String , using dependencies : Dependencies = Dependencies ( ) ) -> Promise < ( OnionRequestResponseInfoType , Room ) > {
@ -198,7 +198,7 @@ public final class OpenGroupAPI: NSObject {
)
return send ( request , using : dependencies )
. decoded ( as : Room . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed )
. decoded ( as : Room . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed , using : dependencies )
}
public static func roomPollInfo ( lastUpdated : Int64 , for roomToken : String , on server : String , using dependencies : Dependencies = Dependencies ( ) ) -> Promise < ( OnionRequestResponseInfoType , RoomPollInfo ) > {
@ -208,7 +208,7 @@ public final class OpenGroupAPI: NSObject {
)
return send ( request , using : dependencies )
. decoded ( as : RoomPollInfo . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed )
. decoded ( as : RoomPollInfo . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed , using : dependencies )
}
// MARK: - M e s s a g e s
@ -221,13 +221,13 @@ public final class OpenGroupAPI: NSObject {
whisperMods : Bool ,
using dependencies : Dependencies = Dependencies ( )
) -> Promise < ( OnionRequestResponseInfoType , Message ) > {
guard let sign edMessage: ( data : Data , signature : Data ) = sign ( message : plaintext , to : roomToken , on : server , using : dependencies ) else {
guard let sign Result: ( publicKey : String , signature : Bytes ) = sign ( plaintext . bytes , for : server , using : dependencies ) else {
return Promise ( error : Error . signingFailed )
}
let requestBody : SendMessageRequest = SendMessageRequest (
data : signedMessage. data ,
signature : signedMessage. signature ,
data : plaintext ,
signature : Data( signResult . signature ) ,
whisperTo : whisperTo ,
whisperMods : whisperMods ,
fileIds : nil // TODO: A d d s u p p o r t f o r ' f i l e I d s ' .
@ -245,7 +245,7 @@ public final class OpenGroupAPI: NSObject {
)
return send ( request , using : dependencies )
. decoded ( as : Message . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed )
. decoded ( as : Message . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed , using : dependencies )
}
public static func message ( _ id : Int64 , in roomToken : String , on server : String , using dependencies : Dependencies = Dependencies ( ) ) -> Promise < ( OnionRequestResponseInfoType , Message ) > {
@ -255,7 +255,7 @@ public final class OpenGroupAPI: NSObject {
)
return send ( request , using : dependencies )
. decoded ( as : Message . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed )
. decoded ( as : Message . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed , using : dependencies )
}
public static func messageUpdate (
@ -265,13 +265,13 @@ public final class OpenGroupAPI: NSObject {
on server : String ,
using dependencies : Dependencies = Dependencies ( )
) -> Promise < ( OnionRequestResponseInfoType , Data ? ) > {
guard let sign edMessage: ( data : Data , signature : Data ) = sign ( message : plaintext , to : roomToken , on : server , using : dependencies ) else {
guard let sign Result: ( publicKey : String , signature : Bytes ) = sign ( plaintext . bytes , for : server , using : dependencies ) else {
return Promise ( error : Error . signingFailed )
}
let requestBody : UpdateMessageRequest = UpdateMessageRequest (
data : signedMessage. data ,
signature : signedMessage. signature
data : plaintext ,
signature : Data( signResult . signature )
)
guard let body : Data = try ? JSONEncoder ( ) . encode ( requestBody ) else {
@ -302,7 +302,7 @@ public final class OpenGroupAPI: NSObject {
)
return send ( request , using : dependencies )
. decoded ( as : [ Message ] . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed )
. decoded ( as : [ Message ] . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed , using : dependencies )
}
// / T h i s i s t h e d i r e c t r e q u e s t t o r e t r i e v e r e c e n t m e s s a g e s f r o m a n O p e n G r o u p s o s h o u l d b e r e t r i e v e d a u t o m a t i c a l l y f r o m t h e ` p o l l ( ) `
@ -319,7 +319,7 @@ public final class OpenGroupAPI: NSObject {
)
return send ( request , using : dependencies )
. decoded ( as : [ Message ] . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed )
. decoded ( as : [ Message ] . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed , using : dependencies )
}
// / T h i s i s t h e d i r e c t r e q u e s t t o r e t r i e v e r e c e n t m e s s a g e s f r o m a n O p e n G r o u p s o s h o u l d b e r e t r i e v e d a u t o m a t i c a l l y f r o m t h e ` p o l l ( ) `
@ -335,7 +335,7 @@ public final class OpenGroupAPI: NSObject {
)
return send ( request , using : dependencies )
. decoded ( as : [ Message ] . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed )
. decoded ( as : [ Message ] . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed , using : dependencies )
}
// MARK: - P i n n i n g
@ -385,7 +385,7 @@ public final class OpenGroupAPI: NSObject {
)
return send ( request , using : dependencies )
. decoded ( as : FileUploadResponse . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed )
. decoded ( as : FileUploadResponse . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed , using : dependencies )
}
// / W a r n i n g : T h i s a p p r o a c h i s l e s s e f f i c i e n t a s i t e x p e c t s t h e d a t a t o b e b a s e 6 4 E n c o d e d ( w i t h i s 3 3 % l a r g e r t h a n b i n a r y ) , p l e a s e u s e t h e b i n a r y a p p r o a c h
@ -400,7 +400,7 @@ public final class OpenGroupAPI: NSObject {
)
return send ( request , using : dependencies )
. decoded ( as : FileUploadResponse . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed )
. decoded ( as : FileUploadResponse . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed , using : dependencies )
}
public static func downloadFile ( _ fileId : Int64 , from roomToken : String , on server : String , using dependencies : Dependencies = Dependencies ( ) ) -> Promise < ( OnionRequestResponseInfoType , Data ) > {
@ -424,7 +424,7 @@ public final class OpenGroupAPI: NSObject {
)
// TODO: T h i s e n d p o i n t i s g e t t i n g r e w r i t t e n t o r e t u r n j u s t d a t a ( p r o p e r t i e s w o u l d c o m e t h r o u g h a s h e a d e r s ) .
return send ( request , using : dependencies )
. decoded ( as : FileDownloadResponse . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed )
. decoded ( as : FileDownloadResponse . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed , using : dependencies )
}
// MARK: - I n b o x ( M e s s a g e R e q u e s t s )
@ -436,7 +436,7 @@ public final class OpenGroupAPI: NSObject {
)
return send ( request , using : dependencies )
. decoded ( as : [ DirectMessage ] . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed )
. decoded ( as : [ DirectMessage ] . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed , using : dependencies )
}
public static func messageRequestsSince ( id : Int64 , on server : String , using dependencies : Dependencies = Dependencies ( ) ) -> Promise < ( OnionRequestResponseInfoType , [ DirectMessage ] ) > {
@ -446,7 +446,7 @@ public final class OpenGroupAPI: NSObject {
)
return send ( request , using : dependencies )
. decoded ( as : [ DirectMessage ] . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed )
. decoded ( as : [ DirectMessage ] . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed , using : dependencies )
}
public static func sendMessageRequest ( _ plaintext : Data , to blindedSessionId : String , on server : String , with serverPublicKey : String , using dependencies : Dependencies = Dependencies ( ) ) -> Promise < ( OnionRequestResponseInfoType , [ DirectMessage ] ) > {
@ -471,7 +471,7 @@ public final class OpenGroupAPI: NSObject {
)
return send ( request , using : dependencies )
. decoded ( as : [ DirectMessage ] . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed )
. decoded ( as : [ DirectMessage ] . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed , using : dependencies )
}
// MARK: - U s e r s
@ -581,79 +581,45 @@ public final class OpenGroupAPI: NSObject {
)
return send ( request , using : dependencies )
. decoded ( as : UserDeleteMessagesResponse . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed )
. decoded ( as : UserDeleteMessagesResponse . self , on : OpenGroupAPI . workQueue , error : Error . parsingFailed , using : dependencies )
}
// MARK: - A u t h e n t i c a t i o n
// / S i g n a m e s s a g e t o b e s e n t t o S O G S ( h a n d l e s b o t h u n - b l i n d e d a n d b l i n d e d s i g n i n g b a s e d o n t h e s e r v e r c a p a b i l i t i e s )
public static func sign ( message : Data , to roomToken : String , on serverName : String , using dependencies : Dependencies = Dependencies ( ) ) -> ( data : Data , signature : Data ) ? {
public static func sign ( _ messageBytes : Bytes , for serverName : String , using dependencies : Dependencies = Dependencies ( ) ) -> ( publicKey : String , signature : Bytes ) ? {
guard let userEdKeyPair : Box . KeyPair = dependencies . storage . getUserED25519KeyPair ( ) else { return nil }
guard let serverPublicKey : String = dependencies . storage . getOpenGroupPublicKey ( for : serverName ) else {
return nil
}
let server : Server ? = dependencies . storage . getOpenGroupServer ( name : serverName )
let targetKeyPair : ECKeyPair
// D e t e r m i n e i f w e w a n t t o s i g n u s i n g s t a n d a r d o r b l i n d e d k e y s b a s e d o n t h e s e r v e r c a p a b i l i t i e s ( a s s u m e
// u n b l i n d e d i f w e h a v e n o n e )
// TODO: R e m o v e t h i s ( b l i n d i n g w i l l b e r e q u i r e d )
// C h e c k i f t h e s e r v e r s u p p o r t s b l i n d e d k e y s , i f s o t h e n s i g n u s i n g t h e b l i n d e d k e y
if server ? . capabilities . capabilities . contains ( . blinding ) = = true {
// TODO: V a l i d a t e t h i s ' o p e n G r o u p I d ' i s c o r r e c t f o r t h e ' g e t O p e n G r o u p ' c a l l
let openGroupId : String = " \( serverName ) . \( roomToken ) "
guard let blindedKeyPair : Box . KeyPair = dependencies . sodium . blindedKeyPair ( serverPublicKey : serverPublicKey , edKeyPair : userEdKeyPair , genericHash : dependencies . genericHash ) else {
return nil
}
// TODO: V a l i d a t e t h i s i s t h e c o r r e c t l o g i c ( M o s t l i k e l y n o t )
guard let openGroup : OpenGroup = Storage . shared . getOpenGroup ( for : openGroupId ) else { return nil }
guard let userEdKeyPair : Box . KeyPair = dependencies . storage . getUserED25519KeyPair ( ) else { return nil }
guard let blindedKeyPair : Box . KeyPair = dependencies . sodium . blindedKeyPair ( serverPublicKey : openGroup . publicKey , edKeyPair : userEdKeyPair , genericHash : dependencies . genericHash ) else {
guard let signatureResult : Bytes = dependencies . sodium . sogsSignature ( message : messageBytes , secretKey : userEdKeyPair . secretKey , blindedSecretKey : blindedKeyPair . secretKey , blindedPublicKey : blindedKeyPair . publicKey ) else {
return nil
}
targetKeyPair = blindedKeyPair
}
else {
guard let userKeyPair : ECKeyPair = dependencies . storage . getUserKeyPair ( ) else { return nil }
targetKeyPair = userKeyPair
}
guard let signature = try ? Ed25519 . sign ( message , with : targetKeyPair ) else {
SNLog ( " Failed to sign open group message. " )
return nil
}
return ( message , signature )
}
// / S i g n a b l i n d e d m e s s a g e r e q u e s t t o b e s e n t t o a u s e r s i n b o x v i a S O G S v 4
private static func sign ( message : Data , to blindedSessionId : String , on serverName : String , with serverPublicKey : String , using dependencies : Dependencies = Dependencies ( ) ) -> Data ? {
guard let userEdKeyPair : Box . KeyPair = dependencies . storage . getUserED25519KeyPair ( ) else { return nil }
guard let blindedKeyPair : BlindedECKeyPair = dependencies . sodium . blindedKeyPair ( serverPublicKey : serverPublicKey , edKeyPair : userEdKeyPair , genericHash : dependencies . genericHash ) else {
return nil
}
guard let blindedRecipientPublicKey : Data = String ( blindedSessionId . suffix ( from : blindedSessionId . index ( blindedSessionId . startIndex , offsetBy : IdPrefix . blinded . rawValue . count ) ) ) . dataFromHex ( ) else {
return nil
return (
publicKey : IdPrefix . blinded . hexEncodedPublicKey ( for : blindedKeyPair . publicKey ) ,
signature : signatureResult
)
}
// / G e n e r a t e t h e s h a r e d S e c r e t b y " a k B | | k A | | k B " w h e r e
// / a , A a r e t h e u s e r s p r i v a t e a n d p u b l i c k e y s r e s p e c t i v e l y ,
// / k A i s t h e u s e r s b l i n d e d p u b l i c k e y
// / k B i s t h e r e c i p i e n t s b l i n d e d p u b l i c k e y
let maybeSharedSecret : Data ? = dependencies . sodium
. sharedEdSecret ( userEdKeyPair . secretKey , blindedRecipientPublicKey . bytes ) ?
. appending ( blindedKeyPair . publicKey . bytes )
. appending ( blindedRecipientPublicKey . bytes )
guard let sharedSecret : Data = maybeSharedSecret else { return nil }
guard let intermediateHash : Bytes = dependencies . genericHash . hash ( message : sharedSecret . bytes ) else { return nil }
// / G e n e r a t e t h e i n n e r m e s s a g e b y " m e s s a g e | | A " w h e r e
// / A i s t h e s e n d e r ' s e d 2 5 5 1 9 m a s t e r p u b k e y ( * * n o t * * k A b l i n d e d p u b k e y )
let innerMessage : Bytes = ( message . bytes + userEdKeyPair . publicKey )
guard let ( ciphertext , nonce ) = dependencies . aeadXChaCha20Poly1305Ietf . encrypt ( message : innerMessage , secretKey : intermediateHash ) else {
// O t h e r w i s e f a l l b a c k t o s i g n u s i n g t h e u n b l i n d e d k e y
guard let signatureResult : Bytes = dependencies . sign . signature ( message : messageBytes , secretKey : userEdKeyPair . secretKey ) else {
return nil
}
// / G e n e r a t e t h e f i n a l d a t a b y " b ' \ x 0 0 ' + c i p h e r t e x t + n o n c e "
let finalData : Bytes = [ 0 ] + ciphertext + nonce
return Data ( finalData )
return (
publicKey : IdPrefix . unblinded . hexEncodedPublicKey ( for : userEdKeyPair . publicKey ) ,
signature : signatureResult
)
}
// / S i g n a r e q u e s t t o b e s e n t t o S O G S ( h a n d l e s b o t h u n - b l i n d e d a n d b l i n d e d s i g n i n g b a s e d o n t h e s e r v e r c a p a b i l i t i e s )
@ -666,13 +632,9 @@ public final class OpenGroupAPI: NSObject {
let method : String = ( request . httpMethod ? ? " GET " )
let timestamp : Int = Int ( floor ( dependencies . date . timeIntervalSince1970 ) )
let nonce : Data = Data ( dependencies . nonceGenerator . nonce ( ) )
let server : Server ? = dependencies . storage . getOpenGroupServer ( name : serverName )
let userPublicKeyHex : String
let signatureBytes : Bytes
guard let serverPublicKeyData : Data = serverPublicKey . dataFromHex ( ) else { return nil }
guard let timestampBytes : Bytes = " \( timestamp ) " . data ( using : . ascii ) ? . bytes else { return nil }
guard let userEdKeyPair : Box . KeyPair = dependencies . storage . getUserED25519KeyPair ( ) else { return nil }
// / G e t a h a s h o f a n y b o d y c o n t e n t
let bodyHash : Bytes ? = {
@ -693,51 +655,24 @@ public final class OpenGroupAPI: NSObject {
// / ` M e t h o d `
// / ` P a t h `
// / ` B o d y ` i s a B l a k e 2 b h a s h o f t h e d a t a ( i f t h e r e i s a b o d y )
let signatureM essageBytes: Bytes = serverPublicKeyData . bytes
let m essageBytes: Bytes = serverPublicKeyData . bytes
. appending ( nonce . bytes )
. appending ( timestampBytes )
. appending ( method . bytes )
. appending ( path . bytes )
. appending ( bodyHash ? ? [ ] )
// D e t e r m i n e i f w e w a n t t o s i g n u s i n g s t a n d a r d o r b l i n d e d k e y s b a s e d o n t h e s e r v e r c a p a b i l i t i e s ( a s s u m e
// u n b l i n d e d i f w e h a v e n o n e )
// TODO: R e m o v e t h i s ( b l i n d i n g w i l l b e r e q u i r e d )
if server ? . capabilities . capabilities . contains ( . blinding ) = = true {
// TODO: M o r e t e s t i n g o f t h i s b l i n d e d i d s i g n i n g ( t h o u g h i t s e e m s t o b e w o r k i n g ! ! ! )
guard let blindedKeyPair : Box . KeyPair = dependencies . sodium . blindedKeyPair ( serverPublicKey : serverPublicKey , edKeyPair : userEdKeyPair , genericHash : dependencies . genericHash ) else {
return nil
}
userPublicKeyHex = IdPrefix . blinded . hexEncodedPublicKey ( for : blindedKeyPair . publicKey )
guard let signatureResult : Bytes = Sodium ( ) . sogsSignature ( message : signatureMessageBytes , secretKey : userEdKeyPair . secretKey , blindedSecretKey : blindedKeyPair . secretKey , blindedPublicKey : blindedKeyPair . publicKey ) else {
return nil
}
signatureBytes = signatureResult
}
else {
userPublicKeyHex = IdPrefix . unblinded . hexEncodedPublicKey ( for : userEdKeyPair . publicKey )
// TODO: s h i f t t h i s t o d e p e n d e n c i e s
guard let signatureResult : Bytes = Sodium ( ) . sign . signature ( message : signatureMessageBytes , secretKey : userEdKeyPair . secretKey ) else {
return nil
}
signatureBytes = signatureResult
// / S i g n t h e a b o v e m e s s a g e
guard let signResult : ( publicKey : String , signature : Bytes ) = sign ( messageBytes , for : serverName , using : dependencies ) else {
return nil
}
print ( " RAWR X-SOGS-Pubkey: \( userPublicKeyHex ) " )
print ( " RAWR X-SOGS-Timestamp: \( timestamp ) " )
print ( " RAWR X-SOGS-Nonce: \( nonce . base64EncodedString ( ) ) " )
print ( " RAWR X-SOGS-Signature: \( signatureBytes . toBase64 ( ) ) " )
updatedRequest . allHTTPHeaderFields = ( request . allHTTPHeaderFields ? ? [ : ] )
. updated ( with : [
Header . sogsPubKey . rawValue : userPublicKeyHex ,
Header . sogsPubKey . rawValue : signResult . publicKey ,
Header . sogsTimestamp . rawValue : " \( timestamp ) " ,
Header . sogsNonce . rawValue : nonce . base64EncodedString ( ) ,
Header . sogsSignature . rawValue : sign atureBytes . toBase64 ( )
Header . sogsSignature . rawValue : signResult . signature . toBase64 ( )
] )
return updatedRequest
@ -756,7 +691,7 @@ public final class OpenGroupAPI: NSObject {
urlRequest . httpBody = request . body
if request . useOnionRouting {
guard let publicKey = SNMessagingKitConfiguration. shared . storage . getOpenGroupPublicKey ( for : request . server ) else {
guard let publicKey = dependencies . storage . getOpenGroupPublicKey ( for : request . server ) else {
return Promise ( error : Error . noPublicKey )
}