Merge branch 'issue-1477' into calamares

FIXES #1477
main
Adriaan de Groot 5 years ago
commit 43f9f2e2f4

@ -71,4 +71,7 @@ calamares_add_test(
SOURCES
Tests.cpp
Config.cpp
CheckPWQuality.cpp
LIBRARIES
${USER_EXTRA_LIB}
)

@ -22,7 +22,6 @@
#include <QCoreApplication>
#include <QString>
#include <QWidget>
#ifdef HAVE_LIBPWQUALITY
#include <pwquality.h>

@ -26,6 +26,7 @@
#include "utils/String.h"
#include "utils/Variant.h"
#include <QCoreApplication>
#include <QFile>
#include <QRegExp>
@ -36,6 +37,22 @@ 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;
const NamedEnumTable< HostNameAction >&
hostNameActionNames()
{
// *INDENT-OFF*
// clang-format off
static const NamedEnumTable< HostNameAction > names {
{ QStringLiteral( "none" ), HostNameAction::None },
{ QStringLiteral( "etcfile" ), HostNameAction::EtcHostname },
{ QStringLiteral( "hostnamed" ), HostNameAction::SystemdHostname }
};
// clang-format on
// *INDENT-ON*
return names;
}
Config::Config( QObject* parent )
: QObject( parent )
{
@ -343,6 +360,106 @@ Config::setAutoLogin( bool b )
}
}
void
Config::setReuseUserPasswordForRoot( bool reuse )
{
if ( reuse != m_reuseUserPasswordForRoot )
{
m_reuseUserPasswordForRoot = reuse;
emit reuseUserPasswordForRootChanged( reuse );
}
}
void
Config::setRequireStrongPasswords( bool strong )
{
if ( strong != m_requireStrongPasswords )
{
m_requireStrongPasswords = strong;
emit requireStrongPasswordsChanged( strong );
}
}
bool
Config::isPasswordAcceptable( const QString& password, QString& message )
{
bool failureIsFatal = requireStrongPasswords();
for ( auto pc : m_passwordChecks )
{
QString s = pc.filter( password );
if ( !s.isEmpty() )
{
message = s;
return !failureIsFatal;
}
}
return true;
}
void
Config::setUserPassword( const QString& s )
{
m_userPassword = s;
// TODO: check new password status
emit userPasswordChanged( s );
}
void
Config::setUserPasswordSecondary( const QString& s )
{
m_userPasswordSecondary = s;
// TODO: check new password status
emit userPasswordSecondaryChanged( s );
}
void
Config::setRootPassword( const QString& s )
{
if ( writeRootPassword() )
{
m_rootPassword = s;
// TODO: check new password status
emit rootPasswordChanged( s );
}
}
void
Config::setRootPasswordSecondary( const QString& s )
{
if ( writeRootPassword() )
{
m_rootPasswordSecondary = s;
// TODO: check new password status
emit rootPasswordSecondaryChanged( s );
}
}
QString Config::rootPassword() const
{
if ( writeRootPassword() )
{
if ( reuseUserPasswordForRoot() )
return userPassword();
return m_rootPassword;
}
return QString();
}
QString Config::rootPasswordSecondary() const
{
if ( writeRootPassword() )
{
if ( reuseUserPasswordForRoot() )
return userPasswordSecondary();
return m_rootPasswordSecondary;
}
return QString();
}
STATICTEST void
setConfigurationDefaultGroups( const QVariantMap& map, QStringList& defaultGroups )
{
@ -357,6 +474,74 @@ setConfigurationDefaultGroups( const QVariantMap& map, QStringList& defaultGroup
}
}
STATICTEST HostNameActions
getHostNameActions( const QVariantMap& configurationMap )
{
HostNameAction setHostName = HostNameAction::EtcHostname;
QString hostnameActionString = CalamaresUtils::getString( configurationMap, "setHostname" );
if ( !hostnameActionString.isEmpty() )
{
bool ok = false;
setHostName = hostNameActionNames().find( hostnameActionString, ok );
if ( !ok )
{
setHostName = HostNameAction::EtcHostname; // Rather than none
}
}
HostNameAction writeHosts = CalamaresUtils::getBool( configurationMap, "writeHostsFile", true )
? HostNameAction::WriteEtcHosts
: HostNameAction::None;
return setHostName | writeHosts;
}
/** @brief Process entries in the passwordRequirements config entry
*
* Called once for each item in the config entry, which should
* be a key-value pair. What makes sense as a value depends on
* the key. Supported keys are documented in users.conf.
*
* @return if the check was added, returns @c true
*/
STATICTEST bool
addPasswordCheck( const QString& key, const QVariant& value, PasswordCheckList& passwordChecks )
{
if ( key == "minLength" )
{
add_check_minLength( passwordChecks, value );
}
else if ( key == "maxLength" )
{
add_check_maxLength( passwordChecks, value );
}
else if ( key == "nonempty" )
{
if ( value.toBool() )
{
passwordChecks.push_back(
PasswordCheck( []() { return QCoreApplication::translate( "PWQ", "Password is empty" ); },
[]( const QString& s ) { return !s.isEmpty(); },
PasswordCheck::Weight( 1 ) ) );
}
else
{
cDebug() << "nonempty check is mentioned but set to false";
return false;
}
}
#ifdef CHECK_PWQUALITY
else if ( key == "libpwquality" )
{
add_check_libpwquality( passwordChecks, value );
}
#endif // CHECK_PWQUALITY
else
{
cWarning() << "Unknown password-check key" << key;
return false;
}
return true;
}
void
Config::setConfigurationMap( const QVariantMap& configurationMap )
@ -372,9 +557,25 @@ Config::setConfigurationMap( const QVariantMap& configurationMap )
setAutologinGroup( CalamaresUtils::getString( configurationMap, "autologinGroup" ) );
setSudoersGroup( CalamaresUtils::getString( configurationMap, "sudoersGroup" ) );
m_hostNameActions = getHostNameActions( configurationMap );
setConfigurationDefaultGroups( configurationMap, m_defaultGroups );
m_doAutoLogin = CalamaresUtils::getBool( configurationMap, "doAutologin", false );
m_writeRootPassword = CalamaresUtils::getBool( configurationMap, "setRootPassword", true );
Calamares::JobQueue::instance()->globalStorage()->insert( "setRootPassword", m_writeRootPassword );
m_reuseUserPasswordForRoot = CalamaresUtils::getBool( configurationMap, "doReusePassword", false );
m_permitWeakPasswords = CalamaresUtils::getBool( configurationMap, "allowWeakPasswords", false );
m_requireStrongPasswords
= !m_permitWeakPasswords || !CalamaresUtils::getBool( configurationMap, "allowWeakPasswordsDefault", false );
// If the value doesn't exist, or isn't a map, this gives an empty map -- no problem
auto pr_checks( configurationMap.value( "passwordRequirements" ).toMap() );
for ( decltype( pr_checks )::const_iterator i = pr_checks.constBegin(); i != pr_checks.constEnd(); ++i )
{
addPasswordCheck( i.key(), i.value(), m_passwordChecks );
}
std::sort( m_passwordChecks.begin(), m_passwordChecks.end() );
}

@ -21,9 +21,25 @@
#ifndef USERS_CONFIG_H
#define USERS_CONFIG_H
#include "CheckPWQuality.h"
#include "utils/NamedEnum.h"
#include <QObject>
#include <QVariantMap>
enum HostNameAction
{
None = 0x0,
EtcHostname = 0x1, // Write to /etc/hostname directly
SystemdHostname = 0x2, // Set via hostnamed(1)
WriteEtcHosts = 0x4 // Write /etc/hosts (127.0.1.1 is this host)
};
Q_DECLARE_FLAGS( HostNameActions, HostNameAction )
Q_DECLARE_OPERATORS_FOR_FLAGS( HostNameActions )
const NamedEnumTable< HostNameAction >& hostNameActionNames();
class Config : public QObject
{
Q_OBJECT
@ -41,6 +57,22 @@ class Config : public QObject
Q_PROPERTY( QString hostName READ hostName WRITE setHostName NOTIFY hostNameChanged )
Q_PROPERTY( QString hostNameStatus READ hostNameStatus NOTIFY hostNameStatusChanged )
Q_PROPERTY( HostNameActions hostNameActions READ hostNameActions CONSTANT )
Q_PROPERTY( QString userPassword READ userPassword WRITE setUserPassword NOTIFY userPasswordChanged )
Q_PROPERTY( QString userPasswordSecondary READ userPasswordSecondary WRITE setUserPasswordSecondary NOTIFY
userPasswordSecondaryChanged )
Q_PROPERTY( QString rootPassword READ rootPassword WRITE setRootPassword NOTIFY rootPasswordChanged )
Q_PROPERTY( QString rootPasswordSecondary READ rootPasswordSecondary WRITE setRootPasswordSecondary NOTIFY
rootPasswordSecondaryChanged )
Q_PROPERTY( bool writeRootPassword READ writeRootPassword CONSTANT )
Q_PROPERTY( bool reuseUserPasswordForRoot READ reuseUserPasswordForRoot WRITE setReuseUserPasswordForRoot NOTIFY
reuseUserPasswordForRootChanged )
Q_PROPERTY( bool permitWeakPasswords READ permitWeakPasswords CONSTANT )
Q_PROPERTY( bool requireStrongPasswords READ requireStrongPasswords WRITE setRequireStrongPasswords NOTIFY
requireStrongPasswordsChanged )
public:
Config( QObject* parent = nullptr );
@ -71,14 +103,42 @@ public:
QString hostName() const { return m_hostName; }
/// Status message about hostname -- empty for "ok"
QString hostNameStatus() const;
/// How to write the hostname
HostNameActions hostNameActions() const { return m_hostNameActions; }
/// Should the user be automatically logged-in?
bool doAutoLogin() const { return m_doAutoLogin; }
/// Should the root password be written (if false, no password is set and the root account is disabled for login)
bool writeRootPassword() const { return m_writeRootPassword; }
/// Should the user's password be used for root, too? (if root is written at all)
bool reuseUserPasswordForRoot() const { return m_reuseUserPasswordForRoot; }
/// Show UI to change the "require strong password" setting?
bool permitWeakPasswords() const { return m_permitWeakPasswords; }
/// Current setting for "require strong password"?
bool requireStrongPasswords() const { return m_requireStrongPasswords; }
const QStringList& defaultGroups() const { return m_defaultGroups; }
/** @brief Checks if the password is acceptable.
*
* If all is well, sets @p message to empty and returns @c true.
* If there are warnings, but acceptable, sets @p message to something
* non-empty and returns @c true. This happens if requireStrongPasswords
* is turned off (by config or user).
* If the password is not acceptable, sets @p message to something
* non-empty and returns @c false.
*/
bool isPasswordAcceptable( const QString& password, QString& message );
// The user enters a password (and again in a separate UI element)
QString userPassword() const { return m_userPassword; }
QString userPasswordSecondary() const { return m_userPasswordSecondary; }
// The root password **may** be entered in the UI, or may be suppressed
// entirely when writeRootPassword is off, or may be equal to
// the user password when reuseUserPasswordForRoot is on.
QString rootPassword() const;
QString rootPasswordSecondary() const;
static const QStringList& forbiddenLoginNames();
static const QStringList& forbiddenHostNames();
@ -109,6 +169,16 @@ public Q_SLOTS:
/// Sets the autologin flag
void setAutoLogin( bool b );
/// Set to true to use the user password, unchanged, for root too
void setReuseUserPasswordForRoot( bool reuse );
/// Change setting for "require strong password"
void setRequireStrongPasswords( bool strong );
void setUserPassword( const QString& );
void setUserPasswordSecondary( const QString& );
void setRootPassword( const QString& );
void setRootPasswordSecondary( const QString& );
signals:
void userShellChanged( const QString& );
void autologinGroupChanged( const QString& );
@ -119,6 +189,13 @@ signals:
void hostNameChanged( const QString& );
void hostNameStatusChanged( const QString& );
void autoLoginChanged( bool );
void reuseUserPasswordForRootChanged( bool );
void requireStrongPasswordsChanged( bool );
void userPasswordChanged( const QString& );
void userPasswordSecondaryChanged( const QString& );
void rootPasswordChanged( const QString& );
void rootPasswordSecondaryChanged( const QString& );
private:
QStringList m_defaultGroups;
@ -128,11 +205,25 @@ private:
QString m_fullName;
QString m_loginName;
QString m_hostName;
QString m_userPassword;
QString m_userPasswordSecondary; // enter again to be sure
QString m_rootPassword;
QString m_rootPasswordSecondary;
bool m_doAutoLogin = false;
bool m_writeRootPassword = true;
bool m_reuseUserPasswordForRoot = false;
bool m_permitWeakPasswords = false;
bool m_requireStrongPasswords = true;
bool m_customLoginName = false;
bool m_customHostName = false;
HostNameActions m_hostNameActions;
PasswordCheckList m_passwordChecks;
};
#endif

@ -27,13 +27,13 @@
#include <QDir>
#include <QFile>
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusReply>
#include <QDBusConnection>
#include <QDBusInterface>
#include <QDBusReply>
using WriteMode = CalamaresUtils::System::WriteMode;
SetHostNameJob::SetHostNameJob( const QString& hostname, Actions a )
SetHostNameJob::SetHostNameJob( const QString& hostname, HostNameActions a )
: Calamares::Job()
, m_hostname( hostname )
, m_actions( a )
@ -138,7 +138,7 @@ SetHostNameJob::exec()
return Calamares::JobResult::error( tr( "Internal Error" ) );
}
if ( m_actions & Action::EtcHostname )
if ( m_actions & HostNameAction::EtcHostname )
{
if ( !setFileHostname( m_hostname ) )
{
@ -147,7 +147,7 @@ SetHostNameJob::exec()
}
}
if ( m_actions & Action::WriteEtcHosts )
if ( m_actions & HostNameAction::WriteEtcHosts )
{
if ( !writeFileEtcHosts( m_hostname ) )
{
@ -156,7 +156,7 @@ SetHostNameJob::exec()
}
}
if ( m_actions & Action::SystemdHostname )
if ( m_actions & HostNameAction::SystemdHostname )
{
// Does its own logging
setSystemdHostname( m_hostname );

@ -21,23 +21,15 @@
#ifndef SETHOSTNAMEJOB_CPP_H
#define SETHOSTNAMEJOB_CPP_H
#include "Config.h"
#include "Job.h"
class SetHostNameJob : public Calamares::Job
{
Q_OBJECT
public:
enum Action
{
None = 0x0,
EtcHostname = 0x1, // Write to /etc/hostname directly
SystemdHostname = 0x2, // Set via hostnamed(1)
WriteEtcHosts = 0x4 // Write /etc/hosts (127.0.1.1 is this host)
};
Q_DECLARE_FLAGS( Actions, Action )
SetHostNameJob( const QString& hostname, Actions a );
SetHostNameJob( const QString& hostname, HostNameActions a );
QString prettyName() const override;
QString prettyDescription() const override;
QString prettyStatusMessage() const override;
@ -45,9 +37,7 @@ public:
private:
const QString m_hostname;
const Actions m_actions;
const HostNameActions m_actions;
};
Q_DECLARE_OPERATORS_FOR_FLAGS( SetHostNameJob::Actions )
#endif // SETHOSTNAMEJOB_CPP_H

@ -25,6 +25,8 @@
// Implementation details
extern void setConfigurationDefaultGroups( const QVariantMap& map, QStringList& defaultGroups );
extern HostNameActions getHostNameActions( const QVariantMap& configurationMap );
extern bool addPasswordCheck( const QString& key, const QVariant& value, PasswordCheckList& passwordChecks );
/** @brief Test Config object methods and internals
*
@ -40,6 +42,9 @@ private Q_SLOTS:
void initTestCase();
void testDefaultGroups();
void testHostActions_data();
void testHostActions();
void testPasswordChecks();
};
UserTests::UserTests() {}
@ -105,6 +110,52 @@ UserTests::testDefaultGroups()
}
}
void
UserTests::testHostActions_data()
{
QTest::addColumn< bool >( "set" );
QTest::addColumn< QString >( "string" );
QTest::addColumn< int >( "result" );
QTest::newRow( "unset " ) << false << QString() << int( HostNameAction::EtcHostname );
QTest::newRow( "empty " ) << true << QString() << int( HostNameAction::EtcHostname );
QTest::newRow( "bad " ) << true << QString( "derp" ) << int( HostNameAction::EtcHostname );
QTest::newRow( "none " ) << true << QString( "none" ) << int( HostNameAction::None );
QTest::newRow( "systemd" ) << true << QString( "Hostnamed" ) << int( HostNameAction::SystemdHostname );
}
void
UserTests::testHostActions()
{
QFETCH( bool, set );
QFETCH( QString, string );
QFETCH( int, result );
QVariantMap m;
if ( set )
{
m.insert( "setHostname", string );
}
QCOMPARE( getHostNameActions( m ), HostNameActions( result ) | HostNameAction::WriteEtcHosts ); // write bits default to true
m.insert( "writeHostsFile", false );
QCOMPARE( getHostNameActions( m ), HostNameActions( result ) );
m.insert( "writeHostsFile", true );
QCOMPARE( getHostNameActions( m ), HostNameActions( result ) | HostNameAction::WriteEtcHosts );
}
void
UserTests::testPasswordChecks()
{
{
PasswordCheckList l;
QCOMPARE( l.length(), 0 );
QVERIFY( !addPasswordCheck( "nonempty", QVariant(false), l ) ); // a silly setting
QCOMPARE( l.length(), 0 );
QVERIFY( addPasswordCheck( "nonempty", QVariant(true), l ) );
QCOMPARE( l.length(), 1 );
}
}
QTEST_GUILESS_MAIN( UserTests )

@ -50,7 +50,7 @@ enum class Badness
/** Add an error message and pixmap to a label. */
static inline void
labelError( QLabel* pix, QLabel* label, const QString& message, Badness bad = Badness::Fatal )
labelError( QLabel* pix, QLabel* label, const QString& message, Badness bad )
{
label->setText( message );
pix->setPixmap( CalamaresUtils::defaultPixmap( ( bad == Badness::Fatal ) ? CalamaresUtils::StatusError
@ -88,7 +88,7 @@ labelStatus( QLabel* pix, QLabel* label, const QString& value, const QString& st
}
else
{
labelError( pix, label, status );
labelError( pix, label, status, Badness::Fatal );
ok = false;
}
}
@ -105,6 +105,12 @@ UsersPage::UsersPage( Config* config, QWidget* parent )
{
ui->setupUi( this );
ui->checkBoxReusePassword->setVisible( m_config->writeRootPassword() );
ui->checkBoxReusePassword->setChecked( m_config->reuseUserPasswordForRoot() );
ui->checkBoxValidatePassword->setVisible( m_config->permitWeakPasswords() );
ui->checkBoxValidatePassword->setChecked( m_config->requireStrongPasswords() );
// Connect signals and slots
connect( ui->textBoxUserPassword, &QLineEdit::textChanged, this, &UsersPage::onPasswordTextChanged );
connect( ui->textBoxUserVerifiedPassword, &QLineEdit::textChanged, this, &UsersPage::onPasswordTextChanged );
@ -115,21 +121,7 @@ UsersPage::UsersPage( Config* config, QWidget* parent )
onRootPasswordTextChanged( ui->textBoxRootPassword->text() );
checkReady( isReady() );
} );
connect( ui->checkBoxReusePassword, &QCheckBox::stateChanged, this, [this]( const int checked ) {
/* When "reuse" is checked, hide the fields for explicitly
* entering the root password. However, if we're going to
* disable the root password anyway, hide them all regardless of
* the checkbox -- so when writeRoot is false, checked needs
* to be true, to hide them all.
*/
const bool visible = m_config->writeRootPassword() ? !checked : false;
ui->labelChooseRootPassword->setVisible( visible );
ui->labelRootPassword->setVisible( visible );
ui->labelRootPasswordError->setVisible( visible );
ui->textBoxRootPassword->setVisible( visible );
ui->textBoxVerifiedRootPassword->setVisible( visible );
checkReady( isReady() );
} );
connect( ui->checkBoxReusePassword, &QCheckBox::stateChanged, this, &UsersPage::onReuseUserPasswordChanged );
connect( ui->textBoxFullName, &QLineEdit::textEdited, config, &Config::setFullName );
connect( config, &Config::fullNameChanged, this, &UsersPage::onFullNameTextEdited );
@ -147,13 +139,25 @@ UsersPage::UsersPage( Config* config, QWidget* parent )
} );
connect( config, &Config::autoLoginChanged, ui->checkBoxDoAutoLogin, &QCheckBox::setChecked );
ui->checkBoxReusePassword->setVisible( m_config->writeRootPassword() );
ui->checkBoxReusePassword->setChecked( true );
ui->checkBoxValidatePassword->setChecked( true );
if ( m_config->writeRootPassword() )
{
connect( ui->checkBoxReusePassword, &QCheckBox::stateChanged, this, [this]( int checked ) {
m_config->setReuseUserPasswordForRoot( checked != Qt::Unchecked );
} );
connect( config, &Config::reuseUserPasswordForRootChanged, ui->checkBoxReusePassword, &QCheckBox::setChecked );
}
setPasswordCheckboxVisible( false );
if ( m_config->permitWeakPasswords() )
{
connect( ui->checkBoxValidatePassword, &QCheckBox::stateChanged, this, [this]( int checked ) {
m_config->setRequireStrongPasswords( checked != Qt::Unchecked );
} );
connect( config, &Config::requireStrongPasswordsChanged, ui->checkBoxValidatePassword, &QCheckBox::setChecked );
}
CALAMARES_RETRANSLATE_SLOT( &UsersPage::retranslate );
onReuseUserPasswordChanged( m_config->reuseUserPasswordForRoot() );
}
UsersPage::~UsersPage()
@ -195,32 +199,6 @@ UsersPage::isReady() const
return readyFields;
}
QString
UsersPage::getRootPassword() const
{
if ( m_config->writeRootPassword() )
{
if ( ui->checkBoxReusePassword->isChecked() )
{
return ui->textBoxUserPassword->text();
}
else
{
return ui->textBoxRootPassword->text();
}
}
else
{
return QString();
}
}
QPair< QString, QString >
UsersPage::getUserPassword() const
{
return QPair< QString, QString >( m_config->loginName(), ui->textBoxUserPassword->text() );
}
void
UsersPage::fillGlobalStorage() const
{
@ -274,43 +252,26 @@ UsersPage::checkPasswordAcceptance( const QString& pw1, const QString& pw2, QLab
{
if ( pw1 != pw2 )
{
labelError( badge, message, tr( "Your passwords do not match!" ) );
labelError( badge, message, tr( "Your passwords do not match!" ), Badness::Fatal );
return false;
}
else
{
bool failureIsFatal = ui->checkBoxValidatePassword->isChecked();
bool failureFound = false;
if ( m_passwordChecksChanged )
QString s;
bool ok = m_config->isPasswordAcceptable( pw1, s );
if ( !ok )
{
std::sort( m_passwordChecks.begin(), m_passwordChecks.end() );
m_passwordChecksChanged = false;
labelError( badge, message, s, Badness::Fatal );
}
for ( auto pc : m_passwordChecks )
else if ( !s.isEmpty() )
{
QString s = pc.filter( pw1 );
if ( !s.isEmpty() )
{
labelError( badge, message, s, failureIsFatal ? Badness::Fatal : Badness::Warning );
failureFound = true;
if ( failureIsFatal )
{
return false;
}
}
labelError( badge, message, s, Badness::Warning );
}
if ( !failureFound )
else
{
labelOk( badge, message );
}
// Here, if failureFound is true then we've found **warnings**,
// which is ok to continue but the user should know.
return true;
return ok;
}
}
@ -335,58 +296,24 @@ UsersPage::onRootPasswordTextChanged( const QString& )
emit checkReady( isReady() );
}
void
UsersPage::setPasswordCheckboxVisible( bool visible )
{
ui->checkBoxValidatePassword->setVisible( visible );
}
void
UsersPage::setValidatePasswordDefault( bool checked )
{
ui->checkBoxValidatePassword->setChecked( checked );
emit checkReady( isReady() );
}
void
UsersPage::setReusePasswordDefault( bool checked )
{
ui->checkBoxReusePassword->setChecked( checked );
emit checkReady( isReady() );
}
void
UsersPage::addPasswordCheck( const QString& key, const QVariant& value )
UsersPage::onReuseUserPasswordChanged( const int checked )
{
m_passwordChecksChanged = true;
if ( key == "minLength" )
{
add_check_minLength( m_passwordChecks, value );
}
else if ( key == "maxLength" )
{
add_check_maxLength( m_passwordChecks, value );
}
else if ( key == "nonempty" )
{
if ( value.toBool() )
{
m_passwordChecks.push_back(
PasswordCheck( []() { return QCoreApplication::translate( "PWQ", "Password is empty" ); },
[]( const QString& s ) { return !s.isEmpty(); },
PasswordCheck::Weight( 1 ) ) );
}
}
#ifdef CHECK_PWQUALITY
else if ( key == "libpwquality" )
{
add_check_libpwquality( m_passwordChecks, value );
}
#endif // CHECK_PWQUALITY
else
{
cWarning() << "Unknown password-check key" << key;
}
/* When "reuse" is checked, hide the fields for explicitly
* entering the root password. However, if we're going to
* disable the root password anyway, hide them all regardless of
* the checkbox -- so when writeRoot is false, visible needs
* to be false, to hide them all.
*
* In principle this is only connected when writeRootPassword is @c true,
* but it is **always** called at least once in the constructor
* to set up initial visibility.
*/
const bool visible = m_config->writeRootPassword() ? !checked : false;
ui->labelChooseRootPassword->setVisible( visible );
ui->labelRootPassword->setVisible( visible );
ui->labelRootPasswordError->setVisible( visible );
ui->textBoxRootPassword->setVisible( visible );
ui->textBoxVerifiedRootPassword->setVisible( visible );
checkReady( isReady() );
}

@ -24,8 +24,6 @@
#ifndef USERSPAGE_H
#define USERSPAGE_H
#include "CheckPWQuality.h"
#include <QWidget>
class Config;
@ -50,29 +48,13 @@ public:
void onActivate();
void setPasswordCheckboxVisible( bool visible );
void setValidatePasswordDefault( bool checked );
void setReusePasswordDefault( bool checked );
/** @brief Process entries in the passwordRequirements config entry
*
* Called once for each item in the config entry, which should
* be a key-value pair. What makes sense as a value depends on
* the key. Supported keys are documented in users.conf.
*/
void addPasswordCheck( const QString& key, const QVariant& value );
///@brief Root password, depends on settings, may be empty
QString getRootPassword() const;
///@brief User name and password
QPair< QString, QString > getUserPassword() const;
protected slots:
void onFullNameTextEdited( const QString& );
void reportLoginNameStatus( const QString& );
void reportHostNameStatus( const QString& );
void onPasswordTextChanged( const QString& );
void onRootPasswordTextChanged( const QString& );
void onReuseUserPasswordChanged( const int );
signals:
void checkReady( bool );
@ -91,9 +73,6 @@ private:
Ui::Page_UserSetup* ui;
Config* m_config;
PasswordCheckList m_passwordChecks;
bool m_passwordChecksChanged = false;
bool m_readyFullName;
bool m_readyUsername;
bool m_readyHostname;

@ -34,28 +34,9 @@
CALAMARES_PLUGIN_FACTORY_DEFINITION( UsersViewStepFactory, registerPlugin< UsersViewStep >(); )
static const NamedEnumTable< SetHostNameJob::Action >&
hostnameActions()
{
using Action = SetHostNameJob::Action;
// *INDENT-OFF*
// clang-format off
static const NamedEnumTable< Action > names {
{ QStringLiteral( "none" ), Action::None },
{ QStringLiteral( "etcfile" ), Action::EtcHostname },
{ QStringLiteral( "hostnamed" ), Action::SystemdHostname }
};
// clang-format on
// *INDENT-ON*
return names;
}
UsersViewStep::UsersViewStep( QObject* parent )
: Calamares::ViewStep( parent )
, m_widget( nullptr )
, m_actions( SetHostNameJob::Action::None )
, m_config( new Config( this ) )
{
emit nextStatusChanged( true );
@ -151,14 +132,14 @@ UsersViewStep::onLeave()
m_config->doAutoLogin(),
m_config->defaultGroups() );
auto userPW = m_widget->getUserPassword();
j = new SetPasswordJob( userPW.first, userPW.second );
j = new SetPasswordJob( m_config->loginName(), m_config->userPassword() );
m_jobs.append( Calamares::job_ptr( j ) );
j = new SetPasswordJob( "root", m_widget->getRootPassword() );
j = new SetPasswordJob( "root", m_config->rootPassword() );
m_jobs.append( Calamares::job_ptr( j ) );
j = new SetHostNameJob( m_config->hostName(), m_actions );
// TODO: Config object should create jobs
j = new SetHostNameJob( m_config->hostName(), m_config->hostNameActions() );
m_jobs.append( Calamares::job_ptr( j ) );
m_widget->fillGlobalStorage();
@ -168,42 +149,5 @@ UsersViewStep::onLeave()
void
UsersViewStep::setConfigurationMap( const QVariantMap& configurationMap )
{
// Create the widget, after all .. as long as writing configuration to the UI is needed
(void)this->widget();
using CalamaresUtils::getBool;
m_widget->setReusePasswordDefault( getBool( configurationMap, "doReusePassword", false ) );
if ( configurationMap.contains( "passwordRequirements" )
&& configurationMap.value( "passwordRequirements" ).type() == QVariant::Map )
{
auto pr_checks( configurationMap.value( "passwordRequirements" ).toMap() );
for ( decltype( pr_checks )::const_iterator i = pr_checks.constBegin(); i != pr_checks.constEnd(); ++i )
{
m_widget->addPasswordCheck( i.key(), i.value() );
}
}
m_widget->setPasswordCheckboxVisible( getBool( configurationMap, "allowWeakPasswords", false ) );
m_widget->setValidatePasswordDefault( !getBool( configurationMap, "allowWeakPasswordsDefault", false ) );
using Action = SetHostNameJob::Action;
QString hostnameActionString = CalamaresUtils::getString( configurationMap, "setHostname" );
if ( hostnameActionString.isEmpty() )
{
hostnameActionString = QStringLiteral( "EtcFile" );
}
bool ok = false;
auto hostnameAction = hostnameActions().find( hostnameActionString, ok );
if ( !ok )
{
hostnameAction = Action::EtcHostname;
}
Action hostsfileAction = getBool( configurationMap, "writeHostsFile", true ) ? Action::WriteEtcHosts : Action::None;
m_actions = hostsfileAction | hostnameAction;
m_config->setConfigurationMap( configurationMap );
}

@ -20,8 +20,6 @@
#ifndef USERSPAGEPLUGIN_H
#define USERSPAGEPLUGIN_H
#include "SetHostNameJob.h"
#include "DllMacro.h"
#include "utils/PluginFactory.h"
#include "viewpages/ViewStep.h"
@ -61,8 +59,6 @@ private:
UsersPage* m_widget;
QList< Calamares::job_ptr > m_jobs;
SetHostNameJob::Actions m_actions;
Config* m_config;
};

@ -138,4 +138,5 @@ setHostname: EtcFile
# Should /etc/hosts be written with a hostname for this machine
# (also adds localhost and some ipv6 standard entries).
# Defaults to *true*.
writeHostsFile: true

Loading…
Cancel
Save