Téléverser les fichiers vers "workstation-setup/src"

This commit is contained in:
2026-08-19 15:24:29 +02:00
parent d47fe70c5b
commit 16ebd52f79
3 changed files with 641 additions and 1285 deletions
File diff suppressed because it is too large Load Diff
+177 -207
View File
@@ -17,17 +17,20 @@
#include <utility>
namespace {
constexpr int kHelperTimeoutMs = 60000;
constexpr int kHelperTimeoutMs = 120000;
bool containsLineBreak(const QString &value)
{
return value.contains(QLatin1Char('\n')) || value.contains(QLatin1Char('\r'));
}
QString homeDirectoryForEffectiveUser()
QString effectiveHomeDirectory()
{
if (passwd *entry = getpwuid(geteuid())) {
return QString::fromLocal8Bit(entry->pw_dir);
const QString home = QString::fromLocal8Bit(entry->pw_dir);
if (!home.isEmpty() && home != QStringLiteral("/")) {
return home;
}
}
return QDir::homePath();
}
@@ -39,12 +42,13 @@ ProvisioningBackend::ProvisioningBackend(QString targetUser, QObject *parent)
, m_targetUser(std::move(targetUser))
{
refreshState();
appendLog(QStringLiteral("START currentUser=%1 targetUser=%2 authorized=%3 passwordDone=%4 pinDone=%5")
appendLog(QStringLiteral("START currentUser=%1 targetUser=%2 authorized=%3 passwordDone=%4 pinDone=%5 fidoDone=%6")
.arg(m_currentUser,
m_targetUser,
authorizedUser() ? QStringLiteral("yes") : QStringLiteral("no"),
m_passwordDone ? QStringLiteral("yes") : QStringLiteral("no"),
m_pinDone ? QStringLiteral("yes") : QStringLiteral("no")));
m_pinDone ? QStringLiteral("yes") : QStringLiteral("no"),
m_fidoDone ? QStringLiteral("yes") : QStringLiteral("no")));
}
ProvisioningBackend::~ProvisioningBackend()
@@ -58,25 +62,22 @@ ProvisioningBackend::~ProvisioningBackend()
QString ProvisioningBackend::effectiveUserName()
{
const uid_t uid = geteuid();
if (passwd *entry = getpwuid(uid)) {
if (passwd *entry = getpwuid(geteuid())) {
return QString::fromLocal8Bit(entry->pw_name);
}
return {};
}
bool ProvisioningBackend::authorizedUser() const
{
if (m_targetUser.isEmpty()) {
return false;
}
const QByteArray targetName = m_targetUser.toLocal8Bit();
if (passwd *entry = getpwnam(targetName.constData())) {
const QByteArray name = m_targetUser.toLocal8Bit();
if (passwd *entry = getpwnam(name.constData())) {
return entry->pw_uid == geteuid();
}
return false;
}
@@ -89,8 +90,7 @@ QString ProvisioningBackend::stateDirectory() const
return QDir::cleanPath(candidate + QStringLiteral("/nixos-workstations"));
}
}
return QDir::cleanPath(homeDirectoryForEffectiveUser()
return QDir::cleanPath(effectiveHomeDirectory()
+ QStringLiteral("/.local/state/nixos-workstations"));
}
@@ -109,15 +109,22 @@ QString ProvisioningBackend::pinMarker() const
return stateDirectory() + QStringLiteral("/yubikey-pin-created");
}
QString ProvisioningBackend::fidoMarker() const
{
return stateDirectory() + QStringLiteral("/yubikey-fido-enrolled");
}
void ProvisioningBackend::refreshState()
{
const bool oldPassword = m_passwordDone;
const bool oldPin = m_pinDone;
const bool oldFido = m_fidoDone;
m_passwordDone = QFileInfo::exists(passwordMarker());
m_pinDone = QFileInfo::exists(pinMarker());
m_fidoDone = QFileInfo::exists(fidoMarker());
if (oldPassword != m_passwordDone || oldPin != m_pinDone) {
if (oldPassword != m_passwordDone || oldPin != m_pinDone || oldFido != m_fidoDone) {
emit stateChanged();
}
}
@@ -139,11 +146,10 @@ bool ProvisioningBackend::ensureStateWritable()
if (!probe.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
return false;
}
const bool writeOk = probe.write("ok\n") == 3;
const bool ok = probe.write("ok\n") == 3;
probe.close();
probe.remove();
return writeOk;
return ok;
}
bool ProvisioningBackend::createMarker(const QString &path)
@@ -157,8 +163,7 @@ bool ProvisioningBackend::createMarker(const QString &path)
return false;
}
const QByteArray content =
QByteArrayLiteral("completed=")
const QByteArray content = QByteArrayLiteral("completed=")
+ QDateTime::currentDateTimeUtc().toString(Qt::ISODate).toUtf8()
+ '\n';
@@ -166,14 +171,12 @@ bool ProvisioningBackend::createMarker(const QString &path)
marker.cancelWriting();
return false;
}
if (!marker.commit()) {
return false;
}
return QFile::setPermissions(path,
QFileDevice::ReadOwner
| QFileDevice::WriteOwner);
QFileDevice::ReadOwner | QFileDevice::WriteOwner);
}
void ProvisioningBackend::appendLog(const QString &message) const
@@ -182,7 +185,6 @@ void ProvisioningBackend::appendLog(const QString &message) const
if (!QDir().mkpath(dir)) {
return;
}
QFile::setPermissions(dir,
QFileDevice::ReadOwner
| QFileDevice::WriteOwner
@@ -193,17 +195,13 @@ void ProvisioningBackend::appendLog(const QString &message) const
return;
}
const QByteArray line =
QDateTime::currentDateTimeUtc().toString(Qt::ISODateWithMs).toUtf8()
log.write(QDateTime::currentDateTimeUtc().toString(Qt::ISODateWithMs).toUtf8()
+ QByteArrayLiteral(" ")
+ message.toUtf8()
+ '\n';
log.write(line);
+ '\n');
log.close();
QFile::setPermissions(diagnosticLogPath(),
QFileDevice::ReadOwner
| QFileDevice::WriteOwner);
QFileDevice::ReadOwner | QFileDevice::WriteOwner);
}
void ProvisioningBackend::setBusy(bool busy)
@@ -229,9 +227,30 @@ void ProvisioningBackend::secureClear(QByteArray &data)
QString ProvisioningBackend::operationName(Operation operation)
{
return operation == Operation::Password
? QStringLiteral("PASSWORD")
: QStringLiteral("PIN");
switch (operation) {
case Operation::Password:
return QStringLiteral("PASSWORD");
case Operation::Pin:
return QStringLiteral("PIN");
case Operation::Fido:
return QStringLiteral("FIDO");
}
return QStringLiteral("UNKNOWN");
}
void ProvisioningBackend::emitResult(Operation operation, bool success, const QString &message)
{
switch (operation) {
case Operation::Password:
emit passwordChangeFinished(success, message);
break;
case Operation::Pin:
emit pinChangeFinished(success, message);
break;
case Operation::Fido:
emit fidoEnrollmentFinished(success, message);
break;
}
}
void ProvisioningBackend::changePassword(const QString &currentPassword,
@@ -239,47 +258,31 @@ void ProvisioningBackend::changePassword(const QString &currentPassword,
const QString &confirmation)
{
if (!authorizedUser()) {
appendLog(QStringLiteral("PASSWORD refused: unauthorized user"));
emit passwordChangeFinished(false,
QStringLiteral("Cette opération n'est pas autorisée pour cet utilisateur."));
emit passwordChangeFinished(false, QStringLiteral("Cette opération n'est pas autorisée pour cet utilisateur."));
return;
}
if (m_busy) {
emit passwordChangeFinished(false,
QStringLiteral("Une opération de configuration est déjà en cours."));
emit passwordChangeFinished(false, QStringLiteral("Une opération de configuration est déjà en cours."));
return;
}
if (m_passwordDone) {
emit passwordChangeFinished(true,
QStringLiteral("Le mot de passe a déjà été personnalisé."));
emit passwordChangeFinished(true, QStringLiteral("Le mot de passe a déjà été personnalisé."));
return;
}
if (currentPassword.isEmpty() || newPassword.isEmpty() || confirmation.isEmpty()) {
emit passwordChangeFinished(false,
QStringLiteral("Tous les champs du mot de passe doivent être renseignés."));
emit passwordChangeFinished(false, QStringLiteral("Tous les champs du mot de passe doivent être renseignés."));
return;
}
if (newPassword != confirmation) {
emit passwordChangeFinished(false,
QStringLiteral("Les deux nouveaux mots de passe ne correspondent pas."));
emit passwordChangeFinished(false, QStringLiteral("Les deux nouveaux mots de passe ne correspondent pas."));
return;
}
if (containsLineBreak(currentPassword) || containsLineBreak(newPassword)
|| containsLineBreak(confirmation)) {
emit passwordChangeFinished(false,
QStringLiteral("Le mot de passe contient un caractère non pris en charge."));
if (containsLineBreak(currentPassword) || containsLineBreak(newPassword) || containsLineBreak(confirmation)) {
emit passwordChangeFinished(false, QStringLiteral("Le mot de passe contient un caractère non pris en charge."));
return;
}
if (!ensureStateWritable()) {
appendLog(QStringLiteral("PASSWORD refused: state directory is not writable"));
emit passwordChangeFinished(false,
QStringLiteral("Impossible d'enregistrer l'état de configuration dans votre profil. Contactez le service informatique."));
emit passwordChangeFinished(false, QStringLiteral("Impossible d'enregistrer l'état de configuration dans votre profil."));
return;
}
@@ -294,62 +297,72 @@ void ProvisioningBackend::initializePin(const QString &newPin,
const QString &confirmation)
{
if (!authorizedUser()) {
appendLog(QStringLiteral("PIN refused: unauthorized user"));
emit pinChangeFinished(false,
QStringLiteral("Cette opération n'est pas autorisée pour cet utilisateur."));
emit pinChangeFinished(false, QStringLiteral("Cette opération n'est pas autorisée pour cet utilisateur."));
return;
}
if (m_busy) {
emit pinChangeFinished(false,
QStringLiteral("Une opération de configuration est déjà en cours."));
emit pinChangeFinished(false, QStringLiteral("Une opération de configuration est déjà en cours."));
return;
}
if (!m_passwordDone) {
emit pinChangeFinished(false,
QStringLiteral("Le mot de passe doit être personnalisé avant d'initialiser la YubiKey."));
emit pinChangeFinished(false, QStringLiteral("Personnalisez d'abord votre mot de passe."));
return;
}
if (m_pinDone) {
emit pinChangeFinished(true,
QStringLiteral("Le PIN FIDO2 de la YubiKey a déjà été initialisé."));
emit pinChangeFinished(true, QStringLiteral("Le PIN FIDO2 a déjà été initialisé."));
return;
}
if (newPin.size() < 4 || confirmation.size() < 4) {
emit pinChangeFinished(false,
QStringLiteral("Le PIN doit contenir au moins 4 caractères."));
emit pinChangeFinished(false, QStringLiteral("Le PIN doit contenir au moins 4 caractères."));
return;
}
if (newPin != confirmation) {
emit pinChangeFinished(false,
QStringLiteral("Les deux PIN ne correspondent pas."));
emit pinChangeFinished(false, QStringLiteral("Les deux PIN ne correspondent pas."));
return;
}
if (containsLineBreak(newPin) || containsLineBreak(confirmation)) {
emit pinChangeFinished(false,
QStringLiteral("Le PIN contient un caractère non pris en charge."));
emit pinChangeFinished(false, QStringLiteral("Le PIN contient un caractère non pris en charge."));
return;
}
if (!ensureStateWritable()) {
appendLog(QStringLiteral("PIN refused: state directory is not writable"));
emit pinChangeFinished(false,
QStringLiteral("Impossible d'enregistrer l'état de configuration dans votre profil. Contactez le service informatique."));
return;
}
// Le helper Étape 1 lit uniquement les deux premières lignes :
// nouveau PIN puis confirmation. Aucun ancien PIN n'est transmis.
startHelper(Operation::Pin,
QString::fromUtf8(NIXOS_WORKSTATIONS_PIN_HELPER_PATH),
newPin,
confirmation,
QString());
confirmation);
}
void ProvisioningBackend::enrollFido(const QString &currentPassword,
const QString &pin)
{
if (!authorizedUser()) {
emit fidoEnrollmentFinished(false, QStringLiteral("Cette opération n'est pas autorisée pour cet utilisateur."));
return;
}
if (m_busy) {
emit fidoEnrollmentFinished(false, QStringLiteral("Une opération de configuration est déjà en cours."));
return;
}
if (!m_passwordDone || !m_pinDone) {
emit fidoEnrollmentFinished(false, QStringLiteral("Le mot de passe et le PIN doivent être configurés avant l'association FIDO2."));
return;
}
if (m_fidoDone) {
emit fidoEnrollmentFinished(true, QStringLiteral("La YubiKey est déjà associée au home chiffré."));
return;
}
if (currentPassword.isEmpty() || pin.size() < 4) {
emit fidoEnrollmentFinished(false, QStringLiteral("Saisissez votre mot de passe actuel et le PIN de la YubiKey."));
return;
}
if (containsLineBreak(currentPassword) || containsLineBreak(pin)) {
emit fidoEnrollmentFinished(false, QStringLiteral("Un des secrets contient un caractère non pris en charge."));
return;
}
startHelper(Operation::Fido,
QString::fromUtf8(NIXOS_WORKSTATIONS_FIDO_HELPER_PATH),
currentPassword,
pin);
}
void ProvisioningBackend::startHelper(Operation operation,
@@ -360,14 +373,8 @@ void ProvisioningBackend::startHelper(Operation operation,
{
const QFileInfo helperInfo(helperPath);
if (!helperInfo.exists() || !helperInfo.isFile() || !helperInfo.isExecutable()) {
appendLog(operationName(operation)
+ QStringLiteral(" failed: helper missing or not executable"));
const QString message = QStringLiteral("Le composant système requis est introuvable ou inutilisable.");
if (operation == Operation::Password) {
emit passwordChangeFinished(false, message);
} else {
emit pinChangeFinished(false, message);
}
appendLog(operationName(operation) + QStringLiteral(" failed: helper unavailable"));
emitResult(operation, false, QStringLiteral("Le composant système requis est introuvable ou inutilisable."));
return;
}
@@ -396,17 +403,16 @@ void ProvisioningBackend::startHelper(Operation operation,
process->setProgram(helperPath);
process->setProcessChannelMode(QProcess::SeparateChannels);
QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
environment.insert(QStringLiteral("LC_ALL"), QStringLiteral("C"));
environment.insert(QStringLiteral("LANG"), QStringLiteral("C"));
process->setProcessEnvironment(environment);
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert(QStringLiteral("LC_ALL"), QStringLiteral("C"));
env.insert(QStringLiteral("LANG"), QStringLiteral("C"));
process->setProcessEnvironment(env);
auto *timeout = new QTimer(process);
timeout->setSingleShot(true);
timeout->setInterval(kHelperTimeoutMs);
auto *timer = new QTimer(process);
timer->setSingleShot(true);
timer->setInterval(kHelperTimeoutMs);
connect(timeout, &QTimer::timeout, process,
[this, process, operation]() {
connect(timer, &QTimer::timeout, process, [this, process, operation]() {
if (m_process != process || process->state() == QProcess::NotRunning) {
return;
}
@@ -415,125 +421,101 @@ void ProvisioningBackend::startHelper(Operation operation,
process->kill();
});
connect(process, &QProcess::started, this,
[this, process, timeout, operation]() {
connect(process, &QProcess::started, this, [this, process, timer, operation]() {
if (m_process != process) {
return;
}
const qint64 expected = m_pendingPayload.size();
const qint64 written = process->write(m_pendingPayload);
process->write(m_pendingPayload);
process->closeWriteChannel();
secureClear(m_pendingPayload);
if (written != expected) {
appendLog(operationName(operation)
+ QStringLiteral(" warning: incomplete helper input write"));
}
appendLog(operationName(operation) + QStringLiteral(" helper started"));
timeout->start();
timer->start();
});
connect(process, &QProcess::errorOccurred, this,
[this, process, timeout, operation](QProcess::ProcessError error) {
[this, process, timer, operation](QProcess::ProcessError error) {
if (m_process != process || error != QProcess::FailedToStart) {
return;
}
timeout->stop();
timer->stop();
secureClear(m_pendingPayload);
appendLog(operationName(operation)
+ QStringLiteral(" failed to start: ")
+ process->errorString());
m_process = nullptr;
process->deleteLater();
setBusy(false);
const QString message = QStringLiteral("Impossible de démarrer le composant de configuration.");
if (operation == Operation::Password) {
emit passwordChangeFinished(false, message);
} else {
emit pinChangeFinished(false, message);
}
appendLog(operationName(operation) + QStringLiteral(" failed to start"));
emitResult(operation, false, QStringLiteral("Impossible de démarrer le composant de configuration."));
});
connect(process,
qOverload<int, QProcess::ExitStatus>(&QProcess::finished),
this,
[this, process, timeout, operation](int exitCode, QProcess::ExitStatus exitStatus) {
[this, process, timer, operation](int exitCode, QProcess::ExitStatus exitStatus) {
if (m_process != process) {
return;
}
timeout->stop();
timer->stop();
secureClear(m_pendingPayload);
QByteArray stderrData = process->readAllStandardError();
QByteArray stdoutData = process->readAllStandardOutput();
QByteArray combinedOutput;
combinedOutput.reserve(stderrData.size() + stdoutData.size() + 1);
combinedOutput += stderrData;
combinedOutput += '\n';
combinedOutput += stdoutData;
QByteArray combined = stderrData + '\n' + stdoutData;
const bool timedOut = m_helperTimedOut;
const bool helperSucceeded = !timedOut
&& exitStatus == QProcess::NormalExit
&& exitCode == 0;
QString message;
bool markerCreated = false;
QString message;
if (helperSucceeded) {
if (operation == Operation::Password) {
switch (operation) {
case Operation::Password:
markerCreated = createMarker(passwordMarker());
message = markerCreated
? QStringLiteral("Votre mot de passe personnel est maintenant actif.")
: QStringLiteral("Le mot de passe a été modifié, mais l'état local n'a pas pu être enregistré. Contactez le service informatique avant de fermer la session.");
} else {
? QStringLiteral("Votre nouveau mot de passe protège maintenant votre home chiffré.")
: QStringLiteral("Le mot de passe a été modifié mais l'état local n'a pas pu être enregistré.");
break;
case Operation::Pin:
markerCreated = createMarker(pinMarker());
message = markerCreated
? QStringLiteral("Le PIN FIDO2 de votre YubiKey est maintenant initialisé.")
: QStringLiteral("Le PIN a été initialisé, mais l'état local n'a pas pu être enregistré. Contactez le service informatique avant de fermer la session.");
: QStringLiteral("Le PIN a été créé mais l'état local n'a pas pu être enregistré.");
break;
case Operation::Fido:
markerCreated = createMarker(fidoMarker());
message = markerCreated
? QStringLiteral("Votre YubiKey peut maintenant déverrouiller votre home chiffré.")
: QStringLiteral("La YubiKey a été enrôlée mais l'état local n'a pas pu être enregistré.");
break;
}
} else {
message = safeMessageForFailure(operation, exitCode, combinedOutput, timedOut);
message = safeMessageForFailure(operation, exitCode, combined, timedOut);
}
QString helperToken = QString::fromUtf8(combinedOutput).trimmed();
helperToken.remove(QRegularExpression(QStringLiteral("[^A-Za-z0-9_\\-]")));
if (helperToken.size() > 80) {
helperToken.truncate(80);
}
if (helperToken.isEmpty()) {
helperToken = QStringLiteral("none");
}
QString token = QString::fromUtf8(combined).trimmed();
token.remove(QRegularExpression(QStringLiteral("[^A-Za-z0-9_\\-]")));
if (token.size() > 80) token.truncate(80);
if (token.isEmpty()) token = QStringLiteral("none");
appendLog(operationName(operation)
+ QStringLiteral(" helper finished exitCode=%1 normalExit=%2 timeout=%3 marker=%4 token=%5")
+ QStringLiteral(" helper finished exitCode=%1 timeout=%2 marker=%3 token=%4")
.arg(exitCode)
.arg(exitStatus == QProcess::NormalExit ? QStringLiteral("yes") : QStringLiteral("no"))
.arg(timedOut ? QStringLiteral("yes") : QStringLiteral("no"))
.arg(markerCreated ? QStringLiteral("yes") : QStringLiteral("no"))
.arg(helperToken));
.arg(token));
secureClear(stderrData);
secureClear(stdoutData);
secureClear(combinedOutput);
secureClear(combined);
m_process = nullptr;
process->deleteLater();
setBusy(false);
refreshState();
const bool completed = helperSucceeded && markerCreated;
if (operation == Operation::Password) {
emit passwordChangeFinished(completed, message);
} else {
emit pinChangeFinished(completed, message);
}
emitResult(operation, helperSucceeded && markerCreated, message);
});
process->start();
@@ -547,70 +529,58 @@ QString ProvisioningBackend::safeMessageForFailure(Operation operation,
const QString output = QString::fromUtf8(outputData).toLower();
if (timedOut || exitCode == 124 || output.contains(QStringLiteral("timeout"))) {
if (operation == Operation::Password) {
if (output.contains(QStringLiteral("timeout_current_prompt"))) {
return QStringLiteral("Le système n'a pas présenté l'invite d'authentification du mot de passe actuel.");
if (operation == Operation::Fido) {
return QStringLiteral("L'association FIDO2 a expiré. Laissez la YubiKey branchée et touchez-la lorsqu'elle clignote.");
}
if (output.contains(QStringLiteral("timeout_new_prompt"))) {
return QStringLiteral("Le mot de passe actuel a été envoyé, mais le système n'a pas demandé le nouveau mot de passe.");
}
if (output.contains(QStringLiteral("timeout_confirm_prompt"))) {
return QStringLiteral("Le nouveau mot de passe a été envoyé, mais le système n'a pas demandé sa confirmation.");
}
if (output.contains(QStringLiteral("timeout_finish"))) {
return QStringLiteral("Le système a reçu les mots de passe mais n'a pas terminé l'opération.");
}
return QStringLiteral("Le changement de mot de passe a expiré avant la fin de l'opération.");
}
return QStringLiteral("L'opération YubiKey a expiré. Vérifiez que la clé est connectée puis réessayez.");
return QStringLiteral("L'opération a expiré avant de pouvoir être terminée.");
}
if (operation == Operation::Password) {
if (output.contains(QStringLiteral("current_rejected"))
|| output.contains(QStringLiteral("current_prompt_missing"))
|| output.contains(QStringLiteral("current_reprompt"))) {
return QStringLiteral("Le mot de passe temporaire actuel est incorrect ou n'a pas pu être vérifié.");
if (output.contains(QStringLiteral("current_rejected"))) {
return QStringLiteral("Le mot de passe temporaire actuel est incorrect.");
}
if (output.contains(QStringLiteral("new_rejected"))) {
return QStringLiteral("Le système a refusé le nouveau mot de passe. Choisissez-en un autre puis réessayez.");
return QStringLiteral("Le nouveau mot de passe a été refusé par la politique de sécurité.");
}
if (output.contains(QStringLiteral("input_error"))) {
return QStringLiteral("Le composant de changement de mot de passe n'a pas reçu les données attendues.");
}
return QStringLiteral("Le mot de passe n'a pas été modifié. Vérifiez le mot de passe actuel puis réessayez.");
return QStringLiteral("Le mot de passe n'a pas pu être modifié par systemd-homed.");
}
if (operation == Operation::Pin) {
if (output.contains(QStringLiteral("pin_already_configured"))) {
return QStringLiteral("Cette YubiKey possède déjà un PIN FIDO2. Pour l’étape 1, utilisez une clé vierge ou réinitialisée ; aucune tentative de PIN na été effectuée.");
return QStringLiteral("Cette YubiKey possède déjà un PIN FIDO2. Utilisez une YubiKey vierge ou réinitialisée.");
}
if (output.contains(QStringLiteral("pin_auth_blocked"))) {
return QStringLiteral("Les opérations PIN sont temporairement bloquées. Débranchez puis rebranchez la YubiKey avant toute nouvelle opération.");
return QStringLiteral("Les opérations PIN sont temporairement bloquées. Débranchez puis rebranchez la YubiKey.");
}
if (output.contains(QStringLiteral("pin_blocked"))) {
return QStringLiteral("Le PIN FIDO2 de la YubiKey est bloqué. Cette clé nest pas vierge et ne peut pas être initialisée par l’étape 1.");
return QStringLiteral("Le PIN FIDO2 est bloqué. La YubiKey doit être initialisée avant provisioning.");
}
if (output.contains(QStringLiteral("multiple_yubikey"))) {
return QStringLiteral("Plusieurs clés FIDO2 sont détectées. Ne laissez branchée que la YubiKey à initialiser puis réessayez.");
}
if (output.contains(QStringLiteral("no_fido2"))) {
return QStringLiteral("La clé détectée ne fournit pas linterface FIDO2 nécessaire.");
return QStringLiteral("Plusieurs clés FIDO2 sont détectées. Ne laissez branchée que la YubiKey d'Alice.");
}
if (output.contains(QStringLiteral("no_yubikey"))) {
return QStringLiteral("Aucune YubiKey FIDO2 compatible na été détectée ou le système na pas les droits daccès nécessaires.");
return QStringLiteral("Aucune YubiKey FIDO2 compatible n'a été détectée.");
}
if (output.contains(QStringLiteral("pin_policy"))) {
return QStringLiteral("Le PIN choisi ne respecte pas la politique FIDO2 de cette YubiKey.");
return QStringLiteral("Le PIN choisi ne respecte pas la politique FIDO2 de la YubiKey.");
}
if (output.contains(QStringLiteral("pin_state_not_updated"))
|| output.contains(QStringLiteral("pin_state_error"))) {
return QStringLiteral("La commande FIDO2 a été envoyée, mais l’état PIN retourné par la clé est incohérent. Ne réessayez pas avant vérification avec ykman fido info.");
}
if (output.contains(QStringLiteral("input_error"))) {
return QStringLiteral("Le composant dinitialisation de la YubiKey na pas reçu les données attendues.");
}
if (output.contains(QStringLiteral("pin_helper_error"))) {
return QStringLiteral("Le composant FIDO2 a rencontré une erreur interne sans pouvoir confirmer linitialisation du PIN.");
return QStringLiteral("Le PIN FIDO2 n'a pas pu être initialisé.");
}
return QStringLiteral("Le PIN FIDO2 na pas pu être initialisé. Vérifiez que la YubiKey est vierge, connectée et compatible FIDO2.");
if (output.contains(QStringLiteral("fido_bad_password"))) {
return QStringLiteral("Le mot de passe personnel fourni est incorrect ou insuffisant pour mettre à jour le home.");
}
if (output.contains(QStringLiteral("fido_bad_pin"))) {
return QStringLiteral("Le PIN de la YubiKey est incorrect. Ne réessayez pas plusieurs fois : vérifiez le PIN avant une nouvelle tentative.");
}
if (output.contains(QStringLiteral("multiple_yubikey"))) {
return QStringLiteral("Plusieurs clés FIDO2 sont détectées. Ne laissez branchée que la YubiKey d'Alice.");
}
if (output.contains(QStringLiteral("no_yubikey"))) {
return QStringLiteral("Aucune YubiKey FIDO2 compatible n'a été détectée.");
}
if (output.contains(QStringLiteral("fido_enroll_failed"))) {
return QStringLiteral("La YubiKey n'a pas pu être associée au home. Vérifiez le mot de passe, le PIN et touchez la clé lorsqu'elle clignote.");
}
return QStringLiteral("L'association FIDO2 au home chiffré a échoué.");
}
+27 -20
View File
@@ -12,6 +12,7 @@ class ProvisioningBackend final : public QObject
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
Q_PROPERTY(bool passwordDone READ passwordDone NOTIFY stateChanged)
Q_PROPERTY(bool pinDone READ pinDone NOTIFY stateChanged)
Q_PROPERTY(bool fidoDone READ fidoDone NOTIFY stateChanged)
Q_PROPERTY(bool complete READ complete NOTIFY stateChanged)
Q_PROPERTY(QString currentUser READ currentUser CONSTANT)
Q_PROPERTY(QString targetUser READ targetUser CONSTANT)
@@ -24,60 +25,66 @@ public:
bool busy() const { return m_busy; }
bool passwordDone() const { return m_passwordDone; }
bool pinDone() const { return m_pinDone; }
bool complete() const { return m_passwordDone && m_pinDone; }
bool fidoDone() const { return m_fidoDone; }
bool complete() const { return m_passwordDone && m_pinDone && m_fidoDone; }
QString currentUser() const { return m_currentUser; }
QString targetUser() const { return m_targetUser; }
bool authorizedUser() const;
QString stateDirectory() const;
QString diagnosticLogPath() const;
QString passwordMarker() const;
QString pinMarker() const;
static QString effectiveUserName();
Q_INVOKABLE void changePassword(const QString &currentPassword,
const QString &newPassword,
const QString &confirmation);
Q_INVOKABLE void initializePin(const QString &newPin,
const QString &confirmation);
Q_INVOKABLE void enrollFido(const QString &currentPassword,
const QString &pin);
signals:
void busyChanged();
void stateChanged();
void passwordChangeFinished(bool success, const QString &message);
void pinChangeFinished(bool success, const QString &message);
void fidoEnrollmentFinished(bool success, const QString &message);
private:
enum class Operation {
Password,
Pin
Pin,
Fido
};
QString stateDirectory() const;
QString diagnosticLogPath() const;
QString passwordMarker() const;
QString pinMarker() const;
QString fidoMarker() const;
static QString effectiveUserName();
static void secureClear(QByteArray &data);
static QString operationName(Operation operation);
void refreshState();
bool ensureStateWritable();
bool createMarker(const QString &path);
void appendLog(const QString &message) const;
void setBusy(bool busy);
void startHelper(Operation operation,
const QString &helperPath,
const QString &firstSecret,
const QString &secondSecret,
const QString &thirdSecret);
void setBusy(bool busy);
void refreshState();
bool ensureStateWritable();
bool createMarker(const QString &path);
void appendLog(const QString &message) const;
const QString &thirdSecret = {});
void emitResult(Operation operation, bool success, const QString &message);
QString safeMessageForFailure(Operation operation,
int exitCode,
const QByteArray &output,
bool timedOut) const;
static void secureClear(QByteArray &data);
static QString operationName(Operation operation);
bool m_busy = false;
bool m_passwordDone = false;
bool m_pinDone = false;
bool m_fidoDone = false;
bool m_helperTimedOut = false;
QString m_currentUser;
QString m_targetUser;