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

This commit is contained in:
2026-08-19 16:41:52 +02:00
parent cd03626064
commit 9e5668d025
4 changed files with 182 additions and 33 deletions
+62 -18
View File
@@ -339,13 +339,18 @@ Kirigami.ApplicationWindow {
} }
} }
ColumnLayout { Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter Layout.fillHeight: true
Column {
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: 2 spacing: 2
Controls.Label { Controls.Label {
Layout.fillWidth: true width: parent.width
text: modelData.title text: modelData.title
color: "white" color: "white"
font.pixelSize: 14 font.pixelSize: 14
@@ -354,7 +359,7 @@ Kirigami.ApplicationWindow {
} }
Controls.Label { Controls.Label {
Layout.fillWidth: true width: parent.width
text: modelData.subtitle text: modelData.subtitle
color: "#b9cee5" color: "#b9cee5"
font.pixelSize: 11 font.pixelSize: 11
@@ -365,6 +370,7 @@ Kirigami.ApplicationWindow {
} }
} }
} }
}
Item { Layout.fillHeight: true } Item { Layout.fillHeight: true }
@@ -608,34 +614,72 @@ Kirigami.ApplicationWindow {
text: "Saisissez le mot de passe que vous venez de choisir et le PIN de la YubiKey. Aucune recovery key n'est demandée dans ce workflow." text: "Saisissez le mot de passe que vous venez de choisir et le PIN de la YubiKey. Aucune recovery key n'est demandée dans ce workflow."
} }
InfoBox {
visible: !provisioning.busy
iconText: "☝"
text: "Après avoir lancé l'association, l'assistant vous indiquera précisément quand toucher la YubiKey. Plusieurs touchers peuvent être nécessaires."
}
Rectangle { Rectangle {
id: fidoLiveStatus
visible: provisioning.busy && root.currentStep === 3
Layout.fillWidth: true Layout.fillWidth: true
implicitHeight: touchInstruction.implicitHeight + 32 implicitHeight: fidoLiveRow.implicitHeight + 32
radius: 12 radius: 12
color: "#fffbeb" color: provisioning.fidoTouchRequired ? "#fff7ed" : "#eff6ff"
border.width: 2 border.width: provisioning.fidoTouchRequired ? 3 : 1
border.color: "#f59e0b" border.color: provisioning.fidoTouchRequired ? "#f97316" : "#bfdbfe"
SequentialAnimation on opacity {
running: fidoLiveStatus.visible && provisioning.fidoTouchRequired
loops: Animation.Infinite
NumberAnimation { from: 1.0; to: 0.58; duration: 520 }
NumberAnimation { from: 0.58; to: 1.0; duration: 520 }
}
RowLayout { RowLayout {
id: fidoLiveRow
anchors.fill: parent anchors.fill: parent
anchors.margins: 16 anchors.margins: 16
spacing: 14 spacing: 14
Controls.Label { Controls.BusyIndicator {
text: "☝" visible: !provisioning.fidoTouchRequired
font.pixelSize: 25 running: visible
Layout.alignment: Qt.AlignTop Layout.preferredWidth: 30
Layout.preferredHeight: 30
} }
Controls.Label { Controls.Label {
id: touchInstruction visible: provisioning.fidoTouchRequired
text: "☝"
font.pixelSize: 30
Layout.alignment: Qt.AlignTop
}
ColumnLayout {
Layout.fillWidth: true Layout.fillWidth: true
text: "IMPORTANT : après avoir cliqué sur « Associer la YubiKey », surveillez la clé. Elle peut clignoter plusieurs fois. Touchez-la à CHAQUE clignotement jusqu'à la fin de l'association." spacing: 4
Controls.Label {
Layout.fillWidth: true
text: provisioning.fidoTouchRequired
? "TOUCHEZ LA YUBIKEY MAINTENANT"
: "Association FIDO2 en cours"
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
color: "#92400e" color: provisioning.fidoTouchRequired ? "#9a3412" : "#1d4ed8"
font.pixelSize: 14 font.pixelSize: provisioning.fidoTouchRequired ? 18 : 15
font.weight: Font.DemiBold font.weight: Font.Bold
lineHeight: 1.25 }
Controls.Label {
Layout.fillWidth: true
text: provisioning.fidoStatus
wrapMode: Text.WordWrap
color: provisioning.fidoTouchRequired ? "#9a3412" : "#334155"
font.pixelSize: 13
lineHeight: 1.2
}
} }
} }
} }
@@ -213,6 +213,70 @@ void ProvisioningBackend::setBusy(bool busy)
emit busyChanged(); emit busyChanged();
} }
void ProvisioningBackend::resetFidoInteraction()
{
const bool changed = m_fidoTouchRequired
|| m_fidoTouchRequestCount != 0
|| !m_fidoStatus.isEmpty();
m_fidoTouchRequired = false;
m_fidoTouchRequestCount = 0;
m_fidoStatus.clear();
m_helperStdoutBuffer.clear();
if (changed) {
emit fidoInteractionChanged();
}
}
void ProvisioningBackend::handleHelperStdout(Operation operation, const QByteArray &data)
{
if (operation != Operation::Fido || data.isEmpty()) {
return;
}
m_helperStdoutBuffer += data;
qsizetype newlineIndex = -1;
while ((newlineIndex = m_helperStdoutBuffer.indexOf('\n')) >= 0) {
QByteArray line = m_helperStdoutBuffer.left(newlineIndex);
m_helperStdoutBuffer.remove(0, newlineIndex + 1);
if (!line.isEmpty() && line.endsWith('\r')) {
line.chop(1);
}
bool changed = false;
if (line == QByteArrayLiteral("EVENT_FIDO_INITIALIZING")) {
m_fidoTouchRequired = false;
m_fidoStatus = QStringLiteral("Initialisation de l'association FIDO2…");
changed = true;
} else if (line == QByteArrayLiteral("EVENT_FIDO_GENERATING")) {
m_fidoTouchRequired = false;
m_fidoStatus = QStringLiteral("Génération du secret FIDO2…");
changed = true;
} else if (line == QByteArrayLiteral("EVENT_FIDO_UPDATING_HOME")) {
m_fidoTouchRequired = false;
m_fidoStatus = QStringLiteral("Mise à jour du home chiffré…");
changed = true;
} else if (line == QByteArrayLiteral("EVENT_FIDO_SYNCHRONIZING")) {
m_fidoTouchRequired = false;
m_fidoStatus = QStringLiteral("Synchronisation des clés de chiffrement…");
changed = true;
} else if (line == QByteArrayLiteral("EVENT_FIDO_TOUCH_REQUIRED")) {
m_fidoTouchRequired = true;
++m_fidoTouchRequestCount;
m_fidoStatus = QStringLiteral("Touchez la YubiKey maintenant — demande %1. Il peut y avoir plusieurs touchers pendant cette étape.")
.arg(m_fidoTouchRequestCount);
changed = true;
}
if (changed) {
emit fidoInteractionChanged();
}
}
}
void ProvisioningBackend::secureClear(QByteArray &data) void ProvisioningBackend::secureClear(QByteArray &data)
{ {
if (!data.isEmpty()) { if (!data.isEmpty()) {
@@ -359,6 +423,10 @@ void ProvisioningBackend::enrollFido(const QString &currentPassword,
return; return;
} }
resetFidoInteraction();
m_fidoStatus = QStringLiteral("Préparation de l'association FIDO2…");
emit fidoInteractionChanged();
startHelper(Operation::Fido, startHelper(Operation::Fido,
QString::fromUtf8(NIXOS_WORKSTATIONS_FIDO_HELPER_PATH), QString::fromUtf8(NIXOS_WORKSTATIONS_FIDO_HELPER_PATH),
currentPassword, currentPassword,
@@ -396,6 +464,7 @@ void ProvisioningBackend::startHelper(Operation operation,
secureClear(third); secureClear(third);
m_helperTimedOut = false; m_helperTimedOut = false;
m_helperStdoutBuffer.clear();
setBusy(true); setBusy(true);
auto *process = new QProcess(this); auto *process = new QProcess(this);
@@ -432,6 +501,14 @@ void ProvisioningBackend::startHelper(Operation operation,
timer->start(); timer->start();
}); });
connect(process, &QProcess::readyReadStandardOutput, this,
[this, process, operation]() {
if (m_process != process) {
return;
}
handleHelperStdout(operation, process->readAllStandardOutput());
});
connect(process, &QProcess::errorOccurred, this, connect(process, &QProcess::errorOccurred, this,
[this, process, timer, operation](QProcess::ProcessError error) { [this, process, timer, operation](QProcess::ProcessError error) {
if (m_process != process || error != QProcess::FailedToStart) { if (m_process != process || error != QProcess::FailedToStart) {
@@ -443,6 +520,9 @@ void ProvisioningBackend::startHelper(Operation operation,
process->deleteLater(); process->deleteLater();
setBusy(false); setBusy(false);
appendLog(operationName(operation) + QStringLiteral(" failed to start")); appendLog(operationName(operation) + QStringLiteral(" failed to start"));
if (operation == Operation::Fido) {
resetFidoInteraction();
}
emitResult(operation, false, QStringLiteral("Impossible de démarrer le composant de configuration.")); emitResult(operation, false, QStringLiteral("Impossible de démarrer le composant de configuration."));
}); });
@@ -459,6 +539,10 @@ void ProvisioningBackend::startHelper(Operation operation,
QByteArray stderrData = process->readAllStandardError(); QByteArray stderrData = process->readAllStandardError();
QByteArray stdoutData = process->readAllStandardOutput(); QByteArray stdoutData = process->readAllStandardOutput();
if (operation == Operation::Fido && !stdoutData.isEmpty()) {
handleHelperStdout(operation, stdoutData);
stdoutData.clear();
}
QByteArray combined = stderrData + '\n' + stdoutData; QByteArray combined = stderrData + '\n' + stdoutData;
const bool timedOut = m_helperTimedOut; const bool timedOut = m_helperTimedOut;
@@ -515,6 +599,14 @@ void ProvisioningBackend::startHelper(Operation operation,
setBusy(false); setBusy(false);
refreshState(); refreshState();
if (operation == Operation::Fido) {
m_fidoTouchRequired = false;
m_fidoStatus = helperSucceeded && markerCreated
? QStringLiteral("Association FIDO2 terminée.")
: QStringLiteral("Association FIDO2 interrompue.");
emit fidoInteractionChanged();
}
emitResult(operation, helperSucceeded && markerCreated, message); emitResult(operation, helperSucceeded && markerCreated, message);
}); });
@@ -17,6 +17,9 @@ class ProvisioningBackend final : public QObject
Q_PROPERTY(QString currentUser READ currentUser CONSTANT) Q_PROPERTY(QString currentUser READ currentUser CONSTANT)
Q_PROPERTY(QString targetUser READ targetUser CONSTANT) Q_PROPERTY(QString targetUser READ targetUser CONSTANT)
Q_PROPERTY(bool authorizedUser READ authorizedUser CONSTANT) Q_PROPERTY(bool authorizedUser READ authorizedUser CONSTANT)
Q_PROPERTY(bool fidoTouchRequired READ fidoTouchRequired NOTIFY fidoInteractionChanged)
Q_PROPERTY(int fidoTouchRequestCount READ fidoTouchRequestCount NOTIFY fidoInteractionChanged)
Q_PROPERTY(QString fidoStatus READ fidoStatus NOTIFY fidoInteractionChanged)
public: public:
explicit ProvisioningBackend(QString targetUser, QObject *parent = nullptr); explicit ProvisioningBackend(QString targetUser, QObject *parent = nullptr);
@@ -30,6 +33,9 @@ public:
QString currentUser() const { return m_currentUser; } QString currentUser() const { return m_currentUser; }
QString targetUser() const { return m_targetUser; } QString targetUser() const { return m_targetUser; }
bool authorizedUser() const; bool authorizedUser() const;
bool fidoTouchRequired() const { return m_fidoTouchRequired; }
int fidoTouchRequestCount() const { return m_fidoTouchRequestCount; }
QString fidoStatus() const { return m_fidoStatus; }
// Getters de diagnostic utilisés par main.cpp (--diagnose). // Getters de diagnostic utilisés par main.cpp (--diagnose).
QString stateDirectory() const; QString stateDirectory() const;
@@ -52,6 +58,7 @@ signals:
void passwordChangeFinished(bool success, const QString &message); void passwordChangeFinished(bool success, const QString &message);
void pinChangeFinished(bool success, const QString &message); void pinChangeFinished(bool success, const QString &message);
void fidoEnrollmentFinished(bool success, const QString &message); void fidoEnrollmentFinished(bool success, const QString &message);
void fidoInteractionChanged();
private: private:
enum class Operation { enum class Operation {
@@ -69,6 +76,8 @@ private:
bool createMarker(const QString &path); bool createMarker(const QString &path);
void appendLog(const QString &message) const; void appendLog(const QString &message) const;
void setBusy(bool busy); void setBusy(bool busy);
void resetFidoInteraction();
void handleHelperStdout(Operation operation, const QByteArray &data);
void startHelper(Operation operation, void startHelper(Operation operation,
const QString &helperPath, const QString &helperPath,
@@ -91,4 +100,8 @@ private:
QString m_targetUser; QString m_targetUser;
QProcess *m_process = nullptr; QProcess *m_process = nullptr;
QByteArray m_pendingPayload; QByteArray m_pendingPayload;
QByteArray m_helperStdoutBuffer;
bool m_fidoTouchRequired = false;
int m_fidoTouchRequestCount = 0;
QString m_fidoStatus;
}; };
+1 -1
View File
@@ -41,7 +41,7 @@ int main(int argc, char *argv[])
QGuiApplication::setOrganizationName(QStringLiteral("Raspot")); QGuiApplication::setOrganizationName(QStringLiteral("Raspot"));
QGuiApplication::setOrganizationDomain(QStringLiteral("raspot.in")); QGuiApplication::setOrganizationDomain(QStringLiteral("raspot.in"));
QGuiApplication::setApplicationName(QStringLiteral("NixOS Workstations Setup")); QGuiApplication::setApplicationName(QStringLiteral("NixOS Workstations Setup"));
QGuiApplication::setApplicationVersion(QStringLiteral("1.8.4")); QGuiApplication::setApplicationVersion(QStringLiteral("1.8.5"));
QGuiApplication::setDesktopFileName(QStringLiteral("org.raspot.nixosworkstations.setup")); QGuiApplication::setDesktopFileName(QStringLiteral("org.raspot.nixosworkstations.setup"));
QCommandLineParser parser; QCommandLineParser parser;