Skip to content

Commit

Permalink
chore(IT Wallet): [SIW-692] Add PIN auth during presentation (#5255)
Browse files Browse the repository at this point in the history
## Short description
This PR adds the PIN authentication while presenting claims. This
happens in two flows:
1. While issuing a credential, when presenting attributes required to
obtain the credential;
2. While presenting a credential.

## List of changes proposed in this pull request
- Introduces a `itwSagaUtils.ts` which contains any generator function
util which is used across sagas and adds a `verifyPin` utility;
- Replace existing pin authentications with `verifyPin`; 
- Adds `verifyPin` during the credential issuing flow and during
presentation flows;

## How to test
1. Obtain a PID. PIN should be asked when storing the PID;
2. Obtain a credential. PIN should be asked when presenting claims
required to obtain the credential and when storing the credential;
3. Present your PID (scan QR code from the RP demo). PIN should be asked
when confirming the presentation;
4. Present your credential (long press on the credential). PIN should be
asked when confirming the presentation.

---------

Co-authored-by: Mario Perrotta <[email protected]>
  • Loading branch information
LazyAfternoons and hevelius authored Nov 24, 2023
1 parent cdc668b commit 0fe3716
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 51 deletions.
29 changes: 6 additions & 23 deletions ts/features/it-wallet/saga/itwPidSaga.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { SagaIterator } from "redux-saga";
import { call, put, select, take, takeLatest } from "typed-redux-saga/macro";
import { call, put, select, takeLatest } from "typed-redux-saga/macro";
import { isSome } from "fp-ts/lib/Option";
import { PID } from "@pagopa/io-react-native-wallet";
import { ActionType, isActionOf } from "typesafe-actions";
import { ActionType } from "typesafe-actions";
import * as O from "fp-ts/lib/Option";
import { CommonActions } from "@react-navigation/native";
import { itwWiaSelector } from "../store/reducers/itwWiaReducer";
import { getPid } from "../utils/pid";
import { ItWalletErrorTypes } from "../utils/errors/itwErrors";
Expand All @@ -13,13 +12,8 @@ import {
itwDecodePid,
itwPid
} from "../store/actions/itwCredentialsActions";
import {
identificationRequest,
identificationSuccess
} from "../../../store/actions/identification";
import NavigationService from "../../../navigation/NavigationService";
import I18n from "../../../i18n";
import { itwLifecycleValid } from "../store/actions/itwLifecycleActions";
import { verifyPin } from "./itwSagaUtils";

/**
* Watcher for the IT wallet PID related sagas.
Expand Down Expand Up @@ -99,22 +93,11 @@ export function* handlePidDecodeRequest(
export function* handleCredentialsAddPid(
action: ActionType<typeof itwCredentialsAddPid.request>
): SagaIterator {
yield* call(verifyPin);
const pid = action.payload;
if (O.isSome(pid)) {
yield* put(
identificationRequest(false, true, undefined, {
label: I18n.t("global.buttons.cancel"),
onCancel: () =>
NavigationService.dispatchNavigationAction(CommonActions.goBack())
})
);

const res = yield* take(identificationSuccess);

if (isActionOf(identificationSuccess, res)) {
yield* put(itwCredentialsAddPid.success(pid.value));
yield* put(itwLifecycleValid());
}
yield* put(itwCredentialsAddPid.success(pid.value));
yield* put(itwLifecycleValid());
} else {
yield* put(
itwCredentialsAddPid.failure({
Expand Down
3 changes: 3 additions & 0 deletions ts/features/it-wallet/saga/itwRpPresentationSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { ItWalletErrorTypes } from "../utils/errors/itwErrors";
import { ItwCredentialsPidSelector } from "../store/reducers/itwCredentialsReducer";
import { ITW_PID_KEY_TAG } from "../utils/pid";
import { itwWiaSelector } from "../store/reducers/itwWiaReducer";
import { verifyPin } from "./itwSagaUtils";

/*
* This saga handles the RP presentation.
Expand All @@ -25,6 +26,8 @@ export function* handleItwRpPresentationSaga(
_: ActionType<typeof itwRpPresentation.request>
): SagaIterator {
try {
yield* call(verifyPin);

// TODO: this claims should be selected by user
const claims = [
"unique_id",
Expand Down
29 changes: 29 additions & 0 deletions ts/features/it-wallet/saga/itwSagaUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { CommonActions } from "@react-navigation/native";
import { isActionOf } from "typesafe-actions";
import { put, take } from "typed-redux-saga/macro";
import NavigationService from "../../../navigation/NavigationService";
import {
identificationRequest,
identificationSuccess
} from "../../../store/actions/identification";
import I18n from "../../../i18n";

/**
* Generator function that handles the PIN verification.
* Throws an error if the identification fails.
*/
export function* verifyPin() {
yield* put(
identificationRequest(false, true, undefined, {
label: I18n.t("global.buttons.cancel"),
onCancel: () =>
NavigationService.dispatchNavigationAction(CommonActions.goBack())
})
);

const res = yield* take(identificationSuccess);

if (!isActionOf(identificationSuccess, res)) {
throw new Error(); // TODO: needs to be mapped to an ITW error type in the future (SIW-713)
}
}
39 changes: 12 additions & 27 deletions ts/features/it-wallet/saga/new/itwIssuanceSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,10 @@ import {
itwIssuanceChecksDataSelector,
itwIssuanceResultDataSelector
} from "../../store/reducers/new/itwIssuanceReducer";
import {
identificationRequest,
identificationSuccess
} from "../../../../store/actions/identification";
import I18n from "../../../../i18n";
import NavigationService from "../../../../navigation/NavigationService";
import ROUTES from "../../../../navigation/routes";
import { verifyPin } from "../itwSagaUtils";

/**
* Watcher for issuance related sagas.
Expand Down Expand Up @@ -115,6 +112,7 @@ export function* handleIssuanceChecks({
*/
export function* handleIssuanceGetCredential(): SagaIterator {
try {
yield* call(verifyPin);
const issuanceData = yield* select(itwIssuanceChecksDataSelector);

if (O.isNone(issuanceData)) {
Expand Down Expand Up @@ -225,32 +223,19 @@ function* handleAddCredentialWithPin() {
if (O.isNone(resultData)) {
throw new Error();
}
yield* put(
identificationRequest(false, true, undefined, {
label: I18n.t("global.buttons.cancel"),
onCancel: () =>
NavigationService.dispatchNavigationAction(CommonActions.goBack())
yield* call(verifyPin);
yield* put(itwCredentialsAddCredential.success(resultData.value));

yield* call(
NavigationService.dispatchNavigationAction,
CommonActions.navigate(ROUTES.MAIN, {
screen: ROUTES.ITWALLET_HOME
})
);

const res = yield* take(identificationSuccess);

if (isActionOf(identificationSuccess, res)) {
yield* put(itwCredentialsAddCredential.success(resultData.value));

yield* call(
NavigationService.dispatchNavigationAction,
CommonActions.navigate(ROUTES.MAIN, {
screen: ROUTES.ITWALLET_HOME
})
);

IOToast.success(
I18n.t(
"features.itWallet.issuing.credentialPreviewScreen.toast.success"
)
);
}
IOToast.success(
I18n.t("features.itWallet.issuing.credentialPreviewScreen.toast.success")
);
} catch (e) {
IOToast.error(
I18n.t("features.itWallet.issuing.credentialPreviewScreen.toast.failure")
Expand Down
4 changes: 3 additions & 1 deletion ts/features/it-wallet/saga/new/itwPresentationSaga.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { SagaIterator } from "redux-saga";
import { put, delay, takeLatest } from "typed-redux-saga/macro";
import { put, delay, takeLatest, call } from "typed-redux-saga/macro";
import {
itwPresentation,
itwPresentationChecks
} from "../../store/actions/new/itwPresentationActions";
import { verifyPin } from "../itwSagaUtils";

export function* watchItwPresentationSaga(): SagaIterator {
yield* takeLatest(itwPresentationChecks.request, itwPresentationChecksSaga);
Expand All @@ -26,6 +27,7 @@ export function* itwPresentationChecksSaga(): SagaIterator {
* action: ActionType<typeof itwPresentation.request>
*/
export function* itwPresentationSaga(): SagaIterator {
yield* call(verifyPin);
yield* delay(1500);
yield* put(itwPresentation.success());
}

0 comments on commit 0fe3716

Please sign in to comment.