feat(api): accept Yivi condiscon in IrmaAuthRequest#198
Conversation
Add `ConItem` to `pg-core::api`, an `#[serde(untagged)]` enum whose two
variants — `Single(DisclosureAttribute)` and `Discon(Vec<Vec<...>>)` —
let a top-level `con` entry be either one attribute (legacy) or a
disjunction-of-conjunctions (new). `IrmaAuthRequest.con` widens to
`Vec<ConItem>`. The legacy flat `{"con":[{t,v?,optional?}, ...]}` JSON
body still parses, because untagged enums fall through to the matching
variant.
In `pg-pkg::handlers::start`, the request → Yivi `DisclosureRequest`
mapping moves into `con_item_to_discon`. `Single` keeps today's
behaviour (`[[ar]]` or `[[],[ar]]` when `optional`); `Discon` passes
each inner conjunction through verbatim. The auth middleware already
flattens whatever the user disclosed, so verification is unchanged.
Motivation: postguard-website needs to accept a name from one of four
credentials (gemeente fullname OR firstName+lastName from passport /
idcard / drivinglicence). Expressing that requires a Yivi
disjunction-of-conjunctions, which the previous flat shape could not
encode. The condiscon-to-conjunction normalisation already happens
inside `Derive` (Algorithm 3 in the hand-off doc), so this only widens
the HTTP boundary, not the protocol.
Backwards compatible: legacy callers (pg-cli, postguard-js < this PR)
keep working without changes; new callers opt in to discons.
Tests:
- `pg-core/src/api.rs`: round-trip a JSON body containing a discon
entry; round-trip a legacy flat body. Both pass.
- `pg-pkg/src/handlers/start.rs`: unit tests on
`con_item_to_discon` for Single (required + optional) and Discon
(basic + with empty alternative).
`cargo test -p pg-core --features test`: 43/43.
`cargo test -p pg-pkg`: 34/34 (4 new + 30 prior).
|
Dobby has received the request! Routing to the right specialist now... |
|
/dobby review |
|
Dobby has received the request! Routing to the right specialist now... |
There was a problem hiding this comment.
Code review
Widens IrmaAuthRequest.con to Vec<ConItem> (Single | Discon via #[serde(untagged)]). Legacy flat-con clients still parse because the two variant shapes are disjoint, mapping logic in con_item_to_discon is faithful, and tests cover both parse paths plus all four mapping branches. Two minor inline notes on edge cases worth documenting or rejecting.
| } | ||
| ConItem::Discon(disjuncts) => disjuncts | ||
| .iter() | ||
| .map(|conj| conj.iter().map(attr_to_request).collect()) |
There was a problem hiding this comment.
[Code review] Inside the Discon arm, the per-attribute optional: true flag is silently dropped — only Single honors it (via the empty-alternative prepend). A caller setting optional: true on a DisclosureAttribute nested in a Discon will get required-disclosure behavior with no warning. Document that discon-level optionality must use an empty inner conjunction, or reject optional: true here.
| /// A single attribute, optionally marked `optional: true`. | ||
| Single(DisclosureAttribute), | ||
| /// A disjunction of conjunctions of attributes. | ||
| Discon(Vec<Vec<DisclosureAttribute>>), |
There was a problem hiding this comment.
[Code review] ConItem::Discon(vec![]) (empty outer disjunction) deserializes successfully and is forwarded to Yivi as an empty discon, which is semantically unsatisfiable. No test covers this; consider rejecting it at parse or mapping time.
…crypt reactivity (#240) * feat(filesharing): accept signer name from passport/idcard/drivinglicence Replace the previous (PR #239) mandatory pbdf.gemeente.personalData.fullname disclosure with a Yivi disjunction-of-conjunctions: the signer must disclose a name, but they may satisfy that from any one of four credentials -- gemeente fullname, OR firstName+lastName from pbdf.pbdf.{passport,idcard,drivinglicence}. This addresses dobby's review of #239: requiring only the gemeente credential silently locked out everyone without a Dutch municipality attestation. The disjunction is mandatory -- disclosure refuses to complete unless at least one option is satisfied. Optional mobilenumber and dateofbirth remain unchanged. The disjunction lives in a new signAttributes.ts module exporting a typed AttrConItem[] consumed by SendButton.svelte. Splitting it out keeps the component file focused and the attribute list reviewable in isolation. Locale copy updates flagged by dobby on en.json/nl.json: - emailSenderSubHeading describes the four-credential rule. - yiviTip no longer frames the name as optional. The $derived.by + (!canEncrypt) call-site fixes from #239 are preserved. Depends on encryption4all/postguard#198 (PKG), postguard-js#78 (sign.yivi attrs), and cryptify#170 (render firstName+lastName). Supersedes #239 in this repo. npm run check: 0 errors, 0 warnings. * feat(filesharing): only require email on sign step; name is optional Remove the mandatory name disjunction from SIGN_ATTRIBUTES so senders only need to prove their email address (the pre-#239 UX). The condiscon infrastructure in postguard/pg-js remains available for future use. Update locale strings to no longer mention the name requirement. * fix: remove AttrConItem import (not yet in published pg-js) * feat(filesharing): optional name disjunction via pg-js 1.11.0 condiscon Bump @e4a/pg-js to 1.11.0 which adds AttrDiscon support. Use it to request the sender's name optionally from any of four credentials (gemeente fullname, passport, ID card, or driving licence). The leading empty alternative keeps the group skippable for senders without any of these credentials.
Summary
pg-core::api: add untaggedConItemenum (Single|Discon); widenIrmaAuthRequest.contoVec<ConItem>.pg-pkg::handlers::start: extractcon_item_to_discon; mapSingleas today,Disconstraight through to the YiviDisclosureRequest.pg-cli: callers wrap intoConItem::Single(no behaviour change).Backwards compatible at the HTTP boundary — legacy
{"con":[{t,v?,optional?}, ...]}bodies still parse, becauseConItemis#[serde(untagged)].Why
postguard-website needs to accept a sender name from one of four Yivi credentials — gemeente
personalData.fullnameorfirstName+lastNamefrompbdf.pbdf.passport/idcard/drivinglicence. The current flatconshape can only express a conjunction with per-attributeoptionalflags; it cannot express OR across credentials. The PostGuard hand-off doc §2.4 already treats Yivi condiscon as the canonical input that Algorithm 3 normalises into a sorted conjunction — this PR just exposes that shape at the HTTP boundary. No protocol-layer changes (header, wire format, IBE/IBS identities).Test plan
cargo test -p pg-core --features test— 43/43.cargo test -p pg-pkg— 34/34 (4 new tests oncon_item_to_discon+ 30 prior).Singleand one nestedDisconentry to/v2/request/start; check thedisclosure request:log line (start.rs:77) shows the expected nesteddiscon.Companion PRs
postguard-js— exposes the discon shape throughpg.sign.yivi({ attributes }).cryptify— extendssender_displayto renderfirstName + lastNamefrom the three ID credentials.postguard-website— uses the new condiscon to make the name requirement satisfiable from any of the four credentials (supersedes #239 in that repo).