Skip to content
Draft
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
2 changes: 2 additions & 0 deletions credentialsd-common/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ pub trait FlowController {
Output = Result<Pin<Box<dyn Stream<Item = BackgroundEvent> + Send + 'static>>, ()>,
> + Send;
fn enter_client_pin(&mut self, pin: String) -> impl Future<Output = Result<(), ()>> + Send;
fn set_usb_device_pin(&mut self, pin: String) -> impl Future<Output = Result<(), ()>> + Send;
fn set_nfc_device_pin(&mut self, pin: String) -> impl Future<Output = Result<(), ()>> + Send;
fn select_credential(
&self,
credential_id: String,
Expand Down
24 changes: 23 additions & 1 deletion credentialsd-common/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,25 @@ pub struct RequestingParty {
pub origin: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ViewUpdateFailure {
GeneralFailure(String),
/// Request required UV, but it was not set on the device yet
PinNotSet(String),
/// User tried to set PIN, but it was too short
PinPolicyViolation(String),
}

impl ViewUpdateFailure {
pub fn into_string(self) -> String {
match self {
ViewUpdateFailure::GeneralFailure(msg)
| ViewUpdateFailure::PinNotSet(msg)
| ViewUpdateFailure::PinPolicyViolation(msg) => msg,
}
}
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ViewUpdate {
SetTitle((String, String)),
Expand All @@ -131,7 +150,7 @@ pub enum ViewUpdate {

Completed,
Cancelled,
Failed(String),
Failed(ViewUpdateFailure),
}

#[derive(Clone, Debug, Default)]
Expand Down Expand Up @@ -262,6 +281,8 @@ pub enum Error {
PinAttemptsExhausted,
/// The RP requires user verification, but the device has no PIN/Biometrics set.
PinNotSet,
/// The device declined the entered PIN, as it violates the PIN policy (e.g. PIN too short)
PinPolicyViolation,
// TODO: We may want to hide the details on this variant from the public API.
/// Something went wrong with the credential service itself, not the authenticator.
Internal(String),
Expand All @@ -274,6 +295,7 @@ impl Display for Error {
match self {
Self::AuthenticatorError => f.write_str("AuthenticatorError"),
Self::PinNotSet => f.write_str("PinNotSet"),
Self::PinPolicyViolation => f.write_str("PinPolicyViolation"),
Self::NoCredentials => f.write_str("NoCredentials"),
Self::CredentialExcluded => f.write_str("CredentialExcluded"),
Self::PinAttemptsExhausted => f.write_str("PinAttemptsExhausted"),
Expand Down
3 changes: 3 additions & 0 deletions credentialsd-common/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ impl TryFrom<&Value<'_>> for crate::model::Error {
let err = match err_code {
"AuthenticatorError" => crate::model::Error::AuthenticatorError,
"PinNotSet" => crate::model::Error::PinNotSet,
"PinPolicyViolation" => crate::model::Error::PinPolicyViolation,
"NoCredentials" => crate::model::Error::NoCredentials,
"CredentialExcluded" => crate::model::Error::CredentialExcluded,
"PinAttemptsExhausted" => crate::model::Error::PinAttemptsExhausted,
Expand Down Expand Up @@ -438,6 +439,7 @@ impl TryFrom<&Structure<'_>> for crate::model::UsbState {
let err = match err_code {
"AuthenticatorError" => crate::model::Error::AuthenticatorError,
"PinNotSet" => crate::model::Error::PinNotSet,
"PinPolicyViolation" => crate::model::Error::PinPolicyViolation,
"NoCredentials" => crate::model::Error::NoCredentials,
"CredentialExcluded" => crate::model::Error::CredentialExcluded,
"PinAttemptsExhausted" => crate::model::Error::PinAttemptsExhausted,
Expand Down Expand Up @@ -561,6 +563,7 @@ impl TryFrom<&Structure<'_>> for crate::model::NfcState {
let err = match err_code {
"AuthenticatorError" => crate::model::Error::AuthenticatorError,
"PinNotSet" => crate::model::Error::PinNotSet,
"PinPolicyViolation" => crate::model::Error::PinPolicyViolation,
"NoCredentials" => crate::model::Error::NoCredentials,
"CredentialExcluded" => crate::model::Error::CredentialExcluded,
"PinAttemptsExhausted" => crate::model::Error::PinAttemptsExhausted,
Expand Down
85 changes: 85 additions & 0 deletions credentialsd-ui/data/resources/ui/window.ui
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,66 @@
</object>
</child>

<child>
<object class="GtkStackPage">
<property name="name">set_new_pin</property>
<property name="title" translatable="yes">Set a PIN</property>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>

<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Please choose a new PIN for your device.</property>
<property name="wrap">true</property>
</object>
</child>

<child>
<object class="GtkPasswordEntry" id="new_pin_primary_entry">
<property name="placeholder-text" translatable="yes">New PIN</property>
<signal name="changed" handler="handle_setting_pin_change" swapped="true"/>
</object>
</child>

<child>
<object class="GtkPasswordEntry" id="new_pin_confirm_entry">
<property name="placeholder-text" translatable="yes">Confirm PIN</property>
<signal name="changed" handler="handle_setting_pin_change" swapped="true"/>
</object>
</child>

<child>
<object class="GtkBox">
<property name="halign">end</property>
<property name="spacing">6</property>
<child>
<object class="GtkButton" id="new_pin_btn_close_window">
<property name="label" translatable="yes">Close</property>
<signal name="clicked" handler="handle_close_window" swapped="true"/>
</object>
</child>
<child>
<object class="GtkButton" id="new_pin_btn_continue">
<property name="label" translatable="yes">Continue</property>
<binding name="sensitive">
<lookup name="pin_fields_match">
<lookup name="view-model">CredentialsUiWindow</lookup>
</lookup>
</binding>
<style>
<class name="suggested-action"/>
</style>
<signal name="clicked" handler="handle_commit_new_pin" swapped="true"/>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</child>

<child>
<object class="GtkStackPage">
<property name="name">completed</property>
Expand Down Expand Up @@ -244,6 +304,31 @@
<property name="label" translatable="yes">Something went wrong while retrieving a credential. Please try again later or use a different authenticator.</property>
</object>
</child>
<child>
<object class="GtkBox">
<property name="halign">end</property>
<property name="spacing">6</property>
<binding name="visible">
<lookup name="start_setting_new_pin_visible">
<lookup name="view-model">
CredentialsUiWindow
</lookup>
</lookup>
</binding>
<child>
<object class="GtkButton" id="failed_close_window">
<property name="label" translatable="yes">Close</property>
<signal name="clicked" handler="handle_close_window" swapped="true"/>
</object>
</child>
<child>
<object class="GtkButton" id="start_setting_new_pin">
<property name="label" translatable="yes">Set PIN on device</property>
<signal name="clicked" handler="handle_start_setting_new_pin" swapped="true"/>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
Expand Down
77 changes: 56 additions & 21 deletions credentialsd-ui/po/credentialsd-ui.pot
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ msgstr ""
"Project-Id-Version: credentialsd-ui\n"
"Report-Msgid-Bugs-To: \"https://github.com/linux-credentials/credentialsd/"
"issues\"\n"
"POT-Creation-Date: 2026-02-03 10:40+0100\n"
"POT-Creation-Date: 2026-02-12 14:18+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
Expand All @@ -21,7 +21,7 @@ msgstr ""

#: data/xyz.iinuwa.credentialsd.CredentialsUi.desktop.in.in:2
#: data/xyz.iinuwa.credentialsd.CredentialsUi.metainfo.xml.in.in:8
#: src/gui/view_model/gtk/mod.rs:385
#: src/gui/view_model/gtk/mod.rs:401
msgid "Credential Manager"
msgstr ""

Expand Down Expand Up @@ -105,66 +105,95 @@ msgid "Choose credential"
msgstr ""

#: data/resources/ui/window.ui:214
msgid "Set a PIN"
msgstr ""

#: data/resources/ui/window.ui:221
msgid "Please choose a new PIN for your device."
msgstr ""

#: data/resources/ui/window.ui:228
msgid "New PIN"
msgstr ""

#: data/resources/ui/window.ui:235
msgid "Confirm PIN"
msgstr ""

#: data/resources/ui/window.ui:246 data/resources/ui/window.ui:320
msgid "Close"
msgstr ""

#: data/resources/ui/window.ui:252
msgid "Continue"
msgstr ""

#: data/resources/ui/window.ui:274
msgid "Complete"
msgstr ""

#: data/resources/ui/window.ui:220
#: data/resources/ui/window.ui:280
msgid "Done!"
msgstr ""

#: data/resources/ui/window.ui:231
#: data/resources/ui/window.ui:291
msgid "Something went wrong."
msgstr ""

#: data/resources/ui/window.ui:244 src/gui/view_model/mod.rs:290
#: data/resources/ui/window.ui:304 src/gui/view_model/mod.rs:315
#: src/gui/view_model/mod.rs:380
msgid ""
"Something went wrong while retrieving a credential. Please try again later "
"or use a different authenticator."
msgstr ""

#: src/gui/view_model/gtk/mod.rs:147
#: data/resources/ui/window.ui:326
msgid "Set PIN on device"
msgstr ""

#: src/gui/view_model/gtk/mod.rs:154
msgid "Enter your PIN. One attempt remaining."
msgid_plural "Enter your PIN. %d attempts remaining."
msgstr[0] ""
msgstr[1] ""

#: src/gui/view_model/gtk/mod.rs:153
#: src/gui/view_model/gtk/mod.rs:160
msgid "Enter your PIN."
msgstr ""

#: src/gui/view_model/gtk/mod.rs:163
#: src/gui/view_model/gtk/mod.rs:170
msgid "Touch your device again. One attempt remaining."
msgid_plural "Touch your device again. %d attempts remaining."
msgstr[0] ""
msgstr[1] ""

#: src/gui/view_model/gtk/mod.rs:169
#: src/gui/view_model/gtk/mod.rs:176
msgid "Touch your device."
msgstr ""

#: src/gui/view_model/gtk/mod.rs:174
#: src/gui/view_model/gtk/mod.rs:181
msgid "Touch your device"
msgstr ""

#: src/gui/view_model/gtk/mod.rs:177
#: src/gui/view_model/gtk/mod.rs:184
msgid "Scan the QR code with your device to begin authentication."
msgstr ""

#: src/gui/view_model/gtk/mod.rs:187
#: src/gui/view_model/gtk/mod.rs:194
msgid ""
"Connecting to your device. Make sure both devices are near each other and "
"have Bluetooth enabled."
msgstr ""

#: src/gui/view_model/gtk/mod.rs:195
#: src/gui/view_model/gtk/mod.rs:202
msgid "Device connected. Follow the instructions on your device"
msgstr ""

#: src/gui/view_model/gtk/mod.rs:321
#: src/gui/view_model/gtk/mod.rs:333
msgid "Insert your security key."
msgstr ""

#: src/gui/view_model/gtk/mod.rs:340
#: src/gui/view_model/gtk/mod.rs:352
msgid "Multiple devices found. Please select with which to proceed."
msgstr ""

Expand Down Expand Up @@ -226,30 +255,36 @@ msgid ""
"to sign in to \"%s1\". Only proceed if you trust this process."
msgstr ""

#: src/gui/view_model/mod.rs:227
#: src/gui/view_model/mod.rs:244
msgid "Failed to select credential from device."
msgstr ""

#: src/gui/view_model/mod.rs:281
#: src/gui/view_model/mod.rs:298 src/gui/view_model/mod.rs:363
msgid "No matching credentials found on this authenticator."
msgstr ""

#: src/gui/view_model/mod.rs:284
#: src/gui/view_model/mod.rs:302 src/gui/view_model/mod.rs:367
msgid ""
"No more PIN attempts allowed. Try removing your device and plugging it back "
"in."
msgstr ""

#: src/gui/view_model/mod.rs:287
#: src/gui/view_model/mod.rs:306 src/gui/view_model/mod.rs:371
msgid ""
"This server requires your device to have additional protection like a PIN, "
"which is not set. Please set a PIN for this device and try again."
msgstr ""

#: src/gui/view_model/mod.rs:293
#: src/gui/view_model/mod.rs:310 src/gui/view_model/mod.rs:375
msgid ""
"The entered PIN violates the PIN-policy of this device (likely too short). "
"Please try again."
msgstr ""

#: src/gui/view_model/mod.rs:320 src/gui/view_model/mod.rs:385
msgid "This credential is already registered on this authenticator."
msgstr ""

#: src/gui/view_model/mod.rs:395
#: src/gui/view_model/mod.rs:434
msgid "Something went wrong. Try again later or use a different authenticator."
msgstr ""
Loading