From 9018913af53b97acb3bc6eb1a749ec78448b84e9 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 28 Jul 2020 10:45:38 +0200 Subject: [PATCH] [users] Move hostname validation to Config --- src/modules/users/Config.cpp | 73 ++++++++++++++++++++++----- src/modules/users/Config.h | 5 ++ src/modules/users/UsersPage.cpp | 89 +++++++++++---------------------- src/modules/users/UsersPage.h | 2 +- 4 files changed, 97 insertions(+), 72 deletions(-) diff --git a/src/modules/users/Config.cpp b/src/modules/users/Config.cpp index 03ae60b2f..bc1113672 100644 --- a/src/modules/users/Config.cpp +++ b/src/modules/users/Config.cpp @@ -33,6 +33,10 @@ static const QRegExp USERNAME_RX( "^[a-z_][a-z0-9_-]*[$]?$" ); static constexpr const int USERNAME_MAX_LENGTH = 31; +static const QRegExp HOSTNAME_RX( "^[a-zA-Z0-9][-a-zA-Z0-9_]*$" ); +static constexpr const int HOSTNAME_MIN_LENGTH = 2; +static constexpr const int HOSTNAME_MAX_LENGTH = 63; + Config::Config( QObject* parent ) : QObject( parent ) { @@ -106,15 +110,22 @@ Config::loginNameStatus() const return QString(); } - QRegExpValidator validateEntireLoginName( USERNAME_RX ); - QRegExpValidator validateFirstLetter( QRegExp( "[a-z_].*" ) ); // anchors are implicit in QRegExpValidator - int pos = -1; - if ( m_loginName.length() > USERNAME_MAX_LENGTH ) { return tr( "Your username is too long." ); } + for ( const QString& badName : forbiddenLoginNames() ) + { + if ( 0 == QString::compare( badName, m_loginName, Qt::CaseSensitive ) ) + { + return tr( "'%1' is not allowed as username." ).arg( badName ); + } + } + QString login( m_loginName ); // make a copy because validate() doesn't take const& + QRegExpValidator validateEntireLoginName( USERNAME_RX ); + QRegExpValidator validateFirstLetter( QRegExp( "[a-z_].*" ) ); // anchors are implicit in QRegExpValidator + int pos = -1; if ( validateFirstLetter.validate( login, pos ) == QValidator::Invalid ) { return tr( "Your username must start with a lowercase letter or underscore." ); @@ -124,14 +135,6 @@ Config::loginNameStatus() const return tr( "Only lowercase letters, numbers, underscore and hyphen are allowed." ); } - for ( const QString& badName : forbiddenLoginNames() ) - { - if ( 0 == QString::compare( badName, m_loginName, Qt::CaseSensitive ) ) - { - return tr( "'%1' is not allowed as user name." ).arg( badName ); - } - } - return QString(); } @@ -143,7 +146,52 @@ Config::setHostName( const QString& host ) m_customHostName = !host.isEmpty(); m_hostName = host; emit hostNameChanged( host ); + emit hostNameStatusChanged( hostNameStatus() ); + } +} + +const QStringList& +Config::forbiddenHostNames() +{ + static QStringList forbidden { "localhost" }; + return forbidden; +} + +QString +Config::hostNameStatus() const +{ + // An empty hostname is "ok", even if it isn't really + if ( m_hostName.isEmpty() ) + { + return QString(); + } + + if ( m_hostName.length() < HOSTNAME_MIN_LENGTH ) + { + return tr( "Your hostname is too short." ); } + if ( m_hostName.length() > HOSTNAME_MAX_LENGTH ) + { + return tr( "Your hostname is too long." ); + } + for ( const QString& badName : forbiddenHostNames() ) + { + if ( 0 == QString::compare( badName, m_hostName, Qt::CaseSensitive ) ) + { + return tr( "'%1' is not allowed as hostname." ).arg( badName ); + } + } + + QString text = m_hostName; + QRegExpValidator val( HOSTNAME_RX ); + int pos = -1; + + if ( val.validate( text, pos ) == QValidator::Invalid ) + { + return tr( "Only letters, numbers, underscore and hyphen are allowed." ); + } + + return QString(); } @@ -258,6 +306,7 @@ Config::setFullName( const QString& name ) { m_hostName = hostname; emit hostNameChanged( hostname ); + emit hostNameStatusChanged( hostNameStatus() ); } } } diff --git a/src/modules/users/Config.h b/src/modules/users/Config.h index 91a494619..824b70ba8 100644 --- a/src/modules/users/Config.h +++ b/src/modules/users/Config.h @@ -38,6 +38,7 @@ class Config : public QObject Q_PROPERTY( QString loginNameStatus READ loginNameStatus NOTIFY loginNameStatusChanged ) Q_PROPERTY( QString hostName READ hostName WRITE setHostName NOTIFY hostNameChanged ) + Q_PROPERTY( QString hostNameStatus READ hostNameStatus NOTIFY hostNameStatusChanged ) public: Config( QObject* parent = nullptr ); @@ -66,8 +67,11 @@ public: /// The host name (name for the system) QString hostName() const { return m_hostName; } + /// Status message about hostname -- empty for "ok" + QString hostNameStatus() const; static const QStringList& forbiddenLoginNames(); + static const QStringList& forbiddenHostNames(); public Q_SLOTS: /** @brief Sets the user's shell if possible @@ -101,6 +105,7 @@ signals: void loginNameChanged( const QString& ); void loginNameStatusChanged( const QString& ); void hostNameChanged( const QString& ); + void hostNameStatusChanged( const QString& ); private: QString m_userShell; diff --git a/src/modules/users/UsersPage.cpp b/src/modules/users/UsersPage.cpp index cc940502e..7983e29ea 100644 --- a/src/modules/users/UsersPage.cpp +++ b/src/modules/users/UsersPage.cpp @@ -46,11 +46,6 @@ #include #include -static const QRegExp HOSTNAME_RX( "^[a-zA-Z0-9][-a-zA-Z0-9_]*$" ); -static constexpr const int USERNAME_MAX_LENGTH = 31; -static constexpr const int HOSTNAME_MIN_LENGTH = 2; -static constexpr const int HOSTNAME_MAX_LENGTH = 63; - /** @brief How bad is the error for labelError() ? */ enum class Badness { @@ -77,6 +72,32 @@ labelOk( QLabel* pix, QLabel* label ) pix->setPixmap( CalamaresUtils::defaultPixmap( CalamaresUtils::Yes, CalamaresUtils::Original, label->size() ) ); } +/** Indicate error, update @p ok based on @p status */ +static inline void +labelStatus( QLabel* pix, QLabel* label, const QString& value, const QString& status, bool& ok ) +{ + if ( status.isEmpty() ) + { + if ( value.isEmpty() ) + { + // This is different from labelOK() because no checkmark is shown + label->clear(); + pix->clear(); + ok = false; + } + else + { + labelOk( pix, label ); + ok = true; + } + } + else + { + labelError( pix, label, status ); + ok = false; + } +} + UsersPage::UsersPage( Config* config, QWidget* parent ) : QWidget( parent ) , ui( new Ui::Page_UserSetup ) @@ -124,7 +145,7 @@ UsersPage::UsersPage( Config* config, QWidget* parent ) connect( ui->textBoxHostName, &QLineEdit::textEdited, config, &Config::setHostName ); connect( config, &Config::hostNameChanged, ui->textBoxHostName, &QLineEdit::setText ); - connect( config, &Config::hostNameChanged, this, &UsersPage::validateHostnameText ); + connect( config, &Config::hostNameStatusChanged, this, &UsersPage::reportHostNameStatus ); connect( ui->textBoxLoginName, &QLineEdit::textEdited, config, &Config::setLoginName ); connect( config, &Config::loginNameChanged, ui->textBoxLoginName, &QLineEdit::setText ); @@ -279,64 +300,14 @@ UsersPage::onFullNameTextEdited( const QString& textRef ) void UsersPage::reportLoginNameStatus( const QString& status ) { - if ( status.isEmpty() ) - { - if ( m_config->loginName().isEmpty() ) - { - ui->labelUsernameError->clear(); - ui->labelUsername->clear(); - m_readyUsername = false; - } - else - { - labelOk( ui->labelUsername, ui->labelUsernameError ); - m_readyUsername = true; - } - } - else - { - labelError( ui->labelUsername, ui->labelUsernameError, status ); - m_readyUsername = false; - } + labelStatus( ui->labelUsername, ui->labelUsernameError, m_config->loginName(), status, m_readyUsername ); emit checkReady( isReady() ); } void -UsersPage::validateHostnameText( const QString& textRef ) +UsersPage::reportHostNameStatus( const QString& status ) { - QString text = textRef; - QRegExpValidator val( HOSTNAME_RX ); - int pos = -1; - - if ( text.isEmpty() ) - { - ui->labelHostnameError->clear(); - ui->labelHostname->clear(); - m_readyHostname = false; - } - else if ( text.length() < HOSTNAME_MIN_LENGTH ) - { - labelError( ui->labelHostname, ui->labelHostnameError, tr( "Your hostname is too short." ) ); - m_readyHostname = false; - } - else if ( text.length() > HOSTNAME_MAX_LENGTH ) - { - labelError( ui->labelHostname, ui->labelHostnameError, tr( "Your hostname is too long." ) ); - m_readyHostname = false; - } - else if ( val.validate( text, pos ) == QValidator::Invalid ) - { - labelError( ui->labelHostname, - ui->labelHostnameError, - tr( "Only letters, numbers, underscore and hyphen are allowed." ) ); - m_readyHostname = false; - } - else - { - labelOk( ui->labelHostname, ui->labelHostnameError ); - m_readyHostname = true; - } - + labelStatus( ui->labelHostname, ui->labelHostnameError, m_config->hostName(), status, m_readyHostname ); emit checkReady( isReady() ); } diff --git a/src/modules/users/UsersPage.h b/src/modules/users/UsersPage.h index 7cf83100c..7e0830dc0 100644 --- a/src/modules/users/UsersPage.h +++ b/src/modules/users/UsersPage.h @@ -73,7 +73,7 @@ public: protected slots: void onFullNameTextEdited( const QString& ); void reportLoginNameStatus( const QString& ); - void validateHostnameText( const QString& ); + void reportHostNameStatus( const QString& ); void onPasswordTextChanged( const QString& ); void onRootPasswordTextChanged( const QString& );