Skip to content

Commit

Permalink
feat(IT Wallet): [SIW-482] Update io-react-native-wallet version (#…
Browse files Browse the repository at this point in the history
…5031)

## Short description
This PR update the package `io-react-native-wallet` version and related
dependencies. This update resulted in a refactor on some redux-saga.

## List of changes proposed in this pull request
- Update pid, rp and wia saga

## How to test
Start the app with prod env and try all the use cases

Co-authored-by: LazyAfternoons <LazyAfternoons@users.noreply.github.com>
  • Loading branch information
hevelius and LazyAfternoons committed Sep 27, 2023
1 parent 7f38620 commit 59a420b
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 164 deletions.
2 changes: 1 addition & 1 deletion .env.local
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,4 @@ IT_WALLET_EXPERIMENTAL_ENABLED=YES
# IT-WALLET WIA URL
IT_WALLET_WP_URL='https://io-d-wallet-it.azurewebsites.net'
# IT-WALLET PID PROVIDER URL
IT_WALLET_PID_PROVIDER_URL='https://api.eudi-wallet-it-pid-provider.it'
IT_WALLET_PID_PROVIDER_URL='https://api.eudi-wallet-it-pid-provider.it/ci'
2 changes: 1 addition & 1 deletion .env.production
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,4 @@ IT_WALLET_EXPERIMENTAL_ENABLED=YES
# IT-WALLET WIA URL
IT_WALLET_WP_URL='https://io-d-wallet-it.azurewebsites.net'
# IT-WALLET PID PROVIDER URL
IT_WALLET_PID_PROVIDER_URL='https://api.eudi-wallet-it-pid-provider.it'
IT_WALLET_PID_PROVIDER_URL='https://api.eudi-wallet-it-pid-provider.it/ci'
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,9 @@
"@pagopa/io-pagopa-commons": "^3.1.0",
"@pagopa/io-react-native-cie-pid": "^0.1.3",
"@pagopa/io-react-native-crypto": "^0.2.1",
"@pagopa/io-react-native-jwt": "0.6.4",
"@pagopa/io-react-native-jwt": "1.0.0",
"@pagopa/io-react-native-login-utils": "^0.2.0",
"@pagopa/io-react-native-wallet": "0.4.3",
"@pagopa/io-react-native-wallet": "0.5.0",
"@pagopa/react-native-cie": "1.2.0",
"@pagopa/ts-commons": "^10.15.0",
"@react-native-async-storage/async-storage": "^1.17.10",
Expand Down
52 changes: 18 additions & 34 deletions ts/features/it-wallet/saga/itwRpInitializationSaga.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import { SagaIterator } from "redux-saga";
import { apply, call, put, select, take } from "typed-redux-saga/macro";
import { sign } from "@pagopa/io-react-native-crypto";
import { SignJWT } from "@pagopa/io-react-native-jwt";
import { ActionType, getType } from "typesafe-actions";
import { call, put, take } from "typed-redux-saga/macro";
import { ActionType } from "typesafe-actions";
import {
RelyingPartySolution,
WalletInstanceAttestation
createCryptoContextFor
} from "@pagopa/io-react-native-wallet";
import { itwRpInitialization } from "../store/actions/itwRpActions";
import { ItWalletErrorTypes } from "../utils/errors/itwErrors";
import { ITW_WIA_KEY_TAG } from "../utils/wia";
import { itwDecodePid } from "../store/actions/itwCredentialsActions";
import { itwWiaRequest } from "../store/actions/itwWiaActions";
import { ItwCredentialsPidSelector } from "../store/reducers/itwCredentialsReducer";

/*
* This saga handles the RP initialization.
Expand All @@ -23,40 +19,28 @@ export function* handleItwRpInitializationSaga(
): SagaIterator {
try {
const { authReqUrl, clientId } = action.payload;

// Get WIA
yield* put(itwWiaRequest.request());
const wia = yield* take(itwWiaRequest.success);

// Decode PID
const pid = yield* select(ItwCredentialsPidSelector);
yield* put(itwDecodePid.request(pid));
const decodedRes = yield* take<
ActionType<typeof itwDecodePid.success | typeof itwDecodePid.failure>
>([itwDecodePid.success, itwDecodePid.failure]);
if (decodedRes.type === getType(itwDecodePid.failure)) {
throw new Error(); // TODO: Better error mapping
}
const decodedWIA = yield* call(
WalletInstanceAttestation.decode,
wia.payload
);
const RP = new RelyingPartySolution(clientId, wia.payload);
const unsignedDPoP = yield* apply(RP, RP.getUnsignedWalletInstanceDPoP, [
decodedWIA.payload.cnf.jwk,
authReqUrl
]);
const signedDPoP = yield* call(sign, unsignedDPoP, ITW_WIA_KEY_TAG);
const entity = yield* apply(RP, RP.getEntityConfiguration, []);
const signedPayload = yield* call(
SignJWT.appendSignature,
unsignedDPoP,
signedDPoP
// Create crypto context
const wiaCryptoContext = createCryptoContextFor(ITW_WIA_KEY_TAG);

// Get entity configuration for RP
const entity = yield* call(
RelyingPartySolution.getEntityConfiguration(),
clientId
);
const requestObject = yield* apply(RP, RP.getRequestObject, [
signedPayload,

// Get request object configuration
const requestObject = yield* call(
RelyingPartySolution.getRequestObject({ wiaCryptoContext }),
wia.payload,
authReqUrl,
entity
]);
);

yield* put(itwRpInitialization.success({ requestObject, entity }));
} catch (e) {
yield* put(
Expand Down
72 changes: 24 additions & 48 deletions ts/features/it-wallet/saga/itwRpPresentationSaga.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { SagaIterator } from "redux-saga";
import { apply, call, put, select, take } from "typed-redux-saga/macro";
import { sign } from "@pagopa/io-react-native-crypto";
import { SignJWT } from "@pagopa/io-react-native-jwt";
import { call, put, select } from "typed-redux-saga/macro";
import * as O from "fp-ts/lib/Option";
import { ActionType } from "typesafe-actions";
import {
RelyingPartySolution,
WalletInstanceAttestation
createCryptoContextFor
} from "@pagopa/io-react-native-wallet";

import {
Expand All @@ -15,21 +13,17 @@ import {
} from "../store/reducers/itwRpInitializationReducer";
import { itwRpPresentation } from "../store/actions/itwRpActions";
import { ItWalletErrorTypes } from "../utils/errors/itwErrors";
import { ITW_WIA_KEY_TAG } from "../utils/wia";
import { ItwCredentialsPidSelector } from "../store/reducers/itwCredentialsReducer";
import { itwWiaRequest } from "../store/actions/itwWiaActions";
import { ITW_PID_KEY_TAG } from "../utils/pid";

/*
* This saga handles the RP presentation.
* It calls the sendAuthorizationResponse method of the RP solution
* to send the VP token to the RP
*/
export function* handleItwRpPresentationSaga(
action: ActionType<typeof itwRpPresentation.request>
_: ActionType<typeof itwRpPresentation.request>
): SagaIterator {
try {
const { authReqUrl } = action.payload;

// TODO: this claims should be selected by user
const claims = [
"unique_id",
Expand All @@ -41,56 +35,38 @@ export function* handleItwRpPresentationSaga(
"evidence"
];

const requestObject = yield* select(
const requestObjectValue = yield* select(
itwRpInitializationRequestObjectValueSelector
);
const pidToken = yield* select(ItwCredentialsPidSelector);

// Get WIA
yield* put(itwWiaRequest.request());
const wia = yield* take(itwWiaRequest.success);

if (O.isNone(requestObject) || O.isNone(pidToken)) {
if (O.isNone(requestObjectValue) || O.isNone(pidToken)) {
throw new Error("Request object is not defined");
} else {
const RP = new RelyingPartySolution(authReqUrl, wia.payload);
const decodedWia = yield* call(
WalletInstanceAttestation.decode,
wia.payload
);

const walletInstanceId = new URL(
"instance/" + decodedWia.payload.sub,
decodedWia.payload.iss
).href;

const { vp_token: unsignedVpToken, presentation_submission } =
yield* apply(RP, RP.prepareVpToken, [
requestObject.value,
walletInstanceId,
[pidToken.value.credential, claims],
decodedWia.payload.cnf.jwk.kid
]);

const signature = yield* call(sign, unsignedVpToken, ITW_WIA_KEY_TAG);
const vpToken = yield* call(
SignJWT.appendSignature,
unsignedVpToken,
signature
);

// Create PID crypto context
const pidCryptoContext = createCryptoContextFor(ITW_PID_KEY_TAG);
// Retrieve entity configuration for RP
const entity = yield* select(itwRpInitializationEntityValueSelector);

if (O.isNone(entity)) {
throw new Error("Entity is not defined");
} else {
const {
requestObject,
rpEntityConfiguration,
walletInstanceAttestation
} = requestObjectValue.value;

// Submit authorization response
const result = yield* apply(RP, RP.sendAuthorizationResponse, [
requestObject.value,
vpToken,
presentation_submission,
entity.value
]);
const result = yield* call(
RelyingPartySolution.sendAuthorizationResponse({ pidCryptoContext }),
{
requestObject,
rpEntityConfiguration,
walletInstanceAttestation
},
[pidToken.value.credential, claims]
);

yield* put(itwRpPresentation.success(result));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { PidResponse } from "@pagopa/io-react-native-wallet/lib/typescript/pid/issuing";
import { ActionType, createAsyncAction } from "typesafe-actions";
import { PidWithToken } from "@pagopa/io-react-native-wallet/lib/typescript/pid/sd-jwt";
import { PidData } from "@pagopa/io-react-native-cie-pid";
import * as O from "fp-ts/lib/Option";
import { PidResponse } from "@pagopa/io-react-native-wallet/lib/typescript/pid/issuing";
import { ItWalletError } from "../../utils/errors/itwErrors";

/**
Expand Down
8 changes: 3 additions & 5 deletions ts/features/it-wallet/store/actions/itwRpActions.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { ActionType, createAsyncAction } from "typesafe-actions";
import {
RequestObject,
RpEntityConfiguration
} from "@pagopa/io-react-native-wallet/lib/typescript/rp/types";
import { RpEntityConfiguration } from "@pagopa/io-react-native-wallet/lib/typescript/rp/types";
import { RequestObjectConf } from "@pagopa/io-react-native-wallet/lib/typescript/rp";
import { ItWalletError } from "../../utils/errors/itwErrors";

/**
Expand All @@ -14,7 +12,7 @@ export const itwRpInitialization = createAsyncAction(
"ITW_RP_INITIALIZATION_FAILURE"
)<
{ authReqUrl: string; clientId: string },
{ requestObject: RequestObject; entity: RpEntityConfiguration },
{ requestObject: RequestObjectConf; entity: RpEntityConfiguration },
ItWalletError
>();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { getType } from "typesafe-actions";
import * as pot from "@pagopa/ts-commons/lib/pot";
import * as O from "fp-ts/lib/Option";
import {
RequestObject,
RpEntityConfiguration
} from "@pagopa/io-react-native-wallet/lib/typescript/rp/types";
import { RpEntityConfiguration } from "@pagopa/io-react-native-wallet/lib/typescript/rp/types";
import { RequestObjectConf } from "@pagopa/io-react-native-wallet/lib/typescript/rp";
import { Action } from "../../../../store/actions/types";
import { ItWalletError } from "../../utils/errors/itwErrors";
import { GlobalState } from "../../../../store/reducers/types";
import { itwRpInitialization } from "../actions/itwRpActions";

export type ItwRpInitializationType = {
requestObject: O.Option<RequestObject>;
requestObject: O.Option<RequestObjectConf>;
entity: O.Option<RpEntityConfiguration>;
};

Expand Down
72 changes: 24 additions & 48 deletions ts/features/it-wallet/utils/pid.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { thumbprint } from "@pagopa/io-react-native-jwt";
import { PID } from "@pagopa/io-react-native-wallet";
import { getPublicKey, sign } from "@pagopa/io-react-native-crypto";
import { PID, createCryptoContextFor } from "@pagopa/io-react-native-wallet";
import { PidData } from "@pagopa/io-react-native-cie-pid";
import { walletPidProviderUrl, walletProviderUrl } from "../../../config";
import { ITW_WIA_KEY_TAG } from "./wia";
Expand All @@ -17,54 +15,32 @@ export const ITW_PID_KEY_TAG = "ITW_PID_KEY_TAG";
* @returns a PID credential.
*/
export const getPid = async (instanceAttestation: string, pidData: PidData) => {
const walletInstancePublicKey = await getPublicKey(ITW_WIA_KEY_TAG);
// clientId must be the Wallet Instance public key thumbprint
const clientId = await thumbprint(walletInstancePublicKey);
const wiaCryptoContext = createCryptoContextFor(ITW_WIA_KEY_TAG);

// Start pid issuing flow
const issuingPID = new PID.Issuing(
walletPidProviderUrl,
walletProviderUrl,
instanceAttestation,
clientId
);

// Generate jwt for PAR wallet instance attestation
const unsignedJwtForPar = await issuingPID.getUnsignedJwtForPar(
walletInstancePublicKey
// Obtain PID Entity Configuration
const pidEntityConfiguration = await PID.Issuing.getEntityConfiguration()(
walletPidProviderUrl
);
const parSignature = await sign(unsignedJwtForPar, ITW_WIA_KEY_TAG);

// PAR request
await issuingPID.getPar(unsignedJwtForPar, parSignature);

// Token request
const authToken = await issuingPID.getAuthToken();

const pidKey = await generateCryptoKey(ITW_PID_KEY_TAG);

// Generate nonce proof
const unsignedNonceProof = await issuingPID.getUnsignedNonceProof(
authToken.c_nonce
// Auth Token request
const authRequest = PID.Issuing.authorizeIssuing({ wiaCryptoContext });
const authConf = await authRequest(
instanceAttestation,
walletProviderUrl,
pidEntityConfiguration
);
const nonceProofSignature = await sign(unsignedNonceProof, ITW_PID_KEY_TAG);

// Generate DPoP for PID key
const unsignedDPopForPid = await issuingPID.getUnsignedDPoP(pidKey);
const dPopPidSignature = await sign(unsignedDPopForPid, ITW_PID_KEY_TAG);

// Credential reuqest
return await issuingPID.getCredential(
unsignedDPopForPid,
dPopPidSignature,
unsignedNonceProof,
nonceProofSignature,
authToken.access_token,
{
birthDate: pidData.birthDate,
fiscalCode: pidData.fiscalCode,
name: pidData.name,
surname: pidData.surname
}
);
// Generate fresh key for PID binding
// ensure the key esists befor starting the issuing process
await generateCryptoKey(ITW_PID_KEY_TAG);
const pidCryptoContext = createCryptoContextFor(ITW_PID_KEY_TAG);

// Credential request
const credentialRequest = PID.Issuing.getCredential({ pidCryptoContext });
return await credentialRequest(authConf, pidEntityConfiguration, {
birthDate: pidData.birthDate,
fiscalCode: pidData.fiscalCode,
name: pidData.name,
surname: pidData.surname
});
};
21 changes: 10 additions & 11 deletions ts/features/it-wallet/utils/wia.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { sign } from "@pagopa/io-react-native-crypto";
import { WalletInstanceAttestation } from "@pagopa/io-react-native-wallet";
import {
WalletInstanceAttestation,
createCryptoContextFor
} from "@pagopa/io-react-native-wallet";
import { walletProviderUrl } from "../../../config";
import { generateCryptoKey } from "./keychain";

Expand All @@ -14,13 +16,10 @@ export const ITW_WIA_KEY_TAG = "ITW_WIA_CRYTPO";
* @returns the WIA attestation
*/
export const getWia = async () => {
const publicKey = await generateCryptoKey(ITW_WIA_KEY_TAG);
const issuing = new WalletInstanceAttestation.Issuing(walletProviderUrl);
const attestationRequest = await issuing.getAttestationRequestToSign(
publicKey
);
const signature = await sign(attestationRequest, ITW_WIA_KEY_TAG);
return (
await issuing.getAttestation(attestationRequest, signature)
).toString();
await generateCryptoKey(ITW_WIA_KEY_TAG);
const wiaCryptoContext = createCryptoContextFor(ITW_WIA_KEY_TAG);
const issuingAttestation = WalletInstanceAttestation.getAttestation({
wiaCryptoContext
});
return await issuingAttestation(walletProviderUrl);
};
Loading

0 comments on commit 59a420b

Please sign in to comment.