diff --git a/CHANGELOG.md b/CHANGELOG.md index 77a84c8..7b9c926 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,13 @@ # Changelog -## Next - -### Fixes +## 2.0.0 -- Bump `adm-zip`, the Config Plugin's only runtime dependency, to 0.6.1. This clears GHSA-xcpc-8h2w-3j85 (high) and GHSA-vwc7-r8mq-g2x9 (moderate) from consumers' `npm audit`. Neither was reachable: the plugin never extracts to disk, and it only parses the AAR it downloaded after checking its SHA-256, or its own cached copy under `node_modules`. -- **Android**: the Config Plugin matches the maven repository URL exactly when deciding whether `android/build.gradle` already declares it, and ignores declarations inside `//` and `/* */` comments. The substring check it replaces skipped adding the repository when the URL appeared only in a comment or as the prefix of a longer URL. It was also the CodeQL `js/incomplete-url-substring-sanitization` alert. +Upgrading from 1.x: every failure now rejects with a `DocuSignError`. Check any code that branches on `error.code`, matches message text, handles `status: 'error'` from `presentCaptiveSigning*`, or reads `errorCode` in an `addSigningErrorListener` callback. Codes are the lowercase codes the README documents, on both platforms, where iOS previously emitted `ERR_`-prefixed variants and Android rejected most failures as `signing_failed`. The new Android `launchStrategy` is opt-in. Both native SDKs also move forward, see [Native SDKs](#native-sdks) for what that changes in your app. -## 2.0.0 +### Native SDKs -Upgrading from 1.x: every failure now rejects with a `DocuSignError`. Check any code that branches on `error.code`, matches message text, handles `status: 'error'` from `presentCaptiveSigning*`, or reads `errorCode` in an `addSigningErrorListener` callback. Codes are the lowercase codes the README documents, on both platforms, where iOS previously emitted `ERR_`-prefixed variants and Android rejected most failures as `signing_failed`. The new Android `launchStrategy` is opt-in. +- **Android**: DocuSign Android SDK 2.1.4 to 2.1.7, the version DocuSign's install guide documents. Its own dependencies moved to Glide 5.0.4, OkHttp 4.12.0, RxJava 3, Room 2.7.2 and kotlin-stdlib 2.2.10, and it no longer pulls in RxJava 2, slf4j or commons-codec. Gradle resolves these across the whole app, so an app on an older OkHttp or Room gets the newer one. Compiling the module against it needs Kotlin 2.1 or newer, which Expo SDK 55 already ships. The config plugin still strips the Glide class from `sdk-pdf`, now pinned to the 2.1.7 hash, so run `npx expo prebuild` after upgrading to fetch the new AAR. +- **iOS**: DocuSign iOS SDK 4.1.1 to 4.3.0. DocuSign 4.3.0 fixes a double JavaScript invocation that caused signing backend errors. The captive signing screen gains Print, Download and Download Separate PDFs menu options (added in DocuSign 4.2.0), and the SDK has no setup key to hide them. DocuSign also inserted a new error code in the middle of its `DSMErrorCode` enum, so for DocuSign's own errors from 1022 up, `native.code` is one higher than on 4.1.1. A project with a committed `Podfile.lock` needs `pod update DocuSign`, because `pod install` alone keeps the locked 4.1.1 and fails to resolve. ### Breaking changes @@ -34,6 +32,9 @@ Upgrading from 1.x: every failure now rejects with a `DocuSignError`. Check any ### Fixes +- Bump `adm-zip`, the Config Plugin's only runtime dependency, to 0.6.1. This clears GHSA-xcpc-8h2w-3j85 (high) and GHSA-vwc7-r8mq-g2x9 (moderate) from consumers' `npm audit`. Neither was reachable: the plugin never extracts to disk, and it only parses the AAR it downloaded after checking its SHA-256, or its own cached copy under `node_modules`. +- **Android**: the Config Plugin matches the maven repository URL exactly when deciding whether `android/build.gradle` already declares it, and ignores declarations inside `//` and `/* */` comments. The substring check it replaces skipped adding the repository when the URL appeared only in a comment or as the prefix of a longer URL. It was also the CodeQL `js/incomplete-url-substring-sanitization` alert. +- **iOS**: the module compiles without warnings under the Swift 6 compiler. Its exception classes restate the `@unchecked Sendable` conformance they inherit from Expo's `Exception`, and a `??` fallback on `DSMManager.defaultConfigurations()`, which never returns nil, is gone. - **iOS**: the view controller to present from is looked up on the main thread. The lookup read `UIApplication.shared` on the background queue the JS call arrived on. - **iOS**: a missing view controller settles the promise once. It previously completed the pending signing slot with a failure and also threw, rejecting the same call twice. - **iOS**: `endSigningSession` no longer calls `DSMManager` off the main thread. Expo dispatches a synchronous `AsyncFunction` body on a serial background queue, so `clearAllWebCookies()` and `logout()` were reached off-main on every call, including the one `useDocuSignSigning`'s `reset()` makes between flows. The guard now lives in `clearWebCookiesAsync`, the only method touching `DSMManager` and `WKWebsiteDataStore` directly, so it covers every caller. Thanks to @virajpsimformsolutions for finding and fixing this. diff --git a/README.md b/README.md index 9581fe6..e2d1109 100644 --- a/README.md +++ b/README.md @@ -94,12 +94,12 @@ The React Native layer never renders any of the signing UI. It only triggers the | Platform | Minimum OS | SDK version | Language | | -------- | -------------------- | -------------------------- | ----------- | -| iOS | 15.1 | DocuSign iOS SDK 4.1.1 | Swift 5.9 | -| Android | API 24 (Android 7.0) | DocuSign Android SDK 2.1.4 | Kotlin 1.8+ | +| iOS | 15.1 | DocuSign iOS SDK 4.3.0 | Swift 5.9 | +| Android | API 24 (Android 7.0) | DocuSign Android SDK 2.1.7 | Kotlin 2.1+ | **Runtime requirements:** -- Expo SDK 55 or newer, OR bare React Native 0.74+ +- Expo SDK 55 or newer, OR bare React Native 0.74+ (Android needs Kotlin 2.1 or newer) - React Native New Architecture (Fabric + Hermes): supported, no additional configuration - Expo Go: NOT supported (custom native modules require a development build) @@ -107,12 +107,12 @@ The React Native layer never renders any of the signing UI. It only triggers the The DocuSign native SDKs are **NOT bundled** inside this npm package. They are declared as external dependencies and resolved at consumer build time: -- **iOS**: `pod 'DocuSign-iOS-SDK', '~> 4.1.1'` from the public CocoaPods trunk -- **Android**: `com.docusign:androidsdk:2.1.4` from DocuSign's Maven repository (the config plugin adds the repo automatically) +- **iOS**: the `DocuSign` pod (`~> 4.3.0`) from the public CocoaPods trunk, declared by this package's podspec +- **Android**: `com.docusign:androidsdk:2.1.7` from DocuSign's Maven repository (the config plugin adds the repo automatically) ### Android Glide collision workaround -DocuSign's `com.docusign:sdk-pdf:2.1.4` AAR ships a pre-generated `com.bumptech.glide.GeneratedAppGlideModuleImpl.class` that collides at dex time with any other Glide-based library in the host app (notably `expo-image`, `react-native-fast-image`, and similar). To avoid this without redistributing DocuSign's binary, the Expo Config Plugin downloads `sdk-pdf-2.1.4.aar` directly from DocuSign's public Maven during `expo prebuild`, verifies its SHA-256 against a pinned hash, removes the offending class from the AAR's `classes.jar` in-memory, and writes the stripped artifact to `node_modules/react-native-docusign/android/libs/`. The existing flatDir injection picks it up at consumer build time. The download is cached after the first run; corrupted or partial caches are detected and regenerated. SHA mismatch or fetch failure aborts `expo prebuild` with an actionable error rather than silently letting the Android build fail later at the dex step. +DocuSign's `com.docusign:sdk-pdf:2.1.7` AAR ships a pre-generated `com.bumptech.glide.GeneratedAppGlideModuleImpl.class` that collides at dex time with any other Glide-based library in the host app (notably `expo-image`, `react-native-fast-image`, and similar). To avoid this without redistributing DocuSign's binary, the Expo Config Plugin downloads `sdk-pdf-2.1.7.aar` directly from DocuSign's public Maven during `expo prebuild`, verifies its SHA-256 against a pinned hash, removes the offending class from the AAR's `classes.jar` in-memory, and writes the stripped artifact to `node_modules/react-native-docusign/android/libs/`. The existing flatDir injection picks it up at consumer build time. The download is cached after the first run; corrupted or partial caches are detected and regenerated. SHA mismatch or fetch failure aborts `expo prebuild` with an actionable error rather than silently letting the Android build fail later at the dex step. ### What ships inside this package @@ -182,7 +182,7 @@ npx expo run:android If you are not using Expo prebuild, you must manually: -- **iOS**: add `pod 'DocuSign-iOS-SDK', '~> 4.1.1'` to your Podfile and run `pod install` +- **iOS**: run `pod install`. This package's podspec already depends on the `DocuSign` pod, so your Podfile needs no entry for it - **Android**: add the Maven repo and the DocuSign dependency to your `android/build.gradle` + `android/app/build.gradle` - **iOS**: add the `NSCameraUsageDescription` and `NSPhotoLibraryUsageDescription` keys to your `Info.plist` - **Android**: add the required permissions to your `AndroidManifest.xml` @@ -209,7 +209,7 @@ type DocuSignPluginProps = { /** * URL of the Android Maven repository that serves the DocuSign Android SDK. - * Defaults to 'https://maven.docusign.com/'. + * Defaults to 'https://docucdn-a.akamaihd.net/prod/docusignandroidsdk'. * Override only if DocuSign moves their repo. */ androidMavenRepo?: string; @@ -899,24 +899,26 @@ The config plugin writes these keys automatically, or you can configure them man ### iOS build fails with "No such module 'DocuSignSDK'" -Ensure `pod install` completed successfully inside `ios/`. The podspec declares a dependency on `DocuSign-iOS-SDK`; if CocoaPods trunk is unreachable, the pod cannot be installed. Check your network, proxy, and CocoaPods version (`pod --version` should be 1.14+). +Ensure `pod install` completed successfully inside `ios/`. The podspec declares a dependency on the `DocuSign` pod; if CocoaPods trunk is unreachable, the pod cannot be installed. Check your network, proxy, and CocoaPods version (`pod --version` should be 1.14+). ### iOS build fails with "Undefined symbols" for DSMManager The DocuSign SDK must be set to `use_frameworks!` mode. Most Expo projects use frameworks by default. If you recently switched to static libraries, add `use_frameworks! :linkage => :static` to your Podfile and rebuild. -### Android build fails with "Could not find com.docusign:androidsdk:2.1.4" +### Android build fails with "Could not find com.docusign:androidsdk:2.1.7" The DocuSign Android SDK is not on Maven Central; it is hosted on DocuSign's own Maven repository. Ensure the config plugin has added the repo to your project-level `build.gradle`. If running a bare project, manually add: ```groovy allprojects { repositories { - maven { url "https://maven.docusign.com/" } + maven { url "https://docucdn-a.akamaihd.net/prod/docusignandroidsdk" } } } ``` +This is the URL DocuSign's own [Android SDK install guide](https://github.com/docusign/mobile-android-sdk) uses. It is a static file host with no index page, so opening it in a browser returns 404 even though Gradle resolves artifacts under it, such as `com/docusign/androidsdk/2.1.7/androidsdk-2.1.7.pom`. It also serves no `maven-metadata.xml`, so declare exact versions: a dynamic version such as `2.+` does not resolve. + ### "not_logged_in" error when calling `presentCaptiveSigning` The SDK login state is in-memory and does not survive app restarts. Always call `loginWithAccessToken()` before `presentCaptiveSigning()` within the same app session. @@ -953,6 +955,7 @@ The module uses `appContext.activityProvider.currentActivity` to get the current | This package version | Expo SDK | React Native | iOS SDK | Android SDK | | -------------------- | -------- | ------------ | ------------------ | ---------------------- | | 1.0.x | 55.x | 0.82.x | DocuSign iOS 4.1.1 | DocuSign Android 2.1.4 | +| 2.0.x | 55.x+ | 0.85.x+ | DocuSign iOS 4.3.0 | DocuSign Android 2.1.7 | ## Limitations diff --git a/android/build.gradle b/android/build.gradle index cab473a..f75d55f 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -70,14 +70,14 @@ dependencies { // collides with expo-image (and any other Glide-based library) at dex time. // We exclude the upstream sdk-pdf and link a locally-stripped copy from // libs/ that has the generated Glide classes removed. - implementation('com.docusign:androidsdk:2.1.4') { + implementation('com.docusign:androidsdk:2.1.7') { exclude group: 'com.docusign', module: 'sdk-pdf' } - implementation 'com.docusign:sdk-common:2.1.4' + implementation 'com.docusign:sdk-common:2.1.7' // Direct file reference instead of flatDir (name:..., ext:...). Gradle 9.0 no // longer honors subproject-scoped flatDir when resolving across project - // boundaries, so the stripped AAR (placed at libs/sdk-pdf-2.1.4-stripped.aar + // boundaries, so the stripped AAR (placed at libs/sdk-pdf-2.1.7-stripped.aar // by the config plugin) wasn't found and the build failed with - // "Could not find :sdk-pdf-2.1.4-stripped:". - implementation files("$projectDir/libs/sdk-pdf-2.1.4-stripped.aar") + // "Could not find :sdk-pdf-2.1.7-stripped:". + implementation files("$projectDir/libs/sdk-pdf-2.1.7-stripped.aar") } diff --git a/ios/DocuSignError.swift b/ios/DocuSignError.swift index 51c5724..286cb68 100644 --- a/ios/DocuSignError.swift +++ b/ios/DocuSignError.swift @@ -5,7 +5,7 @@ import ExpoModulesCore // when none is set, which would surface NotInitializedException to JS as ERR_NOT_INITIALIZED, not // the not_initialized documented in the README error table and emitted by the Android module. -internal class InitializeFailedException: GenericException { +internal class InitializeFailedException: GenericException, @unchecked Sendable { override var code: String { "initialize_failed" } @@ -15,7 +15,7 @@ internal class InitializeFailedException: GenericException { } } -internal class SigningInProgressException: Exception { +internal class SigningInProgressException: Exception, @unchecked Sendable { override var code: String { "signing_in_progress" } @@ -25,7 +25,7 @@ internal class SigningInProgressException: Exception { } } -internal class InvalidSigningUrlException: Exception { +internal class InvalidSigningUrlException: Exception, @unchecked Sendable { override var code: String { "invalid_signing_url" } @@ -35,7 +35,7 @@ internal class InvalidSigningUrlException: Exception { } } -internal class NotInitializedException: Exception { +internal class NotInitializedException: Exception, @unchecked Sendable { override var code: String { "not_initialized" } @@ -45,7 +45,7 @@ internal class NotInitializedException: Exception { } } -internal class NotLoggedInException: Exception { +internal class NotLoggedInException: Exception, @unchecked Sendable { override var code: String { "not_logged_in" } @@ -55,7 +55,7 @@ internal class NotLoggedInException: Exception { } } -internal class PresentationException: GenericException { +internal class PresentationException: GenericException, @unchecked Sendable { override var code: String { "presentation_failed" } diff --git a/ios/DocuSignManager.swift b/ios/DocuSignManager.swift index 8116b18..380b494 100644 --- a/ios/DocuSignManager.swift +++ b/ios/DocuSignManager.swift @@ -88,7 +88,7 @@ internal final class DocuSignManager: NSObject { self.environment = environment let dispatchSetup: () -> Void = { - var configurations = DSMManager.defaultConfigurations() ?? [:] + var configurations = DSMManager.defaultConfigurations() if options.disablePoweredByBranding { configurations[DSM_SETUP_POWERED_BY_DOCUSIGN_ENABLED] = DSM_SETUP_FALSE_VALUE } diff --git a/ios/ReactNativeDocuSign.podspec b/ios/ReactNativeDocuSign.podspec index 33f870a..9c1a0d9 100644 --- a/ios/ReactNativeDocuSign.podspec +++ b/ios/ReactNativeDocuSign.podspec @@ -18,7 +18,7 @@ Pod::Spec.new do |s| s.static_framework = true s.dependency 'ExpoModulesCore' - s.dependency 'DocuSign', '~> 4.1.1' + s.dependency 'DocuSign', '~> 4.3.0' s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', diff --git a/plugin/src/index.ts b/plugin/src/index.ts index 0f7f52b..e750e2b 100644 --- a/plugin/src/index.ts +++ b/plugin/src/index.ts @@ -16,16 +16,16 @@ const DEFAULT_CAMERA_PERMISSION = const DEFAULT_PHOTO_PERMISSION = 'Allows selecting photos to attach to DocuSign documents.'; -const SDK_PDF_VERSION = '2.1.4'; +const SDK_PDF_VERSION = '2.1.7'; const SDK_PDF_UPSTREAM_URL = `https://docucdn-a.akamaihd.net/prod/docusignandroidsdk/com/docusign/sdk-pdf/${SDK_PDF_VERSION}/sdk-pdf-${SDK_PDF_VERSION}.aar`; -// SHA-256 of the upstream `sdk-pdf-2.1.4.aar` as published on DocuSign's CDN. +// SHA-256 of the upstream `sdk-pdf-2.1.7.aar` as published on DocuSign's CDN. // Verified at the time this version of the plugin was cut. Any deviation // (CDN tampering, DNS hijack, partial download) causes the plugin to throw // rather than write a binary we cannot vouch for. To bump the upstream SDK // version, recompute this hash locally: // curl -sSL | shasum -a 256 const SDK_PDF_SHA256 = - '26eb53effd74d117397fbfd77e46a94786bbbd05fb9318fdbbff389c1a4dcb0a'; + '3f9be5ffcde3405ae422f7fe926d6ea716336b7cfc8ff9185d7cfb1d6203ab4a'; const STRIPPED_AAR_FILENAME = `sdk-pdf-${SDK_PDF_VERSION}-stripped.aar`; const GLIDE_GENERATED_CLASS = 'com/bumptech/glide/GeneratedAppGlideModuleImpl.class'; @@ -172,7 +172,7 @@ const withDocuSignAndroidStrippedAarFlatDir: ConfigPlugin = (config) => }); /** - * Downloads the upstream `com.docusign:sdk-pdf:2.1.4` AAR from DocuSign's + * Downloads the upstream `com.docusign:sdk-pdf:2.1.7` AAR from DocuSign's * public Maven repository and strips the pre-generated * `com.bumptech.glide.GeneratedAppGlideModuleImpl` class from its * `classes.jar`. The stripped artifact is written to