Skip to content
This repository has been archived by the owner on Apr 11, 2023. It is now read-only.

Feat: introduce pairing support for protecting against shoulder surfing #35

Merged
merged 82 commits into from
Jun 11, 2021

Conversation

ivard
Copy link
Member

@ivard ivard commented Dec 2, 2020

Fixes #4

Release notes:

In this release, we introduce support for device pairing that can be enabled to prevent QR theft. When enabling this feature, an extra state is added between scanning a IRMA QR code and actually performing the session. In this state, a pairing code is visible in the IRMA app. The user should enter that pairing code in the frontend to continue.

For the following session types it is important that the right user scans the QR, since the session might contain sensitive information.

  • Issuing sessions
  • Disclosing sessions with fixed attribute values (e.g. show that your email address is [email protected])
  • Signing sessions (the message that needs signing might contain sensitive information)

Furthermore, this release includes frontend support for chained sessions.

In order to use device pairing and chained sessions, your IRMA server should have version 0.8.0 or higher.

Global API changes

The changes below concern changes in behaviour of the exported methods of irma-core and irma-frontend.

Added

Changed

  • When your custom plugin returns a value in its close() method, the start() method of irma-core now includes this value in the result on resolve. The exact format of this result can be found here. On Promise rejection, the error value remains unchanged.
  • The abort() method returns a Promise now to indicate when aborting is being processed by the state machine. The plugins may take some extra time to close down, so the Promise from start() and the Promise from abort() may not resolve at the same time.
  • For the state options serverSentEvents and polling of irma-client, the url option has been replaced by endpoint. The new url and legacyUrl options (see above) are used to actually build the URL.

Changes in individual packages

The changes mentioned below are specific changes within individual packages. Changes in the API that concern the functioning of the irma-frontend-packages as a whole can be found in the global API changes section.

TODO: Checken of local links (zoals in 'global API changes section') werken als de daadwerkelijke release wordt aangemaakt op GitHub.

irma-core

These changes are relevant for developers of custom plugins.

Added

  • New states EnterPairingCode and Pairing in the state machine for the new pairing phase.
  • New states PreparingQRCode and PreparingIrmaButton to enable irma-client to correctly configure pairing at the IRMA server.
  • New state PreparingResult to be able to display a loading indicator when the session result is being fetched.
  • There is a new method selectTransition in the state machine to select the transition you want the state machine to do.

Changed

  • The state MediumContemplation has been renamed to CheckingUserAgent, because the responsibility for converting the sessionPtr has been delegated to irma-client / irma-dummy. In the previous implementation irma-core itself was responsible for the transitions in the MediumContemplation state, which was not very clean.
  • The previous states ShowingQRCode and ShowingQRCodeInstead are now merged in one state ShowingQRCode.
  • The close() method of a custom plugin does not necessarily have to return a Promise anymore.
  • The deprecated transition and finalTransition methods (see below) of the state machine return Promises now. This means they are not blocking anymore; you have to explicitly wait for completion. In this way, we can guarantee that the order of state changes is the same for all plugins.
  • When initiating an invalid transition, there is no implicit fallback to fail anymore when the transition is invalid. As developer, you are now responsible yourself to select an alternative. This gives more control over the behaviour of the state machine.

Deprecated

  • The transition and finalTransition methods of the irma-core state machine are deprecated. Please use selectTransition instead.

Removed

  • We fixed the bug that we sometimes miss the appConnected transition in irma-client, so we removed the succeed transition from the ShowingQRCode and ShowingIrmaButton states now. This transition was only there to deal with this bug.
  • Because of the changed behaviour that there is no implicit fallback to fail anymore, we removed the possibility to initiate a fail transition from the Uninitialized state. This transition became superfluous.
  • The getState, isValidTransition and isEndState methods of the state machine are removed. Their return value is not reliable for the selection of a desired transition anymore. You can use selectTransition instead. Below you can find some examples as a guide for refactoring your custom plugin.
// Old
if (this._stateMachine.getState() == 'Uninitialized') this._stateMachine.transition('initialize');
// New
this._stateMachine.selectTransition(
 ({state}) => state == 'Uninitialized' ? { transition: 'initialize' } : false
);

// Old
if (this._stateMachine.isValidTransition('fail')) this._stateMachine.transition('fail');
// New
this._stateMachine.selectTransition(
 ({validTransitions}) => validTransitions.includes('fail') ? { transition: 'fail' } : false
);

// Old
if (!this._stateMachine.isEndState()) this._stateMachine.transition('abort');
// New
this._stateMachine.selectTransition(
 ({inEndState}) => inEndState ? false : { transition: 'abort' }
);

Fixed

  • The order of state changes was not always correct when initiating a new transition from within stateChange.

irma-css

Added

  • Styling for the new state EnterPairingCode.

Changed

  • Loading indicator has been restyled to prevent graphical artifacts in Google Chrome.
  • Buttons have rounded corners now.
  • On all sides, the border of the body of an irma-form has rounded corners now.

irma-client

Added

  • This plugin now initiates the prepareQRCode or the prepareButton transition within the CheckingUserAgent state. Checking the user agent was done by irma-core first, but has been delegated to this plugin now.

Changed

  • The plugin has been updated to deal with the updated irma-core state machine.

Fixed

  • Bug that succeed transition (now prepareResult transition) could already be initiated in the ShowingQRCode and ShowingIrmaButton state.

irma-console

Added

  • Support for entering pairing codes (the EnterPairingCode state)

Changed

  • The plugin has been updated to deal with the updated irma-core state machine.

Fixed

  • Plugin now triggers an error when the state gets changed to ShowingIrmaButton. This state should not happen when using irma-console, since this can only occur on mobile.

irma-web

Added

  • Support for entering pairing codes (the EnterPairingCode state)

Changed

  • The plugin has been updated to deal with the updated irma-core state machine.
  • Being in the Aborted state is mentioned in HTML comments (as already was the case for all other states).
  • In the default locales for Dutch (nl), the line Eén moment alsjeblieft has been replaced by Een moment alstublieft and Open IRMA app is replaced by Open IRMA-app.

irma-popup

On top of the changes mentioned below, the changes in irma-web also apply to this package.

Fixed

  • The pop-up could loose focus, making it possible to control the underlying web page using your keyboard.
  • The close() method of irma-web was not called when closing the pop-up.

irma-dummy

Added

  • This plugin now initiates the prepareQRCode or the prepareButton transition within the CheckingUserAgent state. Checking the user agent was done by irma-core first, but has been delegated to this plugin now.
  • New options for testing the pairing and the mobile flow.
  • New option prepare within the timing options to customize the time that preparing the session and the result should take.

Changed

  • The plugin has been updated to deal with the updated irma-core state machine.

plugins/irma-web/index.js Outdated Show resolved Hide resolved
@ivard ivard marked this pull request as draft December 2, 2020 16:43
@ivard ivard force-pushed the shoulder-surf branch 4 times, most recently from 208d0fa to f799cbb Compare December 11, 2020 18:58
@ivard ivard changed the title WIP: Feat: introduce pairing support for protecting against shoulder surfing Feat: introduce pairing support for protecting against shoulder surfing Dec 14, 2020
@ivard ivard marked this pull request as ready for review December 14, 2020 11:50
irma-core/state-transitions.js Outdated Show resolved Hide resolved
@ivard
Copy link
Member Author

ivard commented Feb 15, 2021

To help understanding the state machine, I made a quick and ugly state machine diagram of the new situation:

irma-core-state-machine (2)

(Edit: I added the pairingRejected transition, which I was forgotten)

@ivard ivard requested a review from leonbotros February 16, 2021 13:50
Copy link

@leonbotros leonbotros left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say this looks good. The new state machine makes sense to me. Your question regarding multiple plugins not just monitoring - but also changing - the state is a tough one. Let me know what you think about the idea I posted there. That way each callback (in this case only stateChange) are then chained in the order of the use calls. But this way any callback needs the next callback as an argument somehow (like middleware). Let me know if that's even feasible.

It's not approved yet because I want to test all plugins.

irma-core/state-machine.js Outdated Show resolved Hide resolved
plugins/irma-client/state-client.js Outdated Show resolved Hide resolved
@leonbotros
Copy link

I see I left some notes double. I thought github would see that... Anyway, I deleted the double comments..

@leonbotros
Copy link

So, I tested the following cases:

  • any app (old/new) + an old irma server that doesn't support pairing.
    Outcome: Frontend requests pairing, but the IRMA server does not give either a frontendAuth or a pairingHint. Frontend and apps skip pairing altogether.

  • an old app + new irma server. Outcome: IRMA server does not output the pairing state during the session because protocol negotiation. Pairing is skipped.

Since the frontend determines if pairing should happen, the case where an old frontend talks with newer servers should not be that interesting.

One little bug I found during testing in an application that re-uses the web-form of irma web for multiple sessions:

  • The text field listener is still registered to the completed session and it tries to transition from the success state once a code meant for the second session is entered.

@ivard
Copy link
Member Author

ivard commented Mar 4, 2021

One little bug I found during testing in an application that re-uses the web-form of irma web for multiple sessions:

  • The text field listener is still registered to the completed session and it tries to transition from the success state once a code meant for the second session is entered.

I'll fix this bug.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Shoulder surfing prevention
4 participants