2019-11-07 18:54:41 +11:00
//
// F e e d l y R e f r e s h A c c e s s T o k e n O p e r a t i o n . s w i f t
// A c c o u n t
//
// C r e a t e d b y K i e l G i l l a r d o n 4 / 1 1 / 1 9 .
// C o p y r i g h t © 2 0 1 9 R a n c h e r o S o f t w a r e , L L C . A l l r i g h t s r e s e r v e d .
//
import Foundation
import os . log
import RSWeb
2020-04-09 21:07:56 -05:00
import Secrets
2019-11-07 18:54:41 +11:00
final class FeedlyRefreshAccessTokenOperation : FeedlyOperation {
2020-01-19 14:19:06 -08:00
2019-11-07 18:54:41 +11:00
let service : OAuthAccessTokenRefreshing
let oauthClient : OAuthAuthorizationClient
let account : Account
let log : OSLog
2020-04-19 08:31:20 +10:00
// / T h e m o m e n t t h e r e f r e s h i s b e i n g r e q u e s t e d . T h e t o k e n w i l l r e f r e s h o n l y i f t h e a c c o u n t ' s ` l a s t C r e d e n t i a l R e n e w T i m e ` i s n o t o n t h e s a m e d a y a s t h i s m o m e n t . W h e n n i l , t h e o p e r a t i o n w i l l a l w a y s r e f r e s h t h e t o k e n .
let refreshDate : Date ?
init ( account : Account , service : OAuthAccessTokenRefreshing , oauthClient : OAuthAuthorizationClient , refreshDate : Date ? , log : OSLog ) {
2019-11-07 18:54:41 +11:00
self . oauthClient = oauthClient
self . service = service
self . account = account
2020-04-19 08:31:20 +10:00
self . refreshDate = refreshDate
2019-11-07 18:54:41 +11:00
self . log = log
}
2020-01-15 21:30:37 -08:00
override func run ( ) {
2020-04-19 08:31:20 +10:00
// O n l y r e f r e s h t h e t o k e n i f t h e s e d a t e s a r e n o t o n t h e s a m e d a y .
let shouldRefresh : Bool = {
guard let date = refreshDate , let lastRenewDate = account . metadata . lastCredentialRenewTime else {
return true
}
return ! Calendar . current . isDate ( lastRenewDate , equalTo : date , toGranularity : . day )
} ( )
guard shouldRefresh else {
2020-04-19 08:45:51 +10:00
os_log ( . debug , log : log , " Skipping access token renewal. " )
2020-04-19 08:31:20 +10:00
didFinish ( )
return
}
2019-11-07 18:54:41 +11:00
let refreshToken : Credentials
do {
guard let credentials = try account . retrieveCredentials ( type : . oauthRefreshToken ) else {
os_log ( . debug , log : log , " Could not find a refresh token in the keychain. Check the refresh token is added to the Keychain, remove the account and add it again. " )
throw TransportError . httpError ( status : 403 )
}
refreshToken = credentials
} catch {
2020-01-19 14:19:06 -08:00
didFinish ( with : error )
2019-11-07 18:54:41 +11:00
return
}
os_log ( . debug , log : log , " Refreshing access token. " )
// I g n o r e c a n c e l l a t i o n a f t e r t h e r e q u e s t i s r e s u m e d o t h e r w i s e w e m a y c o n t i n u e s t o r i n g a p o t e n t i a l l y i n v a l i d t o k e n !
service . refreshAccessToken ( with : refreshToken . secret , client : oauthClient ) { result in
self . didRefreshAccessToken ( result )
}
}
private func didRefreshAccessToken ( _ result : Result < OAuthAuthorizationGrant , Error > ) {
assert ( Thread . isMainThread )
switch result {
case . success ( let grant ) :
do {
os_log ( . debug , log : log , " Storing refresh token. " )
// S t o r e t h e r e f r e s h t o k e n f i r s t b e c a u s e i t s e n d s t h i s t o k e n t o t h e a c c o u n t d e l e g a t e .
if let token = grant . refreshToken {
try account . storeCredentials ( token )
}
os_log ( . debug , log : log , " Storing access token. " )
// N o w s t o r e t h e a c c e s s t o k e n b e c a u s e w e w a n t t h e a c c o u n t d e l e g a t e t o u s e i t .
try account . storeCredentials ( grant . accessToken )
2020-04-19 08:31:20 +10:00
account . metadata . lastCredentialRenewTime = Date ( )
2019-11-07 18:54:41 +11:00
didFinish ( )
} catch {
2020-01-19 14:19:06 -08:00
didFinish ( with : error )
2019-11-07 18:54:41 +11:00
}
case . failure ( let error ) :
2020-01-19 14:19:06 -08:00
didFinish ( with : error )
2019-11-07 18:54:41 +11:00
}
}
}