cadrumo.entrypoints.tui.secret.registration module

Registration: full-screen credential entry that creates and unlocks one profile.

This is the literal first surface of the application. Everything else — the manager, the overview, filing — is behind it, because everything else needs an unlocked encrypted bucket and this is where that bucket is created.

The screen is deliberately a single page rather than a paged flow. The three fields are one decision (“who am I on this machine, and what protects it”), and a password field needs its confirmation and its strength feedback visible at the same time as itself; splitting them across pages would make the operator hold state in their head for no gain. The paged substrate remains the right shape for the many-question profile detail that follows, and is used there.

The copy carries what an offline CLI tool owes the operator at this moment: what is being created, why a password is being asked for at all when nothing is going over a network, and what happens if it is lost.

Recovery is an explicit, skippable follow-up. Once the profile exists the screen asks whether to set up a recovery code, says plainly what it buys (a way to reset a forgotten passphrase) and what declining means, and defaults to declining. Choosing it shows the code once and asks for it back before anything is installed; cancelling at any point leaves the freshly created profile exactly as it was, with its passphrase as its only door.

See also

register_profile_with_credentials()

The application door this screen drives; it creates the profile, provisions the key material, and leaves the session unlocked.

enroll_profile_recovery()

The optional second door, driven from the offer that follows creation.

assess_profile_password()

The canonical assessment behind validation and the live strength line.

LoginScreen

The other credential surface; the two share their attempt lifecycle and panel layout through CredentialScreen.

class RegistrationRefusal(message_key, context=())[source]

Bases: object

Secret-free localized refusal retained as data until rendering.

Parameters:
message_key: str
context: tuple[tuple[str, object], ...]
render(*, locale=None)[source]

Resolve the refusal under the screen’s active language.

Return type:

str

Parameters:

locale (str | None)

exception RecoveryHandoverDeclinedError(message=None, *, context=None, translated_message=None)[source]

Bases: CadrumoError

The operator did not confirm the code; raised inside the handover to abort enrolment.

The application treats any exception from the handover as “nothing was installed”, which is exactly the outcome a decline wants. The enrolment door in this module catches it and reports a decline, not a refusal.

Parameters:
  • message (str | None)

  • context (Mapping[str, object] | None)

  • translated_message (str | None)

Return type:

None

code
class RegistrationAttempt(outcome=None, expected_refusal=None)[source]

Bases: object

The outcome of asking the application to create a profile.

A refusal arrives as text the screen displays, not as an exception it has to recognise. That keeps refusal classification with the layer that owns the rules, and leaves the screen doing what a screen does: show the operator what happened.

Parameters:
outcome: ProfileRegistrationOutcome | None
expected_refusal: RegistrationRefusal | None
property refusal: str | None

Render expected refusal data only at the presentation boundary.

class RecoveryEnrollmentAttempt(enrolled=False, declined=False, expected_refusal=None)[source]

Bases: object

The outcome of asking the application to enrol recovery after creation.

enrolled is true only when the wrapper was installed after the operator confirmed the code. declined records a deliberate cancel, which is not a refusal and shows nothing. Anything else is an expected refusal carried as localized data.

Parameters:
enrolled: bool
declined: bool
expected_refusal: RegistrationRefusal | None
class RegistrationScreen(*, assess, register, enroll_recovery=None, suggested_name=None)[source]

Bases: CredentialScreen[ProfileRegistrationOutcome]

Full-screen credential entry that creates and unlocks one profile.

Parameters:
SCOPED_CSS: ClassVar[bool]

Should default css be limited to the widget type?

DEFAULT_CSS: ClassVar[str]

Default TCSS.

ATTEMPT_NAME: ClassVar[str]
compose()[source]

Yield the banner, the credential form, and the footer.

Return type:

Iterable[Widget]

on_mount()[source]

Install the theme, render copy, and focus profile-name entry.

Return type:

None

on_select_changed(event)[source]

Re-word the whole page in the language the operator just picked.

The choice has to reach the screen and not only the profile it will create: this is the first surface of the application, so an operator who cannot read the language it opened in has nothing else to go to. Applying it here is also what makes the chooser legible as a chooser — the page answering in the chosen language is the confirmation that the setting took.

Return type:

None

Parameters:

event (Changed)

on_input_changed(event)[source]

Re-render the advisory strength line as the password is typed.

Return type:

None

Parameters:

event (Changed)

selected_output_language()[source]

Return the closed language selection for the profile being created.

Return type:

str

output_locale()[source]

Return the registration surface’s task-independent locale.

Return type:

str

resolve_attempt_refusal(attempt)[source]

Render structured registration refusals under this screen’s locale.

Return type:

str | None

Parameters:

attempt (CredentialAttempt[ProfileRegistrationOutcome])

on_button_pressed(event)[source]

Route the create-profile button intent.

Return type:

None

Parameters:

event (Pressed)

on_input_submitted(event)[source]

Enter advances to the next field, and submits from the last one.

Return type:

None

Parameters:

event (Submitted)

action_create()[source]

Validate the form locally, then create the profile.

Local checks cover only what the screen can see — a blank name, a mismatched confirmation, an invalid password. Everything else (a duplicate label, a storage refusal) is the application door’s decision, surfaced here as its translated message rather than re-derived, so the screen never becomes a second authority on what a valid registration is.

Return type:

None

default_refusal()[source]

Text shown when a refusal carries no message.

Return type:

str

progress_message()[source]

Operator-facing description of the subclass’s in-flight attempt.

Return type:

str

refuse(message)[source]

Show refusal and return the keyboard to the form.

A refusal the application door raises – a duplicate label, a storage refusal – arrives while the fields are disabled, so re-enabling them leaves nothing focused and the operator cannot type without reaching for the mouse. The local checks focus the field they name immediately after calling this, so the name field is only the landing place for a refusal that named none.

Return type:

None

Parameters:

message (str)

leave(outcome)[source]

Offer recovery once the profile exists; leave immediately otherwise.

The base lifecycle calls this with the successful outcome. Instead of closing straight away, the screen holds the outcome and puts the one optional question to the operator. Declining, cancelling, and finishing enrolment all end here again through _finish_registration(), which is the only path that closes.

Return type:

None

Parameters:

outcome (ProfileRegistrationOutcome | None)

on_worker_state_changed(event)[source]

Settle the enrolment worker here; everything else is the base attempt.

Return type:

None

Parameters:

event (StateChanged)

on_unmount()[source]

Release every pending handoff and wipe the passphrase when the application stops.

Return type:

None

set_busy(*, busy)[source]

Render registration progress and freeze inputs while storage mutates.

Return type:

None

Parameters:

busy (bool)

can_focus: bool

Widget may receive focus.

can_focus_children: bool

Widget’s children may receive focus.

class RecoveryOfferScreen(*, locale, on_accept, on_skip)[source]

Bases: Screen[None]

Ask once whether to set up recovery, with the trade-off stated plainly.

Parameters:
  • locale (str)

  • on_accept (Callable[[], None])

  • on_skip (Callable[[], None])

BINDINGS: ClassVar

A list of key bindings.

DEFAULT_CSS: ClassVar[str]

Default TCSS.

compose()[source]

Called by Textual to create child widgets.

This method is called when a widget is mounted or by setting recompose=True when calling [refresh()][textual.widget.Widget.refresh].

Note that you don’t typically need to explicitly call this method.

Return type:

Iterable[Widget]

Example

def compose(self) -> ComposeResult:
    yield Header()
    yield Label("Press the button below:")
    yield Button()
    yield Footer()
on_mount()[source]

Focus the skip choice: declining is the default and costs nothing.

Return type:

None

action_skip_recovery()[source]

Escape declines the offer, which is what leaving it already means.

Return type:

None

action_toggle_appearance()[source]

Switch appearance here as on every other credential surface.

Return type:

None

on_unmount()[source]

Treat escape, shutdown, and every non-accept exit as a skip.

Return type:

None

can_focus: bool

Widget may receive focus.

can_focus_children: bool

Widget’s children may receive focus.

class RecoveryCodeScreen(*, enrollment, locale, on_confirm, on_cancel)[source]

Bases: Screen[None]

Show the recovery code once and return masked exact re-entry proof.

Parameters:
BINDINGS: ClassVar

A list of key bindings.

DEFAULT_CSS: ClassVar[str]

Default TCSS.

compose()[source]

Called by Textual to create child widgets.

This method is called when a widget is mounted or by setting recompose=True when calling [refresh()][textual.widget.Widget.refresh].

Note that you don’t typically need to explicitly call this method.

Return type:

Iterable[Widget]

Example

def compose(self) -> ComposeResult:
    yield Header()
    yield Label("Press the button below:")
    yield Button()
    yield Footer()
action_cancel_code()[source]

Escape declines enrolment, so nothing is installed for this code.

Return type:

None

action_toggle_appearance()[source]

Switch appearance here as on every other credential surface.

Return type:

None

can_focus: bool

Widget may receive focus.

can_focus_children: bool

Widget’s children may receive focus.

on_unmount()[source]

Treat escape, shutdown, and every non-confirm exit as refusal.

Return type:

None

build_profile_registration_attempt(label, candidate_passphrase, output_language)[source]

Adapt the public registration door into this screen’s result contract.

This is the production register door. It classifies nothing itself: the application owns which refusals are expected, and this only carries the localized message key and its context forward as data. No passphrase is retained beyond the call.

Return type:

RegistrationAttempt

Parameters:
  • label (str)

  • candidate_passphrase (str)

  • output_language (str)

build_profile_recovery_enrollment_attempt(profile_id, current_passphrase, recovery_handover)[source]

Adapt the public enrolment door into this screen’s result contract.

A declined handover is not a refusal: the operator chose to keep the profile passphrase-only, and the application installed nothing.

Return type:

RecoveryEnrollmentAttempt

Parameters: