Merge lp:~unity-team/unity8/wrong-password-handling into lp:unity8

Proposed by Michał Sawicz
Status: Merged
Approved by: Michał Sawicz
Approved revision: 1027
Merged at revision: 1152
Proposed branch: lp:~unity-team/unity8/wrong-password-handling
Merge into: lp:unity8
Prerequisite: lp:~unity-team/unity8/greeter-misc-cleanups
Diff against target: 1533 lines (+663/-115)
43 files modified
cmake/modules/QmlTest.cmake (+2/-2)
cmake/modules/autopilot.cmake (+2/-2)
debian/control (+2/-1)
debian/unity8-private.install (+0/-2)
plugins/AccountsService/50-com.canonical.unity.AccountsService.pkla (+0/-6)
plugins/AccountsService/AccountsService.cpp (+27/-1)
plugins/AccountsService/AccountsService.h (+9/-0)
plugins/AccountsService/CMakeLists.txt (+0/-10)
plugins/AccountsService/com.canonical.unity.AccountsService.policy (+0/-24)
plugins/AccountsService/com.canonical.unity.AccountsService.xml (+28/-5)
plugins/LightDM/Greeter.cpp (+4/-1)
plugins/LightDM/Greeter.h (+1/-1)
plugins/Ubuntu/CMakeLists.txt (+1/-0)
plugins/Ubuntu/SystemImage/CMakeLists.txt (+10/-0)
plugins/Ubuntu/SystemImage/SystemImage.cpp (+34/-0)
plugins/Ubuntu/SystemImage/SystemImage.h (+38/-0)
plugins/Ubuntu/SystemImage/SystemImage.qmltypes (+17/-0)
plugins/Ubuntu/SystemImage/plugin.cpp (+34/-0)
plugins/Ubuntu/SystemImage/plugin.h (+31/-0)
plugins/Ubuntu/SystemImage/qmldir (+3/-0)
po/unity8.pot (+72/-19)
qml/Components/Lockscreen.qml (+32/-9)
qml/Components/PassphraseLockscreen.qml (+3/-4)
qml/Components/PinLockscreen.qml (+3/-4)
qml/Notifications/NotificationMenuItemFactory.qml (+0/-1)
qml/Shell.qml (+50/-5)
tests/mocks/AccountsService/AccountsService.cpp (+13/-1)
tests/mocks/AccountsService/AccountsService.h (+8/-0)
tests/mocks/LightDM/Greeter.cpp (+11/-0)
tests/mocks/LightDM/Greeter.h (+3/-0)
tests/mocks/LightDM/full/GreeterPrivate.cpp (+4/-4)
tests/mocks/LightDM/single-passphrase/GreeterPrivate.cpp (+2/-9)
tests/mocks/LightDM/single-pin/GreeterPrivate.cpp (+3/-2)
tests/mocks/Ubuntu/CMakeLists.txt (+1/-0)
tests/mocks/Ubuntu/SystemImage/CMakeLists.txt (+10/-0)
tests/mocks/Ubuntu/SystemImage/MockSystemImage.cpp (+27/-0)
tests/mocks/Ubuntu/SystemImage/MockSystemImage.h (+36/-0)
tests/mocks/Ubuntu/SystemImage/SystemImage.qmltypes (+18/-0)
tests/mocks/Ubuntu/SystemImage/plugin.cpp (+34/-0)
tests/mocks/Ubuntu/SystemImage/plugin.h (+31/-0)
tests/mocks/Ubuntu/SystemImage/qmldir (+3/-0)
tests/qmltests/Greeter/tst_Lockscreen.qml (+0/-2)
tests/qmltests/tst_ShellWithPin.qml (+56/-0)
To merge this branch: bzr merge lp:~unity-team/unity8/wrong-password-handling
Reviewer Review Type Date Requested Status
Michał Sawicz Approve
PS Jenkins bot continuous-integration Pending
David Planella Pending
Michael Zanetti Pending
Albert Astals Cid Pending
Review via email: mp+230734@code.launchpad.net

This proposal supersedes a proposal from 2014-08-01.

Commit message

Make wrong-password handling much nicer by showing a pretty spinner while we wait for PAM, by improving the prompt text to match designs, by forcing the user to wait five seconds after every five failed attemps, and by supporting (but not yet enabling) an opt-in "factory-reset your phone after X failed attemps" feature.

Description of the change

Make wrong-password handling much nicer by showing a pretty spinner while we wait for PAM, by improving the prompt text to match designs, by forcing the user to wait five seconds after every five failed attemps, and by supporting (but not yet enabling) an opt-in "factory-reset your phone after X failed attemps" feature.

For the spec, see the "passcode incorrect" part of:
https://docs.google.com/a/canonical.com/document/d/1VajNkWbBH61iVixXJAmOvNGiG__GWQTMXGNOZijXWJw

It should go without saying, but BE PREPARED TO HAVE YOUR PHONE WIPED while testing the factory-reset bit (which, if you want to test, you have to manually edit the maxFailedLogins field in the qml).

I've added a tiny plugin for calling the system-image daemon's FactoryReset method. Maybe it will be useful for more things in the future.

I also cleaned up the AccountsService field definitions a bit.

== Using AccountsService to store the failedLogins count ==

I thought this might deserve a few words.

My original thought was to take advantage of our PAM infrastructure and use pam_tally2, which can do fancy tallying, login denial, and timeouts. But (A) that does not give any extra security since we'd need to specify a user-writable tally file as long as we don't have a split greeter, (B) it does not give us any warning when we are about to go over our limit, and (C) does not tell us *when* we are delaying due to too many failed logins, so we can't tell the user.

So we needed to store it ourselves. I could have used gsettings or similar, but we want to keep track of this per-user and stuffing a map into a settings backend isn't always convenient.

While AccountsService is mostly designed for data that can be shared between greeters and user sessions, it seemed like not an awful place to store the data and gives us per-user semantics for free. And we can share the data store with the eventually-split greeter (although that is certainly small potatoes).

== Checklist ==

 * Are there any related MPs required for this MP to build/function as expected? Please list.
 - Yes, greeter-misc-cleanups

 * Did you perform an exploratory manual test run of your code change and any related functionality?
 - Yes

 * Did you make sure that your branch does not contain spurious tags?
 - Yes

 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
 - I'm on the team

 * If you changed the UI, has there been a design review?
 - Olga and Esti are fine with this for now, but the visuals are all being updated. I just wanted to get the backend work in.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal

Seems like the qmluitests failure may be related to this, no?

review: Needs Fixing
Revision history for this message
David Planella (dpm) wrote : Posted in a previous version of this proposal

This merge proposal is introducing a few new translatable strings. Could it provide an updated .pot file as well, so that translators can do their job in time? Thanks!

review: Needs Fixing
Revision history for this message
Michał Sawicz (saviq) wrote : Posted in a previous version of this proposal

Indeed, make pot_file please.

We've a plan for a ~push hook that will warn us if stuff like this happens, but... too many higher priority items...

Revision history for this message
Michael Terry (mterry) wrote : Posted in a previous version of this proposal

Updated pot file and fixed the test.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Michał Sawicz (saviq) wrote : Posted in a previous version of this proposal

Please delete tag 7.85+14.10.20140428.2-0ubuntu1 in this branch and any local checkouts you might have.

review: Needs Fixing
Revision history for this message
Michael Terry (mterry) wrote : Posted in a previous version of this proposal

Deleted that tag.

Revision history for this message
Michał Sawicz (saviq) : Posted in a previous version of this proposal
review: Abstain
Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

The lockscreen features showInfoPopup(). You should use that one for the wipe warning instead of adding your own Dialog component in order to keep design consistent with the same warning for locking the SIM card etc.

review: Needs Fixing
Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

On the graphical changes, the Spinner in the lockscreen etc, that doesn't match with the new design... I'll probably have to kill/redo that again when merging the new-lockscreen-design branch.

Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

I'm curious if there are any downsides of adding all those plugins with just one method. You think it might make sense to merge the SystemImage plugin with e.g. the Powerd plugin into a single "System" plugin supporting Powerd, SystemImage etc?

Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

some inline comments

Revision history for this message
Michael Terry (mterry) wrote : Posted in a previous version of this proposal

I can use the existing dialog support, didn't even notice it.

The spinner can go away. Design didn't like it anyway. I was going to wait until I landed the "nodelay" change so PAM feedback is instant, but it can go away now instead, if it makes the other merge easier.

As for the plugin... It's just a bunch more boilerplate. And maybe some extra binary-size overhead? I worry that a generic "System" plugin would be a bit of a dumping place with little cohesion between the pieces. But I'm not a -1, just a +0 on the idea.

OK, working on the dialog and spinner bits, as well as merging with trunk again.

Revision history for this message
Michael Terry (mterry) wrote : Posted in a previous version of this proposal

OK. No spinner and I'm using the built-in lockscreen dialog. Plus merged from trunk.

I didn't address the bevy-of-tiny-plugins issue. How strong did you feel about it?

Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

2 inline comments. You forgot to update some things after the latest changes.

review: Needs Fixing
Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

there's also some more test failures:

FAIL! : qmltestrunner::ShellWithPin::test_factoryReset() function returned unexpected result
   Actual (): false
   Expected (): true
   Loc: [/home/mzanetti/Development/reviews/wrong-password-handling/tests/qmltests/tst_ShellWithPin.qml(223)]
FAIL! : qmltestrunner::ShellWithPin::test_failedLoginsCount() property showProgress
   Actual (): 1
   Expected (): 0
   Loc: [/home/mzanetti/Development/reviews/wrong-password-handling/tests/qmltests/tst_ShellWithPin.qml(106)]
FAIL! : qmltestrunner::ShellWithPin::test_failedLoginsCount() property failedLogins
   Actual (): 0
   Expected (): 1
   Loc: [/home/mzanetti/Development/reviews/wrong-password-handling/tests/qmltests/tst_ShellWithPin.qml(195)]
FAIL! : qmltestrunner::ShellWithPin::test_login() property showProgress
   Actual (): 1
   Expected (): 0
   Loc: [/home/mzanetti/Development/reviews/wrong-password-handling/tests/qmltests/tst_ShellWithPin.qml(106)]
FAIL! : qmltestrunner::ShellWithPin::test_login() property count
   Actual (): 0
   Expected (): 1
   Loc: [/home/mzanetti/Development/reviews/wrong-password-handling/tests/qmltests/tst_ShellWithPin.qml(128)]
FAIL! : qmltestrunner::ShellWithPin::test_wrongEntries() property showProgress
   Actual (): 1
   Expected (): 0
   Loc: [/home/mzanetti/Development/reviews/wrong-password-handling/tests/qmltests/tst_ShellWithPin.qml(106)]
FAIL! : qmltestrunner::ShellWithPin::test_wrongEntries() property text
   Actual (): Enter your passcode
   Expected (): Incorrect passcode
Please re-enter
   Loc: [/home/mzanetti/Development/reviews/wrong-password-handling/tests/qmltests/tst_ShellWithPin.qml(208)]
PASS : qmltestrunner::ShellWithPin::cleanupTestCase()
Totals: 6 passed, 7 failed, 0 skipped

review: Needs Fixing
Revision history for this message
Michael Terry (mterry) wrote : Posted in a previous version of this proposal

Ugh, you're right. I was hasty. Pot updated again, and test fixed.

Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

ok. lookin good now. thanks

 * Did you perform an exploratory manual test run of the code change and any related functionality?

yes

 * Did CI run pass? If not, please explain why.

waiting on the latest run, but there seem to be general problems with tests atm.

review: Approve
Revision history for this message
Michał Sawicz (saviq) wrote :

Approving as per superseded, this only has a merge.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cmake/modules/QmlTest.cmake'
2--- cmake/modules/QmlTest.cmake 2014-08-06 12:59:59 +0000
3+++ cmake/modules/QmlTest.cmake 2014-08-14 00:00:43 +0000
4@@ -103,7 +103,7 @@
5 endif()
6
7 set(qmltest_command
8- env ${qmltest_ENVIRONMENT}
9+ env ${qmltest_ENVIRONMENT} UNITY_TESTING=1
10 ${qmltestrunner_exe} -input ${CMAKE_CURRENT_SOURCE_DIR}/${qmltest_FILE}.qml
11 ${qmltestrunner_imports}
12 ${ITERATIONS_STRING}
13@@ -117,7 +117,7 @@
14 set(LD_PRELOAD_PATH "LD_PRELOAD=/usr/lib/${ARCH_TRIPLET}/mesa/libGL.so.1")
15 endif()
16 set(qmltest_xvfb_command
17- env ${qmltest_ENVIRONMENT} ${LD_PRELOAD_PATH}
18+ env ${qmltest_ENVIRONMENT} ${LD_PRELOAD_PATH} UNITY_TESTING=1
19 xvfb-run --server-args "-screen 0 1024x768x24" --auto-servernum
20 ${qmltestrunner_exe} -input ${CMAKE_CURRENT_SOURCE_DIR}/${qmltest_FILE}.qml
21 ${qmltestrunner_imports}
22
23=== modified file 'cmake/modules/autopilot.cmake'
24--- cmake/modules/autopilot.cmake 2014-03-17 14:27:05 +0000
25+++ cmake/modules/autopilot.cmake 2014-08-14 00:00:43 +0000
26@@ -2,7 +2,7 @@
27
28 function(declare_autopilot_test TEST_NAME TEST_SUITE WORKING_DIR)
29 add_custom_target(autopilot-${TEST_NAME}
30- COMMAND LANG=C QML2_IMPORT_PATH=${SHELL_INSTALL_QML}/mocks python3 -m autopilot.run run ${TEST_SUITE}
31+ COMMAND UNITY_TESTING=1 LANG=C QML2_IMPORT_PATH=${SHELL_INSTALL_QML}/mocks python3 -m autopilot.run run ${TEST_SUITE}
32 WORKING_DIRECTORY ${WORKING_DIR}
33 DEPENDS fake_install
34 )
35@@ -14,7 +14,7 @@
36 add_dependencies(autopilot autopilot-${TEST_NAME})
37
38 add_custom_target(autopilot2-${TEST_NAME}
39- COMMAND LANG=C QML2_IMPORT_PATH=${SHELL_INSTALL_QML}/mocks python2 -m autopilot.run run ${TEST_SUITE}
40+ COMMAND UNITY_TESTING=1 LANG=C QML2_IMPORT_PATH=${SHELL_INSTALL_QML}/mocks python2 -m autopilot.run run ${TEST_SUITE}
41 WORKING_DIRECTORY ${WORKING_DIR}
42 DEPENDS fake_install
43 )
44
45=== modified file 'debian/control'
46--- debian/control 2014-08-11 19:02:49 +0000
47+++ debian/control 2014-08-14 00:00:43 +0000
48@@ -165,7 +165,8 @@
49 Architecture: any
50 Multi-Arch: same
51 Pre-Depends: ${misc:Pre-Depends},
52-Depends: gsettings-ubuntu-schemas,
53+Depends: accountsservice-ubuntu-schemas,
54+ gsettings-ubuntu-schemas,
55 libhardware2,
56 libunity-core-6.0-9,
57 pay-service,
58
59=== modified file 'debian/unity8-private.install'
60--- debian/unity8-private.install 2014-06-27 20:48:38 +0000
61+++ debian/unity8-private.install 2014-08-14 00:00:43 +0000
62@@ -10,5 +10,3 @@
63 usr/lib/*/unity8/qml/Utils
64 usr/share/accountsservice/interfaces
65 usr/share/dbus-1/interfaces
66-usr/share/polkit-1
67-var/lib/polkit-1
68
69=== removed file 'plugins/AccountsService/50-com.canonical.unity.AccountsService.pkla'
70--- plugins/AccountsService/50-com.canonical.unity.AccountsService.pkla 2013-08-12 18:41:45 +0000
71+++ plugins/AccountsService/50-com.canonical.unity.AccountsService.pkla 1970-01-01 00:00:00 +0000
72@@ -1,6 +0,0 @@
73-[Allow LightDM to set Unity AccountsService fields]
74-Identity=unix-user:lightdm
75-Action=com.canonical.unity.AccountsService.ModifyAnyUser
76-ResultActive=yes
77-ResultInactive=yes
78-ResultAny=yes
79
80=== modified file 'plugins/AccountsService/AccountsService.cpp'
81--- plugins/AccountsService/AccountsService.cpp 2014-07-02 16:17:14 +0000
82+++ plugins/AccountsService/AccountsService.cpp 2014-08-14 00:00:43 +0000
83@@ -27,7 +27,8 @@
84 m_user(qgetenv("USER")),
85 m_demoEdges(false),
86 m_statsWelcomeScreen(false),
87- m_passwordDisplayHint(Keyboard)
88+ m_passwordDisplayHint(Keyboard),
89+ m_failedLogins(0)
90 {
91 connect(m_service, SIGNAL(propertiesChanged(const QString &, const QString &, const QStringList &)),
92 this, SLOT(propertiesChanged(const QString &, const QString &, const QStringList &)));
93@@ -49,6 +50,7 @@
94 updateBackgroundFile();
95 updateStatsWelcomeScreen();
96 updatePasswordDisplayHint();
97+ updateFailedLogins();
98 }
99
100 bool AccountsService::demoEdges() const
101@@ -113,6 +115,26 @@
102 }
103 }
104
105+void AccountsService::updateFailedLogins()
106+{
107+ uint failedLogins = m_service->getUserProperty(m_user, "com.canonical.unity.AccountsService.Private", "FailedLogins").toUInt();
108+ if (m_failedLogins != failedLogins) {
109+ m_failedLogins = failedLogins;
110+ Q_EMIT failedLoginsChanged();
111+ }
112+}
113+
114+uint AccountsService::failedLogins() const
115+{
116+ return m_failedLogins;
117+}
118+
119+void AccountsService::setFailedLogins(uint failedLogins)
120+{
121+ m_failedLogins = failedLogins;
122+ m_service->setUserProperty(m_user, "com.canonical.unity.AccountsService.Private", "FailedLogins", failedLogins);
123+}
124+
125 void AccountsService::propertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
126 {
127 if (m_user != user) {
128@@ -123,6 +145,10 @@
129 if (changed.contains("demo-edges")) {
130 updateDemoEdges();
131 }
132+ } else if (interface == "com.canonical.unity.AccountsService.Private") {
133+ if (changed.contains("FailedLogins")) {
134+ updateFailedLogins();
135+ }
136 } else if (interface == "com.ubuntu.touch.AccountsService.SecurityPrivacy") {
137 if (changed.contains("StatsWelcomeScreen")) {
138 updateStatsWelcomeScreen();
139
140=== modified file 'plugins/AccountsService/AccountsService.h'
141--- plugins/AccountsService/AccountsService.h 2014-07-02 16:17:14 +0000
142+++ plugins/AccountsService/AccountsService.h 2014-08-14 00:00:43 +0000
143@@ -45,6 +45,10 @@
144 Q_PROPERTY (PasswordDisplayHint passwordDisplayHint
145 READ passwordDisplayHint
146 NOTIFY passwordDisplayHintChanged)
147+ Q_PROPERTY (uint failedLogins
148+ READ failedLogins
149+ WRITE setFailedLogins
150+ NOTIFY failedLoginsChanged)
151
152 public:
153 enum PasswordDisplayHint {
154@@ -61,6 +65,8 @@
155 QString backgroundFile() const;
156 bool statsWelcomeScreen() const;
157 PasswordDisplayHint passwordDisplayHint() const;
158+ uint failedLogins() const;
159+ void setFailedLogins(uint failedLogins);
160
161 Q_SIGNALS:
162 void userChanged();
163@@ -68,6 +74,7 @@
164 void backgroundFileChanged();
165 void statsWelcomeScreenChanged();
166 void passwordDisplayHintChanged();
167+ void failedLoginsChanged();
168
169 private Q_SLOTS:
170 void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
171@@ -78,6 +85,7 @@
172 void updateBackgroundFile();
173 void updateStatsWelcomeScreen();
174 void updatePasswordDisplayHint();
175+ void updateFailedLogins();
176
177 AccountsServiceDBusAdaptor *m_service;
178 QString m_user;
179@@ -85,6 +93,7 @@
180 QString m_backgroundFile;
181 bool m_statsWelcomeScreen;
182 PasswordDisplayHint m_passwordDisplayHint;
183+ uint m_failedLogins;
184 };
185
186 #endif
187
188=== modified file 'plugins/AccountsService/CMakeLists.txt'
189--- plugins/AccountsService/CMakeLists.txt 2014-05-02 22:57:00 +0000
190+++ plugins/AccountsService/CMakeLists.txt 2014-08-14 00:00:43 +0000
191@@ -10,8 +10,6 @@
192
193 add_unity8_plugin(AccountsService 0.1 AccountsService TARGETS AccountsService-qml)
194
195-set(POLKIT_LIB_DIR "${CMAKE_INSTALL_LOCALSTATEDIR}/lib/polkit-1")
196-set(POLKIT_DATA_DIR "${CMAKE_INSTALL_PREFIX}/share/polkit-1")
197 set(DBUS_IFACE_DIR "${CMAKE_INSTALL_PREFIX}/share/dbus-1/interfaces")
198 set(ACCOUNTS_IFACE_DIR "${CMAKE_INSTALL_PREFIX}/share/accountsservice/interfaces")
199
200@@ -24,11 +22,3 @@
201 execute_process(COMMAND mkdir -p \"\$ENV{DESTDIR}${ACCOUNTS_IFACE_DIR}\")
202 execute_process(COMMAND ln -sf ../../dbus-1/interfaces/com.canonical.unity.AccountsService.xml \"\$ENV{DESTDIR}${ACCOUNTS_IFACE_DIR}\")
203 ")
204-
205-install(FILES com.canonical.unity.AccountsService.policy
206- DESTINATION "${POLKIT_DATA_DIR}/actions"
207- )
208-
209-install(FILES 50-com.canonical.unity.AccountsService.pkla
210- DESTINATION "${POLKIT_LIB_DIR}/localauthority/10-vendor.d"
211- )
212
213=== removed file 'plugins/AccountsService/com.canonical.unity.AccountsService.policy'
214--- plugins/AccountsService/com.canonical.unity.AccountsService.policy 2013-08-12 18:41:45 +0000
215+++ plugins/AccountsService/com.canonical.unity.AccountsService.policy 1970-01-01 00:00:00 +0000
216@@ -1,24 +0,0 @@
217-<?xml version="1.0" encoding="UTF-8"?>
218-
219-<policyconfig>
220- <action id="com.canonical.unity.AccountsService.ModifyOwnUser">
221- <description>Set properties of own user</description>
222- <message>Authentication is required to set one's own unity properties.</message>
223- <defaults>
224- <allow_any>yes</allow_any>
225- <allow_inactive>yes</allow_inactive>
226- <allow_active>yes</allow_active>
227- </defaults>
228- </action>
229-
230- <action id="com.canonical.unity.AccountsService.ModifyAnyUser">
231- <description>Set properties of any user</description>
232- <message>Authentication is required to set another user's unity
233-properties.</message>
234- <defaults>
235- <allow_any>no</allow_any>
236- <allow_inactive>no</allow_inactive>
237- <allow_active>no</allow_active>
238- </defaults>
239- </action>
240-</policyconfig>
241
242=== modified file 'plugins/AccountsService/com.canonical.unity.AccountsService.xml'
243--- plugins/AccountsService/com.canonical.unity.AccountsService.xml 2013-08-23 19:49:18 +0000
244+++ plugins/AccountsService/com.canonical.unity.AccountsService.xml 2014-08-14 00:00:43 +0000
245@@ -3,22 +3,45 @@
246
247 <annotation name="org.freedesktop.Accounts.VendorExtension" value="true"/>
248
249- <annotation name="org.freedesktop.Accounts.Authentication.ChangeOwn"
250- value="com.canonical.unity.AccountsService.ModifyOwnUser"/>
251-
252 <annotation name="org.freedesktop.Accounts.Authentication.ReadAny"
253- value="com.canonical.unity.AccountsService.ModifyAnyUser"/>
254+ value="com.ubuntu.AccountsService.GreeterReadAny"/>
255
256 <annotation name="org.freedesktop.Accounts.Authentication.ChangeAny"
257- value="com.canonical.unity.AccountsService.ModifyAnyUser"/>
258+ value="com.ubuntu.AccountsService.GreeterChangeAny"/>
259
260+ <!-- Should have been named DemoEdges, sorry folks. -mterry -->
261 <property name="demo-edges" type="b" access="readwrite">
262 <annotation name="org.freedesktop.Accounts.DefaultValue" value="true"/>
263 </property>
264
265+ <!-- Should have been named LauncherItems, sorry folks. -mterry -->
266 <property name="launcher-items" type="aa{sv}" access="readwrite">
267 <annotation name="org.freedesktop.Accounts.DefaultValue" value="[{'defaults': <true>}]"/>
268 </property>
269
270 </interface>
271+
272+ <!-- This interface is for bits of data that the greeter wants to track
273+ per-user in a persistent way, but that users shouldn't be able to edit
274+ in an ideal world.
275+
276+ This interface is identical in permissions to the above one for now,
277+ but once we stop running the greeter in user-space, we should
278+ disallow org.freedesktop.Accounts.Authentication.ChangeOwn from the
279+ Private inteface. -->
280+ <interface name="com.canonical.unity.AccountsService.Private">
281+
282+ <annotation name="org.freedesktop.Accounts.VendorExtension" value="true"/>
283+
284+ <annotation name="org.freedesktop.Accounts.Authentication.ReadAny"
285+ value="com.ubuntu.AccountsService.GreeterReadAny"/>
286+
287+ <annotation name="org.freedesktop.Accounts.Authentication.ChangeAny"
288+ value="com.ubuntu.AccountsService.GreeterChangeAny"/>
289+
290+ <property name="FailedLogins" type="u" access="readwrite">
291+ <annotation name="org.freedesktop.Accounts.DefaultValue" value="0"/>
292+ </property>
293+
294+ </interface>
295 </node>
296
297=== modified file 'plugins/LightDM/Greeter.cpp'
298--- plugins/LightDM/Greeter.cpp 2014-06-18 19:49:22 +0000
299+++ plugins/LightDM/Greeter.cpp 2014-08-14 00:00:43 +0000
300@@ -17,6 +17,7 @@
301 */
302
303 #include "Greeter.h"
304+#include <libintl.h>
305 #include <QLightDM/Greeter>
306
307 class GreeterPrivate
308@@ -125,13 +126,15 @@
309 Q_D(Greeter);
310 d->wasPrompted = true;
311
312+ bool isDefaultPrompt = (text == dgettext("Linux-PAM", "Password: "));
313+
314 // Strip prompt of any colons at the end
315 QString trimmedText = text.trimmed();
316 if (trimmedText.endsWith(":") || trimmedText.endsWith(":")) {
317 trimmedText.chop(1);
318 }
319
320- Q_EMIT showPrompt(trimmedText, type == QLightDM::Greeter::PromptTypeSecret);
321+ Q_EMIT showPrompt(trimmedText, type == QLightDM::Greeter::PromptTypeSecret, isDefaultPrompt);
322 }
323
324 void Greeter::showMessageFilter(const QString &text, QLightDM::Greeter::MessageType type)
325
326=== modified file 'plugins/LightDM/Greeter.h'
327--- plugins/LightDM/Greeter.h 2014-06-27 22:08:19 +0000
328+++ plugins/LightDM/Greeter.h 2014-08-14 00:00:43 +0000
329@@ -55,7 +55,7 @@
330
331 Q_SIGNALS:
332 void showMessage(const QString &text, bool isError);
333- void showPrompt(const QString &text, bool isSecret);
334+ void showPrompt(const QString &text, bool isSecret, bool isDefaultPrompt);
335 void authenticationComplete();
336 void authenticationUserChanged(const QString &user);
337 void isActiveChanged();
338
339=== modified file 'plugins/Ubuntu/CMakeLists.txt'
340--- plugins/Ubuntu/CMakeLists.txt 2014-05-29 14:36:21 +0000
341+++ plugins/Ubuntu/CMakeLists.txt 2014-08-14 00:00:43 +0000
342@@ -1,3 +1,4 @@
343 add_subdirectory(Gestures)
344 add_subdirectory(DownloadDaemonListener)
345 add_subdirectory(Payments)
346+add_subdirectory(SystemImage)
347
348=== added directory 'plugins/Ubuntu/SystemImage'
349=== added file 'plugins/Ubuntu/SystemImage/CMakeLists.txt'
350--- plugins/Ubuntu/SystemImage/CMakeLists.txt 1970-01-01 00:00:00 +0000
351+++ plugins/Ubuntu/SystemImage/CMakeLists.txt 2014-08-14 00:00:43 +0000
352@@ -0,0 +1,10 @@
353+set(SYSTEMIMAGE_SOURCES
354+ plugin.cpp
355+ SystemImage.cpp
356+)
357+
358+add_library(SystemImage MODULE ${SYSTEMIMAGE_SOURCES})
359+
360+qt5_use_modules(SystemImage Qml DBus Core)
361+
362+add_unity8_plugin(Ubuntu.SystemImage 0.1 Ubuntu/SystemImage TARGETS SystemImage)
363
364=== added file 'plugins/Ubuntu/SystemImage/SystemImage.cpp'
365--- plugins/Ubuntu/SystemImage/SystemImage.cpp 1970-01-01 00:00:00 +0000
366+++ plugins/Ubuntu/SystemImage/SystemImage.cpp 2014-08-14 00:00:43 +0000
367@@ -0,0 +1,34 @@
368+/*
369+ * Copyright (C) 2014 Canonical, Ltd.
370+ *
371+ * This program is free software; you can redistribute it and/or modify
372+ * it under the terms of the GNU General Public License as published by
373+ * the Free Software Foundation; version 3.
374+ *
375+ * This program is distributed in the hope that it will be useful,
376+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
377+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
378+ * GNU General Public License for more details.
379+ *
380+ * You should have received a copy of the GNU General Public License
381+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
382+ */
383+
384+#include "SystemImage.h"
385+#include <QDBusConnection>
386+#include <QDBusInterface>
387+
388+SystemImage::SystemImage(QObject *parent)
389+ : QObject(parent),
390+ m_interface(new QDBusInterface("com.canonical.SystemImage",
391+ "/Service",
392+ "com.canonical.SystemImage",
393+ QDBusConnection::systemBus(),
394+ this))
395+{
396+}
397+
398+void SystemImage::factoryReset()
399+{
400+ m_interface->call("FactoryReset");
401+}
402
403=== added file 'plugins/Ubuntu/SystemImage/SystemImage.h'
404--- plugins/Ubuntu/SystemImage/SystemImage.h 1970-01-01 00:00:00 +0000
405+++ plugins/Ubuntu/SystemImage/SystemImage.h 2014-08-14 00:00:43 +0000
406@@ -0,0 +1,38 @@
407+/*
408+ * Copyright (C) 2014 Canonical, Ltd.
409+ *
410+ * This program is free software; you can redistribute it and/or modify
411+ * it under the terms of the GNU General Public License as published by
412+ * the Free Software Foundation; version 3.
413+ *
414+ * This program is distributed in the hope that it will be useful,
415+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
416+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
417+ * GNU General Public License for more details.
418+ *
419+ * You should have received a copy of the GNU General Public License
420+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
421+ */
422+
423+#ifndef SYSTEMIMAGE_H
424+#define SYSTEMIMAGE_H
425+
426+#include <QObject>
427+
428+class QDBusInterface;
429+
430+class SystemImage : public QObject
431+{
432+ Q_OBJECT
433+ Q_DISABLE_COPY(SystemImage)
434+
435+public:
436+ explicit SystemImage(QObject *parent = 0);
437+
438+ Q_INVOKABLE void factoryReset();
439+
440+private:
441+ QDBusInterface *m_interface;
442+};
443+
444+#endif // SYSTEMIMAGE_H
445
446=== added file 'plugins/Ubuntu/SystemImage/SystemImage.qmltypes'
447--- plugins/Ubuntu/SystemImage/SystemImage.qmltypes 1970-01-01 00:00:00 +0000
448+++ plugins/Ubuntu/SystemImage/SystemImage.qmltypes 2014-08-14 00:00:43 +0000
449@@ -0,0 +1,17 @@
450+import QtQuick.tooling 1.1
451+
452+// This file describes the plugin-supplied types contained in the library.
453+// It is used for QML tooling purposes only.
454+//
455+// This file was auto-generated by:
456+// 'qmlplugindump -notrelocatable Ubuntu.SystemImage 0.1 plugins'
457+
458+Module {
459+ Component {
460+ name: "SystemImage"
461+ prototype: "QObject"
462+ exports: ["Ubuntu.SystemImage/SystemImage 0.1"]
463+ exportMetaObjectRevisions: [0]
464+ Method { name: "factoryReset" }
465+ }
466+}
467
468=== added file 'plugins/Ubuntu/SystemImage/plugin.cpp'
469--- plugins/Ubuntu/SystemImage/plugin.cpp 1970-01-01 00:00:00 +0000
470+++ plugins/Ubuntu/SystemImage/plugin.cpp 2014-08-14 00:00:43 +0000
471@@ -0,0 +1,34 @@
472+/*
473+ * Copyright (C) 2014 Canonical, Ltd.
474+ *
475+ * This program is free software; you can redistribute it and/or modify
476+ * it under the terms of the GNU General Public License as published by
477+ * the Free Software Foundation; version 3.
478+ *
479+ * This program is distributed in the hope that it will be useful,
480+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
481+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
482+ * GNU General Public License for more details.
483+ *
484+ * You should have received a copy of the GNU General Public License
485+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
486+ */
487+
488+#include "plugin.h"
489+#include "SystemImage.h"
490+
491+#include <QtQml>
492+
493+static QObject *service_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
494+{
495+ Q_UNUSED(engine)
496+ Q_UNUSED(scriptEngine)
497+ return new SystemImage();
498+}
499+
500+void BackendPlugin::registerTypes(const char *uri)
501+{
502+ Q_ASSERT(uri == QLatin1String("Ubuntu.SystemImage"));
503+
504+ qmlRegisterSingletonType<SystemImage>(uri, 0, 1, "SystemImage", service_provider);
505+}
506
507=== added file 'plugins/Ubuntu/SystemImage/plugin.h'
508--- plugins/Ubuntu/SystemImage/plugin.h 1970-01-01 00:00:00 +0000
509+++ plugins/Ubuntu/SystemImage/plugin.h 2014-08-14 00:00:43 +0000
510@@ -0,0 +1,31 @@
511+/*
512+ * Copyright (C) 2014 Canonical, Ltd.
513+ *
514+ * This program is free software; you can redistribute it and/or modify
515+ * it under the terms of the GNU General Public License as published by
516+ * the Free Software Foundation; version 3.
517+ *
518+ * This program is distributed in the hope that it will be useful,
519+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
520+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
521+ * GNU General Public License for more details.
522+ *
523+ * You should have received a copy of the GNU General Public License
524+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
525+ */
526+
527+#ifndef SYSTEMIMAGE_PLUGIN_H
528+#define SYSTEMIMAGE_PLUGIN_H
529+
530+#include <QQmlExtensionPlugin>
531+
532+class BackendPlugin : public QQmlExtensionPlugin
533+{
534+ Q_OBJECT
535+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
536+
537+public:
538+ void registerTypes(const char *uri);
539+};
540+
541+#endif // SYSTEMIMAGE_PLUGIN_H
542
543=== added file 'plugins/Ubuntu/SystemImage/qmldir'
544--- plugins/Ubuntu/SystemImage/qmldir 1970-01-01 00:00:00 +0000
545+++ plugins/Ubuntu/SystemImage/qmldir 2014-08-14 00:00:43 +0000
546@@ -0,0 +1,3 @@
547+module Ubuntu.SystemImage
548+plugin SystemImage
549+typeinfo SystemImage.qmltypes
550
551=== modified file 'po/unity8.pot'
552--- po/unity8.pot 2014-08-08 09:17:29 +0000
553+++ po/unity8.pot 2014-08-14 00:00:43 +0000
554@@ -8,7 +8,7 @@
555 msgstr ""
556 "Project-Id-Version: unity8\n"
557 "Report-Msgid-Bugs-To: \n"
558-"POT-Creation-Date: 2014-08-08 11:17+0200\n"
559+"POT-Creation-Date: 2014-08-13 14:09-0400\n"
560 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
561 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
562 "Language-Team: LANGUAGE <LL@li.org>\n"
563@@ -17,6 +17,10 @@
564 "Content-Type: text/plain; charset=UTF-8\n"
565 "Content-Transfer-Encoding: 8bit\n"
566
567+#: plugins/LightDM/Greeter.cpp:129
568+msgid "Password: "
569+msgstr ""
570+
571 #: plugins/Unity/Launcher/launcheritem.cpp:43
572 #: plugins/Unity/Launcher/launcheritem.cpp:73
573 msgid "Pin shortcut"
574@@ -88,39 +92,51 @@
575 "phone<br><br>Tap on the screen to start"
576 msgstr ""
577
578-#: qml/Components/Lockscreen.qml:220
579+#: qml/Components/Lockscreen.qml:161
580+msgid "Too many incorrect attempts"
581+msgstr ""
582+
583+#: qml/Components/Lockscreen.qml:163
584+msgid "Please wait"
585+msgstr ""
586+
587+#: qml/Components/Lockscreen.qml:245
588 msgid "Emergency Call"
589 msgstr ""
590
591-#: qml/Components/Lockscreen.qml:243
592+#: qml/Components/Lockscreen.qml:268
593 msgid "OK"
594 msgstr ""
595
596-#: qml/Components/PassphraseLockscreen.qml:62
597+#: qml/Components/PassphraseLockscreen.qml:61
598 #, qt-format
599 msgid "Hello %1"
600 msgstr ""
601
602-#: qml/Components/PassphraseLockscreen.qml:62
603+#: qml/Components/PassphraseLockscreen.qml:61
604 msgid "Hello"
605 msgstr ""
606
607-#: qml/Components/PinLockscreen.qml:198
608+#: qml/Components/PinLockscreen.qml:197
609 msgid "CANCEL"
610 msgstr ""
611
612-#: qml/Components/PinLockscreen.qml:216
613+#: qml/Components/PinLockscreen.qml:215
614 msgid "DONE"
615 msgstr ""
616
617-#: qml/Dash/GenericScopeView.qml:358
618+#: qml/Dash/GenericScopeView.qml:360
619 msgid "See less"
620 msgstr ""
621
622-#: qml/Dash/GenericScopeView.qml:358
623+#: qml/Dash/GenericScopeView.qml:360
624 msgid "See all"
625 msgstr ""
626
627+#: qml/Dash/GenericScopeView.qml:423 qml/Panel/SearchIndicator.qml:27
628+msgid "Search"
629+msgstr ""
630+
631 #: qml/Dash/Previews/PreviewActionCombo.qml:34
632 msgid "More..."
633 msgstr ""
634@@ -141,15 +157,15 @@
635 msgid "Send"
636 msgstr ""
637
638-#: qml/Dash/ScopesOverview.qml:200
639+#: qml/Dash/ScopesOverview.qml:201
640 msgid "Manage Dash"
641 msgstr ""
642
643-#: qml/Dash/ScopesOverview.qml:405
644+#: qml/Dash/ScopesOverview.qml:408
645 msgid "Done"
646 msgstr ""
647
648-#: qml/Dash/ScopesOverview.qml:431
649+#: qml/Dash/ScopesOverview.qml:434
650 msgid "Store"
651 msgstr ""
652
653@@ -233,11 +249,48 @@
654 msgid "Roaming"
655 msgstr ""
656
657-#: qml/Panel/SearchIndicator.qml:27
658-msgid "Search"
659-msgstr ""
660-
661-#: qml/Shell.qml:256
662-#, qt-format
663-msgid "Please enter %1"
664+#: qml/Shell.qml:267
665+msgid "passphrase"
666+msgstr ""
667+
668+#: qml/Shell.qml:267
669+msgid "passcode"
670+msgstr ""
671+
672+#: qml/Shell.qml:269
673+#, qt-format
674+msgid "Enter your %1"
675+msgstr ""
676+
677+#: qml/Shell.qml:270
678+#, qt-format
679+msgid "Incorrect %1"
680+msgstr ""
681+
682+#: qml/Shell.qml:272
683+msgid "Please re-enter"
684+msgstr ""
685+
686+#: qml/Shell.qml:306
687+msgid "Sorry, incorrect passphrase."
688+msgstr ""
689+
690+#: qml/Shell.qml:307
691+msgid "Sorry, incorrect passcode."
692+msgstr ""
693+
694+#: qml/Shell.qml:308
695+msgid "This will be your last attempt."
696+msgstr ""
697+
698+#: qml/Shell.qml:310
699+msgid ""
700+"If passphrase is entered incorrectly, your phone will conduct a factory "
701+"reset and all personal data will be deleted."
702+msgstr ""
703+
704+#: qml/Shell.qml:311
705+msgid ""
706+"If passcode is entered incorrectly, your phone will conduct a factory reset "
707+"and all personal data will be deleted."
708 msgstr ""
709
710=== modified file 'qml/Components/Lockscreen.qml'
711--- qml/Components/Lockscreen.qml 2014-08-14 00:00:43 +0000
712+++ qml/Components/Lockscreen.qml 2014-08-14 00:00:43 +0000
713@@ -57,10 +57,15 @@
714
715 onRequiredChanged: {
716 if (required && pinPadLoader.item) {
717- pinPadLoader.item.clear(false);
718+ clear(false)
719 }
720 }
721
722+ function forceDelay(delay) {
723+ forcedDelayTimer.interval = delay
724+ forcedDelayTimer.start()
725+ }
726+
727 function reset() {
728 // This causes the loader below to destry and recreate the source
729 pinPadLoader.resetting = true;
730@@ -71,12 +76,19 @@
731 if (pinPadLoader.item) {
732 pinPadLoader.item.clear(showAnimation);
733 }
734+ pinPadLoader.showWrongText = showAnimation
735+ pinPadLoader.waiting = false
736 }
737
738 function showInfoPopup(title, text) {
739 PopupUtils.open(infoPopupComponent, root, {title: title, text: text})
740 }
741
742+ Timer {
743+ id: forcedDelayTimer
744+ onTriggered: pinPadLoader.showWrongText = false
745+ }
746+
747 Rectangle {
748 // In case background fails to load or is undefined
749 id: backgroundBackup
750@@ -133,8 +145,6 @@
751 }
752 }
753
754-
755-
756 Loader {
757 id: pinPadLoader
758 objectName: "pinPadLoader"
759@@ -145,13 +155,24 @@
760 verticalCenterOffset: root.alphaNumeric ? -units.gu(10) : -units.gu(4)
761 }
762 property bool resetting: false
763+ property bool waiting: false
764+ property bool showWrongText: false
765+
766+ readonly property string forcedDelayText: i18n.tr("Too many incorrect attempts") +
767+ "\n" +
768+ i18n.tr("Please wait")
769
770 source: (!resetting && root.required) ? (root.alphaNumeric ? "PassphraseLockscreen.qml" : "PinLockscreen.qml") : ""
771+ onSourceChanged: {
772+ waiting = false
773+ showWrongText = false
774+ }
775
776 Connections {
777 target: pinPadLoader.item
778
779 onEntered: {
780+ pinPadLoader.waiting = true
781 root.entered(passphrase);
782 }
783
784@@ -173,18 +194,20 @@
785 Binding {
786 target: pinPadLoader.item
787 property: "placeholderText"
788- value: root.placeholderText
789- }
790- Binding {
791- target: pinPadLoader.item
792- property: "wrongPlaceholderText"
793- value: root.wrongPlaceholderText
794+ value: forcedDelayTimer.running ? pinPadLoader.forcedDelayText :
795+ (pinPadLoader.showWrongText ? root.wrongPlaceholderText :
796+ root.placeholderText)
797 }
798 Binding {
799 target: pinPadLoader.item
800 property: "username"
801 value: root.username
802 }
803+ Binding {
804+ target: pinPadLoader.item
805+ property: "entryEnabled"
806+ value: !pinPadLoader.waiting && !forcedDelayTimer.running
807+ }
808 }
809
810 Column {
811
812=== modified file 'qml/Components/PassphraseLockscreen.qml'
813--- qml/Components/PassphraseLockscreen.qml 2014-07-02 18:40:30 +0000
814+++ qml/Components/PassphraseLockscreen.qml 2014-08-14 00:00:43 +0000
815@@ -23,15 +23,14 @@
816 height: highlightItem.height
817
818 property string placeholderText
819- property string wrongPlaceholderText
820 property string username: ""
821+ property bool entryEnabled: true
822
823 signal entered(string passphrase)
824 signal cancel()
825
826 function clear(playAnimation) {
827 pinentryField.text = "";
828- pinentryField.enabled = true
829 if (playAnimation) {
830 wrongPasswordAnimation.start();
831 pinentryField.forceActiveFocus();
832@@ -76,11 +75,11 @@
833 echoMode: TextInput.Password
834 opacity: 0.9
835 hasClearButton: false
836- placeholderText: wrongPasswordAnimation.running ? root.wrongPlaceholderText : root.placeholderText
837+ enabled: entryEnabled
838+ placeholderText: root.placeholderText
839
840 onAccepted: {
841 if (pinentryField.text) {
842- pinentryField.enabled = false;
843 root.entered(pinentryField.text);
844 }
845 }
846
847=== modified file 'qml/Components/PinLockscreen.qml'
848--- qml/Components/PinLockscreen.qml 2014-06-06 11:37:55 +0000
849+++ qml/Components/PinLockscreen.qml 2014-08-14 00:00:43 +0000
850@@ -25,7 +25,6 @@
851 spacing: units.gu(3.5)
852
853 property alias placeholderText: pinentryField.placeholderText
854- property alias wrongPlaceholderText: pinentryField.wrongPlaceholderText
855 property int padWidth: units.gu(34)
856 property int padHeight: units.gu(28)
857 property int minPinLength: -1
858@@ -58,7 +57,6 @@
859 radius: "medium"
860 property string text: ""
861 property string placeholderText: ""
862- property string wrongPlaceholderText: ""
863
864 function appendChar(character) {
865 if (root.maxPinLength == -1 || pinentryField.text.length < root.maxPinLength) {
866@@ -90,9 +88,10 @@
867 id: pinentryFieldPlaceHolder
868 objectName: "pinentryFieldPlaceHolder"
869 anchors.centerIn: parent
870+ horizontalAlignment: Text.AlignHCenter
871 color: "#f3f3e7"
872 opacity: 0.6
873- text: wrongPasswordAnimation.running ? parent.wrongPlaceholderText : parent.placeholderText
874+ text: parent.placeholderText
875 visible: pinentryFieldLabel.text.length == 0
876 }
877
878@@ -107,7 +106,7 @@
879 bottom: parent.bottom
880 bottomMargin: units.gu(1)
881 }
882- visible: !priv.autoConfirm
883+ visible: entryEnabled && !priv.autoConfirm
884 width: height
885 name: "erase"
886 color: "#f3f3e7"
887
888=== modified file 'qml/Notifications/NotificationMenuItemFactory.qml'
889--- qml/Notifications/NotificationMenuItemFactory.qml 2014-07-22 12:13:02 +0000
890+++ qml/Notifications/NotificationMenuItemFactory.qml 2014-08-14 00:00:43 +0000
891@@ -117,7 +117,6 @@
892
893 onEntered: {
894 menuModel.changeState(menuIndex, passphrase);
895- entryEnabled = false;
896 }
897
898 onCancel: {
899
900=== modified file 'qml/Shell.qml'
901--- qml/Shell.qml 2014-08-14 00:00:43 +0000
902+++ qml/Shell.qml 2014-08-14 00:00:43 +0000
903@@ -19,7 +19,9 @@
904 import GSettings 1.0
905 import Unity.Application 0.1
906 import Ubuntu.Components 0.1
907+import Ubuntu.Components.Popups 1.0
908 import Ubuntu.Gestures 0.1
909+import Ubuntu.SystemImage 0.1
910 import Unity.Launcher 0.1
911 import Utils 0.1
912 import LightDM 0.1 as LightDM
913@@ -53,6 +55,10 @@
914 property bool sideStageEnabled: shell.width >= units.gu(100)
915 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
916
917+ property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
918+ property int failedLoginsDelayAttempts: 7 // number of failed logins
919+ property int failedLoginsDelaySeconds: 5 * 60 // seconds of forced waiting
920+
921 function activateApplication(appId) {
922 if (ApplicationManager.findApplication(appId)) {
923 ApplicationManager.requestFocusApplication(appId);
924@@ -255,7 +261,15 @@
925
926 onShowPrompt: {
927 if (greeter.narrowMode) {
928- lockscreen.placeholderText = i18n.tr("Please enter %1").arg(text.toLowerCase());
929+ var promptText = text.toLowerCase()
930+ if (isDefaultPrompt) {
931+ promptText = lockscreen.alphaNumeric ?
932+ i18n.tr("passphrase") : i18n.tr("passcode")
933+ }
934+ lockscreen.placeholderText = i18n.tr("Enter your %1").arg(promptText)
935+ lockscreen.wrongPlaceholderText = i18n.tr("Incorrect %1").arg(promptText) +
936+ "\n" +
937+ i18n.tr("Please re-enter")
938 lockscreen.show();
939 }
940 }
941@@ -270,13 +284,40 @@
942 }
943
944 onAuthenticationComplete: {
945+ if (LightDM.Greeter.authenticated) {
946+ AccountsService.failedLogins = 0
947+ }
948+ // Else only penalize user for a failed login if they actually were
949+ // prompted for a password. We do this below after the promptless
950+ // early exit.
951+
952 if (LightDM.Greeter.promptless) {
953 return;
954 }
955+
956 if (LightDM.Greeter.authenticated) {
957 lockscreen.hide();
958 greeter.login();
959 } else {
960+ AccountsService.failedLogins++
961+ if (maxFailedLogins >= 2) { // require at least a warning
962+ if (AccountsService.failedLogins === maxFailedLogins - 1) {
963+ var title = lockscreen.alphaNumeric ?
964+ i18n.tr("Sorry, incorrect passphrase.") :
965+ i18n.tr("Sorry, incorrect passcode.")
966+ var text = i18n.tr("This will be your last attempt.") + " " +
967+ (lockscreen.alphaNumeric ?
968+ i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
969+ i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."))
970+ lockscreen.showInfoPopup(title, text)
971+ } else if (AccountsService.failedLogins >= maxFailedLogins) {
972+ SystemImage.factoryReset() // Ouch!
973+ }
974+ }
975+ if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
976+ lockscreen.forceDelay(failedLoginsDelaySeconds * 1000)
977+ }
978+
979 lockscreen.clear(true);
980 if (greeter.narrowMode) {
981 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
982@@ -311,6 +352,14 @@
983 }
984
985 property bool fullyShown: showProgress === 1.0
986+ onFullyShownChanged: {
987+ // Wait until the greeter is completely covering lockscreen before resetting it.
988+ if (fullyShown && !LightDM.Greeter.authenticated) {
989+ lockscreen.reset();
990+ lockscreen.show();
991+ }
992+ }
993+
994 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
995 onShowProgressChanged: if (LightDM.Greeter.authenticated && showProgress === 0) greeter.login()
996
997@@ -350,10 +399,6 @@
998 if (greeter.narrowMode) {
999 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
1000 }
1001- if (!LightDM.Greeter.authenticated) {
1002- lockscreen.reset();
1003- lockscreen.show();
1004- }
1005 greeter.fakeActiveForApp = "";
1006 greeter.forceActiveFocus();
1007 }
1008
1009=== modified file 'tests/mocks/AccountsService/AccountsService.cpp'
1010--- tests/mocks/AccountsService/AccountsService.cpp 2014-07-02 16:17:14 +0000
1011+++ tests/mocks/AccountsService/AccountsService.cpp 2014-08-14 00:00:43 +0000
1012@@ -23,7 +23,8 @@
1013 AccountsService::AccountsService(QObject* parent)
1014 : QObject(parent),
1015 m_backgroundFile(qmlDirectory() + "graphics/phone_background.jpg"),
1016- m_statsWelcomeScreen(true)
1017+ m_statsWelcomeScreen(true),
1018+ m_failedLogins(0)
1019 {
1020 }
1021
1022@@ -78,3 +79,14 @@
1023 else
1024 return PasswordDisplayHint::Keyboard;
1025 }
1026+
1027+uint AccountsService::failedLogins() const
1028+{
1029+ return m_failedLogins;
1030+}
1031+
1032+void AccountsService::setFailedLogins(uint failedLogins)
1033+{
1034+ m_failedLogins = failedLogins;
1035+ failedLoginsChanged();
1036+}
1037
1038=== modified file 'tests/mocks/AccountsService/AccountsService.h'
1039--- tests/mocks/AccountsService/AccountsService.h 2014-07-02 16:17:14 +0000
1040+++ tests/mocks/AccountsService/AccountsService.h 2014-08-14 00:00:43 +0000
1041@@ -47,6 +47,10 @@
1042 Q_PROPERTY (PasswordDisplayHint passwordDisplayHint
1043 READ passwordDisplayHint
1044 NOTIFY passwordDisplayHintChanged)
1045+ Q_PROPERTY (uint failedLogins
1046+ READ failedLogins
1047+ WRITE setFailedLogins
1048+ NOTIFY failedLoginsChanged)
1049
1050 public:
1051 enum PasswordDisplayHint {
1052@@ -65,6 +69,8 @@
1053 bool statsWelcomeScreen() const;
1054 void setStatsWelcomeScreen(bool statsWelcomeScreen);
1055 PasswordDisplayHint passwordDisplayHint() const;
1056+ uint failedLogins() const;
1057+ void setFailedLogins(uint failedLogins);
1058
1059 Q_SIGNALS:
1060 void userChanged();
1061@@ -72,11 +78,13 @@
1062 void backgroundFileChanged();
1063 void statsWelcomeScreenChanged();
1064 void passwordDisplayHintChanged();
1065+ void failedLoginsChanged();
1066
1067 private:
1068 QString m_backgroundFile;
1069 QString m_user;
1070 bool m_statsWelcomeScreen;
1071+ uint m_failedLogins;
1072 };
1073
1074 #endif
1075
1076=== modified file 'tests/mocks/LightDM/Greeter.cpp'
1077--- tests/mocks/LightDM/Greeter.cpp 2014-06-11 15:36:51 +0000
1078+++ tests/mocks/LightDM/Greeter.cpp 2014-08-14 00:00:43 +0000
1079@@ -19,6 +19,7 @@
1080 #include "Greeter.h"
1081 #include "GreeterPrivate.h"
1082 #include <QtCore/QCoreApplication>
1083+#include <QTimer>
1084
1085 namespace QLightDM
1086 {
1087@@ -164,4 +165,14 @@
1088 d->handleRespond(response);
1089 }
1090
1091+void Greeter::sendAuthenticationComplete()
1092+{
1093+ if (qgetenv("UNITY_TESTING").isEmpty()) {
1094+ // simulate PAM's delay
1095+ QTimer::singleShot(1000, this, SIGNAL(authenticationComplete()));
1096+ } else {
1097+ Q_EMIT authenticationComplete();
1098+ }
1099+}
1100+
1101 }
1102
1103=== modified file 'tests/mocks/LightDM/Greeter.h'
1104--- tests/mocks/LightDM/Greeter.h 2014-06-11 15:36:51 +0000
1105+++ tests/mocks/LightDM/Greeter.h 2014-08-14 00:00:43 +0000
1106@@ -96,6 +96,9 @@
1107 void authenticationComplete();
1108 void autologinTimerExpired();
1109
1110+protected:
1111+ void sendAuthenticationComplete();
1112+
1113 private:
1114 GreeterPrivate *d_ptr;
1115 Q_DECLARE_PRIVATE(Greeter)
1116
1117=== modified file 'tests/mocks/LightDM/full/GreeterPrivate.cpp'
1118--- tests/mocks/LightDM/full/GreeterPrivate.cpp 2014-07-02 16:17:14 +0000
1119+++ tests/mocks/LightDM/full/GreeterPrivate.cpp 2014-08-14 00:00:43 +0000
1120@@ -54,7 +54,7 @@
1121 authenticated = true;
1122 Q_EMIT q->authenticationComplete();
1123 } else if (authenticationUser == "has-pin"){
1124- Q_EMIT q->showPrompt("Password:", Greeter::PromptTypeSecret);
1125+ Q_EMIT q->showPrompt("Password: ", Greeter::PromptTypeSecret);
1126 } else if (authenticationUser == "auth-error") {
1127 authenticated = false;
1128 Q_EMIT q->authenticationComplete();
1129@@ -78,11 +78,11 @@
1130 Q_EMIT q->showPrompt("otp", Greeter::PromptTypeQuestion);
1131 } else {
1132 authenticated = false;
1133- Q_EMIT q->authenticationComplete();
1134+ q->sendAuthenticationComplete();
1135 }
1136 } else {
1137 authenticated = (response == "otp");
1138- Q_EMIT q->authenticationComplete();
1139+ q->sendAuthenticationComplete();
1140 }
1141 return;
1142 }
1143@@ -92,7 +92,7 @@
1144 } else {
1145 authenticated = (response == "password");
1146 }
1147- Q_EMIT q->authenticationComplete();
1148+ q->sendAuthenticationComplete();
1149 }
1150
1151 }
1152
1153=== modified file 'tests/mocks/LightDM/single-passphrase/GreeterPrivate.cpp'
1154--- tests/mocks/LightDM/single-passphrase/GreeterPrivate.cpp 2013-06-06 12:18:34 +0000
1155+++ tests/mocks/LightDM/single-passphrase/GreeterPrivate.cpp 2014-08-14 00:00:43 +0000
1156@@ -19,8 +19,6 @@
1157 #include "../Greeter.h"
1158 #include "../GreeterPrivate.h"
1159
1160-#include <QDebug>
1161-
1162 namespace QLightDM
1163 {
1164
1165@@ -34,20 +32,15 @@
1166 void GreeterPrivate::handleAuthenticate()
1167 {
1168 Q_Q(Greeter);
1169-
1170- qDebug() << "handleAuthentication called!" << authenticationUser;
1171-
1172- Q_EMIT q->showPrompt("Password:", Greeter::PromptTypeSecret);
1173+ Q_EMIT q->showPrompt("Password: ", Greeter::PromptTypeSecret);
1174 }
1175
1176 void GreeterPrivate::handleRespond(const QString &response)
1177 {
1178 Q_Q(Greeter);
1179
1180-
1181 authenticated = (response == "password");
1182- qDebug() << "responding" << response << authenticated;
1183- Q_EMIT q->authenticationComplete();
1184+ q->sendAuthenticationComplete();
1185 }
1186
1187 }
1188
1189=== modified file 'tests/mocks/LightDM/single-pin/GreeterPrivate.cpp'
1190--- tests/mocks/LightDM/single-pin/GreeterPrivate.cpp 2014-07-02 16:17:14 +0000
1191+++ tests/mocks/LightDM/single-pin/GreeterPrivate.cpp 2014-08-14 00:00:43 +0000
1192@@ -32,14 +32,15 @@
1193 void GreeterPrivate::handleAuthenticate()
1194 {
1195 Q_Q(Greeter);
1196- Q_EMIT q->showPrompt("Password:", Greeter::PromptTypeSecret);
1197+ Q_EMIT q->showPrompt("Password: ", Greeter::PromptTypeSecret);
1198 }
1199
1200 void GreeterPrivate::handleRespond(const QString &response)
1201 {
1202 Q_Q(Greeter);
1203+
1204 authenticated = (response == "1234");
1205- Q_EMIT q->authenticationComplete();
1206+ q->sendAuthenticationComplete();
1207 }
1208
1209 }
1210
1211=== modified file 'tests/mocks/Ubuntu/CMakeLists.txt'
1212--- tests/mocks/Ubuntu/CMakeLists.txt 2014-07-07 08:51:33 +0000
1213+++ tests/mocks/Ubuntu/CMakeLists.txt 2014-08-14 00:00:43 +0000
1214@@ -1,4 +1,5 @@
1215 add_subdirectory(DownloadDaemonListener)
1216 add_subdirectory(Payments)
1217+add_subdirectory(SystemImage)
1218 add_subdirectory(Telephony)
1219 add_subdirectory(Thumbnailer)
1220
1221=== added directory 'tests/mocks/Ubuntu/SystemImage'
1222=== added file 'tests/mocks/Ubuntu/SystemImage/CMakeLists.txt'
1223--- tests/mocks/Ubuntu/SystemImage/CMakeLists.txt 1970-01-01 00:00:00 +0000
1224+++ tests/mocks/Ubuntu/SystemImage/CMakeLists.txt 2014-08-14 00:00:43 +0000
1225@@ -0,0 +1,10 @@
1226+set(MOCK_SYSTEMIMAGE_SOURCES
1227+ plugin.cpp
1228+ MockSystemImage.cpp
1229+)
1230+
1231+add_library(MockSystemImage MODULE ${MOCK_SYSTEMIMAGE_SOURCES})
1232+
1233+qt5_use_modules(MockSystemImage Qml Quick Core)
1234+
1235+add_unity8_mock(Ubuntu.SystemImage 0.1 Ubuntu/SystemImage TARGETS MockSystemImage)
1236
1237=== added file 'tests/mocks/Ubuntu/SystemImage/MockSystemImage.cpp'
1238--- tests/mocks/Ubuntu/SystemImage/MockSystemImage.cpp 1970-01-01 00:00:00 +0000
1239+++ tests/mocks/Ubuntu/SystemImage/MockSystemImage.cpp 2014-08-14 00:00:43 +0000
1240@@ -0,0 +1,27 @@
1241+/*
1242+ * Copyright (C) 2014 Canonical, Ltd.
1243+ *
1244+ * This program is free software; you can redistribute it and/or modify
1245+ * it under the terms of the GNU General Public License as published by
1246+ * the Free Software Foundation; version 3.
1247+ *
1248+ * This program is distributed in the hope that it will be useful,
1249+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1250+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1251+ * GNU General Public License for more details.
1252+ *
1253+ * You should have received a copy of the GNU General Public License
1254+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1255+ */
1256+
1257+#include "MockSystemImage.h"
1258+
1259+MockSystemImage::MockSystemImage(QObject *parent)
1260+ : QObject(parent)
1261+{
1262+}
1263+
1264+void MockSystemImage::factoryReset()
1265+{
1266+ Q_EMIT resettingDevice();
1267+}
1268
1269=== added file 'tests/mocks/Ubuntu/SystemImage/MockSystemImage.h'
1270--- tests/mocks/Ubuntu/SystemImage/MockSystemImage.h 1970-01-01 00:00:00 +0000
1271+++ tests/mocks/Ubuntu/SystemImage/MockSystemImage.h 2014-08-14 00:00:43 +0000
1272@@ -0,0 +1,36 @@
1273+/*
1274+ * Copyright (C) 2014 Canonical, Ltd.
1275+ *
1276+ * This program is free software; you can redistribute it and/or modify
1277+ * it under the terms of the GNU General Public License as published by
1278+ * the Free Software Foundation; version 3.
1279+ *
1280+ * This program is distributed in the hope that it will be useful,
1281+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1282+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1283+ * GNU General Public License for more details.
1284+ *
1285+ * You should have received a copy of the GNU General Public License
1286+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1287+ */
1288+
1289+#ifndef MOCK_SYSTEMIMAGE_H
1290+#define MOCK_SYSTEMIMAGE_H
1291+
1292+#include <QObject>
1293+
1294+class MockSystemImage : public QObject
1295+{
1296+ Q_OBJECT
1297+ Q_DISABLE_COPY(MockSystemImage)
1298+
1299+public:
1300+ explicit MockSystemImage(QObject *parent = 0);
1301+
1302+ Q_INVOKABLE void factoryReset();
1303+
1304+Q_SIGNALS:
1305+ void resettingDevice(); // only for mock
1306+};
1307+
1308+#endif // MOCK_SYSTEMIMAGE_H
1309
1310=== added file 'tests/mocks/Ubuntu/SystemImage/SystemImage.qmltypes'
1311--- tests/mocks/Ubuntu/SystemImage/SystemImage.qmltypes 1970-01-01 00:00:00 +0000
1312+++ tests/mocks/Ubuntu/SystemImage/SystemImage.qmltypes 2014-08-14 00:00:43 +0000
1313@@ -0,0 +1,18 @@
1314+import QtQuick.tooling 1.1
1315+
1316+// This file describes the plugin-supplied types contained in the library.
1317+// It is used for QML tooling purposes only.
1318+//
1319+// This file was auto-generated by:
1320+// 'qmlplugindump -notrelocatable Ubuntu.SystemImage 0.1 plugins'
1321+
1322+Module {
1323+ Component {
1324+ name: "MockSystemImage"
1325+ prototype: "QObject"
1326+ exports: ["Ubuntu.SystemImage/SystemImage 0.1"]
1327+ exportMetaObjectRevisions: [0]
1328+ Signal { name: "resettingDevice" }
1329+ Method { name: "factoryReset" }
1330+ }
1331+}
1332
1333=== added file 'tests/mocks/Ubuntu/SystemImage/plugin.cpp'
1334--- tests/mocks/Ubuntu/SystemImage/plugin.cpp 1970-01-01 00:00:00 +0000
1335+++ tests/mocks/Ubuntu/SystemImage/plugin.cpp 2014-08-14 00:00:43 +0000
1336@@ -0,0 +1,34 @@
1337+/*
1338+ * Copyright (C) 2014 Canonical, Ltd.
1339+ *
1340+ * This program is free software; you can redistribute it and/or modify
1341+ * it under the terms of the GNU General Public License as published by
1342+ * the Free Software Foundation; version 3.
1343+ *
1344+ * This program is distributed in the hope that it will be useful,
1345+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1346+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1347+ * GNU General Public License for more details.
1348+ *
1349+ * You should have received a copy of the GNU General Public License
1350+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1351+ */
1352+
1353+#include "plugin.h"
1354+#include "MockSystemImage.h"
1355+
1356+#include <QtQml>
1357+
1358+static QObject *service_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
1359+{
1360+ Q_UNUSED(engine)
1361+ Q_UNUSED(scriptEngine)
1362+ return new MockSystemImage();
1363+}
1364+
1365+void BackendPlugin::registerTypes(const char *uri)
1366+{
1367+ Q_ASSERT(uri == QLatin1String("Ubuntu.SystemImage"));
1368+
1369+ qmlRegisterSingletonType<MockSystemImage>(uri, 0, 1, "SystemImage", service_provider);
1370+}
1371
1372=== added file 'tests/mocks/Ubuntu/SystemImage/plugin.h'
1373--- tests/mocks/Ubuntu/SystemImage/plugin.h 1970-01-01 00:00:00 +0000
1374+++ tests/mocks/Ubuntu/SystemImage/plugin.h 2014-08-14 00:00:43 +0000
1375@@ -0,0 +1,31 @@
1376+/*
1377+ * Copyright (C) 2014 Canonical, Ltd.
1378+ *
1379+ * This program is free software; you can redistribute it and/or modify
1380+ * it under the terms of the GNU General Public License as published by
1381+ * the Free Software Foundation; version 3.
1382+ *
1383+ * This program is distributed in the hope that it will be useful,
1384+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1385+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1386+ * GNU General Public License for more details.
1387+ *
1388+ * You should have received a copy of the GNU General Public License
1389+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1390+ */
1391+
1392+#ifndef MOCK_SYSTEMIMAGE_PLUGIN_H
1393+#define MOCK_SYSTEMIMAGE_PLUGIN_H
1394+
1395+#include <QQmlExtensionPlugin>
1396+
1397+class BackendPlugin : public QQmlExtensionPlugin
1398+{
1399+ Q_OBJECT
1400+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
1401+
1402+public:
1403+ void registerTypes(const char *uri);
1404+};
1405+
1406+#endif // MOCK_SYSTEMIMAGE_PLUGIN_H
1407
1408=== added file 'tests/mocks/Ubuntu/SystemImage/qmldir'
1409--- tests/mocks/Ubuntu/SystemImage/qmldir 1970-01-01 00:00:00 +0000
1410+++ tests/mocks/Ubuntu/SystemImage/qmldir 2014-08-14 00:00:43 +0000
1411@@ -0,0 +1,3 @@
1412+module Ubuntu.SystemImage
1413+plugin MockSystemImage
1414+typeinfo SystemImage.qmltypes
1415
1416=== modified file 'tests/qmltests/Greeter/tst_Lockscreen.qml'
1417--- tests/qmltests/Greeter/tst_Lockscreen.qml 2014-07-02 16:17:14 +0000
1418+++ tests/qmltests/Greeter/tst_Lockscreen.qml 2014-08-14 00:00:43 +0000
1419@@ -319,11 +319,9 @@
1420 if (data.animation) {
1421 if (data.alphanumeric) {
1422 tryCompare(inputField, "placeholderText", lockscreen.wrongPlaceholderText)
1423- tryCompare(inputField, "placeholderText", lockscreen.placeholderText)
1424 } else {
1425 var label = findChild(lockscreen, "pinentryFieldPlaceHolder");
1426 tryCompare(label, "text", lockscreen.wrongPlaceholderText)
1427- tryCompare(label, "text", lockscreen.placeholderText)
1428 }
1429 }
1430
1431
1432=== modified file 'tests/qmltests/tst_ShellWithPin.qml'
1433--- tests/qmltests/tst_ShellWithPin.qml 2014-08-05 18:18:09 +0000
1434+++ tests/qmltests/tst_ShellWithPin.qml 2014-08-14 00:00:43 +0000
1435@@ -16,8 +16,10 @@
1436
1437 import QtQuick 2.0
1438 import QtTest 1.0
1439+import AccountsService 0.1
1440 import GSettings 1.0
1441 import LightDM 0.1 as LightDM
1442+import Ubuntu.SystemImage 0.1
1443 import Unity.Application 0.1
1444 import Unity.Test 0.1 as UT
1445 import Powerd 0.1
1446@@ -25,6 +27,7 @@
1447 import "../../qml"
1448
1449 Item {
1450+ id: root
1451 width: shell.width
1452 height: shell.height
1453
1454@@ -53,6 +56,12 @@
1455 signalName: "sessionStarted"
1456 }
1457
1458+ SignalSpy {
1459+ id: resetSpy
1460+ target: SystemImage
1461+ signalName: "resettingDevice"
1462+ }
1463+
1464 UT.UnityTestCase {
1465 name: "ShellWithPin"
1466 when: windowShown
1467@@ -64,6 +73,8 @@
1468
1469 function init() {
1470 swipeAwayGreeter()
1471+ shell.failedLoginsDelayAttempts = -1
1472+ shell.maxFailedLogins = -1
1473 }
1474
1475 function cleanup() {
1476@@ -111,6 +122,7 @@
1477 }
1478
1479 function test_login() {
1480+ sessionSpy.clear()
1481 tryCompare(sessionSpy, "count", 0)
1482 enterPin("1234")
1483 tryCompare(sessionSpy, "count", 1)
1484@@ -175,5 +187,49 @@
1485 ApplicationManager.startApplication("gallery-app", ApplicationManager.NoFlag)
1486 tryCompare(lockscreen, "shown", true)
1487 }
1488+
1489+ function test_failedLoginsCount() {
1490+ AccountsService.failedLogins = 0
1491+
1492+ enterPin("1111")
1493+ tryCompare(AccountsService, "failedLogins", 1)
1494+
1495+ enterPin("1234")
1496+ tryCompare(AccountsService, "failedLogins", 0)
1497+ }
1498+
1499+ function test_wrongEntries() {
1500+ shell.failedLoginsDelayAttempts = 3
1501+
1502+ var placeHolder = findChild(shell, "pinentryFieldPlaceHolder")
1503+ tryCompare(placeHolder, "text", "Enter your passcode")
1504+
1505+ enterPin("1111")
1506+ tryCompare(placeHolder, "text", "Incorrect passcode\nPlease re-enter")
1507+
1508+ enterPin("1111")
1509+ tryCompare(placeHolder, "text", "Incorrect passcode\nPlease re-enter")
1510+
1511+ enterPin("1111")
1512+ tryCompare(placeHolder, "text", "Too many incorrect attempts\nPlease wait")
1513+ }
1514+
1515+ function test_factoryReset() {
1516+ shell.maxFailedLogins = 3
1517+ resetSpy.clear()
1518+
1519+ enterPin("1111")
1520+ enterPin("1111")
1521+ tryCompareFunction(function() {return findChild(root, "infoPopup") !== null}, true)
1522+
1523+ var dialog = findChild(root, "infoPopup")
1524+ var button = findChild(dialog, "infoPopupOkButton")
1525+ mouseClick(button, units.gu(1), units.gu(1))
1526+ tryCompareFunction(function() {return findChild(root, "infoPopup")}, null)
1527+
1528+ tryCompare(resetSpy, "count", 0)
1529+ enterPin("1111")
1530+ tryCompare(resetSpy, "count", 1)
1531+ }
1532 }
1533 }

Subscribers

People subscribed via source and target branches