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 20 commits into
base: develop
Choose a base branch
from
Open

Added Box support #34

wants to merge 20 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

The CryptomatorCloudAccess project now integrates with Box cloud storage, introducing BoxCloudProvider for various storage operations, BoxError for error handling, BoxItem for representing items, and BoxAuthenticator for authentication. The setup includes new files, organization, and dependency adjustments for the Box SDK.

Changes

File Path Change Summary
Sources/CryptomatorCloudAccess/Box/*.swift, Sources/CryptomatorCloudAccess/BoxCloudProviderIntegrationTests.swift Introduces BoxCloudProvider, BoxError, BoxItem, and related functionality for Box integration. Includes BoxItem struct, BoxError enum, and BoxCloudProvider class.
CryptomatorCloudAccess.xcodeproj/project.pbxproj, Package.swift Adds Box SDK dependency, organizes Box-related files, and updates build settings.
create-integration-test-secrets-file.sh Adds declarations for Box access and refresh tokens.

Possibly related issues

  • Add Box support ios#319: The issue requests Box support due to the end of WebDAV by Box. This PR directly addresses adding Box integration, fulfilling the issue's requirements.

🐇✨
In the code where bits align,
A Box now opens, secrets to find.
Swift like the wind, through digital leaves,
A rabbit hops, with code it weaves.
Celebrate, for connections grow,
In cloud's embrace, data will flow. 🎉📦


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.

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 a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @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. 😉

@@ -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

@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

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)

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

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

@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

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.

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