Skip to content

Commit

Permalink
Merge pull request #1319 from matrix-org/langleyd/5292_refresh_tokens
Browse files Browse the repository at this point in the history
SDK: Refresh Token implementation
  • Loading branch information
langleyd authored Jan 31, 2022
2 parents 6ce9d8f + 4660b34 commit cd839f5
Show file tree
Hide file tree
Showing 34 changed files with 807 additions and 367 deletions.
20 changes: 20 additions & 0 deletions MatrixSDK.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,12 @@
3AF85F9226FC7AE800A9E67B /* MXSpaceNotificationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF85F9126FC7AE800A9E67B /* MXSpaceNotificationState.swift */; };
3AF85F9326FC7AE800A9E67B /* MXSpaceNotificationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF85F9126FC7AE800A9E67B /* MXSpaceNotificationState.swift */; };
3B60DCAB92D470B91262BF0C /* libPods-MatrixSDKTests-macOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 15D7F292D95EB58AEE801C4E /* libPods-MatrixSDKTests-macOS.a */; };
66398BA527A4085B00466E89 /* MXRefreshResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 66398BA427A4085B00466E89 /* MXRefreshResponse.m */; };
66398BA627A4085B00466E89 /* MXRefreshResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 66398BA427A4085B00466E89 /* MXRefreshResponse.m */; };
66AC9D23278CE627002E9B8F /* MXRefreshTokenData.h in Headers */ = {isa = PBXBuildFile; fileRef = 66AC9D21278CE626002E9B8F /* MXRefreshTokenData.h */; };
66AC9D24278CE627002E9B8F /* MXRefreshTokenData.h in Headers */ = {isa = PBXBuildFile; fileRef = 66AC9D21278CE626002E9B8F /* MXRefreshTokenData.h */; };
66AC9D25278CE627002E9B8F /* MXRefreshTokenData.m in Sources */ = {isa = PBXBuildFile; fileRef = 66AC9D22278CE626002E9B8F /* MXRefreshTokenData.m */; };
66AC9D26278CE627002E9B8F /* MXRefreshTokenData.m in Sources */ = {isa = PBXBuildFile; fileRef = 66AC9D22278CE626002E9B8F /* MXRefreshTokenData.m */; };
71DE22E01BC7C51200284153 /* MXReceiptData.m in Sources */ = {isa = PBXBuildFile; fileRef = 71DE22DC1BC7C51200284153 /* MXReceiptData.m */; };
71DE22E11BC7C51200284153 /* MXReceiptData.h in Headers */ = {isa = PBXBuildFile; fileRef = 71DE22DD1BC7C51200284153 /* MXReceiptData.h */; settings = {ATTRIBUTES = (Public, ); }; };
8EC511042568216B00EC4E5B /* MXTaggedEventInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 8EC511022568216B00EC4E5B /* MXTaggedEventInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -2247,6 +2253,10 @@
3AF85F9126FC7AE800A9E67B /* MXSpaceNotificationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MXSpaceNotificationState.swift; sourceTree = "<group>"; };
492C3485159D57C2116EDCBD /* Pods-SDK-MatrixSDK-macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDK-MatrixSDK-macOS.debug.xcconfig"; path = "Target Support Files/Pods-SDK-MatrixSDK-macOS/Pods-SDK-MatrixSDK-macOS.debug.xcconfig"; sourceTree = "<group>"; };
6257D945D115DA658F44E8D4 /* Pods-SDK-MatrixSDK-macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDK-MatrixSDK-macOS.release.xcconfig"; path = "Target Support Files/Pods-SDK-MatrixSDK-macOS/Pods-SDK-MatrixSDK-macOS.release.xcconfig"; sourceTree = "<group>"; };
66398BA427A4085B00466E89 /* MXRefreshResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXRefreshResponse.m; sourceTree = "<group>"; };
66398BA727A408C000466E89 /* MXRefreshResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXRefreshResponse.h; sourceTree = "<group>"; };
66AC9D21278CE626002E9B8F /* MXRefreshTokenData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXRefreshTokenData.h; sourceTree = "<group>"; };
66AC9D22278CE626002E9B8F /* MXRefreshTokenData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXRefreshTokenData.m; sourceTree = "<group>"; };
6869D206EA7C7FB05EAB75B0 /* Pods-MatrixSDKTests-iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MatrixSDKTests-iOS.release.xcconfig"; path = "Target Support Files/Pods-MatrixSDKTests-iOS/Pods-MatrixSDKTests-iOS.release.xcconfig"; sourceTree = "<group>"; };
71DE22DC1BC7C51200284153 /* MXReceiptData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXReceiptData.m; sourceTree = "<group>"; };
71DE22DD1BC7C51200284153 /* MXReceiptData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXReceiptData.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2751,6 +2761,8 @@
F082946C1DB66C3D00CEAB63 /* MXInvite3PID.m */,
327137251A24D50A00DB6757 /* MXMyUser.h */,
327137261A24D50A00DB6757 /* MXMyUser.m */,
66AC9D21278CE626002E9B8F /* MXRefreshTokenData.h */,
66AC9D22278CE626002E9B8F /* MXRefreshTokenData.m */,
ECD2899726EB3C7A00F268CF /* MXRoomSummaryProtocol.h */,
ECD289A426EB97E800F268CF /* MXRoomSummaryDataTypes.h */,
ECD289B326F9F00E00F268CF /* MXRoomSummarySentStatus.h */,
Expand Down Expand Up @@ -3372,6 +3384,8 @@
B14EECD42577DE4400448735 /* Login */,
3281E8B319E42DFE00976E1A /* MXJSONModel.h */,
3281E8B419E42DFE00976E1A /* MXJSONModel.m */,
66398BA727A408C000466E89 /* MXRefreshResponse.h */,
66398BA427A4085B00466E89 /* MXRefreshResponse.m */,
3281E8B519E42DFE00976E1A /* MXJSONModels.h */,
3281E8B619E42DFE00976E1A /* MXJSONModels.m */,
323E0C591A306D7A00A31D73 /* MXEvent.h */,
Expand Down Expand Up @@ -4663,6 +4677,7 @@
3297912E23AA126500F7BB9B /* MXKeyVerificationStatusResolver.h in Headers */,
3245A7521AF7B2930001D8A7 /* MXCallManager.h in Headers */,
32B94E05228EE90300716A26 /* MXRealmReactionRelation.h in Headers */,
66AC9D23278CE627002E9B8F /* MXRefreshTokenData.h in Headers */,
C6FE1EF01E65C4F7008587E4 /* MXAnalyticsDelegate.h in Headers */,
92634B7F1EF2A37A00DB9F60 /* MXCallAudioSessionConfigurator.h in Headers */,
323F8864212D4E470001C73C /* MXMatrixVersions.h in Headers */,
Expand Down Expand Up @@ -4958,6 +4973,7 @@
324AAC812399143400380A66 /* MXKeyVerificationKey.h in Headers */,
B1798D0724091A0100308A8F /* MXBase64Tools.h in Headers */,
B14EF29D2397E90400758AF0 /* MXRealmEventScan.h in Headers */,
66AC9D24278CE627002E9B8F /* MXRefreshTokenData.h in Headers */,
323F8774255460B5009E9E67 /* MXProfiler.h in Headers */,
EC8A53B425B1BC77004E0802 /* MXUserModel.h in Headers */,
32CEEF4423AD2A6C0039BA98 /* MXCrossSigningKey.h in Headers */,
Expand Down Expand Up @@ -5580,6 +5596,7 @@
F03EF4FF1DF014D9009DF592 /* MXMediaLoader.m in Sources */,
320A8841217F4E3F002EA952 /* MXMegolmBackupAuthData.m in Sources */,
B1A0270226162110001AADFF /* MXSpaceChildrenResponse.m in Sources */,
66398BA527A4085B00466E89 /* MXRefreshResponse.m in Sources */,
327E9AF72289D53800A98BC1 /* MXReactionCount.m in Sources */,
32FFB4F1217E146A00C96002 /* MXRecoveryKey.m in Sources */,
32DC15D51A8CF874006F9AD3 /* MXPushRuleEventMatchConditionChecker.m in Sources */,
Expand Down Expand Up @@ -5726,6 +5743,7 @@
1838927A2702F553003F0C4F /* MXSendReplyEventDefaultStringLocalizer.m in Sources */,
EC0B941E27186C3500B4D440 /* MXRoomListDataSortable.swift in Sources */,
32581DEA23C8C0C900832EAA /* MXUserTrustLevel.m in Sources */,
66AC9D25278CE627002E9B8F /* MXRefreshTokenData.m in Sources */,
3271878A1DA7DCE50071C818 /* MXOlmEncryption.m in Sources */,
327187861DA7D0220071C818 /* MXOlmDecryption.m in Sources */,
EC383BA8253DE6EE002FBBE6 /* MXSyncResponseFileStore.swift in Sources */,
Expand Down Expand Up @@ -6073,6 +6091,7 @@
B14EF1DF2397E90400758AF0 /* MXAggregatedEditsUpdater.m in Sources */,
B14EF1E02397E90400758AF0 /* MXRealmCryptoStore.m in Sources */,
B14EF1E12397E90400758AF0 /* MXRoomSummary.m in Sources */,
66398BA627A4085B00466E89 /* MXRefreshResponse.m in Sources */,
B14EF1E22397E90400758AF0 /* MXPushRuleRoomMemberCountConditionChecker.m in Sources */,
B14EF1E32397E90400758AF0 /* MXCall.m in Sources */,
B14EF1E42397E90400758AF0 /* MXWellknownIntegrations.m in Sources */,
Expand Down Expand Up @@ -6219,6 +6238,7 @@
1838927B2702F553003F0C4F /* MXSendReplyEventDefaultStringLocalizer.m in Sources */,
EC0B941F27186C3500B4D440 /* MXRoomListDataSortable.swift in Sources */,
EC8A539825B1BC77004E0802 /* MXCallReplacesEventContent.m in Sources */,
66AC9D26278CE627002E9B8F /* MXRefreshTokenData.m in Sources */,
B18B0E6825FBDC3000E32151 /* MXSpace.swift in Sources */,
B14EF22D2397E90400758AF0 /* MXRealmReactionCount.m in Sources */,
B14EF22E2397E90400758AF0 /* MXCryptoTools.m in Sources */,
Expand Down
4 changes: 2 additions & 2 deletions MatrixSDK/Background/MXBackgroundSyncService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public enum MXBackgroundSyncServiceError: Error {

/// Initializer
/// - Parameter credentials: account credentials
public init(withCredentials credentials: MXCredentials) {
public init(withCredentials credentials: MXCredentials, persistTokenDataHandler: MXRestClientPersistTokenDataHandler? = nil, unauthenticatedHandler: MXRestClientUnauthenticatedHandler? = nil) {
processingQueue = DispatchQueue(label: "MXBackgroundSyncServiceQueue-" + MXTools.generateSecret())
self.credentials = credentials

Expand All @@ -76,7 +76,7 @@ public enum MXBackgroundSyncServiceError: Error {
let syncResponseStore = MXSyncResponseFileStore(withCredentials: credentials)
syncResponseStoreManager = MXSyncResponseStoreManager(syncResponseStore: syncResponseStore)

restClient = MXRestClient(credentials: credentials, unrecognizedCertificateHandler: nil)
restClient = MXRestClient(credentials: credentials, unrecognizedCertificateHandler: nil, persistentTokenDataHandler: persistTokenDataHandler, unauthenticatedHandler: unauthenticatedHandler)
restClient.completionQueue = processingQueue
store = MXBackgroundStore(withCredentials: credentials)
// We can flush any crypto data if our sync response store is empty
Expand Down
4 changes: 0 additions & 4 deletions MatrixSDK/Contrib/Swift/MXEnumConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -211,10 +211,6 @@ extension MXSessionState: CustomStringConvertible {
return "pauseRequested"
case .initialSyncFailed:
return "initialSyncFailed"
case .unknownToken:
return "unknownToken"
case .softLogout:
return "softLogout"
@unknown default:
return "\(self.rawValue)"
}
Expand Down
4 changes: 2 additions & 2 deletions MatrixSDK/Contrib/Swift/MXRestClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ public extension MXRestClient {
- returns: a `MXRestClient` instance.
*/
@nonobjc convenience init(credentials: MXCredentials, unrecognizedCertificateHandler handler: MXHTTPClientOnUnrecognizedCertificate?) {
self.init(__credentials: credentials, andOnUnrecognizedCertificateBlock: handler)
@nonobjc convenience init(credentials: MXCredentials, unrecognizedCertificateHandler handler: MXHTTPClientOnUnrecognizedCertificate? = nil, persistentTokenDataHandler: MXRestClientPersistTokenDataHandler? = nil, unauthenticatedHandler: MXRestClientUnauthenticatedHandler? = nil) {
self.init(__credentials: credentials, andOnUnrecognizedCertificateBlock: handler, andPersistentTokenDataHandler: persistentTokenDataHandler, andUnauthenticatedHandler: unauthenticatedHandler)
}


Expand Down
2 changes: 1 addition & 1 deletion MatrixSDK/Crypto/MXCrypto.m
Original file line number Diff line number Diff line change
Expand Up @@ -1915,7 +1915,7 @@ - (instancetype)initWithMatrixSession:(MXSession*)matrixSession cryptoQueue:(dis
_deviceList = [[MXDeviceList alloc] initWithCrypto:self];

// Use our own REST client that answers on the crypto thread
_matrixRestClient = [[MXRestClient alloc] initWithCredentials:_mxSession.matrixRestClient.credentials andOnUnrecognizedCertificateBlock:nil];
_matrixRestClient = [[MXRestClient alloc] initWithCredentials:_mxSession.matrixRestClient.credentials andOnUnrecognizedCertificateBlock:nil andPersistentTokenDataHandler:_mxSession.matrixRestClient.persistTokenDataHandler andUnauthenticatedHandler:_mxSession.matrixRestClient.unauthenticatedHandler];
_matrixRestClient.completionQueue = _cryptoQueue;

roomEncryptors = [NSMutableDictionary dictionary];
Expand Down
11 changes: 11 additions & 0 deletions MatrixSDK/Data/MXCredentials.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#import <Foundation/Foundation.h>

@class MXLoginResponse;
@class MXRefreshResponse;

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -47,6 +48,16 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic, nullable) NSString *accessToken;

/**
The timestamp in milliseconds for when the access token will expire
*/
@property (nonatomic) uint64_t accessTokenExpiresAt;

/**
The refresh token, which can be used to obtain new access tokens. (optional)
*/
@property (nonatomic, nullable) NSString *refreshToken;

/**
The access token to create a MXIdentityServerRestClient
*/
Expand Down
50 changes: 48 additions & 2 deletions MatrixSDK/Data/MXCredentials.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#import "MXJSONModels.h"

#import "MXTools.h"
#import "MXRestClient.h"
#import "MXRefreshTokenData.h"

@implementation MXCredentials

Expand All @@ -31,6 +33,8 @@ - (instancetype)initWithHomeServer:(NSString *)homeServer userId:(NSString *)use
_homeServer = [homeServer copy];
_userId = [userId copy];
_accessToken = [accessToken copy];

[self registerRestClientWillRefreshTokensNotification];
}
return self;
}
Expand All @@ -43,6 +47,8 @@ - (instancetype)initWithLoginResponse:(MXLoginResponse*)loginResponse
{
_userId = loginResponse.userId;
_accessToken = loginResponse.accessToken;
_accessTokenExpiresAt = ((uint64_t)[NSDate date].timeIntervalSince1970 * 1000) + loginResponse.expiresInMs;
_refreshToken = loginResponse.refreshToken;
_deviceId = loginResponse.deviceId;
_loginOthers = loginResponse.others;

Expand Down Expand Up @@ -91,10 +97,16 @@ - (instancetype)initWithLoginResponse:(MXLoginResponse*)loginResponse
{
_identityServer = [defaultCredentials.identityServer copy];
}
[self registerRestClientWillRefreshTokensNotification];
}
return self;
}

- (void)dealloc
{
[self unregisterRestClientWillRefreshTokensNotification];
}

+ (instancetype)initialSyncCacheCredentialsFrom:(MXCredentials *)credentials
{
MXCredentials *result = [credentials copy];
Expand All @@ -119,17 +131,21 @@ - (BOOL)isEqual:(id)other

return [_homeServer isEqualToString:otherCredentials.homeServer]
&& [_userId isEqualToString:otherCredentials.userId]
&& [_accessToken isEqualToString:otherCredentials.accessToken];
&& [_accessToken isEqualToString:otherCredentials.accessToken]
&& _accessTokenExpiresAt == otherCredentials.accessTokenExpiresAt
&& ((_refreshToken == nil && otherCredentials.refreshToken == nil) || [_refreshToken isEqualToString:otherCredentials.refreshToken]);
}

- (NSUInteger)hash
{
NSUInteger prime = 31;
NSUInteger result = 1;

result = prime * result + [_homeServer hash];
result = prime * result + [_userId hash];
result = prime * result + [_accessToken hash];
result = prime * result + (NSUInteger)_accessTokenExpiresAt;
result = prime * result + [_refreshToken hash];

return result;
}
Expand All @@ -143,6 +159,9 @@ - (id)copyWithZone:(NSZone *)zone
credentials.userId = [_userId copyWithZone:zone];
credentials.homeServer = [_homeServer copyWithZone:zone];
credentials.accessToken = [_accessToken copyWithZone:zone];
credentials.accessTokenExpiresAt = _accessTokenExpiresAt;
credentials.refreshToken = [_refreshToken copyWithZone:zone];
credentials.accessToken = [_accessToken copyWithZone:zone];
credentials.identityServer = [_identityServer copyWithZone:zone];
credentials.identityServerAccessToken = [_identityServerAccessToken copyWithZone:zone];
credentials.deviceId = [_deviceId copyWithZone:zone];
Expand All @@ -152,4 +171,31 @@ - (id)copyWithZone:(NSZone *)zone
return credentials;
}

#pragma mark - Homeserver Access/Refresh Token updates

- (void)registerRestClientWillRefreshTokensNotification
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleRestClientWillRefreshTokensNotification:) name:MXCredentialsUpdateTokensNotification object:nil];
}

- (void)unregisterRestClientWillRefreshTokensNotification
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:MXCredentialsUpdateTokensNotification object:nil];
}

- (void)handleRestClientWillRefreshTokensNotification:(NSNotification*)notification
{
MXRefreshTokenData *tokenData = notification.userInfo[kMXCredentialsNewRefreshTokenDataKey];

if(tokenData && tokenData.userId && self.userId && [self.userId isEqualToString:tokenData.userId]
&& tokenData.homeserver && self.homeServer && [tokenData.homeserver isEqualToString:self.homeServer])
{
if (tokenData.refreshToken) {
self.refreshToken = tokenData.refreshToken;
}
self.accessToken = tokenData.accessToken;
self.accessTokenExpiresAt = tokenData.accessTokenExpiresAt;
}
}

@end
53 changes: 53 additions & 0 deletions MatrixSDK/Data/MXRefreshTokenData.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

/**
`MXRefreshTokenData` used to update `MXCredentials` that it's token data has updated. see `MXCredentialsUpdateTokensNotification`.
*/
@interface MXRefreshTokenData : NSObject

/**
The user id.
*/
@property (nonatomic, readonly, nonnull) NSString *userId;

/**
The homeserver URL.
*/
@property (nonatomic, readonly, nonnull) NSString *homeserver;


/**
The access token to create a MXRestClient
*/
@property (nonatomic, readonly, nonnull) NSString *accessToken;

/**
The timestamp in milliseconds for when the access token will expire
*/
@property (nonatomic, readonly) uint64_t accessTokenExpiresAt;

/**
The refresh token, which can be used to obtain new access tokens. (optional)
*/
@property (nonatomic, readonly, nullable) NSString *refreshToken;

- (instancetype _Nonnull)initWithUserId:(NSString*_Nonnull)userId
homeserver:(NSString*_Nonnull)homeserver
accessToken:(NSString*_Nonnull)accessToken
refreshToken:(NSString*_Nonnull)refreshToken
accessTokenExpiresAt:(uint64_t)accessTokenExpiresAt;
@end
30 changes: 30 additions & 0 deletions MatrixSDK/Data/MXRefreshTokenData.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// MXRefreshTokenData.m
// MatrixSDK
//
// Created by David Langley on 17/12/2021.
//

#import <Foundation/Foundation.h>
#import "MXRefreshTokenData.h"

@implementation MXRefreshTokenData
- (instancetype)initWithUserId:(NSString*)userId
homeserver:(NSString*)homeserver
accessToken:(NSString*)accessToken
refreshToken:(NSString*)refreshToken
accessTokenExpiresAt:(uint64_t)accessTokenExpiresAt
{
self = [super init];
if (self)
{
_userId = userId;
_homeserver = homeserver;
_accessToken = accessToken;
_refreshToken = refreshToken;
_accessTokenExpiresAt = accessTokenExpiresAt;
}
return self;
}

@end
Loading

0 comments on commit cd839f5

Please sign in to comment.