Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Box support #34

Open
wants to merge 24 commits into
base: develop
Choose a base branch
from
Open

Added Box support #34

wants to merge 24 commits into from

Conversation

iammajid
Copy link
Contributor

@iammajid iammajid commented Apr 15, 2024

Introduces Box Cloud as a new cloud provider in cloud-access-swift

This PR integrates Box Cloud into the cloud-access-swift framework. It includes the implementation of the CloudProvider functionalities, OAuth2 authentication, addition of necessary credentials, and the creation of integration tests.

All integration tests are running successfully without any errors.

Copy link

coderabbitai bot commented Apr 15, 2024

Walkthrough

This update introduces significant enhancements to the Cryptomator iOS app for Box cloud integration. New authentication functionalities have been added, including OAuth login and token storage mechanisms. Additionally, comprehensive cloud storage operations using promises and detailed automated integration testing guidelines for developers have been incorporated.

Changes

Files/Paths Change Summaries
Sources/.../BoxAuthenticator.swift Added methods for OAuth authentication, error handling, and secure token storage.
Sources/.../BoxCloudProvider.swift Introduced BoxCredential class and BoxCloudProvider class for detailed Box cloud operations and credential management.
CryptomatorCloudAccess.xcodeproj/.../Package.resolved Added entry for box-swift-sdk-gen and updated swift-log dependencies.
CryptomatorCloudAccess.xcodeproj/.../BoxIntegrationTests.xcscheme Introduced BoxIntegrationTests.xcscheme for configuration settings in Xcode, including build, test, launch, profile, analyze, and archive actions.
Tests/.../README.md Added instructions for obtaining Box Developer Token, using Developer Tokens for integration tests, and a guide for Dropbox access token utilization.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant App as Cryptomator App
    participant Box as Box API
    participant TokenStorage as Token Storage

    User->>App: Initiate Box Authentication
    App->>Box: OAuth Request
    Box-->>User: OAuth Login Page
    User->>Box: Provide Credentials
    Box-->>App: Access Token
    App->>TokenStorage: Store Access Token
    TokenStorage-->>App: Confirmation
    App-->>User: Authentication Success
Loading

Poem

In the vault of clouds, a rabbit leaps,
Secure and swift, where Box now keeps. 🐰
Tokens stored with care, so fine,
OAuth dances in a stately line.
Code and clouds in harmony blend,
For a seamless, secure cloud-friend. 🌥️✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Actionable comments outside the diff hunks (1)
create-integration-test-secrets-file.sh (1)

Line range hint 3-3: Replace source with . to improve the portability of the script and ensure compatibility with POSIX sh.

- source ./.integration-test-secrets.sh
+ . ./.integration-test-secrets.sh

@tobihagemann tobihagemann changed the title Feature/boxcloud integration Added Box support Apr 16, 2024
Copy link
Member

@tobihagemann tobihagemann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've probably seen that the CI failed: https://github.com/cryptomator/cloud-access-swift/actions/runs/8694502837/job/23843551721

Make sure to fix the formatting issues raised by SwiftFormat and SwiftLint. In the root of the project, I believe you can run:

swiftformat .
swiftlint --fix

If you want, you can also add a pre-commit hook so that you will notice these issues earlier: https://github.com/cryptomator/cloud-access-swift?tab=readme-ov-file#contributing

After that, I'll go through the PR more thoroughly. 😄

@tobihagemann tobihagemann linked an issue Apr 16, 2024 that may be closed by this pull request
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Out of diff range and nitpick comments (1)
create-integration-test-secrets-file.sh (1)

Line range hint 3-3: Replace 'source' with '.' for better POSIX compliance.

-  source ./.integration-test-secrets.sh
+  . ./.integration-test-secrets.sh

Copy link
Member

@tobihagemann tobihagemann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All in all, I'm quite happy with the implementation. Just did some minor changes between 79bb7cd...eb9a34d.

This is almost ready for a merge, but I'd like to request updated READMEs (both in the root directory and in the integration tests).

We should make sure that the integration tests work reliably with the current BoxCredentialMock implementation, which requires an access token and refresh token. I think you mentioned that there are some issues with that? As a fallback, we can require the usage of a developer token, but I'm not that happy with the 60 minutes limitation, to be honest.

Edit: You can try to set expiresIn to 59 or something lower (I think 60 is the tokenRefreshThreshold) instead of 3600, so that the SDK instantly tries to refresh the token. In that case, I would even argue that we don't need to specify an access token, because you'll always get a new access token, similar to the integration tests of Google Drive and OneDrive.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Tests/CryptomatorCloudAccessIntegrationTests/README.md Outdated Show resolved Hide resolved
README.md Outdated
Comment on lines 86 to 88
let tokenStore = BoxTokenStore()
let viewController = ... // the presenting `UIViewController`
BoxAuthenticator.authenticate(credential: credential, from: viewController).then {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating the BoxCredential is missing here. 😉

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 995defc.

@@ -33,6 +35,21 @@ If you are building via a CI system, set these secret environment variables acco

### How to Get the Secrets

#### Box

To get the access token for Box, generate a developer token in the Box Developer Portal. For more detailed instructions, check out the [OAuth 2.0 Documentation from Box](https://developer.box.com/guides/authentication/oauth2/).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wanted to mention here that the developer token shouldn't be mixed up with the access token from OAuth. The access token can actually be extracted at the same time when extracting the refresh token, which you've described below.

However, we should experiment with a solution that doesn't require an access token at all, as I've described in a different comment. My guess is that a refresh token would be enough for Box to get a new access token.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 995defc.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Out of diff range and nitpick comments (1)
create-integration-test-secrets-file.sh (1)

Line range hint 3-3: Replace 'source' with '.' for POSIX compliance.

-  source ./.integration-test-secrets.sh
+  . ./.integration-test-secrets.sh


private static let credential = BoxCredentialMock()
// swiftlint:disable:next force_try
private static let cloudProvider = try! BoxCloudProvider(credential: credential)
Copy link

@coderabbitai coderabbitai bot Apr 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid using 'force_try' in tests to prevent crashes during test execution.

- private static let cloudProvider = try! BoxCloudProvider(credential: credential)
+ private static let cloudProvider = try? BoxCloudProvider(credential: credential)

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
private static let cloudProvider = try! BoxCloudProvider(credential: credential)
private static let cloudProvider = try? BoxCloudProvider(credential: credential)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, but not necessary.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@iammajid, understood! If you need further assistance or have any other requests in the future, feel free to let me know. Happy coding! 🐰

Comment on lines 41 to 50
To obtain the refresh token from Box, it is recommended to extract it from `authenticate` after a successful login. The easiest way to do this is to set a breakpoint inside the `BoxAuthenticator`:

```swift
public static func authenticate(from viewController: UIViewController, tokenStore: TokenStore) -> Promise<(BoxClient, String)> {
return Promise {
// ...
fulfill((client, user.id)) // set breakpoint here
// ...
}
```
Copy link

@coderabbitai coderabbitai bot Apr 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add detailed comments within the authenticate function to guide users on using breakpoints effectively for extracting the refresh token.

+  // Note: The breakpoint will allow you to inspect the authentication process and extract the refresh token.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
To obtain the refresh token from Box, it is recommended to extract it from `authenticate` after a successful login. The easiest way to do this is to set a breakpoint inside the `BoxAuthenticator`:
```swift
public static func authenticate(from viewController: UIViewController, tokenStore: TokenStore) -> Promise<(BoxClient, String)> {
return Promise {
// ...
fulfill((client, user.id)) // set breakpoint here
// ...
}
```
public static func authenticate(from viewController: UIViewController, tokenStore: TokenStore) -> Promise<(BoxClient, String)> {
return Promise {
// ...
fulfill((client, user.id)) // set breakpoint here
// Note: The breakpoint will allow you to inspect the authentication process and extract the refresh token.
// ...
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, but not necessary.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@iammajid, understood! If there's anything else you need, feel free to let me know. Happy coding!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Out of diff range and nitpick comments (4)
Tests/CryptomatorCloudAccessIntegrationTests/README.md (4)

39-39: Clarify the expiration details of the Box developer token to prevent confusion during testing.


Line range hint 47-47: Add a comment in the GoogleDriveAuthenticator code snippet to explain the purpose of the breakpoint for new developers.

+  // Set a breakpoint here to extract the refresh token after successful authentication

Line range hint 91-91: In the PCloudAuthenticator code snippet, clarify what the developer should look for when the breakpoint is hit to make the token extraction process clearer.

+  // Set a breakpoint here to capture the PCloudCredential details after successful authorization

Line range hint 170-170: The file should end with a single newline character to adhere to POSIX standards.

+

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Outside diff range and nitpick comments (1)
CryptomatorCloudAccess.xcodeproj/project.pbxproj (1)

189-200: Review overall project settings for potential optimization.

Consider reviewing the overall project settings to optimize build times and resource usage, especially with the addition of new components like Box.

Also applies to: 421-421

Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between b63b18d and 23b077e.
Files selected for processing (11)
  • CryptomatorCloudAccess.xcodeproj/project.pbxproj (18 hunks)
  • CryptomatorCloudAccess.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved (5 hunks)
  • CryptomatorCloudAccess.xcodeproj/xcshareddata/xcschemes/BoxIntegrationTests.xcscheme (1 hunks)
  • Package.resolved (1 hunks)
  • Package.swift (3 hunks)
  • Sources/CryptomatorCloudAccess/Box/BoxAuthenticator.swift (1 hunks)
  • Sources/CryptomatorCloudAccess/Box/BoxCloudProvider.swift (1 hunks)
  • Sources/CryptomatorCloudAccess/Box/BoxCredential.swift (1 hunks)
  • Sources/CryptomatorCloudAccess/Box/BoxIdentifierCache.swift (1 hunks)
  • Sources/CryptomatorCloudAccess/Box/BoxItem.swift (1 hunks)
  • Tests/CryptomatorCloudAccessIntegrationTests/Box/BoxCredentialMock.swift (1 hunks)
Files skipped from review due to trivial changes (2)
  • CryptomatorCloudAccess.xcodeproj/xcshareddata/xcschemes/BoxIntegrationTests.xcscheme
  • Package.resolved
Additional Context Used
Learnings (1)
Sources/CryptomatorCloudAccess/Box/BoxAuthenticator.swift (1)
User: tobihagemann
URL: https://github.com/cryptomator/cloud-access-swift/pull/34

Timestamp: 2024-04-16T06:03:14.688Z
Learning: The `BoxAuthenticatorError` enum in `BoxAuthenticator.swift` includes a case `invalidContext` for handling scenarios where a `UIViewController` cannot be cast to `ASWebAuthenticationPresentationContextProviding`.
Additional comments not posted (22)
Sources/CryptomatorCloudAccess/Box/BoxIdentifierCache.swift (3)

15-25: The constructor correctly sets up the in-memory database and handles its initialization errors by propagating them. Good use of resource initialization.


33-37: The addOrUpdate(_:) method correctly handles database operations with appropriate error propagation.


39-43: Good use of parameterized queries in invalidate(_:) to prevent SQL injection.

Sources/CryptomatorCloudAccess/Box/BoxAuthenticator.swift (1)

22-46: The authenticate(from:tokenStorage:) method is well-implemented with safe casting and proper error handling. It also makes good use of modern Swift concurrency features.

Sources/CryptomatorCloudAccess/Box/BoxCredential.swift (3)

22-26: The constructor init(tokenStore:) is correctly implemented with proper initialization of OAuth configuration and client.


28-42: The deauthenticate() method correctly handles token revocation with appropriate error handling.


44-61: The getUsername() method is well-implemented, handling both the presence and absence of a username correctly, and providing clear error handling.

Tests/CryptomatorCloudAccessIntegrationTests/Box/BoxCredentialMock.swift (2)

35-47: The constructor of BoxCredentialMock is well-implemented, setting up the necessary test environment and initializing the superclass correctly.


49-54: The deauthenticate() method in BoxCredentialMock is correctly implemented for testing purposes, setting the client to an invalid token.

Sources/CryptomatorCloudAccess/Box/BoxItem.swift (3)

13-22: The BoxItem struct is well-defined, with clear properties and appropriate protocol conformances for database operations.


24-50: The extension of BoxItem is well-implemented, providing initializers for different item types and correctly handling unsupported types by throwing an error.


52-58: The encoding functionality in the BoxItem extension is correctly implemented, ensuring that item properties are properly encoded for database operations.

Package.swift (1)

Line range hint 17-46: The package configuration in Package.swift is correctly set up, including the necessary dependencies and targets for the integration of the Box SDK.

CryptomatorCloudAccess.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved (1)

31-39: Added dependency on box-swift-sdk-gen version 0.2.0.

This addition aligns with the PR's objective to integrate Box Cloud support. Ensure that this version of the SDK is compatible with the rest of the project dependencies and the Swift version used.

Sources/CryptomatorCloudAccess/Box/BoxCloudProvider.swift (6)

18-22: Ensure proper initialization of BoxCloudProvider.

The constructor correctly initializes the credential, identifierCache, and maxPageSize properties. The use of max(1, min(maxPageSize, 1000)) ensures that maxPageSize remains within a sensible range, which is good for controlling the size of data pages handled by the provider.


24-28: Review the implementation of metadata fetching.

The method fetchItemMetadata uses a promise chain to resolve the item path and then fetch its metadata. This approach is clean and maintains readability while handling asynchronous operations effectively.


36-44: Check preconditions and handle file download correctly.

The method downloadFile correctly checks if the URL is a file URL and if the file already exists, returning an error if so. This prevents overwriting existing files unintentionally. The rest of the method handles the download task asynchronously, which is appropriate for network operations.


46-70: Ensure robust file upload handling.

The uploadFile method includes comprehensive checks for the file's existence and type before proceeding. The conditional logic around replaceExisting is correctly implemented to throw an error if an attempt is made to replace a folder with a file. The use of promises to chain these checks and the final upload task is well done.


72-82: Validate folder creation logic.

The method createFolder properly checks if the folder already exists before attempting to create it, which avoids unnecessary API calls and potential errors. The promise chain is used effectively to handle asynchronous operations.


339-373: Review deletion logic and error handling in deleteFile.

The deleteFile method includes comprehensive error handling, including specific checks for expired tokens and file not found errors. The use of detailed logging helps in debugging and maintaining the system. The method also updates the cache upon successful deletion, which is crucial for consistency.

CryptomatorCloudAccess.xcodeproj/project.pbxproj (2)

189-200: Integration of Box-related files and framework appears correctly implemented.

Ensure that all newly added files are correctly referenced and that the BoxSdkGen framework is properly configured in the build settings.

Also applies to: 421-421


189-200: Configuration settings for Box integration are correctly added.

Verify that the build configurations for the new Box-related files are correctly set to ensure smooth builds and integration tests.

Comment on lines +27 to +31
func get(_ cloudPath: CloudPath) -> BoxItem? {
try? inMemoryDB.read { db in
return try BoxItem.fetchOne(db, key: cloudPath)
}
}
Copy link

@coderabbitai coderabbitai bot May 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding error logging in the get(_:) method to aid in debugging when database read operations fail.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, but not necessary.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@iammajid, understood! If you need any further assistance or a fresh set of eyes on other parts of your code in the future, feel free to reach out. Happy coding! 🚀

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between 23b077e and 17de27a.
Files selected for processing (2)
  • Sources/CryptomatorCloudAccess/Box/BoxAuthenticator.swift (1 hunks)
  • Sources/CryptomatorCloudAccess/Box/BoxCredential.swift (1 hunks)
Files skipped from review as they are similar to previous changes (2)
  • Sources/CryptomatorCloudAccess/Box/BoxAuthenticator.swift
  • Sources/CryptomatorCloudAccess/Box/BoxCredential.swift

Comment on lines 32 to 37
"identity" : "box-swift-sdk-gen",
"kind" : "remoteSourceControl",
"location" : "https://github.com/box/box-ios-sdk.git",
"location" : "https://github.com/box/box-swift-sdk-gen.git",
"state" : {
"revision" : "daffd86b861a5f5882655bf7a01b891f6b808c1f",
"version" : "5.5.0"
"revision" : "e5069af728c4b4f048078dfb5aed683c926da857",
"version" : "0.2.0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This selection is fine. However, you've introduced further changes in this file that are unrelated. I know that Xcode sometimes does this automatically, but please revert them to avoid unwanted changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted in commit 0af03cd.

value = ""
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would revert these changes. They don't seem to change anything useful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted in commit 0af03cd.

}
public var client: BoxClient

public init(tokenStore: TokenStorage) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename tokenStore to tokenStorage to be more consistent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit d544b20.

}
// Run the login flow and store the access token using tokenStorage
try await oauth.runLoginFlow(options: .init(), context: context)
// TODO: Catch error when login failed
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wanted to clarify here that I meant "when login is being cancelled". I just assumed that runLoginFlow would throw a special error in that case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented in commit d544b20.

#if canImport(CryptomatorCloudAccessCore)
@testable import CryptomatorCloudAccessCore
#else
@testable import CryptomatorCloudAccess
#endif

// Custom in-memory token storage
class InMemoryTokenStore: TokenStorage {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in commit d544b20.

Comment on lines +51 to +52
let invalidTokenAuth = BoxDeveloperTokenAuth(token: "invalid")
client = BoxClient(auth: invalidTokenAuth)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should use a different Authentication implemention of BoxSdk, because we don't use the developer token in the main app, but an OAuth token.

If you compare BoxDeveloperTokenAuth.swift with BoxOAuth.swift, you can see the different BoxSDKErrors that can be thrown.

I'm actually a little annoyed that you can't just catch the status code 401 for this.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 17de27a and 0af03cd.

Files selected for processing (2)
  • CryptomatorCloudAccess.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved (2 hunks)
  • CryptomatorCloudAccess.xcodeproj/xcshareddata/xcschemes/BoxIntegrationTests.xcscheme (1 hunks)
Files not reviewed due to errors (2)
  • CryptomatorCloudAccess.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved (no review received)
  • CryptomatorCloudAccess.xcodeproj/xcshareddata/xcschemes/BoxIntegrationTests.xcscheme (no review received)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 0af03cd and d544b20.

Files selected for processing (4)
  • Sources/CryptomatorCloudAccess/Box/BoxAuthenticator.swift (1 hunks)
  • Sources/CryptomatorCloudAccess/Box/BoxCloudProvider.swift (1 hunks)
  • Sources/CryptomatorCloudAccess/Box/BoxCredential.swift (1 hunks)
  • Tests/CryptomatorCloudAccessIntegrationTests/Box/BoxCredentialMock.swift (1 hunks)
Files not reviewed due to errors (1)
  • Tests/CryptomatorCloudAccessIntegrationTests/Box/BoxCredentialMock.swift (no review received)
Additional context used
Learnings (2)
Tests/CryptomatorCloudAccessIntegrationTests/Box/BoxCredentialMock.swift (1)
User: tobihagemann
URL: https://github.com/cryptomator/cloud-access-swift/pull/34

Timestamp: 2024-04-16T06:03:14.688Z
Learning: The `BoxAuthenticatorError` enum in `BoxAuthenticator.swift` includes a case `invalidContext` for handling scenarios where a `UIViewController` cannot be cast to `ASWebAuthenticationPresentationContextProviding`.
Sources/CryptomatorCloudAccess/Box/BoxAuthenticator.swift (1)
User: tobihagemann
URL: https://github.com/cryptomator/cloud-access-swift/pull/34

Timestamp: 2024-04-16T06:03:14.688Z
Learning: The `BoxAuthenticatorError` enum in `BoxAuthenticator.swift` includes a case `invalidContext` for handling scenarios where a `UIViewController` cannot be cast to `ASWebAuthenticationPresentationContextProviding`.
SwiftLint
Sources/CryptomatorCloudAccess/Box/BoxCloudProvider.swift

[Warning] 320-320: Function body should span 50 lines or less excluding comments and whitespace: currently spans 51 lines (function_body_length)


[Warning] 382-382: Function body should span 50 lines or less excluding comments and whitespace: currently spans 59 lines (function_body_length)


[Warning] 382-382: Function should have 5 parameters or less: it currently has 7 (function_parameter_count)

Additional comments not posted (1)
Sources/CryptomatorCloudAccess/Box/BoxAuthenticator.swift (1)

23-54: Review of BoxAuthenticator.authenticate method

This method is well-structured and uses modern Swift concurrency features. It correctly handles different error scenarios, including invalid context and login cancellation. The use of ASWebAuthenticationSessionError for specific error handling is a good practice. However, ensure that all possible errors from the ASWebAuthenticationSession are handled appropriately.

Comment on lines +19 to +76
public class BoxCredential {
public var client: BoxClient

public init(tokenStorage: TokenStorage) {
let config = OAuthConfig(clientId: BoxSetup.constants.clientId, clientSecret: BoxSetup.constants.clientSecret, tokenStorage: tokenStorage)
let oauth = BoxOAuth(config: config)
self.client = BoxClient(auth: oauth)
}

public func deauthenticate() -> Promise<Void> {
let pendingPromise = Promise<Void>.pending()

_Concurrency.Task {
do {
let networkSession = NetworkSession()
try await self.client.auth.revokeToken(networkSession: networkSession)
pendingPromise.fulfill(())
} catch {
pendingPromise.reject(error)
}
}

return pendingPromise
}

public func getUsername() -> Promise<String> {
let pendingPromise = Promise<String>.pending()

_Concurrency.Task {
do {
let user = try await client.users.getUserMe()
if let name = user.name {
pendingPromise.fulfill(name)
} else {
pendingPromise.reject(BoxCredentialErrors.noUsername)
}
} catch {
pendingPromise.reject(error)
}
}

return pendingPromise
}

public func getUserId() -> Promise<String> {
let pendingPromise = Promise<String>.pending()

_Concurrency.Task {
do {
let user = try await client.users.getUserMe()
pendingPromise.fulfill(user.id)
} catch {
pendingPromise.reject(error)
}
}

return pendingPromise
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comprehensive review of BoxCredential methods

The implementation of deauthenticate, getUsername, and getUserId methods in BoxCredential uses Promises effectively. Each method is implemented with proper error handling and concurrency. However, consider adding more detailed logging in error handling blocks to aid in debugging and maintenance.

- pendingPromise.reject(error)
+ CloudAccessDDLogDebug("Error occurred: \(error.localizedDescription)")
+ pendingPromise.reject(error)
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public class BoxCredential {
public var client: BoxClient
public init(tokenStorage: TokenStorage) {
let config = OAuthConfig(clientId: BoxSetup.constants.clientId, clientSecret: BoxSetup.constants.clientSecret, tokenStorage: tokenStorage)
let oauth = BoxOAuth(config: config)
self.client = BoxClient(auth: oauth)
}
public func deauthenticate() -> Promise<Void> {
let pendingPromise = Promise<Void>.pending()
_Concurrency.Task {
do {
let networkSession = NetworkSession()
try await self.client.auth.revokeToken(networkSession: networkSession)
pendingPromise.fulfill(())
} catch {
pendingPromise.reject(error)
}
}
return pendingPromise
}
public func getUsername() -> Promise<String> {
let pendingPromise = Promise<String>.pending()
_Concurrency.Task {
do {
let user = try await client.users.getUserMe()
if let name = user.name {
pendingPromise.fulfill(name)
} else {
pendingPromise.reject(BoxCredentialErrors.noUsername)
}
} catch {
pendingPromise.reject(error)
}
}
return pendingPromise
}
public func getUserId() -> Promise<String> {
let pendingPromise = Promise<String>.pending()
_Concurrency.Task {
do {
let user = try await client.users.getUserMe()
pendingPromise.fulfill(user.id)
} catch {
pendingPromise.reject(error)
}
}
return pendingPromise
}
public class BoxCredential {
public var client: BoxClient
public init(tokenStorage: TokenStorage) {
let config = OAuthConfig(clientId: BoxSetup.constants.clientId, clientSecret: BoxSetup.constants.clientSecret, tokenStorage: tokenStorage)
let oauth = BoxOAuth(config: config)
self.client = BoxClient(auth: oauth)
}
public func deauthenticate() -> Promise<Void> {
let pendingPromise = Promise<Void>.pending()
_Concurrency.Task {
do {
let networkSession = NetworkSession()
try await self.client.auth.revokeToken(networkSession: networkSession)
pendingPromise.fulfill(())
} catch {
CloudAccessDDLogDebug("Error occurred: \(error.localizedDescription)")
pendingPromise.reject(error)
}
}
return pendingPromise
}
public func getUsername() -> Promise<String> {
let pendingPromise = Promise<String>.pending()
_Concurrency.Task {
do {
let user = try await client.users.getUserMe()
if let name = user.name {
pendingPromise.fulfill(name)
} else {
pendingPromise.reject(BoxCredentialErrors.noUsername)
}
} catch {
CloudAccessDDLogDebug("Error occurred: \(error.localizedDescription)")
pendingPromise.reject(error)
}
}
return pendingPromise
}
public func getUserId() -> Promise<String> {
let pendingPromise = Promise<String>.pending()
_Concurrency.Task {
do {
let user = try await client.users.getUserMe()
pendingPromise.fulfill(user.id)
} catch {
CloudAccessDDLogDebug("Error occurred: \(error.localizedDescription)")
pendingPromise.reject(error)
}
}
return pendingPromise
}

return pendingPromise
}

private func normalFileUpload(for parentItem: BoxItem, from localURL: URL, to cloudPath: CloudPath, onTaskCreation: ((URLSessionUploadTask?) -> Void)?) -> Promise<CloudItemMetadata> {
Copy link

@coderabbitai coderabbitai bot Jun 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function length and parameter count issues in BoxCloudProvider

The normalFileUpload and chunkedFileUpload functions exceed the recommended line count and parameter count. Consider refactoring these functions to improve readability and maintainability.

- private func chunkedFileUpload(client: BoxClient, from localURL: URL, fileSize: Int64, targetFileName: String, parentItem: BoxItem, cloudPath: CloudPath, onTaskCreation: ((URLSessionUploadTask?) -> Void)?)
+ private func chunkedFileUpload(uploadSession: UploadSessionDetails)

Refactor to use a struct for passing multiple parameters.

Also applies to: 382-382

Tools
SwiftLint

[Warning] 320-320: Function body should span 50 lines or less excluding comments and whitespace: currently spans 51 lines (function_body_length)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's okay for now.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@iammajid, understood! If you decide to revisit this in the future or need any assistance, feel free to reach out. Happy coding! 🚀


Learnings added
User: iammajid
PR: cryptomator/cloud-access-swift#34
File: Sources/CryptomatorCloudAccess/Box/BoxCloudProvider.swift:320-320
Timestamp: 2024-06-21T13:51:55.137Z
Learning: iammajid prefers to keep the function lengths and parameter counts as they are in the `BoxCloudProvider` for now.

Note: Learnings are effective only in the context of specific code segments. To apply general coding guidelines, please configure review instructions.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between d544b20 and ee2f7a6.

Files selected for processing (1)
  • Tests/CryptomatorCloudAccessIntegrationTests/README.md (2 hunks)
Additional context used
Learnings (1)
Common learnings
User: iammajid
PR: cryptomator/cloud-access-swift#34
File: Sources/CryptomatorCloudAccess/Box/BoxCloudProvider.swift:320-320
Timestamp: 2024-06-21T13:51:55.259Z
Learning: iammajid prefers to keep the function lengths and parameter counts as they are in the `BoxCloudProvider` for now.
LanguageTool
Tests/CryptomatorCloudAccessIntegrationTests/README.md

[style] ~32-~32: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym. (ENGLISH_WORD_REPEAT_BEGINNING_RULE)
Context: ...on, you have to run that script again. If you are building via a CI system, set t...

Markdownlint
Tests/CryptomatorCloudAccessIntegrationTests/README.md

172-172: null (MD047, single-trailing-newline)
Files should end with a single newline character

Additional comments not posted (3)
Tests/CryptomatorCloudAccessIntegrationTests/README.md (3)

39-41: Review the new instructions for Box developer tokens.

The instructions are clear and emphasize the practicality of using developer tokens for integration tests. Please verify that the external link to the Box OAuth 2.0 Documentation is correct and accessible to ensure users can follow these steps without issues.


Line range hint 32-32: Consider varying sentence structure.

To enhance readability, consider rewording the sentences to avoid repetitive beginnings. This is a minor style improvement that could make the instructions clearer.


Line range hint 172-172: Add a trailing newline at the end of the file.

To comply with Markdown formatting standards, please ensure the file ends with a single newline character.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Box support
2 participants