open-standards/openpay/crates/op-3ds2/Cargo.toml
David Charlot 84fc32449a
All checks were successful
jouleclaw public surface must stay documented / Public-surface audit (jouleclaw-rs) (push) Successful in 57s
chore(deps): update dependencies for Rust 1.98, pinning the crypto generations
Finishes the workspace-wide dependency refresh on stable 1.98.0. Most crates
took the newest release cleanly; the ones below could not, and the reason is
worth recording because "latest" is the wrong answer for several of them.

rand is pinned to 0.8, not 0.10. rand 0.10 dropped `rand::RngCore` and
`rand::rngs::OsRng`, but the real blocker is that it ships rand_core 0.10
while every signature crate here (ed25519-dalek 2.x, bls12_381, k256/p256)
is built on rand_core 0.6 -- so a 0.10 RNG is not even the right *type* to
hand to `SigningKey::generate`. rand 0.8 re-exports rand_core 0.6, which is
exactly what those crates want. rand_chacha follows it to 0.3 for the same
reason. The RNG generation is pinned by the crypto ecosystem, not by recency.

aes is pinned to 0.8 (cipher 0.4) in smart-byte-nostr and op-mobile-wallets:
aes 0.9 moved to cipher 0.5, which removed `BlockEncryptMut`,
`encrypt_padded_vec_mut` and `StreamCipherCoreWrapper::new` that this code
uses, and aes-gcm 0.10 pulls cipher 0.4 anyway -- so 0.9 also put two aes and
two cipher versions in the graph. op-3ds2 declared aes/cbc for an encrypted
deviceInfo block it never implemented; dropping those unused deps removes the
last cipher 0.5 edge, leaving a single aes and a single cipher.

reqwest 0.13 moved `RequestBuilder::query` and `::form` behind new features,
which `default-features = false` was silently excluding. Enabled per crate.

Source changes are the matching API drift:
  - hmac's `new_from_slice` lives on `KeyInit`, not `Mac`
  - secp256k1 0.31 takes the array by value in `from_byte_array`, and its own
    re-exported `rand` is used for keygen so the two can never drift again
  - smart-byte-mdl reads OS entropy from getrandom directly. It was reaching
    for a rand RNG only to get 32 bytes, and going to the primitive genuinely
    removes the CryptoRng skew with p256 0.14-rc that the comment there
    described dodging -- and drops rand from that crate entirely.

Verified: all 20 workspaces in the monorepo compile with
`cargo check --workspace --all-targets` on 1.98.0, zero errors.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-26 12:19:50 -04:00

72 lines
2.9 KiB
TOML

[package]
name = "op-3ds2"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
repository.workspace = true
description = "OpenPay 3-D Secure 2.x: full 3DS Requestor / Server / DS / ACS message stack for protocol versions 2.1.0, 2.2.0, and 2.3.0. SCA exemption evaluator covering PSD2 RTS + PSD3 (2026) update. Browser-fingerprint collection, app-based 3DS, decoupled authentication, data-only, and 3RI flows."
publish = false
[dependencies]
op-core = { path = "../op-core" }
# Core serde + JSON. EMVCo 3DS 2.x messages are JSON over HTTPS; the
# only XML-flavoured corner is a small set of legacy 2.1.0 transitional
# payloads which we round-trip through quick-xml when present.
serde = { workspace = true }
serde_json = { workspace = true }
# Time handling. Chrono is the de-facto choice in 2026 for DateTime<Utc>
# round-tripping over JSON; we use it for trusted-beneficiary
# enrolment timestamps and challenge timeouts.
chrono = { version = "0.4", default-features = false, features = ["clock", "serde", "std"] }
# UUIDs for messageVersion / threeDSServerTransID / acsTransID /
# dsTransID. EMVCo spec mandates UUIDv4 format for all transaction IDs.
uuid = { workspace = true }
# Base64 for CAVV, TAVV, deviceInfo, and the various opaque blobs that
# travel inside 3DS messages.
base64 = "0.22"
# SHA-256 for the AReq -> AReq hash used in the 3DS Method invocation
# and for CAVV verification.
sha2 = "0.11"
# NOTE: the encrypted deviceInfo block (SDK device data, AES-CBC under a
# session key established via ECDH-P-256) is not implemented yet, so no
# aes/cbc dependency is declared. Add them when that lands -- and match the
# cipher 0.4 generation the rest of the workspace uses (aes 0.8 / cbc 0.1),
# so the build keeps a single aes + cipher in the graph.
# RSA for legacy issuer ACS public keys, P-256 for the modern
# ECDH-based session key establishment used by the SDK device-binding
# flow.
rsa = "0.9"
p256 = { version = "0.13", features = ["ecdh", "ecdsa"] }
# X.509 parsing for DS / ACS certificate chain validation. Each card
# scheme issues its own DS certificate; we parse and pin against the
# scheme root.
x509-parser = "0.18"
# quick-xml for the small set of legacy XML payloads (DS version-check
# in the 2.1.0 transition window and some scheme-specific extensions).
quick-xml = { workspace = true }
# Async runtime + HTTP client for DS / ACS calls.
tokio = { workspace = true }
reqwest = { version = "0.13", default-features = false, features = ["rustls", "json"] }
# Object-safe async trait surface (DirectoryServer / AcsServer are
# trait objects). Native async-fn-in-trait is stable on 1.95 but
# the dyn-compat form still needs the macro shim.
async-trait = "0.1"
thiserror = { workspace = true }
tracing = { workspace = true }
[dev-dependencies]
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
serde_json = { workspace = true }