Skip to content

Replace unmaintained libs#373

Merged
overheadhunter merged 5 commits intodevelopfrom
feature/noble-libs
Dec 12, 2025
Merged

Replace unmaintained libs#373
overheadhunter merged 5 commits intodevelopfrom
feature/noble-libs

Conversation

@overheadhunter
Copy link
Copy Markdown
Member

This pull request updates the frontend's cryptography and encoding libraries to improve security, compatibility, and maintainability. The main changes involve replacing the deprecated miscreant and rfc4648 libraries with @noble/ciphers and @scure/base, updating related code to use the new APIs, and upgrading several dependencies to their latest versions.

Dependency updates and library replacements:

  • Replaced the miscreant and rfc4648 libraries with @noble/ciphers and @scure/base for cryptographic operations and base encoding/decoding. Updated all related imports and method calls in frontend/src/common/crypto.ts, frontend/src/common/jwe.ts, and frontend/src/common/backend.ts. [1] [2] [3] [4]

  • Upgraded several dev and runtime dependencies in frontend/package.json, including vite, vitest, vue, vue-i18n, @intlify/devtools-types, and removed unused/deprecated packages. [1] [2] [3]

Code refactoring for new libraries:

  • Refactored all base encoding/decoding operations to use the new @scure/base methods (encode, decode, etc.), replacing previous usage of stringify/parse and changing method signatures where necessary. This affects key import/export, JWT and JWE handling, and cryptographic utilities in multiple classes (VaultKeys, UserKeys, BrowserKeys, JWEParser, JWEBuilder, etc.). [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19]

Cryptography improvements:

  • Switched the AES-SIV implementation from miscreant to @noble/ciphers/aes.js for deterministic encryption, updating the relevant logic and comments in VaultKeys.hashDirectoryId.

Type and compatibility fixes:

  • Updated types for various cryptographic buffers to ensure compatibility with the new libraries (e.g., using Uint8Array<ArrayBuffer> where required). [1] [2] [3]

These changes modernize the codebase, remove deprecated dependencies, and ensure more robust cryptographic handling.

* `miscreant` → `@noble/ciphers`
* `rfc4648` → `@scure/base`
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request modernizes the frontend's cryptography stack by replacing deprecated libraries (miscreant and rfc4648) with actively maintained alternatives (@noble/ciphers and @scure/base). The migration includes:

  • Replacing all base encoding/decoding operations throughout the codebase
  • Migrating AES-SIV implementation to a new library
  • Updating multiple dependencies to their latest versions
  • Adding skipLibCheck: true to TypeScript configuration

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated no comments.

Show a summary per file
File Description
frontend/package.json Removed miscreant and rfc4648, added @noble/ciphers and @scure/base, updated vitest, vite, vue, and other dependencies
frontend/package-lock.json Updated lockfile with new dependencies and removed old ones
frontend/tsconfig.json Added skipLibCheck: true compiler option
frontend/src/common/crypto.ts Migrated to new APIs: base64.decode() instead of base64.parse(), aessiv() instead of miscreant.SIV, updated all encoding operations
frontend/src/common/jwe.ts Updated all base64url encoding/decoding to use base64urlnopad from @scure/base
frontend/src/common/jwt.ts Migrated JWT encoding/decoding to new base64url API
frontend/src/common/backend.ts Updated base64 import and usage
frontend/src/common/util.ts Added Uint8Array<ArrayBuffer> return type annotations
frontend/src/common/userdata.ts Updated type annotations and decode calls
frontend/src/common/wot.ts Migrated base64 decoding with type casts
frontend/src/components/*.vue Updated base64 imports and decode calls in Vue components
frontend/test/common/*.spec.ts Updated test files to use new encoding APIs

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Dec 8, 2025

Walkthrough

This PR replaces rfc4648 and miscreant with @scure/base and @noble/ciphers, adds @noble/ciphers and @scure/base to dependencies, updates multiple frontend dependency versions, and removes some deprecated optional deps. Encoding APIs were changed from base64.parse/stringify and base64url to base64.decode/encode and base64urlnopad; many return and field types were widened to Uint8Array. AES‑SIV usage was swapped to @noble/ciphers, and JWT/JWE construction/parsing was updated to use the new encoders. Small runtime error-handling and tsconfig changes were also included.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Files/areas needing extra attention:
    • frontend/src/common/crypto.ts — AES‑SIV replacement, key encode/decode flows, and public API signature widenings.
    • frontend/src/common/jwe.ts and frontend/src/common/jwt.ts — JWE/JWT encoding, header/payload/signature composition with base64urlnopad and type changes.
    • Type propagation: many return/field types changed to Uint8Array (userdata, util, wot, components) and tests updated accordingly.
    • frontend/package.json and tsconfig.json — dependency changes and compiler option adjustments.

Possibly related PRs

  • Web of Trust #281 — Overlapping frontend Web-of-Trust and crypto changes touching files like frontend/src/common/backend.ts and AuditLogDetailsSignedWotId.vue.

Suggested reviewers

  • to bihagemann
  • SailReal

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title directly summarizes the main change: replacing unmaintained libraries (miscreant and rfc4648 with @noble/ciphers and @scure/base), which is the primary objective of the changeset.
Description check ✅ Passed The description comprehensively covers the pull request changes including library replacements, dependency updates, code refactoring, and type adjustments, all directly related to the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/noble-libs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/common/crypto.ts (1)

207-222: Incorrect AES-SIV key handling—pass raw key directly to @noble/ciphers.

@noble/ciphers expects a single raw AES key (16/24/32 bytes) and internally derives/splits subkeys for SIV. The code manually splits the raw key into macKey and encKey, then reorders them before passing to aessiv(). This manual key manipulation contradicts the library's design and should be removed. Pass the raw key directly: aessiv(rawkey).encrypt(dirHash).

🧹 Nitpick comments (2)
frontend/tsconfig.json (1)

19-19: Stale comment referencing removed dependency.

The comment references miscreant as a workaround, but this PR removes miscreant in favor of @noble/ciphers. Consider removing this comment or updating it to reflect the current reason for useUnknownInCatchVariables: false.

-    "useUnknownInCatchVariables": false, // Workaround for `node_modules/miscreant/src/providers/webcrypto.ts:21:11 - error TS18046: 'e' is of type 'unknown'.`
+    "useUnknownInCatchVariables": false,
frontend/src/common/jwe.ts (1)

15-15: Typed-array generics (Uint8Array<ArrayBuffer>) are wired through correctly; minor JSDoc nit

Updating ConcatKDF.kdf, JWEParser’s internal buffers, and ECDH_ES.lengthPrefixed to use Uint8Array<ArrayBuffer> keeps them compatible with WebCrypto’s BufferSource expectations while making the backing buffer type explicit; current call sites (deriveContentKey, AES‑GCM encrypt/decrypt, unwrapKey, etc.) all remain valid.

The only nit is that otherInfo in ConcatKDF.kdf is documented as “Optional” but is required by the signature and always passed in; consider updating the comment (or adding a default) so the docs reflect actual usage.

Also applies to: 56-59, 240-245

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 00e499e and 1061a42.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (13)
  • frontend/package.json (3 hunks)
  • frontend/src/common/backend.ts (2 hunks)
  • frontend/src/common/crypto.ts (13 hunks)
  • frontend/src/common/jwe.ts (10 hunks)
  • frontend/src/common/jwt.ts (4 hunks)
  • frontend/src/common/userdata.ts (4 hunks)
  • frontend/src/common/util.ts (2 hunks)
  • frontend/src/common/wot.ts (3 hunks)
  • frontend/src/components/AuditLogDetailsSignedWotId.vue (2 hunks)
  • frontend/src/components/GrantPermissionDialog.vue (2 hunks)
  • frontend/test/common/crypto.spec.ts (4 hunks)
  • frontend/test/common/jwe.spec.ts (2 hunks)
  • frontend/tsconfig.json (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2024-07-27T13:14:40.963Z
Learnt from: overheadhunter
Repo: cryptomator/hub PR: 282
File: frontend/src/common/userdata.ts:82-88
Timestamp: 2024-07-27T13:14:40.963Z
Learning: The error handling suggestion for `createBrowserKeys` in `frontend/src/common/userdata.ts` was discussed and resolved in PR #282, and should not be repeated in future reviews.

Applied to files:

  • frontend/src/common/userdata.ts
📚 Learning: 2025-02-13T10:33:38.555Z
Learnt from: overheadhunter
Repo: cryptomator/hub PR: 315
File: backend/src/main/java/org/cryptomator/hub/api/UserDto.java:0-0
Timestamp: 2025-02-13T10:33:38.555Z
Learning: In the UserDto class of the Cryptomator Hub project, the `JsonCreator` constructor is used to handle both new and legacy field names (e.g., `ecdhPublicKey`/`publicKey` and `privateKeys`/`privateKey`) during JSON deserialization, while a separate regular constructor is used for programmatic object creation with only the new field names.

Applied to files:

  • frontend/src/common/crypto.ts
🧬 Code graph analysis (4)
frontend/src/common/wot.ts (2)
frontend/src/common/crypto.ts (2)
  • asPublicKey (458-464)
  • UserKeys (260-383)
frontend/src/common/userdata.ts (2)
  • ecdhPublicKey (68-75)
  • ecdsaPublicKey (82-86)
frontend/src/common/jwt.ts (1)
frontend/src/common/util.ts (1)
  • UTF8 (3-26)
frontend/src/common/userdata.ts (1)
frontend/src/common/backend.ts (1)
  • me (268-270)
frontend/src/common/crypto.ts (2)
frontend/src/common/util.ts (1)
  • UTF8 (3-26)
frontend/src/common/userdata.ts (1)
  • ecdsaPublicKey (82-86)
🔇 Additional comments (38)
frontend/src/common/backend.ts (2)

324-324: Switch to base64.encode(bytes) for SVG data URL is appropriate

Encoding the UTF‑8 SVG bytes with base64.encode(bytes) to build the data:image/svg+xml;base64,... URL is correct and matches the intended deterministic behavior of the previous Base64 implementation.


1-1: Import of base64 from @scure/base is correct

The named base64 export from @scure/base is a documented API that provides encode(bytes: Uint8Array): string and decode(str: string): Uint8Array methods. This import is appropriate for the use case.

frontend/package.json (3)

25-25: LGTM on minor/patch version updates.

The patch bumps for @intlify/devtools-types (^11.1.12 → ^11.2.2) and vite (^7.1.10 → ^7.2.7), along with runtime updates (vue, vue-i18n) are low-risk and appropriately scoped.

Also applies to: 43-43


34-34: Verify vitest v4 breaking changes and compatibility.

The vitest ecosystem jump from v3 to v4 is a major version bump. Confirm that the test suite and any vitest plugins/integrations (e.g., @vitest/coverage-v8, vue integration) are compatible with v4.0.15 and that no breaking changes affect existing test configuration or test code.

Run the following shell script to check for test suite compatibility with vitest v4:

#!/bin/bash
# Description: Verify vitest v4 migration compatibility

# Check if vitest config file exists and show its content
fd -e 'vitest.config|vite.config' -t f | head -5 | xargs -I {} sh -c 'echo "=== {} ===" && cat {}'

# Check package.json for vitest-related scripts and plugins
echo -e "\n=== Test Scripts ===" && jq '.scripts | select(. != null) | to_entries[] | select(.value | contains("vitest"))' frontend/package.json

# Check for test files to understand test patterns
echo -e "\n=== Test Files ===" && fd -e '\.test\.(ts|js)$|\.spec\.(ts|js)$' frontend/ -t f | head -10

Also applies to: 44-44


51-52: @noble/ciphers and @scure/base are production-ready and well-maintained.

Both libraries are actively maintained with recent releases (2025), independently audited by Cure53 (@scure/base in Jan 2022, @noble/ciphers in Sep 2024), and follow strong supply-chain practices with PGP-signed commits and CI provenance. No known vulnerabilities or malicious activity reported. These are appropriate replacements for miscreant and rfc4648.

frontend/src/common/wot.ts (3)

1-1: LGTM!

The import migration from rfc4648 to @scure/base is correct and consistent with the rest of the codebase changes.


73-73: Consistent encoding migration.

The change from base64.parse to base64.decode with the Uint8Array<ArrayBuffer> cast follows the established pattern across the codebase. The decoded key is correctly passed to asPublicKey.


87-88: Fingerprint computation updated correctly.

Both ECDH and ECDSA public key decoding uses the same consistent pattern as line 73.

frontend/src/components/AuditLogDetailsSignedWotId.vue (2)

41-41: LGTM!

Import migration is consistent with the codebase-wide change.


78-78: Decoding updated correctly for signature verification.

The base64.decode with Uint8Array<ArrayBuffer> cast matches the pattern used elsewhere for key material decoding.

frontend/test/common/crypto.spec.ts (4)

1-1: LGTM!

Test imports correctly updated to use @scure/base with both base64 and base64urlnopad variants.


113-113: Test data decoding updated correctly.

The test key decoding uses the same pattern as production code.


194-214: Key export encoding tests updated correctly.

All base64.stringify calls replaced with base64.encode. The expected base64 strings remain unchanged, confirming encoding compatibility.


244-244: JWK thumbprint test updated correctly.

Using base64urlnopad.encode instead of base64url.stringify(..., { pad: false }) is the correct migration. The expected value matches RFC 7638 Section 3.1.

frontend/src/common/util.ts (2)

12-14: LGTM!

The return type annotation Uint8Array<ArrayBuffer> accurately reflects what TextEncoder.encode() returns and improves type consistency across the codebase.


141-164: LGTM!

The return type annotation change is correct since new Uint8Array(length) creates an ArrayBuffer-backed typed array.

frontend/src/common/jwt.ts (5)

1-1: LGTM!

Correct import for unpadded base64url encoding as required by JWT specification.


23-27: JWT building correctly updated.

The header and payload encoding using base64urlnopad.encode is correct for JWT format per RFC 7519.


40-40: Signature encoding updated correctly.

The signature is correctly encoded using unpadded base64url.


50-61: JWT parsing correctly updated.

Header and payload decoding using base64urlnopad.decode is consistent with the encoding changes.


68-68: Signature decoding correctly updated.

The cast to Uint8Array<ArrayBuffer> ensures type compatibility with crypto.subtle.verify.

frontend/src/common/userdata.ts (4)

1-1: LGTM!

Import migration is consistent with the codebase-wide change.


68-75: LGTM!

The return type update and decoding change are correct. The cast ensures type compatibility with downstream crypto operations.


82-86: LGTM!

Consistent with the ecdhPublicKey getter pattern, handling the optional case correctly.


168-168: LGTM!

Device public key decoding correctly migrated for the ECDSA key migration flow.

frontend/src/common/crypto.ts (10)

1-4: LGTM!

Import changes correctly bring in the new cryptographic primitives from @noble/ciphers and encoding utilities from @scure/base.


87-92: LGTM!

Key decoding from JWE payload correctly migrated with proper zeroing of sensitive data in the finally block.


115-126: LGTM!

PBKDF2 salt and wrapped key decoding correctly updated for the legacy admin password flow.


148-148: LGTM!

Public key cast ensures type compatibility with crypto.subtle.importKey.


197-204: LGTM!

Vault config JWT creation correctly uses base64urlnopad for header, payload, and signature encoding.


313-319: LGTM!

Private key decoding in createFromJwe correctly uses base64.decode with proper type casting for crypto.subtle.importKey.


334-344: LGTM!

Public key encoding methods correctly migrated from base64.stringify to base64.encode.


363-367: LGTM!

The signature change to Uint8Array<ArrayBuffer> is consistent with the type annotations used throughout the codebase for decoded key material.


374-377: LGTM!

Private key encoding for JWE payload correctly migrated.


449-454: LGTM!

Browser key ID and public key encoding correctly updated to use base16.encode and base64.encode respectively.

frontend/test/common/jwe.spec.ts (2)

1-1: Switching test base64 import to @scure/base matches the runtime code

Using base64urlnopad here keeps the test harness aligned with the implementation in src/common/jwe.ts, so encoded values should stay in lockstep with production behavior.

Please confirm that vitest runs against this branch use the same @scure/base version as the app build so tests don’t mask version‑specific differences.


115-123: apu/apv encoding via base64urlnopad.encode preserves the ECDH-ES test vector

Encoding the apu / apv Uint8Arrays with base64urlnopad.encode matches the JOSE requirement for unpadded base64url and should yield the same strings as the previous stringify(..., { pad: false }) for this vector.

Please re‑run the ECDH‑ES vector test and, if you have older artifacts, spot‑check that apu/apv encodings are identical across the library swap.

frontend/src/common/jwe.ts (1)

1-1: Base64 migration to @scure/base looks consistent and JOSE‑compliant

All JWE‑related encoding/decoding (header, IV, encrypted key, ciphertext, tag, apu/apv, and p2s) now uses base64urlnopad.encode/.decode, and builder/parser remain symmetric, which aligns with RFC 7516/7518’s requirement for unpadded base64url encodings.

One behavioral change to be aware of is that base64urlnopad.decode may be stricter than the previous rfc4648 helper (especially around padding or “loose” inputs), so if you accept JWEs from third parties that might emit padded or non‑canonical encodings, it’s worth double‑checking that they still parse cleanly or normalizing inputs before decode.

If you have sample JWEs from external producers (esp. for PBES2 and ECDH‑ES flows), please run decryption against this branch to confirm there are no regressions in how non‑canonical base64url inputs are handled.

Also applies to: 62-66, 103-104, 145-151, 166-176, 189-193, 206-207, 218-221

overheadhunter and others added 2 commits December 8, 2025 21:45
`Type 'unknown' is not assignable to type 'Error | null | undefined'`
Copy link
Copy Markdown
Contributor

@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

🧹 Nitpick comments (1)
frontend/src/components/SignUserKeysDialog.vue (1)

119-120: Good defensive error handling with logging.

The addition of console.error improves debugging visibility, and the instanceof Error check ensures type-safe error handling for the template.

Optionally, consider preserving the original error value when it's not an Error instance:

-    onSignError.value = error instanceof Error ? error : new Error('Unknown Error');
+    onSignError.value = error instanceof Error ? error : new Error(`Unknown Error: ${error}`);

This would capture more diagnostic information if an unexpected non-Error value is thrown.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0cbc706 and f507da5.

📒 Files selected for processing (1)
  • frontend/src/components/SignUserKeysDialog.vue (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-07-27T13:14:40.963Z
Learnt from: overheadhunter
Repo: cryptomator/hub PR: 282
File: frontend/src/common/userdata.ts:82-88
Timestamp: 2024-07-27T13:14:40.963Z
Learning: The error handling suggestion for `createBrowserKeys` in `frontend/src/common/userdata.ts` was discussed and resolved in PR #282, and should not be repeated in future reviews.

Applied to files:

  • frontend/src/components/SignUserKeysDialog.vue
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run Tests

@overheadhunter overheadhunter added this to the 1.5.0 milestone Dec 12, 2025
@overheadhunter overheadhunter merged commit c916c78 into develop Dec 12, 2025
8 checks passed
@overheadhunter overheadhunter deleted the feature/noble-libs branch December 12, 2025 09:53
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