mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			124 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Swift
		
	
		
		
			
		
	
	
			124 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Swift
		
	
| 
											8 years ago
										 | // | ||
|  | //  Copyright (c) 2017 Open Whisper Systems. All rights reserved. | ||
|  | // | ||
|  | 
 | ||
|  | import Foundation | ||
|  | import PromiseKit | ||
| 
											8 years ago
										 | import SignalServiceKit | ||
| 
											8 years ago
										 | 
 | ||
| 
											8 years ago
										 | @objc | ||
|  | public class OWS106EnsureProfileComplete: OWSDatabaseMigration { | ||
| 
											8 years ago
										 | 
 | ||
|  |     let TAG = "[OWS106EnsureProfileComplete]" | ||
|  | 
 | ||
| 
											8 years ago
										 |     private static var sharedCompleteRegistrationFixerJob: CompleteRegistrationFixerJob? | ||
|  | 
 | ||
| 
											8 years ago
										 |     // increment a similar constant for each migration. | ||
|  |     class func migrationId() -> String { | ||
|  |         return "106" | ||
|  |     } | ||
|  | 
 | ||
|  |     // Overriding runUp since we have some specific completion criteria which | ||
|  |     // is more likely to fail since it involves network requests. | ||
| 
											8 years ago
										 |     override public func runUp() { | ||
| 
											8 years ago
										 |         guard type(of: self).sharedCompleteRegistrationFixerJob == nil else { | ||
|  |             owsFail("\(self.TAG) should only be called once.") | ||
|  |             return | ||
|  |         } | ||
|  | 
 | ||
|  |         let job = CompleteRegistrationFixerJob(completionHandler: { | ||
| 
											8 years ago
										 |             Logger.info("\(self.TAG) Completed. Saving.") | ||
|  |             self.save() | ||
| 
											8 years ago
										 |         }) | ||
|  | 
 | ||
|  |         type(of: self).sharedCompleteRegistrationFixerJob = job | ||
|  | 
 | ||
|  |         job.start() | ||
| 
											8 years ago
										 |     } | ||
|  | 
 | ||
|  |     /**
 | ||
|  |      * A previous client bug made it possible for re-registering users to register their new account | ||
|  |      * but never upload new pre-keys. The symptom is that there will be accounts with no uploaded | ||
|  |      * identity key. We detect that here and fix the situation | ||
|  |      */ | ||
|  |     private class CompleteRegistrationFixerJob { | ||
|  | 
 | ||
|  |         let TAG = "[CompleteRegistrationFixerJob]" | ||
|  | 
 | ||
|  |         // Duration between retries if update fails. | ||
|  |         static let kRetryInterval: TimeInterval = 5 * 60 | ||
|  | 
 | ||
|  |         var timer: Timer? | ||
|  |         let completionHandler: () -> Void | ||
|  | 
 | ||
| 
											8 years ago
										 |         init(completionHandler: @escaping () -> Void) { | ||
| 
											8 years ago
										 |             self.completionHandler = completionHandler | ||
|  |         } | ||
|  | 
 | ||
|  |         func start() { | ||
|  |             assert(self.timer == nil) | ||
|  | 
 | ||
| 
											8 years ago
										 |             let timer = WeakTimer.scheduledTimer(timeInterval: CompleteRegistrationFixerJob.kRetryInterval, target: self, userInfo: nil, repeats: true) { [weak self] aTimer in | ||
| 
											8 years ago
										 |                 guard let strongSelf = self else { | ||
|  |                     return | ||
|  |                 } | ||
|  | 
 | ||
|  |                 var isCompleted = false | ||
|  |                 strongSelf.ensureProfileComplete().then { _ -> Void in | ||
|  |                     guard isCompleted == false else { | ||
|  |                         Logger.info("Already saved. Skipping redundant call.") | ||
|  |                         return | ||
|  |                     } | ||
|  |                     Logger.info("\(strongSelf.TAG) complete. Canceling timer and saving.") | ||
|  |                     isCompleted = true | ||
| 
											8 years ago
										 |                     aTimer.invalidate() | ||
| 
											8 years ago
										 |                     strongSelf.completionHandler() | ||
|  |                 }.catch { error in | ||
|  |                     Logger.error("\(strongSelf.TAG) failed with \(error). We'll try again in \(CompleteRegistrationFixerJob.kRetryInterval) seconds.") | ||
|  |                 }.retainUntilComplete() | ||
|  |             } | ||
|  |             self.timer = timer | ||
|  | 
 | ||
|  |             timer.fire() | ||
|  |         } | ||
|  | 
 | ||
|  |         func ensureProfileComplete() -> Promise<Void> { | ||
|  |             guard let localRecipientId = TSAccountManager.localNumber() else { | ||
|  |                 // local app doesn't think we're registered, so nothing to worry about. | ||
|  |                 return Promise(value: ()) | ||
|  |             } | ||
|  | 
 | ||
|  |             let (promise, fulfill, reject) = Promise<Void>.pending() | ||
|  | 
 | ||
| 
											8 years ago
										 |             guard let networkManager = Environment.current().networkManager else { | ||
| 
											8 years ago
										 |                 owsFail("\(TAG) network manager was unexpectedly not set") | ||
|  |                 return Promise(error: OWSErrorMakeAssertionError()) | ||
|  |             } | ||
|  | 
 | ||
|  |             ProfileFetcherJob(networkManager: networkManager).getProfile(recipientId: localRecipientId).then { _ -> Void in | ||
|  |                 Logger.info("\(self.TAG) verified recipient profile is in good shape: \(localRecipientId)") | ||
|  | 
 | ||
|  |                 fulfill() | ||
|  |             }.catch { error in | ||
|  |                 switch error { | ||
|  |                 case SignalServiceProfile.ValidationError.invalidIdentityKey(let description): | ||
|  |                     Logger.warn("\(self.TAG) detected incomplete profile for \(localRecipientId) error: \(description)") | ||
|  |                     // This is the error condition we're looking for. Update prekeys to properly set the identity key, completing registration. | ||
|  |                     TSPreKeyManager.registerPreKeys(with: .signedAndOneTime, | ||
|  |                                                     success: { | ||
|  |                                                         Logger.info("\(self.TAG) successfully uploaded pre-keys. Profile should be fixed.") | ||
|  |                                                         fulfill() | ||
|  |                     }, | ||
|  |                                                     failure: { _ in | ||
|  |                                                         reject(OWSErrorWithCodeDescription(.signalServiceFailure, "\(self.TAG) Unknown error in \(#function)")) | ||
|  |                     }) | ||
|  |                 default: | ||
|  |                     reject(error) | ||
|  |                 } | ||
|  |             }.retainUntilComplete() | ||
|  | 
 | ||
|  |             return promise | ||
|  |         } | ||
|  |     } | ||
|  | } |