Commit Graph

159 Commits (master)

Author SHA1 Message Date
Johan Ouwerkerk 98f73c57a5 chore: implement fixes suggested by static analysis
These are potentially blocking the basic QR parsing and versioning features from landing.

See-Also: https://invent.kde.org/utilities/keysmith/-/merge_requests/57
See-Also: https://invent.kde.org/utilities/keysmith/-/merge_requests/58
2020-10-26 18:02:20 +01:00
Johan Ouwerkerk dadd9d3973 chore: implement fixes suggested by static analysis
These are potentially blocking the basic QR parsing feature from landing.

See-Also: https://invent.kde.org/utilities/keysmith/-/merge_requests/57
2020-10-24 18:57:13 +02:00
Johan Ouwerkerk 17cac143fa refactor: use CONSTANT properties instead of a dummy signal 2020-10-22 03:10:27 +00:00
Johan Ouwerkerk f1dbd0c4b7 feat: reduce apparent latency when re-computing tokens by computing the 'next' token in advance.
One downside of offloading the token computation to a worker thread and having to do token decryption is an increase in latency.
For the case with a few accounts this latency does not matter, but in case of many accounts it can induce a significant delay when refreshing tokens in the UI.

To hide this latency, when computing an OTP token for the current state of the account the logical 'next' token is also computed as well and cached in the Account object.
When the next (re)computation of the OTP token is requested, the cached 'next' value is reused if still valid before the next pair of tokens is being computed.
This way the apparent latency of a token update is reduced to an near immediate property update in the UI, hiding the actual latency of the computation itself.

This 'optimisation' is implemented in the dumbest possible fashion that can still work.
This means that the code complexity of the change is quite limited, at the cost of rougly doubling the actual work being performed in the worker thread.
2020-09-16 04:54:15 +00:00
Johan Ouwerkerk 2fcb0938d0 fix: disable visually hidden "add account" action on the accounts overview page
Previously a user could accidentally trigger an additional 'add account' action even when the action (button) was not visible in the UI.
This oversight is now fixed.
2020-09-15 20:41:07 +02:00
Johan Ouwerkerk 1736d6c935 fix: reduce memory consumption by re-using AccountView objects. 2020-08-19 17:25:16 +02:00
Johan Ouwerkerk 46da8be7b3 feat: add support for QML debugging/profiling 2020-08-14 20:02:43 +02:00
Johan Ouwerkerk 9cad36441e refactor: simplify linking of the Keysmith application 2020-08-14 20:02:43 +02:00
Johan Ouwerkerk 035bc8be5c refactor: add a way to set raw counter values on validated input model
This change prepares for applying token details from a otpauth URI (QR code)
2020-08-14 20:02:43 +02:00
Johan Ouwerkerk 4f35d2129e fix: const-correctness when setting secret strings on validated input model 2020-08-14 20:02:43 +02:00
Johan Ouwerkerk fa4f6f651e feat: support configuring remaining TOTP token details
With this change both epoch and hash algoritm may now be configured for TOTP tokens.

Issues: #7
2020-08-08 09:17:55 +02:00
Johan Ouwerkerk e539f2cf22 feat: support configuring remaining HOTP token details
With this change both checksum and custom truncation may now be enabled for HOTP tokens.

Issues: #7
2020-08-08 09:17:55 +02:00
Johan Ouwerkerk 28211b7791 feat: rework token details UX in add account form
- Hide token details by default
 - Only show relevant token details depending on token type

Issues: #7
2020-08-08 09:17:55 +02:00
Johan Ouwerkerk b3984dd054 refactor: prepare code for reworking account details when adding new accounts
- Introduce re-usable account name + issuer form. This will help to support overriding account name/issuer when adding accounts via OTP token URI/QR code
 - Move common settings out of TokenDetailsForm into AddAccount.qml

Issues: #7
2020-08-08 09:17:55 +02:00
Johan Ouwerkerk 668a969d4f refactor: rename unsigned integer parsing function
Make the name for unsigned integer parsing (counter validator) fit better with the new custom datetime validator.
2020-08-08 09:17:55 +02:00
Johan Ouwerkerk 63033b568d refactor: introduce model class to collate validated input from add account forms (flow)
This change prepares the UI for supporting alternative and more complex flows for adding accounts.
All parameters are now collated into a single "validated input" object which is more convenient to pass around between views
This makes it possible to support back- and forth navigation between "basic" and "advanced/details" forms for adding accounts.

Additionally it provides a fundamental building block for adding alternative ways to add accounts (e.g. via OTP token URI/QR code).

Issues: #7
2020-08-08 09:17:55 +02:00
Johan Ouwerkerk 170d7f1811 refactor: introduce custom datetime validator
This change is a preparation for allowing the user to configure custom epochs for TOTP tokens

Issues: #7
2020-08-08 09:17:55 +02:00
Johan Ouwerkerk f632b5ecf3 refactor: extract common fixup() logic for name/issuer validators 2020-08-08 09:17:55 +02:00
Johan Ouwerkerk 09df98d3a4 refactor: prepare AccountStorage for more complex tokens
With this the AccountStorage module now fully supports some HOTP/TOTP parameters which are uncommon (but still part of HOTP/TOTP specifications).

 - Better types for offset, tokenLength. Make this consistent throughout
 - Finish support for offset, checksum parameters for HOTP tokens in AccountStorage
 - Finish support for hashing algorithm, epoch parameters for TOTP tokens in AccountStorage
 - Better API for creating oath::Algorithm instances
 - Code formatting (break up long lines)

Issues: #7
2020-08-08 09:17:55 +02:00
Johan Ouwerkerk 456cd658e5 fix: make sure to actually return a null-valued QVariant() if the role is wrong
Improve the code flow a little while at it.
2020-07-23 18:24:13 +02:00
Johan Ouwerkerk d358d8abcc feat: Support configuring the issuer when adding a new account in Keysmith.
With this change, issuers are now fully supported.

Resolves: #13
2020-07-23 18:24:13 +02:00
Johan Ouwerkerk 0d40912360 feat: Add basic support for account 'issuer' in Keysmith.
With this change account storage and model work with accounts for which an issuer is recorded.
This is a prerequisite for fully supporting otpauth:// URIs (necessary for QR code support) in Keysmith.

Issues: #7, #13
See-Also: https://github.com/google/google-authenticator/wiki/Key-Uri-Format
2020-07-23 18:24:13 +02:00
Johan Ouwerkerk 3f100d4530 Minor code cleanups in src/model 2020-06-11 07:28:16 +00:00
Johan Ouwerkerk 029754b97c Improve the visuals of the health indicator/life timer for TOTP tokens:
- Increase height
 - Make the left edge sit flush with the edge of the list item
 - Fix colour contrast when a list item is being highlighted (pressed/checked)
2020-05-31 16:44:04 +02:00
Johan Ouwerkerk 532f606142 Make sure to sort entries by account (name) in the overview list. 2020-05-31 16:44:04 +02:00
Johan Ouwerkerk 6182d26d6f Fix Android flood fill effect when pressing an account entry.
Turns out that SwipeListItem (and derivatives) absolutely must have an `id` value of `listItem`.
With this change the account list entries now display a proper flood fill effect when pressed on Android.
2020-05-27 23:35:06 +02:00
Johan Ouwerkerk 07108d9be6 Fix text colouring when the SwipeListItem is pressed (or checked).
With this change, the theme's "active text" colour should now be used for the pressed/checked state, resulting in better contrast.
2020-05-27 23:35:06 +02:00
Johan Ouwerkerk 077e0b82d7 Sort of fix broken SwipeListItem's on Android by setting an implicit height.
Also fix positioning of the health indicator rectangle (should be based off of the root SwipeListItem geometry).
2020-05-27 23:35:06 +02:00
Johan Ouwerkerk 2281b5a6e9 Fix stale UI when the app is resumed from suspend.
In some cases Keysmith may be suspended and animations/timers are no longer updated.
With this change, the application now detects when it is being 'woken' from suspend and refreshes the UI.
2020-05-26 21:29:42 +02:00
Johan Ouwerkerk d9d110ed96 Sort of fix labels running off the ends of pages and being clipped.
Simply impose a max width and enable word wrapping to get labels to trade width for height.
2020-05-26 21:25:52 +02:00
Johan Ouwerkerk 598d536d3c Make sure to install libsodium when built as an external project. 2020-05-25 20:31:41 +02:00
Johan Ouwerkerk db41697dbf Build libsodium as a CMake external project 2020-05-15 17:54:37 +02:00
Johan Ouwerkerk bf67a42cb1 Rework account entry list delegate QML
- Refactor code to have delegates per account-type & simplify code
 - Rework layouting in terms of anchors
 - Fix positioning of account name and token labels to be vertically
   centered
 - Make health indicator/token life timer for TOTP accounts sit flush
   with the bottom of the TOTP delegate UI itself and extend along the
   whole width. This resolves issue #11
2020-04-30 17:08:45 +02:00
Johan Ouwerkerk 24de2abacf Add inline error message for account storage errors
Show an inline error message when an error occurs while loading or
otherwise manipulating the account storage.
2020-04-24 18:05:05 +02:00
Johan Ouwerkerk f83b77eee8 Add loaded/error properties to account list model
This change provides a property API on top of the low level state tracking
performed in AccountStorage.
2020-04-24 18:05:05 +02:00
Johan Ouwerkerk b70feaf620 Track loaded/error state of AccountStorage objects
Two bits of boolean state are introduces to track whether or not:

 - an error has occurred
 - accounts have been loaded from storage yet

This change paves the way for having error handling UX.
2020-04-24 18:05:05 +02:00
Johan Ouwerkerk 035348caa5 Implement encryption/decryption of token secrets
With this change token secrets are encrypted prior to writing them to
storage, and decrypted as and when needed to generate tokens. Additional
validation is performed to verify that token secrets can be decrypted
successfully when loading accounts from storage.

With this change issue #6 should finally be resolved.
2020-04-24 18:01:34 +02:00
Johan Ouwerkerk d048adf921 UI/UX to ask for the accounts password on start up
With this change Keysmith now prompts the user to either:

 - setup a new password
 - supply an existing password (if detected)

Additionally the organisation/structure of the QML is cleaned up a bit.
All QML pages are dedicated QML files and a few signals are introduced
to provide slightly better encapsulation/decouple interdependencies.
2020-04-23 19:00:36 +02:00
Johan Ouwerkerk f16eba4505 Plumbing for asking for passwords from QML
This change introduces a model to signal the UI what password "scenario" is
applicable and provides the necessary plumbing to expose it QML.
2020-04-23 18:59:17 +02:00
Johan Ouwerkerk 4d966c3926 Add support for a master key in account storage
With this change an unlock stage is introduced to loading account storage.
Key derivation parameters for a master key are recorded, and the master
password may be supplied to "unlock" the account secret(s) in storage.

This change paves the way for actually decrypting encrypted account
secrets later, and finally solving issue #6.
2020-04-23 18:59:17 +02:00
Johan Ouwerkerk a9ed1507b2 Add support for encrypting/decrypting token secrets
Introduce a secrets library which implements the necessary crypto using
libsodium. This change provides the basic building blocks for resolving
issue #6.
2020-04-23 18:59:17 +02:00
Johan Ouwerkerk dca55eee4b Ask for confirmation before removing accounts
This change provides a modal dialog to prompt for confirmation when the
user clicks the delete button.
2020-04-23 18:55:13 +02:00
Johan Ouwerkerk f4bacefb10 Remove unused QtDebug header 2020-04-19 19:59:24 +02:00
Johan Ouwerkerk f04b15340f Fix TODO items about logging for C++ code 2020-04-14 19:45:29 +02:00
Johan Ouwerkerk b4dada08d8 Add convenient macros to set up logging for Keymsith 2020-04-14 19:39:13 +02:00
Johan Ouwerkerk ecf3476faa Fix up outdated token length validation
Keysmith can generate up to 10 digit HOTP/TOTP tokens and with this change
token length validation also permits it.
2020-04-11 21:46:19 +02:00
Johan Ouwerkerk 567d9c3c97 Do not reuse QML account entry UI delegates.
Delegate recycling causes a bug when removing an account and then adding
it back: the old, stale UI for the account is reused instead of a new one.

In combination with 'alive' guard property on the UI for account entries,
this results in the account entry becoming frozen in the old stale state.
(Incorrect helath indicators, tokens that do not update and buttons that no
longer respond anymore.)
2020-04-10 14:11:12 +02:00
Johan Ouwerkerk 438e341000 Avoid operations on a possibly expired account object.
After triggering the removal of an account from storage in the UI, it may
be possible for the UI not to fully reflect this change for a while yet.
During this short time window, it is possible for an operation to occur on
an already deleted account object which is a use-after-free bug.

In particular signals from animations and timers in the QML UI might still
trigger which causes a slot to be invoked that accesses the underlying
account object.

This change introduces a guard property called 'alive' which is flipped
when the account removal operation is triggered. Slots are updated to
check for the alive status of the UI before proceeding with other logic.
2020-04-10 14:10:47 +02:00
Johan Ouwerkerk b451bd2556 Fix up licensing for REUSE compliance.
This adds licensing and copyright information where missing and normalises
existing licensing/copyright statements to SPDX metadata tags.
2020-04-10 13:34:31 +02:00
Johan Ouwerkerk 41d94024c2 Add basic clipboard support for copying tokens 2020-04-04 11:35:43 +02:00
Johan Ouwerkerk 1a1c531dd3 Boyscout: fix a few compiler warnings about unused variables 2020-04-04 11:25:37 +02:00
Johan Ouwerkerk a23e5473a6 UI updates: prevent "invalid" accounts, better secret UI.
With this change the "Add" button in the "Add account" page is not enabled
until the entered account name and details are valid. Additionally, the UI
for entering the token secret now uses a password field with appropriate
hints for input methods.
2020-04-04 11:24:26 +02:00
Johan Ouwerkerk 768ccdba97 Refactor and update input validation
This change fixes input validation for the following cases:

 - Check that entered account names are still available
 - Working validation for time steps (input mask was completely broken)
 - Allow longer tokens: liboath is no longer used, Keysmith can handle it

Additionally the QML code is refactored significantly:

 - Extracted the main accounts overview page
 - Extracted the add an account page
 - Completed the internal renaming of "Oath" to "Keysmith" for QML types
2020-04-04 11:22:15 +02:00
Johan Ouwerkerk 2a9c80fff5 Add a custom validator that checks if the name is still available. 2020-04-04 10:51:39 +02:00
Johan Ouwerkerk 28454721df Do not fix up input during validation
This change is a workaround for behaviour of QML controls: when fixup is
called during input validation, the `acceptableInput` property is not
updated correctly.
2020-04-04 10:50:52 +02:00
Johan Ouwerkerk 19f457960e Fixup: comment about minimum HOTP token lengths. 2020-02-18 19:53:09 +01:00
Johan Ouwerkerk 8b3fd592b7 Fix: always call endGroup()
Make sure to call endGroup() even if the account is rejected before
moving on to examine the next (possible) account.
2020-02-18 19:49:45 +01:00
Johan Ouwerkerk 6a06a2f5f0 Fixup HMAC key size sanity checking.
Key lengths should be checked against the output size of the hashing
algorithm (instead of block size, which was used previously).
2020-02-17 07:08:09 +00:00
Yuri Chornoivan 112b4bdf8b Fix minor typos 2020-02-13 20:27:57 +02:00
Nicolas Fella ce1b5e8db4 [android] bundle icons 2020-02-12 22:18:26 +01:00
Johan Ouwerkerk 0cc2fbc98e Fixup: signedness in comparison. 2020-02-08 17:10:17 +01:00
Johan Ouwerkerk e5929e7dd5 Fixups for the flatpak build 2020-02-08 16:54:52 +01:00
Johan Ouwerkerk 8bd765e385 Remove the dependency on oath-toolkit.
This resolves issue #9.
2020-02-08 14:46:55 +01:00
Johan Ouwerkerk f950526f8b Port HOTP/TOTP algorithms away from oath-toolkit. 2020-02-08 14:46:55 +01:00
Johan Ouwerkerk 8729b92b8b Provide a custom HOTP/TOTP primitives.
Provides a building block for re-implementing the HOTP/TOTP algorithms
without using oath-toolkit: see issue #9.
2020-02-08 14:46:55 +01:00
Johan Ouwerkerk 2fe3eb8083 Provide a custom HMAC implementation
Provide a building block towards re-implementing the HOTP/TOTP
algorithms without using oath-toolkit: see issue #9.

The hmac::compute function trades simplicity (having to pre-allocate
a scratch buffer) for avoding accidental leaks of key material
(security).

This particular trade-off will help with resolving issue #6.
2020-02-08 14:21:45 +01:00
Johan Ouwerkerk 26d6d62cbe Validate that an account secret is valid base32. 2020-02-08 14:21:45 +01:00
Johan Ouwerkerk ea81dafb8e Port base32 decoding away from liboath
Provide a custom base32 implementation; relates to issues: #9 and #6.

In particular being able to control memory allocation prior to
decoding base32 will help with resolving issue #6 in a (more) secure
fashion.
2020-02-08 14:21:45 +01:00
Johan Ouwerkerk 771ebccab5 Fixup reference error 2020-01-29 19:40:01 +01:00
Johan Ouwerkerk 6ae5f7be21 Rework main page UX:
- Get rid of cards in favour of a more plain list view
 - Implement removing (deleting) accounts
2020-01-28 17:56:39 +01:00
Johan Ouwerkerk a0caf83da2 Use the new Account models.
Drop the AccountDetailsPage instead of trying to update it: see issue #7

With this change issue #2 should be fixed
2020-01-28 06:49:06 +00:00
Johan Ouwerkerk 1f15fb6e08 Introduce an 'application context' (sub)module for Keysmtih.
This module is meant to simplify consumption of various Keysmith objects in QML by not having to expose/manage all C++ dependencies.
2020-01-28 06:49:06 +00:00
Johan Ouwerkerk a813810dfe Rewrite Account model(s) as a separate (sub)module within Keysmith, layered on top of the new Account (storage) module.
This fixes the model part in issue #2
2020-01-28 06:49:06 +00:00
Johan Ouwerkerk 0d5b792637 Rewrite Account (storage) management as a separate (sub)module within Keysmtih
This provides the ground work to finally fix issue #2
2020-01-28 06:49:06 +00:00
Johan Ouwerkerk 40a5491026 Remove application title property binding: it is redundant and causes QML warnings at runtime. 2019-12-31 18:20:58 +01:00
Bhushan Shah 78240a9efb
Rename binary to keysmith
org.kde prefix is definitely unusual so get rid of it.
2019-12-31 20:04:35 +05:30
Bhushan Shah f4264b9c8c app: add i18n support 2019-12-31 19:34:33 +05:30
Johan Ouwerkerk a5794e02da Refactor: turn the base32 wrapper into a static library
This library is meant for private use by Keysmith, to simplify linking to the base32 functionality in CMake files.
2019-12-28 06:40:31 +00:00
Yuri Chornoivan 38bb10de49 Fix minor typos 2019-12-18 18:49:58 +02:00
Friedrich W. H. Kossebau 7daddb524c Cleanup CMakeLists.txt a bit
* do cmake_minimum_required as first thing, as recommended
* bump KF to 5.37, first release with Kirigami (Qt 5.7 matching min dep)
* use KF5_MIN_VERSION also with ECM
* include KDE CMake settings as first
* remove unused cmake includes
* remove duplicated enable_testing()
* use correct KDEInstallDirs variables
2019-12-18 17:29:13 +01:00
Johan Ouwerkerk e6a53b6f3b Rebrand otpclient as Keysmith 2019-10-21 19:16:51 +02:00
Johan Ouwerkerk 4d7bf2f975 Add a rudimentary details page for accounts and wire up navigation to/from it.
The account details page has a kind of modality:

 - hide mode: in which the user is shown the account info but sensitive information such as secret keys should not be displayed openly visible.
 - show mode: the same, but in this case all details are openly visible. This will be useful for showing QR codes explicitly.
 - edit mode: in which the user may edit account details (all except the name).
2019-10-20 14:09:39 +02:00
Johan Ouwerkerk c64273355a Refactor: extract the token details form UI to its own re-usable component. 2019-10-20 14:09:39 +02:00
Johan Ouwerkerk ba4d370ee6 Refactor: prefer Q_ENUM for declaring C++ enums to the Qt meta type system 2019-10-20 14:09:39 +02:00
Johan Ouwerkerk 3734e908a9 Hide main 'Add' action if the add account form is already opened.
In this way we can avoid the confusing situation with multiple add account forms open by mistake.
2019-10-20 14:06:22 +02:00
Johan Ouwerkerk 042b51d183 Use the unsigned long long validator for the HOTP counter input field in the QML UI. 2019-10-02 21:56:58 +02:00
Johan Ouwerkerk 543766b819 Introduce a validator for the HOTP counter field. 2019-10-02 21:56:58 +02:00
Johan Ouwerkerk f0b5f8121f Refactor: extract strip_spaces() utility function. 2019-10-02 21:34:33 +02:00
Johan Ouwerkerk 668e912dfe Apply the name validator to the account name input field in the QML UI. 2019-09-30 20:25:56 +02:00
Johan Ouwerkerk 3bc3a14575 Introduce a validator for name input fields (account name). 2019-09-30 20:25:56 +02:00
Johan Ouwerkerk 73acbb68ae Add the new base32 secret validator to the UI: attach it to the secret input field. 2019-09-29 12:57:07 +02:00
Johan Ouwerkerk b791bbad45 Add QML bindings for custom validators
- Add convenience function to set up QML bindings under the Oath.Validators namespace
 - Wire up the validator library in the otpclient application
2019-09-29 12:53:49 +02:00
Johan Ouwerkerk eeeac7511c Introduce a custom base32 secret validator to perform input validation.
- Add a new static library "validator_lib" covering the "validators" namespace in C++
 - Introduce the Base32Validator to perform input field validation with fixup support
2019-09-29 12:48:25 +02:00
Johan Ouwerkerk c37bf03b8e Fix typo: OAth -> Oath (the name is oath or OATH). 2019-09-29 12:40:22 +02:00
Johan Ouwerkerk 8d40008201 Use a SpinBox for more appropriate UI/UX when entering token lengths
Due to our use of liboath for generating the actual tokens, we also support only a limited range of valid token lengths.
This means that it is more user friendly to express those limits  directly in the UI through a SpinBox instead of allowing the user type in values we do not currently support.
2019-09-28 00:22:55 +02:00
Johan Ouwerkerk 29e9348097 Modernise AccountModel C++ code a bit 2019-09-25 15:38:25 +02:00
Johan Ouwerkerk 8b03fe5123 Modernise Account C++ code a bit 2019-09-25 14:40:53 +02:00
Johan Ouwerkerk 4cff5519ed Automatically show the "add OTP" form when there are no OTP tokens yet on start up.
This is a small UX improvement to make it a little easier to get started with the app.
2019-09-25 11:17:48 +02:00
Johan Ouwerkerk 3a4df16a1c Make the 'clock' an injectable dependency via the Account constructor.
In this way we can fake the current date/time during tests, making it possible to reliably test TOTP and derivative type tokens.
2019-09-11 09:40:44 +02:00
Johan Ouwerkerk 750025f05c Fixup Account to make sure all HOTP/TOTP algorithm properties are properly initialised by the constructor. 2019-09-11 09:40:44 +02:00