Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Upgrading from 1.x: every failure now rejects with a `DocuSignError`. Check any

- 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.
- **Android**: the Config Plugin no longer adds a `flatDir` block to `android/build.gradle`, and no longer warns Kotlin Script projects to add one by hand. The module has referenced the stripped `sdk-pdf` AAR by file path since 1.0.4, so the block did nothing. On current Expo templates it was never added anyway, because its pattern could not match the nested `maven { ... }` entry inside `allprojects.repositories`.
- **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.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ The DocuSign native SDKs are **NOT bundled** inside this npm package. They are d

### Android Glide collision workaround

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.
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 module's `android/build.gradle` references it by file path 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

Expand Down
13 changes: 13 additions & 0 deletions plugin/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,19 @@ describe('withDocuSign android maven repository', () => {
);
});

it('changes build.gradle only by adding the DocuSign repository', async () => {
const original = buildProjectGradle([]);

const contents = await applyProjectBuildGradleMods(original);

expect(contents).toBe(
original.replace(
'allprojects {\n repositories {',
`allprojects {\n repositories {\n maven { url "${DOCUSIGN_REPO}" }`,
),
);
});

it('adds androidMavenRepo instead of the DocuSign repository when provided', async () => {
const contents = await applyProjectBuildGradleMods(buildProjectGradle([]), {
androidMavenRepo: CUSTOM_REPO,
Expand Down
50 changes: 4 additions & 46 deletions plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,53 +132,13 @@ const withDocuSignAndroidMavenRepo: ConfigPlugin<DocuSignPluginProps> = (
});
};

const FLAT_DIR_MARKER = 'react-native-docusign-stripped-aar-flatdir';

const withDocuSignAndroidStrippedAarFlatDir: ConfigPlugin = (config) =>
withProjectBuildGradle(config, (cfg) => {
if (cfg.modResults.language !== 'groovy') {
WarningAggregator.addWarningAndroid(
'react-native-docusign',
'android/build.gradle is Kotlin Script (.kts); cannot auto-inject the stripped sdk-pdf flatDir. Add this inside allprojects:\n afterEvaluate {\n rootProject.findProject(":react-native-docusign")?.let { docusignProject ->\n repositories { flatDir { dirs("${docusignProject.projectDir}/libs") } }\n }\n }',
);
return cfg;
}

if (cfg.modResults.contents.includes(FLAT_DIR_MARKER)) {
return cfg;
}

const flatDirBlock = ` // ${FLAT_DIR_MARKER}: exposes the stripped sdk-pdf AAR bundled with react-native-docusign.
// The AAR has com.bumptech.glide.GeneratedAppGlideModuleImpl removed to prevent
// duplicate-class collisions with expo-image and other Glide-based libraries.
afterEvaluate {
def docusignProject = rootProject.findProject(':react-native-docusign')
if (docusignProject != null) {
repositories {
flatDir { dirs "\${docusignProject.projectDir}/libs" }
}
}
}`;

const allprojectsRegex = /(allprojects\s*\{(?:[^{}]|\{[^{}]*\})*)(\n\})/;
if (allprojectsRegex.test(cfg.modResults.contents)) {
cfg.modResults.contents = cfg.modResults.contents.replace(
allprojectsRegex,
`$1\n${flatDirBlock}$2`,
);
}

return cfg;
});

/**
* 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
* `node_modules/react-native-docusign/android/libs/` so the existing flatDir
* Gradle injection (added by `withDocuSignAndroidStrippedAarFlatDir`) can
* resolve it at consumer build time.
* `node_modules/react-native-docusign/android/libs/`, where the module's
* `android/build.gradle` references it by file path at consumer build time.
*
* The strip prevents a duplicate-class collision at the consumer's
* `mergeDexDebug` / `mergeDexRelease` step when the host app also includes
Expand Down Expand Up @@ -233,9 +193,8 @@ const withDocuSignAndroidStripDocusignSdkPdf: ConfigPlugin = (config) =>
withDangerousMod(config, [
'android',
async (cfg) => {
// Resolve the installed package's android/libs/ directory so the
// `flatDir` injection (which references docusignProject.projectDir/libs)
// finds the stripped AAR.
// Resolve the installed package's android/libs/ directory, which the
// module's android/build.gradle references by file path.
let packageRoot: string;
try {
const packageJsonPath = require.resolve(
Expand Down Expand Up @@ -289,7 +248,6 @@ const withDocuSign: ConfigPlugin<DocuSignPluginProps | void> = (
updated = withDocuSignAndroidPermissions(updated);
updated = withDocuSignAndroidMavenRepo(updated, resolvedProps);
updated = withDocuSignAndroidStripDocusignSdkPdf(updated);
updated = withDocuSignAndroidStrippedAarFlatDir(updated);
return updated;
};

Expand Down
Loading