Skip to content

Commit b1bfa76

Browse files
committed
Fix upload test file URL reuse, update integration test secret docs
1 parent 143694e commit b1bfa76

2 files changed

Lines changed: 30 additions & 25 deletions

File tree

Tests/CryptomatorCloudAccessIntegrationTests/CloudAccessIntegrationTest.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,7 @@ class CloudAccessIntegrationTest: XCTestCase {
567567
let initialLocalURL = tmpDirURL.appendingPathComponent(UUID().uuidString, isDirectory: false)
568568
let initialTestContent = "Start content"
569569
try initialTestContent.write(to: initialLocalURL, atomically: true, encoding: .utf8)
570+
let overwrittenUploadURL = tmpDirURL.appendingPathComponent(UUID().uuidString, isDirectory: false)
570571
let overwrittenLocalURL = tmpDirURL.appendingPathComponent(UUID().uuidString, isDirectory: false)
571572
let overwrittenTestContent = "Overwritten content"
572573
let cloudPath = type(of: self).integrationTestRootCloudPath.appendingPathComponent("testFolder/EmptySubfolder/FileToOverwrite.txt")
@@ -578,10 +579,10 @@ class CloudAccessIntegrationTest: XCTestCase {
578579
provider.uploadFile(from: initialLocalURL, to: cloudPath, replaceExisting: false).then { cloudItemMetadata -> Promise<CloudItemMetadata> in
579580
XCTAssertTrue(progress.completedUnitCount >= progress.totalUnitCount)
580581
self.assertReceivedCorrectMetadataAfterUploading(file: initialLocalURL, to: cloudPath, metadata: cloudItemMetadata)
581-
try overwrittenTestContent.write(to: initialLocalURL, atomically: true, encoding: .utf8)
582-
return self.provider.uploadFile(from: initialLocalURL, to: cloudPath, replaceExisting: true)
582+
try overwrittenTestContent.write(to: overwrittenUploadURL, atomically: true, encoding: .utf8)
583+
return self.provider.uploadFile(from: overwrittenUploadURL, to: cloudPath, replaceExisting: true)
583584
}.then { cloudItemMetadata -> Promise<Void> in
584-
self.assertReceivedCorrectMetadataAfterUploading(file: initialLocalURL, to: cloudPath, metadata: cloudItemMetadata)
585+
self.assertReceivedCorrectMetadataAfterUploading(file: overwrittenUploadURL, to: cloudPath, metadata: cloudItemMetadata)
585586
return self.provider.downloadFile(from: cloudPath, to: overwrittenLocalURL)
586587
}.then { _ in
587588
self.provider.deleteFile(at: cloudPath)

Tests/CryptomatorCloudAccessIntegrationTests/README.md

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -42,41 +42,47 @@ To get the access token for Dropbox, generate a token in the Dropbox Developer P
4242

4343
#### Google Drive
4444

45-
To get the refresh token for Google Drive, it is recommended to extract it from the `authState` after a successful login. The easiest way to do this is to set a breakpoint inside the `GoogleDriveAuthenticator`:
45+
To get the refresh token for Google Drive, extract it from the keychain after a successful login. The auth session is stored by GTMAppAuth with the item name `GoogleDriveAuth` + user ID. The following method can be used to extract the refresh token:
4646

4747
```swift
48-
private static func getAuthState(for configuration: OIDServiceConfiguration, with presentingViewController: UIViewController, credential: GoogleDriveCredential) -> Promise<OIDAuthState> {
49-
// ...
50-
fulfill(authState) // set breakpoint here
51-
// ...
48+
import AppAuthCore
49+
import GTMAppAuth
50+
51+
func extractGoogleDriveRefreshToken(userID: String) {
52+
let store = KeychainStore(itemName: "GoogleDriveAuth" + userID)
53+
if let authSession = try? store.retrieveAuthSession() {
54+
print("GOOGLE_DRIVE_REFRESH_TOKEN=\(authSession.authState.refreshToken ?? "nil")")
55+
}
5256
}
5357
```
5458

5559
#### Microsoft Graph
5660

57-
The easiest way to get the secrets for Microsoft Graph is to use OneDrive. It is necessary to extract them from the keychain after a successful login. The following method may help you to extract the Microsoft Graph secrets from the keychain:
61+
To get the refresh token for Microsoft Graph, extract it from the keychain after a successful login. MSAL stores credentials as JSON in the keychain. The following method queries all keychain entries and filters for refresh tokens:
5862

5963
```swift
60-
func extractOneDriveSecretsFromKeychain() {
64+
import Security
65+
66+
func extractMicrosoftGraphRefreshToken() {
6167
let query: [String: Any] = [
6268
kSecClass as String: kSecClassGenericPassword,
6369
kSecReturnAttributes as String: true,
6470
kSecReturnData as String: true,
6571
kSecMatchLimit as String: kSecMatchLimitAll
6672
]
6773
var result: AnyObject?
68-
let lastResultCode = withUnsafeMutablePointer(to: &result) {
74+
let status = withUnsafeMutablePointer(to: &result) {
6975
SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))
7076
}
71-
if lastResultCode == noErr {
72-
guard let array = result as? [[String: Any]] else {
73-
print("No items were found in the keychain")
74-
return
75-
}
77+
if status == noErr, let array = result as? [[String: Any]] {
7678
for item in array {
77-
if let data = item[kSecValueData as String] as? Data, let string = String(data: data, encoding: .utf8) {
78-
if string.contains("\"credential_type\":\"RefreshToken\"") {
79-
print("Microsoft Graph Refresh Token Data:\n\(string)")
79+
if let data = item[kSecValueData as String] as? Data,
80+
let string = String(data: data, encoding: .utf8),
81+
string.contains("\"credential_type\":\"RefreshToken\"") {
82+
if let jsonData = string.data(using: .utf8),
83+
let json = try? JSONSerialization.jsonObject(with: jsonData) as? [String: Any],
84+
let refreshToken = json["secret"] as? String {
85+
print("MICROSOFT_GRAPH_REFRESH_TOKEN=\(refreshToken)")
8086
}
8187
}
8288
}
@@ -86,14 +92,12 @@ func extractOneDriveSecretsFromKeychain() {
8692

8793
#### pCloud
8894

89-
To get the access token for pCloud, it is recommended to extract it from `completeAuthorizationFlow` after a successful login. The easiest way to do this is to set a breakpoint inside the `PCloudAuthenticator`:
95+
To get the access token for pCloud, extract it from the `PCloudCredential` after a successful login. The credential's `user` property has public access to the token and API host name. The following can be added to `CloudAuthenticator.authenticatePCloud` in the iOS app:
9096

9197
```swift
92-
private func completeAuthorizationFlow(result: OAuth.Result) throws -> PCloudCredential {
93-
// ...
94-
return PCloudCredential(user: user) // set breakpoint here
95-
// ...
96-
}
98+
// Inside the .then block, `credential` is a PCloudCredential
99+
print("PCLOUD_ACCESS_TOKEN=\(credential.user.token)")
100+
print("PCLOUD_HTTP_API_HOST_NAME=\(credential.user.httpAPIHostName)")
97101
```
98102

99103
## Create Integration Tests for New Cloud Provider

0 commit comments

Comments
 (0)