Skip to content

Release 1.9.1 - #533

Draft
terrerox wants to merge 68 commits into
masterfrom
release-1.9.1
Draft

Release 1.9.1#533
terrerox wants to merge 68 commits into
masterfrom
release-1.9.1

Conversation

@terrerox

Copy link
Copy Markdown
Contributor

No description provided.

@terrerox
terrerox marked this pull request as draft July 13, 2026 17:37
android:authorities="com.internxt.cloud.documents"
android:exported="true"
android:grantUriPermissions="true"
android:permission="android.permission.MANAGE_DOCUMENTS"
kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock,
kSecValueData as String: value,
]
SecItemAdd(query as CFDictionary, nil)
terrerox added 28 commits July 13, 2026 14:09
Adds a pure-Kotlin HTTP client that talks directly to the Drive and Bridge APIs so the SAF DocumentsProvider can fetch folder contents and download links without the React Native bridge. Covers list/create/rename/move/trash on Drive (Bearer auth) and getDownloadLinks on Bridge (Basic auth with sha256(userId).hex derivation). Typed errors for 401/404/other/network; MockWebServer tests for parsing, auth headers, gateway-required headers, and error mapping.
  - Wire AuthConfig.clientName/clientVersion through
    BuildConfig.INTERNXT_CLIENT_NAME and BuildConfig.INTERNXT_CLIENT_VERSION,
    populated by app/build.gradle from package.json. package.json is now the
    single source of truth for the internxt-client/internxt-version headers.
  - Extract JSON helpers (orEmpty, map, optStringOrNull, optLongFlexible)
    from InternxtApiClient into JsonExtensions.kt; cover each branch in a
    new JsonExtensionsTest.
  - Rename InternxtApiClient.execute -> executeApiRequest.
  - Expand InternxtApiClientTest: listFolderFolders, createFolder, null
    optional fields, size given as a string, and 5xx -> ApiError. Add an
    enqueueJson helper to cut response-stub boilerplate.
  - Add @TamaraFinogina as CODEOWNER for the new documents/crypto/ directory.
  InternxtDocumentsProvider.queryRoots() now reads credentials from EncryptedSharedPreferences via a new
   InternxtAuthManager and returns an empty cursor when no user is signed in, so "Internxt Drive" only
  appears in the system file picker while the app has an active session; credentials are written by a
  new RN bridge (InternxtAuthCredentialsModule) from signInThunk and refreshTokensThunk and cleared from
   signOutThunk, with both paths firing contentResolver.notifyChange(rootsUri) so the picker refreshes
  without restarting the app, while queryRoots() itself stays strictly synchronous and local-only to
  avoid freezing the system picker.
  - Implement queryChildDocuments to paginate folders + files for a parent UUID
  - Implement queryDocument to resolve real metadata via folders/{uuid}/meta
    and files/{uuid}/meta, with a UUID-named placeholder fallback for
    offline / transient failures
  - Add InternxtApiClient.getFolder / getFile (404 → null) plus tests
  - Introduce DocumentRowBuilder (column-keyed rows) and MimeTypes
    (hand-rolled table + Android MimeTypeMap fallback) with tests
  - Surface InternxtApiException + null auth-config via Log.w so silent
    failures are no longer invisible
  - Fix auth slice to sync newToken (not token) to native credentials so
    the documents provider authenticates against drive endpoints
  - Override renameDocument, moveDocument, and deleteDocument in InternxtDocumentsProvider so SAF surfaces the corresponding row actions.
  - Surface FLAG_SUPPORTS_RENAME | FLAG_SUPPORTS_DELETE | FLAG_SUPPORTS_MOVE on file and folder rows; keep root and placeholder rows mutation-free.
  - Cache item kind (file vs folder) per UUID so mutations resolve their endpoint without an extra round-trip on the happy path.
  - Notify affected child-document URIs after each mutation so the picker refreshes without manual reload.
  - Fix InternxtApiClient.renameFile / renameFolder to match the SDK: PUT /{files|folders}/{uuid}/meta with { plainName }, void response.
  - Await clearCredentials in signOutThunk so the SAF root is hidden immediately after logout instead of lingering until documentsui refreshes.
  - Override renameDocument, moveDocument, and deleteDocument in InternxtDocumentsProvider so SAF surfaces the corresponding row actions.
  - Surface FLAG_SUPPORTS_RENAME | FLAG_SUPPORTS_DELETE | FLAG_SUPPORTS_MOVE on file and folder rows; keep root and placeholder rows mutation-free.
  - Cache item kind (file vs folder) per UUID so mutations resolve their endpoint without an extra round-trip on the happy path.
  - Notify affected child-document URIs after each mutation so the picker refreshes without manual reload.
  - Fix InternxtApiClient.renameFile / renameFolder to match the SDK: PUT /{files|folders}/{uuid}/meta with { plainName }, void response.
  - Await clearCredentials in signOutThunk so the SAF root is hidden immediately after logout instead of lingering until documentsui refreshes.
terrerox and others added 27 commits July 13, 2026 14:09
Replace CompletableFuture.get(), Call.execute() and the manual
AtomicReference + setOnCancelListener cancellation plumbing with
kotlinx-coroutines across the native DocumentsProvider stack:
crypto, download and upload now suspend via Call.await()/CallAwait and
CryptoServiceAwait, and openDocument bridges to coroutines through
runBlockingIo (BlockingIo) instead of a plain runBlocking, surfacing
cancellation as FileNotFoundException. Adds kotlinx-coroutines-android
and kotlinx-coroutines-test to android/app/build.gradle and JVM unit
tests for BlockingIo, CryptoServiceAwait, EncryptedFileDownloader and
EncryptedFileUploader.

NOTE: a separate, unrelated change by the maintainer lives in the same
file (InternxtDocumentsProvider.kt) and could not be split out because
interactive staging (git add -p) is unavailable and editing source is
out of scope for the git-manager: refresh() now triggers a background
revalidateChildren (new revalidate/fetchAllRows helpers and the
FolderLoad.isRevalidating flag) instead of invalidateChildren. It is
bundled here intentionally; see progress/git_android_coroutines_migration.md.

Refs: PB-6282
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sync auth credentials to a shared App Group Keychain so the File Provider
extension can read them; register the com.internxt.drive domain on login and
call removeAllDomains on logout so the provider appears/disappears in Files.app.
Bump InternxtFileProvider MARKETING_VERSION 1.0 -> 1.9.0 (Debug+Release) so the
extension version matches the host or iOS won't load it. Device-verified on a
real iPhone.

Refs: PB-5920
The File Provider extension needs the Drive API base URL to build
authenticated requests from the App Group keychain. Add a dedicated
shared key so it can be read alongside the existing auth token.
Replace the placeholder enumerator with real Drive folder browsing:
paginate folders then files for a container, build FileProviderItem
metadata (name, type, size, dates, capabilities) from Drive responses,
and resolve identifiers via a typed folder/file id codec. Add a
DriveAPIFactory that constructs an authenticated DriveAPI from the
shared App Group keychain, and wire the new sources into the
extension target.
Implement item(for:) so the system can resolve any identifier to a
FileProviderItem: return the root container item, decode folder/file
identifiers and fetch their metadata from the Drive API, and map 401
responses to NSFileProviderError.notAuthenticated so the system can
re-request credentials.
Persist the Drive API base URL in the App Group keychain when
credentials are written, so the File Provider extension can build
authenticated Drive requests. Add a wrapper test asserting the native
module receives driveBaseUrl.
Add FileProviderDomainManager.signalEnumeration to notify the working
set enumerator, and call it once the File Provider domain is registered
so the Files app refreshes Drive contents right after credentials
change. Signal failures are logged and ignored to avoid blocking login.
Adds NetworkFacadeFactory and SharedKeychainCredentials to the File Provider
extension so items can be downloaded from the network and decrypted on demand.
Persists bridgeBaseUrl to the shared keychain and JSON-decodes bridgeUser/userId
so the extension reads matching credentials.
Implement the write path in the NSFileProviderReplicatedExtension so the
Files.app can create folders and upload files to Drive. createItem routes
folder creation to the Drive API and file uploads through InternxtSwiftCore
encryption plus network upload, then registers the file and returns the
created NSFileProviderItem. Adds rename support via modifyItem and friendly
non-crashing errors for offline/unauthenticated/generic failures.
…FileProviderError

Revert the FriendlyError helper and fileProviderError factory; surface
plain NSFileProviderError values while keeping the same error codes
(noSuchItem, notAuthenticated, serverUnreachable).
Extract upload, download, mutation, and error-mapping logic out of the
monolithic FileProviderExtension into dedicated services so the extension
becomes a thin coordinator, easing testability and maintenance ahead of
move/trash/versioning work.
Introduce a host-less InternxtFileProviderTests target covering the pure
NSFileProviderError mapping logic now isolated in FileProviderErrorMapper.
Implement modifyItem move/rename and deleteItem-to-backend-trash in the
File Provider extension. Item capabilities use .allowsDeleting (not
.allowsTrashing) so the system routes deletes through deleteItem, which
maps to the Drive backend trash endpoint instead of a local-only trash.
Add a per-folder snapshot/diff change-feed in the File Provider
extension so working-set enumeration surfaces upload, create-folder,
move, rename, trash and restore as changes. SyncAnchorStore persists
the per-domain anchor; FileProviderModule exposes a native bridge so
the host app can signal the enumerator on RN mutations.
Add a cross-platform InternxtSignalingModule with a single
notifyParentChanged(parentUuid) bridge (symmetric to Android) and call
it from the upload, create-folder, move, rename, trash and restore
paths so the native File Provider change-feed refreshes the affected
folder.
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
C Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

💡 Need a hand with PR review? Try Gitar by Sonar!

@terrerox terrerox self-assigned this Jul 15, 2026
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.

2 participants