2.0.3 • Published 1 year ago

@jolocom/react-native-ausweis v2.0.3

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

@jolocom/react-native-ausweis

Description

A react-native module for the AusweisApp2 SDK. To learn more about AusweisApp2 sdk please refer to its documentation.

The communication with the AusweisApp2 SDK is facillitated by messages and commands. Please refer to AusweisApp2 documentation for the explanation of the commands and messages. Furthermore, you can make use of the example workflows from the documentation, which demonstrate the exchange of commands and messages in different contexts. Currently, only two workflows are supported - AUTH and CHANGE_PIN.

Terminology

Module - React-Native module that wraps around the AusweisApp2 SDK

SDK - AusweisApp2 core functionality that is used in this module


Getting started

Installation

$ yarn add @jolocom/react-native-ausweis

iOS specific

  1. Enable the card identifier in your applications Info.plist. For more details refer to the AusweisApp documentation

    <key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
    <array>
      <string>E80704007F00070302</string>
    </array>
    
    <key>NFCReaderUsageDescription</key>
    <string>AusweisApp2 needs NFC to access the ID card.</string>
  2. in Xcode's Signing & Capabilities tab, make sure Near Field Communication Tag Reading capability had been added. If this is the first time you toggle the capabilities, the Xcode will generate a .entitlement file for you

  3. (from the root of your project)

    `$ cd ios && pod install`
    
     this will trigger automatic linking

    Android specific

    in AndroidManifest.xml

    <uses-permission android:name="android.permission.NFC"/>

    Automatic linking

    (for react-native with version < 0.60.0)

    $ react-native link @jolocom/react-native-ausweis


Usage

Initialization

To start interacting with the SDK, you first need to initialize it

import { aa2Module } from '@jolocom/react-native-ausweis'

if (!aa2Module.isInitialized) {
  try {
    await aa2Module.initAa2Sdk()
  } catch (e) {
    console.error(e)
  }
}

Disconnect

Note: currently it is a noop method

await aa2Module.disconnectAa2Sdk()

Messages

When you send a command to the SDK it will respond with a message (or more).

Below is the list of messages supported by the module.

export enum Messages {
  init = 'INIT',
  apiLevel = 'API_LEVEL',
  badState = 'BAD_STATE',
  info = 'INFO',
  auth = 'AUTH',
  accessRights = 'ACCESS_RIGHTS',
  enterPin = 'ENTER_PIN',
  enterPuk = 'ENTER_PUK',
  enterCan = 'ENTER_CAN',
  insertCard = 'INSERT_CARD',
  certificate = 'CERTIFICATE',
  reader = 'READER',
  enterNewPin = 'ENTER_NEW_PIN',
  changePin = 'CHANGE_PIN',
}

Note, there are differences between how the NFC popup is handled on iOS and Android. On iOS, the NFC popup is managed by the SDK and is shown along with the INSERT_CARD message. However, on Android only the INSERT_CARD message is received, allowing the application to proceed with scanning.

Handlers

Some received messages can be processed with handlers.

Below in the list of available message handlers and their signatures:

type CardInfo = {
  inoperative: boolean
  deactivated: boolean
  retryCounter: number
}

interface EventHandlers {
  handlePinRequest: (cardInfo: CardInfo) => void // msg ENTER_PIN
  handleCanRequest: (cardInfo: CardInfo) => void // msg ENTER_CAN
  handlePukRequest: (cardInfo: CardInfo) => void // msg ENTER_PUK
  handleCardInfo: (cardInfo: CardInfo) => void // msg READER
  handleCardRequest: () => void // msg INSERT_CARD
  handleAuthFailed: (url: string, message: string) => void // msg AUTH (user has cancelled the RUN_AUTH flow or RUN_AUTH flow has failed)
  handleAuthSuccess: (url: string) => void // msg AUTH (successful completion of the RUN_AUTH flow)
  handleEnterNewPin: () => void // msg ENTER_NEW_PIN
  handleChangePinCancel: () => void // msg CHANGE_PIN (success: false)
  handleChangePinSuccess: () => void // msg CHANGE_PIN (success: true)
}

To handle a message sent by the SDK you have to register a message handler.

aa2Module.setHandlers({
  // your handlers
})

For example, to handle the ENTER_PUK message, register its handler as follows:

aa2Module.setHandlers({
  handlePinRequest: (cardInfo: CardInfo) => {
    console.log(cardInfo)
  }
})

Reset handlers with:

aa2Module.resetHandlers()

Events

Similarly to handlers, the user can subscribe to message events. An example can be seen below:

aa2Module.messageEmitter.addListener(Messages.reader, (message: ReaderMessage) => {
   ...
})

Commands

In order to communicate with the SDK, the React-Native application must send commands. As a result, the SDK will respond with messages according to the internal protocol. In case the received message does not satisfy the protocol, the command will reject with the Unknown message type error.

Note that each command returns a Promise, which either rejects or resolves based on the received messages. This may vary from command to command.

Nevertheless, messages can also be handled using the handlers registered with aa2Module.setHandlers(${handlers}). Here is the list of available message handlers.

startAuth

To initiate the AUTH workflow, the module sends the RUN_AUTH command. As a response, the SDK sends both AUTH and ACCESS_RIGHTS messages. The startAuth Promise will be resolved as soon as the ACCESS_RIGHTS message is received.

const tcTokenUrl = "https://test.governikus-eid.de/DEMO"
await aa2Module.startAuth(tcTokenUrl) // send RUN_AUTH cmd

startChangePin

To initiate the CHANGE_PIN workflow, the module sends the RUN_CHANGE_PIN command. As a response, the SDK will send the CHANGE_PIN message with payload: {success: false} if the workflow was interrupted (i.e. by canceling NFC popup on iOS), or the ENTER_PIN/ENTER_CAN/ENTER_PUK messages if the workflow continues.

Initiate the CHANGE_PIN workflow

aa2Module.setHandlers({
  handleCardRequest: () => {
    console.log('show NFC popup on Android')
  }
  handlePinRequest: (cardInfo) => {
    console.log('showing pin input')
  }
})

const message = await aa2Module.startChangePin()

// Sequence of events happening: 
// 1. handler is registered with aa2Module.setHandlers
// 2. sending command aa2Module.startChangePin
// 3. a message is send { msg: "INSERT_CARD" } 
// 4. INSERT_CARD handler runs: console.log('show NFC popup on Android')
// 3. user scans eID card
// 4. a message is send { msg: "ENTER_PIN" } and aa2Module.startChangePin promise is resolved

getCertificate

Note this command is part of the AUTH flow and should be sent only after AUTH workflow was initiated with aa2Module.startAuth(tcTokenUrl)

To get more information about the requester, send the GET_CERTIFICATE command. As a result, it will be resolved with the CERTIFICATE message.

await aa2Module.getCertificate() // send GET_CERTIFICATE cmd

setAccessRights

Note this command is part of the AUTH flow and should be sent only after AUTH workflow was initiated with aa2Module.startAuth(tcTokenUrl)

To select which data should be shared within the AUTH workflow, the SET_ACCESS_RIGHTS command is sent together with the choosen fields. As a response, the SDK will send the ACCESS_RIGHTS message.

const optionalFields = ['Address', 'DateOfBirth']
await aa2Module.setAccessRights(optionalFields) // send GET_CERTIFICATE cmd

acceptAuthRequest

Note this command is part of the AUTH flow and should be sent only after AUTH workflow was initiated with aa2Module.startAuth(tcTokenUrl)

To accept the selected access rights, the SDK sends the "ACCEPT" command. As a response, the SDK will send INSERT_CARD message. If user has scanned eID card successfully, the commands will be resolved with the ENTER_PIN/ENTER_CAN/ENTER_PUK messages. If user has cancelled the NFC popup, an AUTH message will be sent.

Note, canceling the NFC popup on iOS will cancel the workflow. You need to explicitly send the CANCEL command on Android.

// setup handler for the INSERT_CARD message 
aa2Module.setHandlers({
  handleCardRequest: () => {
    console.log('show NFC popup on Android')
  }
})
await aa2Module.acceptAuthRequest()

// Sequence of events happening: 
// 1. handler is registered with aa2Module.setHandlers
// 2. sending command aa2Module.acceptAuthRequest
// 3. a message is send { msg: "INSERT_CARD" } 
// 4. INSERT_CARD handler runs: console.log('show NFC popup on Android')
// 3. user scans eID card
// 4. a message is send { msg: "ENTER_PIN" } and aa2Module.acceptAuthRequest promise is resolved

setPin

As a response to the ENTER_PIN message, the module should send the SET_PIN command (using the setPin method). Afterwards, the SDK can send ENTER_PIN (if the PIN provided doesn't match the one stored on the eID card), ENTER_CAN (if the wrong eID PIN was entered 2 times), ENTER_PUK (if the wrong eID PIN was entered 3 times), ENTER_NEW_PIN (if the corect PIN was entered during the CHANGE_PIN workflow), AUTH (if the AUTH workflow was successfully finished), CHANGE_PIN (if the CHANGE_PIN workflow was finished).

Below is an example of handlers for processing both the wrong PIN and the successful completion of the AUTH workflow.

Note, upon successful completion of AUTH workflow you should send a GET request to url provided as an argument to handleAuthSuccess handler

aa2Module.setHandlers({
  handleCardRequest: () => {
    console.log('show NFC popup on Android')
  },
  handlePinRequest: () => {
    console.log('showing pin again, because wrong pin was entered')
  },
  handleAuthSuccess: (url) => {
    console.log('successful completion of AUTH')
    fetch(url)
  },
})
await aa2Module.setPin('123456') 

// Sequence of events happening: 
// 1. handlers are registered with aa2Module.setHandlers
// 2. sending command aa2Module.setPin
// 3. a message is send { msg: "INSERT_CARD" } 
// 4. INSERT_CARD handler runs: console.log('show NFC popup on Android')
// 3. user scans eID card
// 4. a message is send { msg: "ENTER_PIN" } and aa2Module.setPin promise is resolved
// 5. ENTER-PIN handler runs: console.log('showing pin again, because wrong pin was entered')

Below is the example of interrupting the CHANGE_PIN workflow at the step when the eID pin was requested.

Note, on Android you should send the CANCEL command if you decide to interrupt the workflow.

aa2Module.setHandlers({
  handleCardRequest: () => {
    console.log('NFC popup is shown on iOS')
  },
  handleChangePinCancel: () => {
    console.log('CHANGE_PIN workflow was interrupted')
  },
})
await aa2Module.setPin('123456')

// Sequence of events happening: // 1. handlers are registered with aa2Module.setHandlers // 2. sending command aa2Module.setPin // 3. a message is send { msg: "INSERT_CARD" } // 4. INSERT_CARD handler runs: console.log('NFC popup is shown on iOS') // 3. user presses "cancel" btn on NFC popup // 4. a message is send { msg: "CHANGE_PIN", .success: false } and aa2Module.setPin promise is resolved // 5. handleChangePinCancel handler runs: console.log('CHANGE_PIN workflow was interrupted')

### `setCan`
As a response to the `ENTER_CAN` message, the module should send the `SET_CAN` command. Following, the SDK responds with the `ENTER_PIN` message (if the provided CAN was correct), `ENTER_CAN` (if the provided CAN was incorrect), `AUTH` (if `AUTH` workflow was interrupted), `CHANGE_PIN` (if the `CHANGE_PIN` workflow was interrupted).

Below is an example of providing the wrong CAN
```javascript
aa2Module.setHandlers({
  handleCardRequest: () => {
    console.log('NFC popup is shown on iOS')
  },
  handleCanRequest: () => {
    console.log('wrong CAN')
  },
})
await aa2Module.setCan('123456')

// Sequence of events happening: 
// 1. handlers are registered with aa2Module.setHandlers
// 2. sending command aa2Module.setCan
// 3. a message is send { msg: "INSERT_CARD" } 
// 4. INSERT_CARD handler runs: console.log('NFC popup is shown on iOS')
// 5. user scans eID card
// 6. a message is send { msg: "ENTER_CAN" } and aa2Module.setPin promise is resolved
// 7. handleCanRequest handler runs: console.log('wrong can')

setPuk

As a response to the ENTER_PUK message, the module should send the SET_PUK command. Afterwards, the SDK can send the ENTER_PIN message (if the provided PUK was correct), ENTER_PUK (if the provided PUK was incorrect), AUTH (if the AUTH workflow was interrupted), CHANGE_PIN (if CHANGE_PIN workflow was interrupted).

Note in case the card is blocked, the module will reject with CardError.cardIsBlocked error and handleChangePinCancel and handleAuthFailed will not be called

Below is an example of an attempt to provide the PUK within the CHANGE_PIN workflow but user's card is blocked (used the PUK correctly 10 times).

Note, that the same sequence of messages received will happen if user presses "cancel" on NFC popup on iOS

aa2Module.setHandlers({
  handleCardRequest: () => {
    console.log('NFC popup is shown on iOS')
  }
  handleChangePinCancel: () => {
    console.log('change_pin workflow was interrupted')
  }
})
try {
  await aa2Module.setPuk('1234567890')
} catch(e) {
  console.log('Error', e)
}

// Sequence of events happening: // 1. handlers are registered with aa2Module.setHandlers // 2. sending command aa2Module.setPuk // 3. a message is send { msg: "INSERT_CARD" } // 4. INSERT_CARD handler runs: console.log('NFC popup is shown on iOS') // 5. user scans eID card // 6. a message is send { msg: "CHANGE_PIN", success: false } and aa2Module.setPuk promise is rejected with CardError.cardIsBlocked // 7. handleChangePinCancel won't run !!!

## `setNewPin`
> Note this command is part of the [CHANGE_PIN flow](#startChangePin) and should be sent only after the `CHANGE_PIN` workflow was initiated.

As a response to the `ENTER_NEW_PIN` message, the module should send the `SET_NEW_PIN` command. Afterwards, the SDK will send the `CHANGE_PIN` msg with a (boolean) `success` property.

Completing CHANGE_PIN workflow by setting a new pin
```javascript
aa2Module.setHandlers({
  handleChangePinSuccess: () => {
    console.log('CHANGE_PIN workflow was completed')
  }
})
await aa2Module.setNewPin('123456')

// Sequence of events happening: 
// 1. handlers are registered with aa2Module.setHandlers
// 2. sending command aa2Module.setNewPin
// 3. a message is send { msg: "CHANGE_PIN", success: true } and aa2Module.setNewPin promise is resolved
// 7. handleChangePinSuccess runs: console.log('CHANGE_PIN workflow was completed')

cancelFlow

To cancel the AUTH or CHANGE_PIN flows, send the CANCEL command.

Note that on iOS, pressing the "cancel" button on NFC popup also cancels the active workflow. Sending a CANCEL command while the NFC popup is visible will result in a BAD_STATE message.

As a response, the SDK can send the AUTH (if canceled within the AUTH workflow) or CHANGE_PIN (if cancelled within the CHANGE_PIN workflow) messages.

Canceling the AUTH workflow

aa2Module.setHandlers({
  handleAuthFailed: (url, message) => {
    console.log('AUTH workflow was interrupted')
  }
})
await aa2Module.cancelFlow()

// Sequence of events happening: 
// 1. handlers are registered with aa2Module.setHandlers
// 2. sending command aa2Module.cancelFlow
// 3. a message is send { msg: "AUTH", ...payload } and aa2Module.cancelFlow promise is resolved
// 7. handleAuthFailed runs: console.log('AUTH workflow was interrupted')