on xenial help sign in
Merge
2288f24Albert Astals
debian/changelog+9
@@ -1,3 +1,12 @@
1+unity8 (8.00+14.10.20140729.1-0ubuntu1) utopic; urgency=low
2+
3+ [ Michael Terry ]
4+ * Check user's pin/password using PAM, instead of a plaintext keyfile.
5+ New build dependency: libpam0g-dev for phone unlock with PAM (LP:
6+ #1234983)
7+
8+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 29 Jul 2014 23:36:30 +0000
9+
1unity8 (8.00+14.10.20140729-0ubuntu1) utopic; urgency=medium
10unity8 (8.00+14.10.20140729-0ubuntu1) utopic; urgency=medium
2
11
3 [ Gerry Boland ]
12 [ Gerry Boland ]
debian/control+1
@@ -19,6 +19,7 @@ Build-Depends: cmake,
19 libgsettings-qt-dev,
19 libgsettings-qt-dev,
20 libhardware-dev,
20 libhardware-dev,
21 libhud-client2-dev,
21 libhud-client2-dev,
22+ libpam0g-dev,
22 libpay2-dev,
23 libpay2-dev,
23 libpulse-dev,
24 libpulse-dev,
24 libqmenumodel-dev (>= 0.2.8),
25 libqmenumodel-dev (>= 0.2.8),
plugins/AccountsService/AccountsService.cpp+21−1
@@ -26,7 +26,8 @@ AccountsService::AccountsService(QObject* parent)
26 m_service(new AccountsServiceDBusAdaptor(this)),
26 m_service(new AccountsServiceDBusAdaptor(this)),
27 m_user(qgetenv("USER")),
27 m_user(qgetenv("USER")),
28 m_demoEdges(false),
28 m_demoEdges(false),
29− m_statsWelcomeScreen(false)
29+ m_statsWelcomeScreen(false),
30+ m_passwordDisplayHint(Keyboard)
30{
31{
31 connect(m_service, SIGNAL(propertiesChanged(const QString &, const QString &, const QStringList &)),
32 connect(m_service, SIGNAL(propertiesChanged(const QString &, const QString &, const QStringList &)),
32 this, SLOT(propertiesChanged(const QString &, const QString &, const QStringList &)));
33 this, SLOT(propertiesChanged(const QString &, const QString &, const QStringList &)));
@@ -47,6 +48,7 @@ void AccountsService::setUser(const QString &user)
47 updateDemoEdges();
48 updateDemoEdges();
48 updateBackgroundFile();
49 updateBackgroundFile();
49 updateStatsWelcomeScreen();
50 updateStatsWelcomeScreen();
51+ updatePasswordDisplayHint();
50}
52}
51
53
52bool AccountsService::demoEdges() const
54bool AccountsService::demoEdges() const
@@ -70,6 +72,11 @@ bool AccountsService::statsWelcomeScreen() const
70 return m_statsWelcomeScreen;
72 return m_statsWelcomeScreen;
71}
73}
72
74
75+AccountsService::PasswordDisplayHint AccountsService::passwordDisplayHint() const
76+{
77+ return m_passwordDisplayHint;
78+}
79+
73void AccountsService::updateDemoEdges()
80void AccountsService::updateDemoEdges()
74{
81{
75 auto demoEdges = m_service->getUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges").toBool();
82 auto demoEdges = m_service->getUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges").toBool();
@@ -97,6 +104,15 @@ void AccountsService::updateStatsWelcomeScreen()
97 }
104 }
98}
105}
99
106
107+void AccountsService::updatePasswordDisplayHint()
108+{
109+ PasswordDisplayHint passwordDisplayHint = (PasswordDisplayHint)m_service->getUserProperty(m_user, "com.ubuntu.AccountsService.SecurityPrivacy", "PasswordDisplayHint").toInt();
110+ if (m_passwordDisplayHint != passwordDisplayHint) {
111+ m_passwordDisplayHint = passwordDisplayHint;
112+ Q_EMIT passwordDisplayHintChanged();
113+ }
114+}
115+
100void AccountsService::propertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
116void AccountsService::propertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
101{
117{
102 if (m_user != user) {
118 if (m_user != user) {
@@ -111,6 +127,10 @@ void AccountsService::propertiesChanged(const QString &user, const QString &inte
111 if (changed.contains("StatsWelcomeScreen")) {
127 if (changed.contains("StatsWelcomeScreen")) {
112 updateStatsWelcomeScreen();
128 updateStatsWelcomeScreen();
113 }
129 }
130+ } else if (interface == "com.ubuntu.AccountsService.SecurityPrivacy") {
131+ if (changed.contains("PasswordDisplayHint")) {
132+ updatePasswordDisplayHint();
133+ }
114 }
134 }
115}
135}
116
136
plugins/AccountsService/AccountsService.h+13
@@ -27,6 +27,7 @@ class AccountsServiceDBusAdaptor;
27class AccountsService: public QObject
27class AccountsService: public QObject
28{
28{
29 Q_OBJECT
29 Q_OBJECT
30+ Q_ENUMS(PasswordDisplayHint)
30 Q_PROPERTY (QString user
31 Q_PROPERTY (QString user
31 READ user
32 READ user
32 WRITE setUser
33 WRITE setUser
@@ -41,8 +42,16 @@ class AccountsService: public QObject
41 Q_PROPERTY (bool statsWelcomeScreen
42 Q_PROPERTY (bool statsWelcomeScreen
42 READ statsWelcomeScreen
43 READ statsWelcomeScreen
43 NOTIFY statsWelcomeScreenChanged)
44 NOTIFY statsWelcomeScreenChanged)
45+ Q_PROPERTY (PasswordDisplayHint passwordDisplayHint
46+ READ passwordDisplayHint
47+ NOTIFY passwordDisplayHintChanged)
44
48
45public:
49public:
50+ enum PasswordDisplayHint {
51+ Keyboard,
52+ Numeric,
53+ };
54+
46 explicit AccountsService(QObject *parent = 0);
55 explicit AccountsService(QObject *parent = 0);
47
56
48 QString user() const;
57 QString user() const;
@@ -51,12 +60,14 @@ public:
51 void setDemoEdges(bool demoEdges);
60 void setDemoEdges(bool demoEdges);
52 QString backgroundFile() const;
61 QString backgroundFile() const;
53 bool statsWelcomeScreen() const;
62 bool statsWelcomeScreen() const;
63+ PasswordDisplayHint passwordDisplayHint() const;
54
64
55Q_SIGNALS:
65Q_SIGNALS:
56 void userChanged();
66 void userChanged();
57 void demoEdgesChanged();
67 void demoEdgesChanged();
58 void backgroundFileChanged();
68 void backgroundFileChanged();
59 void statsWelcomeScreenChanged();
69 void statsWelcomeScreenChanged();
70+ void passwordDisplayHintChanged();
60
71
61private Q_SLOTS:
72private Q_SLOTS:
62 void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
73 void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
@@ -66,12 +77,14 @@ private:
66 void updateDemoEdges();
77 void updateDemoEdges();
67 void updateBackgroundFile();
78 void updateBackgroundFile();
68 void updateStatsWelcomeScreen();
79 void updateStatsWelcomeScreen();
80+ void updatePasswordDisplayHint();
69
81
70 AccountsServiceDBusAdaptor *m_service;
82 AccountsServiceDBusAdaptor *m_service;
71 QString m_user;
83 QString m_user;
72 bool m_demoEdges;
84 bool m_demoEdges;
73 QString m_backgroundFile;
85 QString m_backgroundFile;
74 bool m_statsWelcomeScreen;
86 bool m_statsWelcomeScreen;
87+ PasswordDisplayHint m_passwordDisplayHint;
75};
88};
76
89
77#endif
90#endif
plugins/AccountsService/plugin.cpp+1
@@ -33,5 +33,6 @@ void AccountsServicePlugin::registerTypes(const char *uri)
33{
33{
34 Q_ASSERT(uri == QLatin1String("AccountsService"));
34 Q_ASSERT(uri == QLatin1String("AccountsService"));
35 qDBusRegisterMetaType<QList<QVariantMap>>();
35 qDBusRegisterMetaType<QList<QVariantMap>>();
36+ qRegisterMetaType<AccountsService::PasswordDisplayHint>("AccountsService::PasswordDisplayHint");
36 qmlRegisterSingletonType<AccountsService>(uri, 0, 1, "AccountsService", service_provider);
37 qmlRegisterSingletonType<AccountsService>(uri, 0, 1, "AccountsService", service_provider);
37}
38}
plugins/Dash/ScopeStyle.qml+2−1
@@ -45,7 +45,8 @@ QtObject {
45
45
46 \note If background colour is not fully opaque, the defaultLightLuminance it's taken into account instead of it.
46 \note If background colour is not fully opaque, the defaultLightLuminance it's taken into account instead of it.
47 */
47 */
48− readonly property real threshold: background.a !== 1.0 ? (d.foregroundLuminance + d.defaultLightLuminance) / 2: (d.foregroundLuminance + d.backgroundLuminance) / 2
48+ readonly property real threshold: background.a !== 1.0 ? (d.foregroundLuminance + d.defaultLightLuminance) / 2
49+ : (d.foregroundLuminance + d.backgroundLuminance) / 2
49
50
50 /*! \brief The lighter of foreground and background colors
51 /*! \brief The lighter of foreground and background colors
51
52
plugins/LightDM/plugin.cpp+2
@@ -69,6 +69,8 @@ void LightDMPlugin::registerTypes(const char *uri)
69 qmlRegisterType<UserMetricsOutput::ColorTheme>();
69 qmlRegisterType<UserMetricsOutput::ColorTheme>();
70
70
71 Q_ASSERT(uri == QLatin1String("LightDM"));
71 Q_ASSERT(uri == QLatin1String("LightDM"));
72+ qRegisterMetaType<QLightDM::Greeter::MessageType>("QLightDM::Greeter::MessageType");
73+ qRegisterMetaType<QLightDM::Greeter::PromptType>("QLightDM::Greeter::PromptType");
72 qmlRegisterSingletonType<Greeter>(uri, 0, 1, "Greeter", greeter_provider);
74 qmlRegisterSingletonType<Greeter>(uri, 0, 1, "Greeter", greeter_provider);
73 qmlRegisterSingletonType<UsersModel>(uri, 0, 1, "Users", users_provider);
75 qmlRegisterSingletonType<UsersModel>(uri, 0, 1, "Users", users_provider);
74 qmlRegisterUncreatableType<QLightDM::UsersModel>(uri, 0, 1, "UserRoles", "Type is not instantiable");
76 qmlRegisterUncreatableType<QLightDM::UsersModel>(uri, 0, 1, "UserRoles", "Type is not instantiable");
po/da.po+4−4
@@ -9,13 +9,13 @@ msgstr ""
9"Project-Id-Version: unity8\n"
9"Project-Id-Version: unity8\n"
10"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
11"POT-Creation-Date: 2014-07-11 14:59+0200\n"
11"POT-Creation-Date: 2014-07-11 14:59+0200\n"
12−"PO-Revision-Date: 2014-07-29 23:18+0000\n"
12+"PO-Revision-Date: 2014-07-30 12:37+0000\n"
13"Last-Translator: Ask Hjorth Larsen <asklarsen@gmail.com>\n"
13"Last-Translator: Ask Hjorth Larsen <asklarsen@gmail.com>\n"
14"Language-Team: Danish <dansk@dansk-gruppen.dk>\n"
14"Language-Team: Danish <dansk@dansk-gruppen.dk>\n"
15"MIME-Version: 1.0\n"
15"MIME-Version: 1.0\n"
16"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Type: text/plain; charset=UTF-8\n"
17"Content-Transfer-Encoding: 8bit\n"
17"Content-Transfer-Encoding: 8bit\n"
18−"X-Launchpad-Export-Date: 2014-07-30 07:08+0000\n"
18+"X-Launchpad-Export-Date: 2014-07-31 07:15+0000\n"
19"X-Generator: Launchpad (build 17131)\n"
19"X-Generator: Launchpad (build 17131)\n"
20
20
21#: plugins/Unity/Launcher/launcheritem.cpp:43
21#: plugins/Unity/Launcher/launcheritem.cpp:43
@@ -114,7 +114,7 @@ msgstr "Seneste"
114
114
115#: qml/Dash/GenericScopeView.qml:330
115#: qml/Dash/GenericScopeView.qml:330
116msgid "See all"
116msgid "See all"
117−msgstr ""
117+msgstr "Se alle"
118
118
119#: qml/Dash/Previews/PreviewActionCombo.qml:34
119#: qml/Dash/Previews/PreviewActionCombo.qml:34
120msgid "More..."
120msgid "More..."
@@ -170,7 +170,7 @@ msgstr "Indtast venligst PIN for SIM"
170
170
171#: qml/Panel/ActiveCallHint.qml:77
171#: qml/Panel/ActiveCallHint.qml:77
172msgid "Tap to return to call..."
172msgid "Tap to return to call..."
173−msgstr ""
173+msgstr "Tryk for at besvare opkaldet..."
174
174
175#: qml/Panel/ActiveCallHint.qml:90
175#: qml/Panel/ActiveCallHint.qml:90
176msgid "Conference"
176msgid "Conference"
po/hu.po+4−4
@@ -8,13 +8,13 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-07-11 14:59+0200\n"
10"POT-Creation-Date: 2014-07-11 14:59+0200\n"
11−"PO-Revision-Date: 2014-07-27 15:04+0000\n"
11+"PO-Revision-Date: 2014-07-30 18:42+0000\n"
12"Last-Translator: Richard Somlói <ricsipontaz@gmail.com>\n"
12"Last-Translator: Richard Somlói <ricsipontaz@gmail.com>\n"
13"Language-Team: Hungarian <hu@li.org>\n"
13"Language-Team: Hungarian <hu@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-07-28 06:44+0000\n"
17+"X-Launchpad-Export-Date: 2014-07-31 07:15+0000\n"
18"X-Generator: Launchpad (build 17131)\n"
18"X-Generator: Launchpad (build 17131)\n"
19
19
20#: plugins/Unity/Launcher/launcheritem.cpp:43
20#: plugins/Unity/Launcher/launcheritem.cpp:43
@@ -82,7 +82,7 @@ msgstr "Vészhívás"
82
82
83#: qml/Components/Lockscreen.qml:231
83#: qml/Components/Lockscreen.qml:231
84msgid "OK"
84msgid "OK"
85−msgstr "OK"
85+msgstr "Oké"
86
86
87#: qml/Components/PassphraseLockscreen.qml:60
87#: qml/Components/PassphraseLockscreen.qml:60
88#, qt-format
88#, qt-format
@@ -127,7 +127,7 @@ msgstr "Kevesebb…"
127
127
128#: qml/Dash/Previews/PreviewRatingInput.qml:81
128#: qml/Dash/Previews/PreviewRatingInput.qml:81
129msgid "Rate this"
129msgid "Rate this"
130−msgstr "Osztályzás"
130+msgstr "Értékelje"
131
131
132#: qml/Dash/Previews/PreviewRatingInput.qml:126
132#: qml/Dash/Previews/PreviewRatingInput.qml:126
133msgid "Add a review"
133msgid "Add a review"
po/ru.po+12−12
@@ -8,13 +8,13 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-07-11 14:59+0200\n"
10"POT-Creation-Date: 2014-07-11 14:59+0200\n"
11−"PO-Revision-Date: 2014-05-15 12:57+0000\n"
11+"PO-Revision-Date: 2014-07-30 12:49+0000\n"
12−"Last-Translator: Zonov Roman <Unknown>\n"
12+"Last-Translator: Jay ZDLin <Unknown>\n"
13"Language-Team: Russian <ru@li.org>\n"
13"Language-Team: Russian <ru@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-07-26 07:17+0000\n"
17+"X-Launchpad-Export-Date: 2014-07-31 07:15+0000\n"
18"X-Generator: Launchpad (build 17131)\n"
18"X-Generator: Launchpad (build 17131)\n"
19
19
20#: plugins/Unity/Launcher/launcheritem.cpp:43
20#: plugins/Unity/Launcher/launcheritem.cpp:43
@@ -85,7 +85,7 @@ msgstr "Экстренный вызов"
85
85
86#: qml/Components/Lockscreen.qml:231
86#: qml/Components/Lockscreen.qml:231
87msgid "OK"
87msgid "OK"
88−msgstr ""
88+msgstr "ОК"
89
89
90#: qml/Components/PassphraseLockscreen.qml:60
90#: qml/Components/PassphraseLockscreen.qml:60
91#, qt-format
91#, qt-format
@@ -98,11 +98,11 @@ msgstr "Привет"
98
98
99#: qml/Components/PinLockscreen.qml:198
99#: qml/Components/PinLockscreen.qml:198
100msgid "CANCEL"
100msgid "CANCEL"
101−msgstr ""
101+msgstr "ОТМЕНИТЬ"
102
102
103#: qml/Components/PinLockscreen.qml:216
103#: qml/Components/PinLockscreen.qml:216
104msgid "DONE"
104msgid "DONE"
105−msgstr ""
105+msgstr "ГОТОВО"
106
106
107#: qml/Components/SeeMore.qml:35
107#: qml/Components/SeeMore.qml:35
108msgid "See more"
108msgid "See more"
@@ -118,7 +118,7 @@ msgstr "Недавние"
118
118
119#: qml/Dash/GenericScopeView.qml:330
119#: qml/Dash/GenericScopeView.qml:330
120msgid "See all"
120msgid "See all"
121−msgstr ""
121+msgstr "Показать всё"
122
122
123#: qml/Dash/Previews/PreviewActionCombo.qml:34
123#: qml/Dash/Previews/PreviewActionCombo.qml:34
124msgid "More..."
124msgid "More..."
@@ -178,15 +178,15 @@ msgstr ""
178
178
179#: qml/Panel/ActiveCallHint.qml:90
179#: qml/Panel/ActiveCallHint.qml:90
180msgid "Conference"
180msgid "Conference"
181−msgstr ""
181+msgstr "Конференция"
182
182
183#: qml/Panel/Indicators/MenuItemFactory.qml:583
183#: qml/Panel/Indicators/MenuItemFactory.qml:583
184msgid "In queue…"
184msgid "In queue…"
185−msgstr ""
185+msgstr "В очереди..."
186
186
187#: qml/Panel/Indicators/MenuItemFactory.qml:587
187#: qml/Panel/Indicators/MenuItemFactory.qml:587
188msgid "Downloading"
188msgid "Downloading"
189−msgstr ""
189+msgstr "Загрузка"
190
190
191#: qml/Panel/Indicators/MenuItemFactory.qml:589
191#: qml/Panel/Indicators/MenuItemFactory.qml:589
192msgid "Paused, tap to resume"
192msgid "Paused, tap to resume"
@@ -194,11 +194,11 @@ msgstr ""
194
194
195#: qml/Panel/Indicators/MenuItemFactory.qml:591
195#: qml/Panel/Indicators/MenuItemFactory.qml:591
196msgid "Canceled"
196msgid "Canceled"
197−msgstr ""
197+msgstr "Отменено"
198
198
199#: qml/Panel/Indicators/MenuItemFactory.qml:593
199#: qml/Panel/Indicators/MenuItemFactory.qml:593
200msgid "Finished"
200msgid "Finished"
201−msgstr ""
201+msgstr "Завершено"
202
202
203#: qml/Panel/Indicators/MenuItemFactory.qml:595
203#: qml/Panel/Indicators/MenuItemFactory.qml:595
204msgid "Failed, tap to retry"
204msgid "Failed, tap to retry"
po/ug.po+1−1
@@ -14,7 +14,7 @@ msgstr ""
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-07-30 07:08+0000\n"
17+"X-Launchpad-Export-Date: 2014-07-31 07:15+0000\n"
18"X-Generator: Launchpad (build 17131)\n"
18"X-Generator: Launchpad (build 17131)\n"
19
19
20#: plugins/Unity/Launcher/launcheritem.cpp:43
20#: plugins/Unity/Launcher/launcheritem.cpp:43
po/uk.po+1−1
@@ -14,7 +14,7 @@ msgstr ""
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-07-30 07:08+0000\n"
17+"X-Launchpad-Export-Date: 2014-07-31 07:15+0000\n"
18"X-Generator: Launchpad (build 17131)\n"
18"X-Generator: Launchpad (build 17131)\n"
19
19
20#: plugins/Unity/Launcher/launcheritem.cpp:43
20#: plugins/Unity/Launcher/launcheritem.cpp:43
po/zh_CN.po+1−1
@@ -14,7 +14,7 @@ msgstr ""
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-07-30 07:08+0000\n"
17+"X-Launchpad-Export-Date: 2014-07-31 07:15+0000\n"
18"X-Generator: Launchpad (build 17131)\n"
18"X-Generator: Launchpad (build 17131)\n"
19
19
20#: plugins/Unity/Launcher/launcheritem.cpp:43
20#: plugins/Unity/Launcher/launcheritem.cpp:43
qml/Components/PassphraseLockscreen.qml+3
@@ -31,8 +31,10 @@ Item {
31
31
32 function clear(playAnimation) {
32 function clear(playAnimation) {
33 pinentryField.text = "";
33 pinentryField.text = "";
34+ pinentryField.enabled = true
34 if (playAnimation) {
35 if (playAnimation) {
35 wrongPasswordAnimation.start();
36 wrongPasswordAnimation.start();
37+ pinentryField.forceActiveFocus();
36 } else {
38 } else {
37 pinentryField.focus = false
39 pinentryField.focus = false
38 }
40 }
@@ -78,6 +80,7 @@ Item {
78
80
79 onAccepted: {
81 onAccepted: {
80 if (pinentryField.text) {
82 if (pinentryField.text) {
83+ pinentryField.enabled = false;
81 root.entered(pinentryField.text);
84 root.entered(pinentryField.text);
82 }
85 }
83 }
86 }
qml/Dash/Dash.qml+24−4
@@ -98,10 +98,12 @@ Showable {
98 }
98 }
99 onFavoriteSelected: {
99 onFavoriteSelected: {
100 setCurrentScope(scopeId, false, false);
100 setCurrentScope(scopeId, false, false);
101+ dashContentCache.scheduleUpdate();
101 hide();
102 hide();
102 }
103 }
103 onAllFavoriteSelected: {
104 onAllFavoriteSelected: {
104 setCurrentScope(scopeId, false, false);
105 setCurrentScope(scopeId, false, false);
106+ dashContentCache.scheduleUpdate();
105 animateDashFromAll(dashContent.currentScopeId);
107 animateDashFromAll(dashContent.currentScopeId);
106 hide();
108 hide();
107 }
109 }
@@ -110,6 +112,7 @@ Showable {
110 if (scopeIndex >= 0) {
112 if (scopeIndex >= 0) {
111 // Is a favorite one
113 // Is a favorite one
112 setCurrentScope(scopeId, false, false);
114 setCurrentScope(scopeId, false, false);
115+ dashContentCache.scheduleUpdate();
113 showDashFromPos(pos, size);
116 showDashFromPos(pos, size);
114 hide();
117 hide();
115 } else {
118 } else {
@@ -128,12 +131,23 @@ Showable {
128 }
131 }
129 }
132 }
130
133
134+ ShaderEffectSource {
135+ id: dashContentCache
136+ parent: scopesOverview.dashItemEater
137+ z: 1
138+ sourceItem: dashContent
139+ height: sourceItem.height
140+ width: sourceItem.width
141+ opacity: 1 - overviewController.progress
142+ visible: overviewController.progress != 0
143+ live: false
144+ }
145+
131 DashContent {
146 DashContent {
132 id: dashContent
147 id: dashContent
133
148
134 property var scopeThatOpenedScope: null
149 property var scopeThatOpenedScope: null
135
150
136− parent: overviewController.progress == 0 ? dash : scopesOverview.dashItemEater
137 objectName: "dashContent"
151 objectName: "dashContent"
138 width: dash.width
152 width: dash.width
139 height: dash.height
153 height: dash.height
@@ -174,8 +188,8 @@ Showable {
174 }
188 }
175 }
189 }
176
190
177− enabled: opacity == 1
191+ enabled: overviewController.progress == 0
178− opacity: scopesOverview.growingDashFromPos ? 1 : 1 - overviewController.progress
192+ opacity: enabled ? 1 : 0
179 }
193 }
180
194
181 DashBackground
195 DashBackground
@@ -239,7 +253,10 @@ Showable {
239 objectName: "overviewDragHandle"
253 objectName: "overviewDragHandle"
240 z: 1
254 z: 1
241 direction: Direction.Upwards
255 direction: Direction.Upwards
256+ enabled: !dashContent.previewShown &&
257+ dashContent.currentScope &&
258+ dashContent.currentScope.searchQuery == "" &&
242− enabled: !dashContent.previewShown && dashContent.currentScope && dashContent.currentScope.searchQuery == "" && (overviewController.progress == 0 || dragging)
259+ (overviewController.progress == 0 || dragging)
243
260
244 readonly property real fullMovement: units.gu(20)
261 readonly property real fullMovement: units.gu(20)
245
262
@@ -247,6 +264,9 @@ Showable {
247 height: units.gu(2)
264 height: units.gu(2)
248
265
249 onSceneDistanceChanged: {
266 onSceneDistanceChanged: {
267+ if (overviewController.enableAnimation) {
268+ dashContentCache.scheduleUpdate();
269+ }
250 overviewController.enableAnimation = false;
270 overviewController.enableAnimation = false;
251 overviewController.progress = Math.max(0, Math.min(1, sceneDistance / fullMovement));
271 overviewController.progress = Math.max(0, Math.min(1, sceneDistance / fullMovement));
252 }
272 }
qml/Dash/DashContent.qml+2−1
@@ -28,7 +28,8 @@ Item {
28 readonly property alias currentIndex: dashContentList.currentIndex
28 readonly property alias currentIndex: dashContentList.currentIndex
29 readonly property string currentScopeId: dashContentList.currentItem ? dashContentList.currentItem.scopeId : ""
29 readonly property string currentScopeId: dashContentList.currentItem ? dashContentList.currentItem.scopeId : ""
30 readonly property var currentScope: dashContentList.currentItem ? dashContentList.currentItem.theScope : null
30 readonly property var currentScope: dashContentList.currentItem ? dashContentList.currentItem.theScope : null
31− readonly property bool previewShown: dashContentList.currentItem && dashContentList.currentItem.item ? dashContentList.currentItem.item.previewShown : false
31+ readonly property bool previewShown: dashContentList.currentItem && dashContentList.currentItem.item ?
32+ dashContentList.currentItem.item.previewShown : false
32
33
33 signal scopeLoaded(string scopeId)
34 signal scopeLoaded(string scopeId)
34 signal gotoScope(string scopeId)
35 signal gotoScope(string scopeId)
qml/Dash/GenericScopeView.qml+1−1
@@ -258,7 +258,7 @@ FocusScope {
258 scopeView.pressAndHoldOverride(index);
258 scopeView.pressAndHoldOverride(index);
259 } else {
259 } else {
260 if (itemModel.uri.indexOf("scope://") !== 0) {
260 if (itemModel.uri.indexOf("scope://") !== 0) {
261− openPreview(index)
261+ openPreview(index);
262 }
262 }
263 }
263 }
264 }
264 }
qml/Dash/ScopesOverviewFavorites.qml+1−1
@@ -27,7 +27,7 @@ Flickable {
27 property real scopeWidth: 0
27 property real scopeWidth: 0
28 property real appliedScale: 1
28 property real appliedScale: 1
29 property int currentIndex: -1
29 property int currentIndex: -1
30− property var currentItem: repeater.itemAt(currentIndex);
30+ property var currentItem: currentIndex < repeater.count ? repeater.itemAt(currentIndex) : null
31
31
32 property alias model: repeater.model
32 property alias model: repeater.model
33
33
qml/Shell.qml+27−21
@@ -342,6 +342,7 @@ Item {
342 width: parent.width
342 width: parent.width
343 height: parent.height - panel.panelHeight
343 height: parent.height - panel.panelHeight
344 background: shell.background
344 background: shell.background
345+ alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
345 minPinLength: 4
346 minPinLength: 4
346 maxPinLength: 4
347 maxPinLength: 4
347
348
@@ -356,7 +357,7 @@ Item {
356 onShownChanged: if (shown) greeter.fakeActiveForApp = ""
357 onShownChanged: if (shown) greeter.fakeActiveForApp = ""
357
358
358 Component.onCompleted: {
359 Component.onCompleted: {
359− if (LightDM.Users.count == 1) {
360+ if (greeter.narrowMode) {
360 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
361 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
361 }
362 }
362 }
363 }
@@ -368,14 +369,17 @@ Item {
368 onShowGreeter: greeter.show()
369 onShowGreeter: greeter.show()
369
370
370 onShowPrompt: {
371 onShowPrompt: {
371− if (LightDM.Users.count == 1) {
372+ if (greeter.narrowMode) {
372− // TODO: There's no better way for now to determine if its a PIN or a passphrase.
373− if (text == "PIN") {
374− lockscreen.alphaNumeric = false
375− } else {
376− lockscreen.alphaNumeric = true
377− }
378− lockscreen.placeholderText = i18n.tr("Please enter %1").arg(text);
373+ lockscreen.placeholderText = i18n.tr("Please enter %1").arg(text.toLowerCase());
374+ lockscreen.show();
375+ }
376+ }
377+
378+ onPromptlessChanged: {
379+ if (LightDM.Greeter.promptless) {
380+ lockscreen.hide()
381+ } else {
382+ lockscreen.reset();
379 lockscreen.show();
383 lockscreen.show();
380 }
384 }
381 }
385 }
@@ -389,6 +393,9 @@ Item {
389 greeter.login();
393 greeter.login();
390 } else {
394 } else {
391 lockscreen.clear(true);
395 lockscreen.clear(true);
396+ if (greeter.narrowMode) {
397+ LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
398+ }
392 }
399 }
393 }
400 }
394 }
401 }
@@ -443,25 +450,24 @@ Item {
443
450
444 function login() {
451 function login() {
445 enabled = false;
452 enabled = false;
446− LightDM.Greeter.startSessionSync();
453+ if (LightDM.Greeter.startSessionSync()) {
447− sessionStarted();
454+ sessionStarted();
448− greeter.hide();
455+ greeter.hide();
449− lockscreen.hide();
456+ lockscreen.hide();
450− launcher.hide();
457+ launcher.hide();
458+ }
451 enabled = true;
459 enabled = true;
452 }
460 }
453
461
454 onShownChanged: {
462 onShownChanged: {
455 if (shown) {
463 if (shown) {
456− lockscreen.reset();
464+ if (greeter.narrowMode) {
457− if (!LightDM.Greeter.promptless) {
458− lockscreen.show();
459− }
460− // If there is only one user, we start authenticating with that one here.
461− // If there are more users, the Greeter will handle that
462− if (LightDM.Users.count == 1) {
463 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
465 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
464 }
466 }
467+ if (!LightDM.Greeter.promptless) {
468+ lockscreen.reset();
469+ lockscreen.show();
470+ }
465 greeter.fakeActiveForApp = "";
471 greeter.fakeActiveForApp = "";
466 greeter.forceActiveFocus();
472 greeter.forceActiveFocus();
467 }
473 }
run.sh+15−6
@@ -8,6 +8,7 @@ GDB=false
8FAKE=false
8FAKE=false
9PINLOCK=false
9PINLOCK=false
10KEYLOCK=false
10KEYLOCK=false
11+USE_MOCKS=false
11MOUSE_TOUCH=true
12MOUSE_TOUCH=true
12
13
13usage() {
14usage() {
@@ -31,9 +32,9 @@ eval set -- "$ARGS"
31while [ $# -gt 0 ]
32while [ $# -gt 0 ]
32do
33do
33 case "$1" in
34 case "$1" in
34− -f|--fake) FAKE=true;;
35+ -f|--fake) FAKE=true; USE_MOCKS=true;;
35− -p|--pinlock) PINLOCK=true;;
36+ -p|--pinlock) PINLOCK=true; USE_MOCKS=true;;
36− -k|--keylock) KEYLOCK=true;;
37+ -k|--keylock) KEYLOCK=true; USE_MOCKS=true;;
37 -g|--gdb) GDB=true;;
38 -g|--gdb) GDB=true;;
38 -h|--help) usage;;
39 -h|--help) usage;;
39 -m|--nomousetouch) MOUSE_TOUCH=false;;
40 -m|--nomousetouch) MOUSE_TOUCH=false;;
@@ -43,20 +44,28 @@ do
43done
44done
44
45
45if $FAKE; then
46if $FAKE; then
46− export QML2_IMPORT_PATH=$QML2_IMPORT_PATH:$PWD/builddir/tests/mocks:$PWD/builddir/plugins:$PWD/builddir/modules
47 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/LightDM/single
47 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/LightDM/single
48fi
48fi
49
49
50if $PINLOCK; then
50if $PINLOCK; then
51− export QML2_IMPORT_PATH=$QML2_IMPORT_PATH:$PWD/builddir/tests/mocks:$PWD/builddir/plugins:$PWD/builddir/modules
52 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/LightDM/single-pin
51 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/LightDM/single-pin
53fi
52fi
54
53
55if $KEYLOCK; then
54if $KEYLOCK; then
56− export QML2_IMPORT_PATH=$QML2_IMPORT_PATH:$PWD/builddir/tests/mocks:$PWD/builddir/plugins:$PWD/builddir/modules
57 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/LightDM/single-passphrase
55 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/LightDM/single-passphrase
58fi
56fi
59
57
58+if $USE_MOCKS; then
59+ rm -f $PWD/builddir/nonmirplugins/LightDM # undo symlink (from below) for cleanliness
60+ export QML2_IMPORT_PATH=$QML2_IMPORT_PATH:$PWD/builddir/tests/mocks:$PWD/builddir/plugins:$PWD/builddir/modules
61+else
62+ # Still fake no-login user for convenience (it's annoying to be prompted for your password when testing)
63+ # And in particular, just link our LightDM mock into the nonmirplugins folder. We don't want the rest of
64+ # our plugins to be used.
65+ ln -s $PWD/builddir/tests/mocks/LightDM $PWD/builddir/nonmirplugins/
66+ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/LightDM/single
67+fi
68+
60QML_PHONE_SHELL_ARGS=""
69QML_PHONE_SHELL_ARGS=""
61if $MOUSE_TOUCH; then
70if $MOUSE_TOUCH; then
62 QML_PHONE_SHELL_ARGS="$QML_PHONE_SHELL_ARGS -mousetouch"
71 QML_PHONE_SHELL_ARGS="$QML_PHONE_SHELL_ARGS -mousetouch"
tests/mocks/AccountsService/AccountsService.cpp+12−2
@@ -29,12 +29,14 @@ AccountsService::AccountsService(QObject* parent)
29
29
30QString AccountsService::user() const
30QString AccountsService::user() const
31{
31{
32− return "testuser";
32+ return m_user;
33}
33}
34
34
35void AccountsService::setUser(const QString &user)
35void AccountsService::setUser(const QString &user)
36{
36{
37− Q_UNUSED(user)
37+ m_user = user;
38+ Q_EMIT userChanged();
39+ Q_EMIT passwordDisplayHintChanged();
38}
40}
39
41
40bool AccountsService::demoEdges() const
42bool AccountsService::demoEdges() const
@@ -68,3 +70,11 @@ void AccountsService::setStatsWelcomeScreen(bool statsWelcomeScreen)
68 m_statsWelcomeScreen = statsWelcomeScreen;
70 m_statsWelcomeScreen = statsWelcomeScreen;
69 statsWelcomeScreenChanged();
71 statsWelcomeScreenChanged();
70}
72}
73+
74+AccountsService::PasswordDisplayHint AccountsService::passwordDisplayHint() const
75+{
76+ if (m_user == "has-pin")
77+ return PasswordDisplayHint::Numeric;
78+ else
79+ return PasswordDisplayHint::Keyboard;
80+}
tests/mocks/AccountsService/AccountsService.h+12
@@ -27,6 +27,7 @@
27class AccountsService: public QObject
27class AccountsService: public QObject
28{
28{
29 Q_OBJECT
29 Q_OBJECT
30+ Q_ENUMS(PasswordDisplayHint)
30 Q_PROPERTY (QString user
31 Q_PROPERTY (QString user
31 READ user
32 READ user
32 WRITE setUser
33 WRITE setUser
@@ -43,8 +44,16 @@ class AccountsService: public QObject
43 READ statsWelcomeScreen
44 READ statsWelcomeScreen
44 WRITE setStatsWelcomeScreen // only available in mock
45 WRITE setStatsWelcomeScreen // only available in mock
45 NOTIFY statsWelcomeScreenChanged)
46 NOTIFY statsWelcomeScreenChanged)
47+ Q_PROPERTY (PasswordDisplayHint passwordDisplayHint
48+ READ passwordDisplayHint
49+ NOTIFY passwordDisplayHintChanged)
46
50
47public:
51public:
52+ enum PasswordDisplayHint {
53+ Keyboard,
54+ Numeric,
55+ };
56+
48 explicit AccountsService(QObject *parent = 0);
57 explicit AccountsService(QObject *parent = 0);
49
58
50 QString user() const;
59 QString user() const;
@@ -55,15 +64,18 @@ public:
55 void setBackgroundFile(const QString &backgroundFile);
64 void setBackgroundFile(const QString &backgroundFile);
56 bool statsWelcomeScreen() const;
65 bool statsWelcomeScreen() const;
57 void setStatsWelcomeScreen(bool statsWelcomeScreen);
66 void setStatsWelcomeScreen(bool statsWelcomeScreen);
67+ PasswordDisplayHint passwordDisplayHint() const;
58
68
59Q_SIGNALS:
69Q_SIGNALS:
60 void userChanged();
70 void userChanged();
61 void demoEdgesChanged();
71 void demoEdgesChanged();
62 void backgroundFileChanged();
72 void backgroundFileChanged();
63 void statsWelcomeScreenChanged();
73 void statsWelcomeScreenChanged();
74+ void passwordDisplayHintChanged();
64
75
65private:
76private:
66 QString m_backgroundFile;
77 QString m_backgroundFile;
78+ QString m_user;
67 bool m_statsWelcomeScreen;
79 bool m_statsWelcomeScreen;
68};
80};
69
81
tests/mocks/AccountsService/CMakeLists.txt+4−1
@@ -5,4 +5,7 @@ add_library(MockAccountsService-qml MODULE
5
5
6qt5_use_modules(MockAccountsService-qml DBus Qml)
6qt5_use_modules(MockAccountsService-qml DBus Qml)
7
7
8−add_unity8_mock(AccountsService 0.1 AccountsService TARGETS MockAccountsService-qml)
8+add_unity8_mock(AccountsService 0.1 AccountsService
9+ PREFIX mocks
10+ TARGETS MockAccountsService-qml
11+ )
tests/mocks/AccountsService/plugin.cpp+1
@@ -32,5 +32,6 @@ static QObject *service_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
32void AccountsServicePlugin::registerTypes(const char *uri)
32void AccountsServicePlugin::registerTypes(const char *uri)
33{
33{
34 Q_ASSERT(uri == QLatin1String("AccountsService"));
34 Q_ASSERT(uri == QLatin1String("AccountsService"));
35+ qRegisterMetaType<AccountsService::PasswordDisplayHint>("AccountsService::PasswordDisplayHint");
35 qmlRegisterSingletonType<AccountsService>(uri, 0, 1, "AccountsService", service_provider);
36 qmlRegisterSingletonType<AccountsService>(uri, 0, 1, "AccountsService", service_provider);
36}
37}
tests/mocks/LightDM/GreeterPrivate.h+2
@@ -24,6 +24,7 @@
24namespace QLightDM
24namespace QLightDM
25{
25{
26class Greeter;
26class Greeter;
27+class GreeterImpl;
27
28
28class GreeterPrivate
29class GreeterPrivate
29{
30{
@@ -40,6 +41,7 @@ public:
40 void handleRespond(const QString &response);
41 void handleRespond(const QString &response);
41
42
42protected:
43protected:
44+ GreeterImpl *m_impl; // if the backend needs more private data
43 Greeter * const q_ptr;
45 Greeter * const q_ptr;
44
46
45private:
47private:
tests/mocks/LightDM/demo/CMakeLists.txt+4−2
@@ -11,11 +11,13 @@ set(LibLightDM_SOURCES
11add_library(MockLightDM-demo STATIC ${LibLightDM_SOURCES})
11add_library(MockLightDM-demo STATIC ${LibLightDM_SOURCES})
12
12
13include_directories(
13include_directories(
14+ ${CMAKE_CURRENT_BINARY_DIR}
14 ${LIBUSERMETRICSOUTPUT_INCLUDE_DIRS}
15 ${LIBUSERMETRICSOUTPUT_INCLUDE_DIRS}
15)
16)
16
17
17target_link_libraries(MockLightDM-demo
18target_link_libraries(MockLightDM-demo
18 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
19 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
20+ -lpam
19− )
21+)
20
22
21−qt5_use_modules(MockLightDM-demo Gui)
23+qt5_use_modules(MockLightDM-demo Concurrent Gui)
tests/mocks/LightDM/demo/GreeterPrivate.cpp+202−30
@@ -18,53 +18,225 @@
18
18
19#include "../Greeter.h"
19#include "../Greeter.h"
20#include "../GreeterPrivate.h"
20#include "../GreeterPrivate.h"
21−#include <QtCore/QDir>
21+#include <QFuture>
22−#include <QtCore/QSettings>
22+#include <QFutureInterface>
23+#include <QFutureWatcher>
24+#include <QQueue>
25+#include <QtConcurrent>
26+#include <QVector>
27+#include <security/pam_appl.h>
23
28
24namespace QLightDM
29namespace QLightDM
25{
30{
26
31
32+class GreeterImpl : public QObject
33+{
34+ Q_OBJECT
35+
36+ typedef QFutureInterface<QString> ResponseFuture;
37+
38+public:
39+ explicit GreeterImpl(Greeter *parent, GreeterPrivate *greeterPrivate)
40+ : QObject(parent),
41+ greeter(parent),
42+ greeterPrivate(greeterPrivate),
43+ pamHandle(NULL)
44+ {
45+ qRegisterMetaType<QLightDM::GreeterImpl::ResponseFuture>("QLightDM::GreeterImpl::ResponseFuture");
46+
47+ connect(&futureWatcher, SIGNAL(finished()),
48+ this, SLOT(finishPam()));
49+ connect(this, SIGNAL(showMessage(QString, QLightDM::Greeter::MessageType)),
50+ greeter, SIGNAL(showMessage(QString, QLightDM::Greeter::MessageType)));
51+ // This next connect is how we pass ResponseFutures between threads
52+ connect(this, SIGNAL(showPrompt(QString, QLightDM::Greeter::PromptType, QLightDM::GreeterImpl::ResponseFuture)),
53+ this, SLOT(handlePrompt(QString, QLightDM::Greeter::PromptType, QLightDM::GreeterImpl::ResponseFuture)));
54+ }
55+
56+ void start(QString username)
57+ {
58+ // Clear out any existing PAM interactions first (we can't simply
59+ // cancel our QFuture because QtConcurrent::run doesn't support cancel)
60+ if (pamHandle != NULL) {
61+ pam_handle *handle = pamHandle;
62+ pamHandle = NULL; // to disable normal finishPam() handling
63+ while (respond(QString())); // clear our local queue of QFutures
64+ pam_end(handle, PAM_CONV_ERR);
65+ }
66+
67+ // Now actually start a new conversation with PAM
68+ pam_conv conversation;
69+ conversation.conv = converseWithPam;
70+ conversation.appdata_ptr = static_cast<void*>(this);
71+
72+ if (pam_start("lightdm", username.toUtf8(), &conversation, &pamHandle) == PAM_SUCCESS) {
73+ futureWatcher.setFuture(QtConcurrent::run(authenticateWithPam, pamHandle));
74+ } else {
75+ greeterPrivate->authenticated = false;
76+ Q_EMIT greeter->showMessage("Internal error: could not start PAM authentication", QLightDM::Greeter::MessageTypeError);
77+ Q_EMIT greeter->authenticationComplete();
78+ }
79+ }
80+
81+ static int authenticateWithPam(pam_handle* pamHandle)
82+ {
83+ int pamStatus = pam_authenticate(pamHandle, 0);
84+ if (pamStatus == PAM_SUCCESS) {
85+ pamStatus = pam_acct_mgmt(pamHandle, 0);
86+ }
87+ if (pamStatus == PAM_NEW_AUTHTOK_REQD) {
88+ pamStatus = pam_chauthtok(pamHandle, PAM_CHANGE_EXPIRED_AUTHTOK);
89+ }
90+ if (pamStatus == PAM_SUCCESS) {
91+ pam_setcred(pamHandle, PAM_REINITIALIZE_CRED);
92+ }
93+ return pamStatus;
94+ }
95+
96+ static int converseWithPam(int num_msg, const pam_message** msg,
97+ pam_response** resp, void* appdata_ptr)
98+ {
99+ if (num_msg <= 0)
100+ return PAM_CONV_ERR;
101+
102+ auto* tmp_response = static_cast<pam_response*>(calloc(num_msg, sizeof(pam_response)));
103+ if (!tmp_response)
104+ return PAM_CONV_ERR;
105+
106+ GreeterImpl* impl = static_cast<GreeterImpl*>(appdata_ptr);
107+
108+ int count;
109+ QVector<ResponseFuture> responses;
110+
111+ for (count = 0; count < num_msg; ++count)
112+ {
113+ switch (msg[count]->msg_style)
114+ {
115+ case PAM_PROMPT_ECHO_ON:
116+ {
117+ QString message(msg[count]->msg);
118+ responses.append(ResponseFuture());
119+ responses.last().reportStarted();
120+ Q_EMIT impl->showPrompt(message, Greeter::PromptTypeQuestion, responses.last());
121+ break;
122+ }
123+ case PAM_PROMPT_ECHO_OFF:
124+ {
125+ QString message(msg[count]->msg);
126+ responses.append(ResponseFuture());
127+ responses.last().reportStarted();
128+ Q_EMIT impl->showPrompt(message, Greeter::PromptTypeSecret, responses.last());
129+ break;
130+ }
131+ case PAM_TEXT_INFO:
132+ {
133+ QString message(msg[count]->msg);
134+ Q_EMIT impl->showMessage(message, Greeter::MessageTypeInfo);
135+ break;
136+ }
137+ default:
138+ {
139+ QString message(msg[count]->msg);
140+ Q_EMIT impl->showMessage(message, Greeter::MessageTypeError);
141+ break;
142+ }
143+ }
144+ }
145+
146+ int i = 0;
147+ bool raise_error = false;
148+
149+ for (auto &response : responses)
150+ {
151+ pam_response* resp_item = &tmp_response[i++];
152+ resp_item->resp_retcode = 0;
153+ resp_item->resp = strdup(response.future().result().toUtf8());
154+
155+ if (!resp_item->resp)
156+ {
157+ raise_error = true;
158+ break;
159+ }
160+ }
161+
162+ if (raise_error)
163+ {
164+ for (int i = 0; i < count; ++i)
165+ free(tmp_response[i].resp);
166+
167+ free(tmp_response);
168+ return PAM_CONV_ERR;
169+ }
170+ else
171+ {
172+ *resp = tmp_response;
173+ return PAM_SUCCESS;
174+ }
175+ }
176+
177+public Q_SLOTS:
178+ bool respond(QString response)
179+ {
180+ if (!futures.isEmpty()) {
181+ futures.dequeue().reportFinished(&response);
182+ return true;
183+ } else {
184+ return false;
185+ }
186+ }
187+
188+Q_SIGNALS:
189+ void showMessage(QString text, QLightDM::Greeter::MessageType type);
190+ void showPrompt(QString text, QLightDM::Greeter::PromptType type, QLightDM::GreeterImpl::ResponseFuture response);
191+
192+private Q_SLOTS:
193+ void finishPam()
194+ {
195+ if (pamHandle == NULL) {
196+ return;
197+ }
198+
199+ int pamStatus = futureWatcher.result();
200+
201+ pam_end(pamHandle, pamStatus);
202+ pamHandle = NULL;
203+
204+ greeterPrivate->authenticated = (pamStatus == PAM_SUCCESS);
205+ Q_EMIT greeter->authenticationComplete();
206+ }
207+
208+ void handlePrompt(QString text, QLightDM::Greeter::PromptType type, QLightDM::GreeterImpl::ResponseFuture future)
209+ {
210+ futures.enqueue(future);
211+ Q_EMIT greeter->showPrompt(text, type);
212+ }
213+
214+private:
215+ Greeter *greeter;
216+ GreeterPrivate *greeterPrivate;
217+ pam_handle* pamHandle;
218+ QFutureWatcher<int> futureWatcher;
219+ QQueue<ResponseFuture> futures;
220+};
221+
27GreeterPrivate::GreeterPrivate(Greeter* parent)
222GreeterPrivate::GreeterPrivate(Greeter* parent)
28 : authenticated(false),
223 : authenticated(false),
29 authenticationUser(),
224 authenticationUser(),
225+ m_impl(new GreeterImpl(parent, this)),
30 q_ptr(parent)
226 q_ptr(parent)
31{
227{
32}
228}
33
229
34void GreeterPrivate::handleAuthenticate()
230void GreeterPrivate::handleAuthenticate()
35{
231{
36− Q_Q(Greeter);
37−
38− QSettings settings(QDir::homePath() + "/.unity8-greeter-demo", QSettings::NativeFormat);
39− settings.beginGroup(authenticationUser);
232+ m_impl->start(authenticationUser);
40− QVariant password = settings.value("password", "none");
41−
42− if (password == "pin") {
43− Q_EMIT q->showPrompt("PIN", Greeter::PromptTypeSecret);
44− } else if (password == "keyboard") {
45− Q_EMIT q->showPrompt("Password", Greeter::PromptTypeSecret);
46− } else {
47− authenticated = true;
48− Q_EMIT q->authenticationComplete();
49− }
50}
233}
51
234
52void GreeterPrivate::handleRespond(const QString &response)
235void GreeterPrivate::handleRespond(const QString &response)
53{
236{
54− Q_Q(Greeter);
237+ m_impl->respond(response);
55−
56− QSettings settings(QDir::homePath() + "/.unity8-greeter-demo", QSettings::NativeFormat);
57− settings.beginGroup(authenticationUser);
58− QVariant password = settings.value("password", "none");
59−
60− QString passwordValue;
61− if (password == "pin") {
62− passwordValue = settings.value("passwordValue", "1234").toString();
63− } else {
64− passwordValue = settings.value("passwordValue", "password").toString();
65− }
66− authenticated = (response == passwordValue);
67− Q_EMIT q->authenticationComplete();
68}
238}
69
239
70}
240}
241+
242+#include "GreeterPrivate.moc"
tests/mocks/LightDM/demo/UsersModelPrivate.cpp+1−1
@@ -29,7 +29,7 @@ UsersModelPrivate::UsersModelPrivate(UsersModel* parent)
29 : q_ptr(parent)
29 : q_ptr(parent)
30{
30{
31 QSettings settings(QDir::homePath() + "/.unity8-greeter-demo", QSettings::NativeFormat);
31 QSettings settings(QDir::homePath() + "/.unity8-greeter-demo", QSettings::NativeFormat);
32− QStringList users = settings.value("users", QStringList() << "phablet").toStringList();
32+ QStringList users = settings.value("users", QStringList() << qgetenv("USER")).toStringList();
33
33
34 Q_FOREACH(const QString &user, users)
34 Q_FOREACH(const QString &user, users)
35 {
35 {
tests/mocks/LightDM/full/GreeterPrivate.cpp+1−1
@@ -54,7 +54,7 @@ void GreeterPrivate::handleAuthenticate()
54 authenticated = true;
54 authenticated = true;
55 Q_EMIT q->authenticationComplete();
55 Q_EMIT q->authenticationComplete();
56 } else if (authenticationUser == "has-pin"){
56 } else if (authenticationUser == "has-pin"){
57− Q_EMIT q->showPrompt("PIN", Greeter::PromptTypeSecret);
57+ Q_EMIT q->showPrompt("Password:", Greeter::PromptTypeSecret);
58 } else if (authenticationUser == "auth-error") {
58 } else if (authenticationUser == "auth-error") {
59 authenticated = false;
59 authenticated = false;
60 Q_EMIT q->authenticationComplete();
60 Q_EMIT q->authenticationComplete();
tests/mocks/LightDM/single-pin/GreeterPrivate.cpp+1−1
@@ -32,7 +32,7 @@ GreeterPrivate::GreeterPrivate(Greeter* parent)
32void GreeterPrivate::handleAuthenticate()
32void GreeterPrivate::handleAuthenticate()
33{
33{
34 Q_Q(Greeter);
34 Q_Q(Greeter);
35− Q_EMIT q->showPrompt("PIN", Greeter::PromptTypeSecret);
35+ Q_EMIT q->showPrompt("Password:", Greeter::PromptTypeSecret);
36}
36}
37
37
38void GreeterPrivate::handleRespond(const QString &response)
38void GreeterPrivate::handleRespond(const QString &response)
tests/mocks/LightDM/single-pin/UsersModelPrivate.cpp+1−1
@@ -26,7 +26,7 @@ UsersModelPrivate::UsersModelPrivate(UsersModel* parent)
26{
26{
27 entries =
27 entries =
28 {
28 {
29− { "single", "Has PIN", 0, 0, false, false, 0, 0 },
29+ { "has-pin", "Has PIN", 0, 0, false, false, 0, 0 },
30 };
30 };
31}
31}
32
32
tests/qmltests/Greeter/tst_Lockscreen.qml+11−5
@@ -18,8 +18,9 @@ import QtQuick 2.0
18import QtTest 1.0
18import QtTest 1.0
19import ".."
19import ".."
20import "../../../qml/Components"
20import "../../../qml/Components"
21−import Ubuntu.Components 0.1
21+import AccountsService 0.1
22import LightDM 0.1 as LightDM
22import LightDM 0.1 as LightDM
23+import Ubuntu.Components 0.1
23import Unity.Test 0.1 as UT
24import Unity.Test 0.1 as UT
24
25
25Rectangle {
26Rectangle {
@@ -53,11 +54,16 @@ Rectangle {
53 }
54 }
54 }
55 }
55
56
57+ function setUser(username) {
58+ AccountsService.user = username
59+ LightDM.Greeter.authenticate(username)
60+ }
61+
56 Connections {
62 Connections {
57 target: LightDM.Greeter
63 target: LightDM.Greeter
58
64
59 onShowPrompt: {
65 onShowPrompt: {
60− if (text === "PIN") {
66+ if (AccountsService.passwordDisplayHint === AccountsService.Numeric) {
61 pinPadCheckBox.checked = false
67 pinPadCheckBox.checked = false
62 } else {
68 } else {
63 pinPadCheckBox.checked = true
69 pinPadCheckBox.checked = true
@@ -139,12 +145,12 @@ Rectangle {
139 Button {
145 Button {
140 text: "start auth (1234)"
146 text: "start auth (1234)"
141 width: parent.width
147 width: parent.width
142− onClicked: LightDM.Greeter.authenticate("has-pin")
148+ onClicked: setUser("has-pin")
143 }
149 }
144 Button {
150 Button {
145 text: "start auth (password)"
151 text: "start auth (password)"
146 width: parent.width
152 width: parent.width
147− onClicked: LightDM.Greeter.authenticate("has-password")
153+ onClicked: setUser("has-password")
148 }
154 }
149
155
150 TextField {
156 TextField {
@@ -255,7 +261,7 @@ Rectangle {
255 enteredLabel.text = ""
261 enteredLabel.text = ""
256 minPinLengthTextField.text = data.minPinLength
262 minPinLengthTextField.text = data.minPinLength
257 maxPinLengthTextField.text = data.maxPinLength
263 maxPinLengthTextField.text = data.maxPinLength
258− LightDM.Greeter.authenticate(data.username)
264+ setUser(data.username)
259 waitForLockscreenReady();
265 waitForLockscreenReady();
260
266
261 var inputField = findChild(lockscreen, "pinentryField")
267 var inputField = findChild(lockscreen, "pinentryField")