Téléverser les fichiers vers "workstation-setup/src"
This commit is contained in:
@@ -15,14 +15,29 @@ Kirigami.ApplicationWindow {
|
||||
property string operationError: ""
|
||||
property bool closeAttempted: false
|
||||
|
||||
property var steps: [
|
||||
{ "title": "Bienvenue", "subtitle": "Première connexion" },
|
||||
{ "title": "Mot de passe", "subtitle": "Protection des données" },
|
||||
{ "title": "YubiKey", "subtitle": "Création du code PIN" },
|
||||
{ "title": "Association", "subtitle": "Association de la clé" },
|
||||
{ "title": "Terminé", "subtitle": "Poste prêt" }
|
||||
property var stepsWithYubiKey: [
|
||||
{ "page": 0, "title": "Bienvenue", "subtitle": "Première connexion" },
|
||||
{ "page": 1, "title": "Mot de passe", "subtitle": "Protection des données" },
|
||||
{ "page": 2, "title": "YubiKey", "subtitle": "Création du code PIN" },
|
||||
{ "page": 3, "title": "Association", "subtitle": "Association de la clé" },
|
||||
{ "page": 4, "title": "Terminé", "subtitle": "Poste prêt" }
|
||||
]
|
||||
|
||||
property var stepsPasswordOnly: [
|
||||
{ "page": 0, "title": "Bienvenue", "subtitle": "Première connexion" },
|
||||
{ "page": 1, "title": "Mot de passe", "subtitle": "Protection des données" },
|
||||
{ "page": 4, "title": "Terminé", "subtitle": "Poste prêt" }
|
||||
]
|
||||
|
||||
property var steps: provisioning.yubiKeyRequested ? stepsWithYubiKey : stepsPasswordOnly
|
||||
property int visibleCurrentStep: {
|
||||
for (var i = 0; i < steps.length; ++i) {
|
||||
if (steps[i].page === currentStep)
|
||||
return i
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
property bool passwordStepValid:
|
||||
currentPassword.text.length > 0 &&
|
||||
newPassword.text.length >= 8 &&
|
||||
@@ -47,8 +62,10 @@ Kirigami.ApplicationWindow {
|
||||
currentStep = 4
|
||||
else if (provisioning.pinDone)
|
||||
currentStep = 3
|
||||
else if (provisioning.passwordDone)
|
||||
currentStep = 2
|
||||
else if (provisioning.passwordDone && provisioning.yubiKeyChoiceMade)
|
||||
currentStep = provisioning.yubiKeyRequested ? 2 : 4
|
||||
else if (provisioning.yubiKeyChoiceMade)
|
||||
currentStep = 1
|
||||
else
|
||||
currentStep = 0
|
||||
}
|
||||
@@ -56,10 +73,16 @@ Kirigami.ApplicationWindow {
|
||||
Connections {
|
||||
target: provisioning
|
||||
|
||||
function onYubiKeyChoiceFinished(success, message) {
|
||||
root.operationError = success ? "" : message
|
||||
if (success)
|
||||
root.currentStep = 1
|
||||
}
|
||||
|
||||
function onPasswordChangeFinished(success, message) {
|
||||
root.operationError = success ? "" : message
|
||||
if (success)
|
||||
root.currentStep = 2
|
||||
root.currentStep = provisioning.yubiKeyRequested ? 2 : 4
|
||||
}
|
||||
|
||||
function onPinChangeFinished(success, message) {
|
||||
@@ -150,6 +173,32 @@ Kirigami.ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
component SecondaryButton: Controls.Button {
|
||||
id: control
|
||||
implicitHeight: 52
|
||||
leftPadding: 26
|
||||
rightPadding: 26
|
||||
implicitWidth: Math.max(210, buttonLabel.implicitWidth + leftPadding + rightPadding)
|
||||
|
||||
contentItem: Controls.Label {
|
||||
id: buttonLabel
|
||||
text: control.text
|
||||
color: control.enabled ? "#1d4ed8" : "#64748b"
|
||||
font.pixelSize: 15
|
||||
font.weight: Font.DemiBold
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
wrapMode: Text.NoWrap
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
radius: 11
|
||||
color: control.down ? "#dbeafe" : control.hovered ? "#eff6ff" : "#ffffff"
|
||||
border.width: 1
|
||||
border.color: control.enabled ? "#93c5fd" : "#cbd5e1"
|
||||
}
|
||||
}
|
||||
|
||||
component SecretField: Controls.TextField {
|
||||
id: field
|
||||
property bool secretVisible: false
|
||||
@@ -319,7 +368,7 @@ Kirigami.ApplicationWindow {
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: 66
|
||||
radius: 12
|
||||
color: index === root.currentStep ? "#173f6f" : "transparent"
|
||||
color: index === root.visibleCurrentStep ? "#173f6f" : "transparent"
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
@@ -330,13 +379,13 @@ Kirigami.ApplicationWindow {
|
||||
Layout.preferredWidth: 34
|
||||
Layout.preferredHeight: 34
|
||||
radius: 17
|
||||
color: index < root.currentStep ? "#22c55e"
|
||||
: index === root.currentStep ? "#ffffff"
|
||||
color: index < root.visibleCurrentStep ? "#22c55e"
|
||||
: index === root.visibleCurrentStep ? "#ffffff"
|
||||
: "#28517e"
|
||||
Controls.Label {
|
||||
anchors.centerIn: parent
|
||||
text: index < root.currentStep ? "✓" : (index + 1)
|
||||
color: index === root.currentStep ? "#0f2b50" : "white"
|
||||
text: index < root.visibleCurrentStep ? "✓" : (index + 1)
|
||||
color: index === root.visibleCurrentStep ? "#0f2b50" : "white"
|
||||
font.weight: Font.Bold
|
||||
}
|
||||
}
|
||||
@@ -356,7 +405,7 @@ Kirigami.ApplicationWindow {
|
||||
text: modelData.title
|
||||
color: "white"
|
||||
font.pixelSize: 14
|
||||
font.weight: index === root.currentStep ? Font.DemiBold : Font.Medium
|
||||
font.weight: index === root.visibleCurrentStep ? Font.DemiBold : Font.Medium
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
}
|
||||
|
||||
@@ -407,7 +456,7 @@ Kirigami.ApplicationWindow {
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: 5
|
||||
radius: 3
|
||||
color: index <= root.currentStep ? "#2563eb" : "#e2e8f0"
|
||||
color: index <= root.visibleCurrentStep ? "#2563eb" : "#e2e8f0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -450,7 +499,7 @@ Kirigami.ApplicationWindow {
|
||||
Controls.Label {
|
||||
Layout.maximumWidth: 720
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: "Votre espace personnel est déjà chiffré. Il reste à remplacer le mot de passe temporaire et à préparer votre YubiKey."
|
||||
text: "Votre espace personnel est déjà chiffré. Vous allez maintenant personnaliser votre mot de passe."
|
||||
wrapMode: Text.WordWrap
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
color: "#64748b"
|
||||
@@ -460,16 +509,34 @@ Kirigami.ApplicationWindow {
|
||||
InfoBox {
|
||||
Layout.maximumWidth: 720
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
iconText: "🔐"
|
||||
text: "À la fin, vous pourrez ouvrir votre espace personnel soit avec votre mot de passe, soit avec votre YubiKey et son code PIN."
|
||||
iconText: "?"
|
||||
text: "Disposez-vous d'une YubiKey ? Si oui, l'assistant vous aidera ensuite à la configurer. Si non, seule la personnalisation de votre mot de passe sera nécessaire."
|
||||
}
|
||||
ErrorBox {
|
||||
Layout.maximumWidth: 720
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
Item { Layout.fillHeight: true }
|
||||
PrimaryButton {
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: "Commencer"
|
||||
spacing: 14
|
||||
|
||||
SecondaryButton {
|
||||
text: "Non, je n'en ai pas"
|
||||
enabled: !provisioning.busy
|
||||
onClicked: {
|
||||
root.operationError = ""
|
||||
root.currentStep = 1
|
||||
provisioning.setYubiKeyUsage(false)
|
||||
}
|
||||
}
|
||||
|
||||
PrimaryButton {
|
||||
text: "Oui, j'ai une YubiKey"
|
||||
enabled: !provisioning.busy
|
||||
onClicked: {
|
||||
root.operationError = ""
|
||||
provisioning.setYubiKeyUsage(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -491,7 +558,9 @@ Kirigami.ApplicationWindow {
|
||||
}
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
text: "Ce mot de passe reste votre solution de secours si la YubiKey est oubliée ou indisponible."
|
||||
text: provisioning.yubiKeyRequested
|
||||
? "Ce mot de passe reste votre solution de secours si la YubiKey est oubliée ou indisponible."
|
||||
: "Ce mot de passe vous permettra d'ouvrir votre espace personnel chiffré."
|
||||
wrapMode: Text.WordWrap
|
||||
color: "#64748b"
|
||||
font.pixelSize: 14
|
||||
@@ -771,7 +840,9 @@ Kirigami.ApplicationWindow {
|
||||
Controls.Label {
|
||||
Layout.maximumWidth: 720
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: "Votre espace personnel est chiffré et votre YubiKey est prête. Vous pourrez ouvrir votre session avec votre mot de passe ou avec votre YubiKey et son code PIN."
|
||||
text: provisioning.yubiKeyRequested
|
||||
? "Votre espace personnel est chiffré et votre YubiKey est prête. Vous pourrez ouvrir votre session avec votre mot de passe ou avec votre YubiKey et son code PIN."
|
||||
: "Votre espace personnel est chiffré et votre mot de passe a été personnalisé. Vous pourrez ouvrir votre session avec ce mot de passe."
|
||||
wrapMode: Text.WordWrap
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
color: "#64748b"
|
||||
@@ -783,7 +854,9 @@ Kirigami.ApplicationWindow {
|
||||
Layout.maximumWidth: 720
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
iconText: "✓"
|
||||
text: "Votre configuration sécurisée est terminée. Conservez votre YubiKey avec vous et mémorisez son code PIN."
|
||||
text: provisioning.yubiKeyRequested
|
||||
? "Votre configuration sécurisée est terminée. Conservez votre YubiKey avec vous et mémorisez son code PIN."
|
||||
: "Votre configuration sécurisée est terminée."
|
||||
}
|
||||
|
||||
Item { Layout.fillHeight: true }
|
||||
|
||||
@@ -42,13 +42,15 @@ 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 fidoDone=%6")
|
||||
appendLog(QStringLiteral("START currentUser=%1 targetUser=%2 authorized=%3 passwordDone=%4 pinDone=%5 fidoDone=%6 yubiKeyChoice=%7 yubiKeyRequested=%8")
|
||||
.arg(m_currentUser,
|
||||
m_targetUser,
|
||||
authorizedUser() ? QStringLiteral("yes") : QStringLiteral("no"),
|
||||
m_passwordDone ? QStringLiteral("yes") : QStringLiteral("no"),
|
||||
m_pinDone ? QStringLiteral("yes") : QStringLiteral("no"),
|
||||
m_fidoDone ? QStringLiteral("yes") : QStringLiteral("no")));
|
||||
m_fidoDone ? QStringLiteral("yes") : QStringLiteral("no"),
|
||||
yubiKeyChoiceMade() ? QStringLiteral("yes") : QStringLiteral("no"),
|
||||
yubiKeyRequested() ? QStringLiteral("yes") : QStringLiteral("no")));
|
||||
}
|
||||
|
||||
ProvisioningBackend::~ProvisioningBackend()
|
||||
@@ -114,17 +116,35 @@ QString ProvisioningBackend::fidoMarker() const
|
||||
return stateDirectory() + QStringLiteral("/yubikey-fido-enrolled");
|
||||
}
|
||||
|
||||
QString ProvisioningBackend::yubiKeyEnabledMarker() const
|
||||
{
|
||||
return stateDirectory() + QStringLiteral("/yubikey-enabled");
|
||||
}
|
||||
|
||||
QString ProvisioningBackend::yubiKeySkippedMarker() const
|
||||
{
|
||||
return stateDirectory() + QStringLiteral("/yubikey-skipped");
|
||||
}
|
||||
|
||||
void ProvisioningBackend::refreshState()
|
||||
{
|
||||
const bool oldPassword = m_passwordDone;
|
||||
const bool oldPin = m_pinDone;
|
||||
const bool oldFido = m_fidoDone;
|
||||
const bool oldYubiKeyEnabled = m_yubiKeyEnabled;
|
||||
const bool oldYubiKeySkipped = m_yubiKeySkipped;
|
||||
|
||||
m_passwordDone = QFileInfo::exists(passwordMarker());
|
||||
m_pinDone = QFileInfo::exists(pinMarker());
|
||||
m_fidoDone = QFileInfo::exists(fidoMarker());
|
||||
m_yubiKeyEnabled = QFileInfo::exists(yubiKeyEnabledMarker());
|
||||
m_yubiKeySkipped = QFileInfo::exists(yubiKeySkippedMarker());
|
||||
|
||||
if (oldPassword != m_passwordDone || oldPin != m_pinDone || oldFido != m_fidoDone) {
|
||||
if (oldPassword != m_passwordDone
|
||||
|| oldPin != m_pinDone
|
||||
|| oldFido != m_fidoDone
|
||||
|| oldYubiKeyEnabled != m_yubiKeyEnabled
|
||||
|| oldYubiKeySkipped != m_yubiKeySkipped) {
|
||||
emit stateChanged();
|
||||
}
|
||||
}
|
||||
@@ -321,6 +341,38 @@ void ProvisioningBackend::emitResult(Operation operation, bool success, const QS
|
||||
}
|
||||
}
|
||||
|
||||
void ProvisioningBackend::setYubiKeyUsage(bool enabled)
|
||||
{
|
||||
if (!authorizedUser()) {
|
||||
emit yubiKeyChoiceFinished(false, QStringLiteral("Cette opération n'est pas autorisée pour cet utilisateur."));
|
||||
return;
|
||||
}
|
||||
if (m_busy) {
|
||||
emit yubiKeyChoiceFinished(false, QStringLiteral("Une opération de configuration est déjà en cours."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Un compte déjà passé par les étapes YubiKey est considéré comme utilisant
|
||||
// toujours sa clé. Cela assure la compatibilité avec les états v1.9.0.
|
||||
if (!enabled && (m_pinDone || m_fidoDone)) {
|
||||
emit yubiKeyChoiceFinished(false, QStringLiteral("Une YubiKey est déjà configurée pour ce compte."));
|
||||
return;
|
||||
}
|
||||
|
||||
const QString selectedMarker = enabled ? yubiKeyEnabledMarker() : yubiKeySkippedMarker();
|
||||
const QString obsoleteMarker = enabled ? yubiKeySkippedMarker() : yubiKeyEnabledMarker();
|
||||
|
||||
if (!createMarker(selectedMarker)) {
|
||||
emit yubiKeyChoiceFinished(false, QStringLiteral("Impossible d'enregistrer votre choix."));
|
||||
return;
|
||||
}
|
||||
|
||||
QFile::remove(obsoleteMarker);
|
||||
refreshState();
|
||||
appendLog(QStringLiteral("YUBIKEY choice=%1").arg(enabled ? QStringLiteral("enabled") : QStringLiteral("skipped")));
|
||||
emit yubiKeyChoiceFinished(true, QString());
|
||||
}
|
||||
|
||||
void ProvisioningBackend::changePassword(const QString ¤tPassword,
|
||||
const QString &newPassword,
|
||||
const QString &confirmation)
|
||||
@@ -333,6 +385,10 @@ void ProvisioningBackend::changePassword(const QString ¤tPassword,
|
||||
emit passwordChangeFinished(false, QStringLiteral("Une opération de configuration est déjà en cours."));
|
||||
return;
|
||||
}
|
||||
if (!yubiKeyChoiceMade()) {
|
||||
emit passwordChangeFinished(false, QStringLiteral("Indiquez d'abord si vous disposez d'une YubiKey."));
|
||||
return;
|
||||
}
|
||||
if (m_passwordDone) {
|
||||
emit passwordChangeFinished(true, QStringLiteral("Le mot de passe a déjà été personnalisé."));
|
||||
return;
|
||||
@@ -372,6 +428,10 @@ void ProvisioningBackend::initializePin(const QString &newPin,
|
||||
emit pinChangeFinished(false, QStringLiteral("Une opération de configuration est déjà en cours."));
|
||||
return;
|
||||
}
|
||||
if (!yubiKeyRequested()) {
|
||||
emit pinChangeFinished(false, QStringLiteral("Aucune YubiKey n'a été sélectionnée pour ce compte."));
|
||||
return;
|
||||
}
|
||||
if (!m_passwordDone) {
|
||||
emit pinChangeFinished(false, QStringLiteral("Personnalisez d'abord votre mot de passe."));
|
||||
return;
|
||||
@@ -410,6 +470,10 @@ void ProvisioningBackend::enrollFido(const QString ¤tPassword,
|
||||
emit fidoEnrollmentFinished(false, QStringLiteral("Une opération de configuration est déjà en cours."));
|
||||
return;
|
||||
}
|
||||
if (!yubiKeyRequested()) {
|
||||
emit fidoEnrollmentFinished(false, QStringLiteral("Aucune YubiKey n'a été sélectionnée pour ce compte."));
|
||||
return;
|
||||
}
|
||||
if (!m_passwordDone || !m_pinDone) {
|
||||
emit fidoEnrollmentFinished(false, QStringLiteral("Le mot de passe et le code PIN doivent être configurés avant d'associer la YubiKey."));
|
||||
return;
|
||||
|
||||
@@ -13,6 +13,8 @@ class ProvisioningBackend final : public QObject
|
||||
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 yubiKeyChoiceMade READ yubiKeyChoiceMade NOTIFY stateChanged)
|
||||
Q_PROPERTY(bool yubiKeyRequested READ yubiKeyRequested NOTIFY stateChanged)
|
||||
Q_PROPERTY(bool complete READ complete NOTIFY stateChanged)
|
||||
Q_PROPERTY(QString currentUser READ currentUser CONSTANT)
|
||||
Q_PROPERTY(QString targetUser READ targetUser CONSTANT)
|
||||
@@ -29,7 +31,9 @@ public:
|
||||
bool passwordDone() const { return m_passwordDone; }
|
||||
bool pinDone() const { return m_pinDone; }
|
||||
bool fidoDone() const { return m_fidoDone; }
|
||||
bool complete() const { return m_passwordDone && m_pinDone && m_fidoDone; }
|
||||
bool yubiKeyChoiceMade() const { return m_yubiKeyEnabled || m_yubiKeySkipped || m_pinDone || m_fidoDone; }
|
||||
bool yubiKeyRequested() const { return !m_yubiKeySkipped && (m_yubiKeyEnabled || m_pinDone || m_fidoDone); }
|
||||
bool complete() const { return m_passwordDone && (m_yubiKeySkipped || (m_pinDone && m_fidoDone)); }
|
||||
QString currentUser() const { return m_currentUser; }
|
||||
QString targetUser() const { return m_targetUser; }
|
||||
bool authorizedUser() const;
|
||||
@@ -43,7 +47,10 @@ public:
|
||||
QString passwordMarker() const;
|
||||
QString pinMarker() const;
|
||||
QString fidoMarker() const;
|
||||
QString yubiKeyEnabledMarker() const;
|
||||
QString yubiKeySkippedMarker() const;
|
||||
|
||||
Q_INVOKABLE void setYubiKeyUsage(bool enabled);
|
||||
Q_INVOKABLE void changePassword(const QString ¤tPassword,
|
||||
const QString &newPassword,
|
||||
const QString &confirmation);
|
||||
@@ -55,6 +62,7 @@ public:
|
||||
signals:
|
||||
void busyChanged();
|
||||
void stateChanged();
|
||||
void yubiKeyChoiceFinished(bool success, const QString &message);
|
||||
void passwordChangeFinished(bool success, const QString &message);
|
||||
void pinChangeFinished(bool success, const QString &message);
|
||||
void fidoEnrollmentFinished(bool success, const QString &message);
|
||||
@@ -95,6 +103,8 @@ private:
|
||||
bool m_passwordDone = false;
|
||||
bool m_pinDone = false;
|
||||
bool m_fidoDone = false;
|
||||
bool m_yubiKeyEnabled = false;
|
||||
bool m_yubiKeySkipped = false;
|
||||
bool m_helperTimedOut = false;
|
||||
QString m_currentUser;
|
||||
QString m_targetUser;
|
||||
|
||||
@@ -41,7 +41,7 @@ int main(int argc, char *argv[])
|
||||
QGuiApplication::setOrganizationName(QStringLiteral("Raspot"));
|
||||
QGuiApplication::setOrganizationDomain(QStringLiteral("raspot.in"));
|
||||
QGuiApplication::setApplicationName(QStringLiteral("NixOS Workstations Setup"));
|
||||
QGuiApplication::setApplicationVersion(QStringLiteral("1.9.0"));
|
||||
QGuiApplication::setApplicationVersion(QStringLiteral("1.9.1"));
|
||||
QGuiApplication::setDesktopFileName(QStringLiteral("org.raspot.nixosworkstations.setup"));
|
||||
|
||||
QCommandLineParser parser;
|
||||
@@ -90,6 +90,8 @@ int main(int argc, char *argv[])
|
||||
qInfo().noquote() << "password_done=" + (provisioning.passwordDone() ? QStringLiteral("yes") : QStringLiteral("no"));
|
||||
qInfo().noquote() << "pin_marker=" + provisioning.pinMarker();
|
||||
qInfo().noquote() << "pin_done=" + (provisioning.pinDone() ? QStringLiteral("yes") : QStringLiteral("no"));
|
||||
qInfo().noquote() << "yubikey_choice=" + (provisioning.yubiKeyChoiceMade() ? QStringLiteral("yes") : QStringLiteral("no"));
|
||||
qInfo().noquote() << "yubikey_requested=" + (provisioning.yubiKeyRequested() ? QStringLiteral("yes") : QStringLiteral("no"));
|
||||
qInfo().noquote() << "log=" + provisioning.diagnosticLogPath();
|
||||
return provisioning.authorizedUser() ? 0 : 3;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user