Skip to content

Commit

Permalink
chore: [IOAPPCIT-24] Add a crypto key pair generation test at applica…
Browse files Browse the repository at this point in the history
…tion startup. (pagopa#4295)

## Short description
This PR adds a crypto key pair generation test at application startup
using
[io-react-native-crypto](https://github.com/pagopa/io-react-native-crypto)
library.

## List of changes proposed in this pull request
- ⚠️ .circleci/config.yml: bumps `node` version from `14.17.4` to
`16.19.0`.
- ⚠️ .node-version: bumps `node` version from `14.17.4` to `16.19.0`.
- ⚠️ android/build.gradle: bumps `kotlin` version from `1.5.21` to
`1.7.0`.
- yarn.lock: adds `io-react-natiive-crypto` library.
- ios/Podfile.lock: adds `io-react-natiive-crypto` library pod.
- package.json: adds `io-react-natiive-crypto` library.
- ts/sagas/startup.ts: adds the key pair generation.
- ts/sagas/startup/generateCryptoKeyPair.ts: this is the new key
generation saga.
- ts/store/reducers/__mock__/backendStatus.ts: update the mock with the
new definitions.
- ts/store/reducers/backendStatus.ts: add the selector for the new
feature flag to enable/disable the key generation.
- ts/utils/crypto.ts: utility functions for the
`io-react-natiive-crypto` library.

## How to test
Run the application on both Android and iOS physical devices against the
[io-dev-api-server](https://github.com/pagopa/io-dev-api-server). Try
running the application also on simulators: it's not guaranteed that the
key generation will be successful, but also a crash-free unsuccessful
event is good.
You must set to `true` this
[flag](https://github.com/pagopa/io-dev-api-server/blob/c9485701686abc0f47c4272f05d6fd5246a6cd7e/src/payloads/backend.ts#L78)
on [io-dev-api-server](https://github.com/pagopa/io-dev-api-server) to
enable the key generation.
Try with different scenarios:
- Try with the flag above in a disabled state with a first onboarding
user. No key generation should happen.
- Then enable the flag and restart the application. You should see a key
generation attempt.
- Try with the flag above in an enabled state with an already logged-in
user: you should see a key generation attempt.
- More up to you ;)

Co-authored-by: Mario Perrotta <[email protected]>
Co-authored-by: Cristiano Tofani <[email protected]>
  • Loading branch information
3 people authored Jan 18, 2023
1 parent b5ec480 commit 7938ce2
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 5 deletions.
6 changes: 3 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ release_tag: &release_tag /^[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?$/
defaults_js: &defaults_js
<<: *defaults
docker:
- image: cimg/node:14.17.4
- image: cimg/node:16.19.0

# android builds
defaults_android: &defaults_android
Expand Down Expand Up @@ -435,8 +435,8 @@ jobs:
name: Configure Node
command: |
brew uninstall node yarn
nvm install 14.17.4
nvm alias default 14.17.4
nvm install 16.19.0
nvm alias default 16.19.0
npm install -g yarn
- run:
Expand Down
2 changes: 1 addition & 1 deletion .node-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
14.17.4
16.19.0
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
buildscript {
ext {
firebaseVersion = "17.6.0"
kotlin_version = "1.5.21"
kotlin_version = "1.7.0"
buildToolsVersion = "31.0.0"
minSdkVersion = 21
compileSdkVersion = 31
Expand Down
6 changes: 6 additions & 0 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ PODS:
- nanopb/decode (2.30908.0)
- nanopb/encode (2.30908.0)
- OpenSSL-Universal (1.1.1100)
- pagopa-io-react-native-crypto (0.2.1):
- React-Core
- PromisesObjC (2.0.0)
- Protobuf (3.19.1)
- RCT-Folly (2021.06.28.00-v2):
Expand Down Expand Up @@ -609,6 +611,7 @@ DEPENDENCIES:
- jail-monkey (from `../node_modules/jail-monkey`)
- libevent (~> 2.1.12)
- OpenSSL-Universal (= 1.1.1100)
- "pagopa-io-react-native-crypto (from `../node_modules/@pagopa/io-react-native-crypto`)"
- RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
Expand Down Expand Up @@ -741,6 +744,8 @@ EXTERNAL SOURCES:
:podspec: "../node_modules/react-native/sdks/hermes/hermes-engine.podspec"
jail-monkey:
:path: "../node_modules/jail-monkey"
pagopa-io-react-native-crypto:
:path: "../node_modules/@pagopa/io-react-native-crypto"
RCT-Folly:
:podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec"
RCTRequired:
Expand Down Expand Up @@ -914,6 +919,7 @@ SPEC CHECKSUMS:
MLKitVision: e87dc3f2e456a6ab32361ebd985e078dd2746143
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
pagopa-io-react-native-crypto: 644fece16966f2e1ea1f872344ee5a3c6c8761a1
PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58
Protobuf: 3724efa50cb2846d7ccebc8691c574e85fd74471
RCT-Folly: b9d9fe1fc70114b751c076104e52f3b1b5e5a95a
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
"@babel/plugin-transform-regenerator": "^7.18.6",
"@gorhom/bottom-sheet": "^4.1.5",
"@pagopa/io-pagopa-commons": "^3.1.0",
"@pagopa/io-react-native-crypto": "^0.2.1",
"@pagopa/react-native-cie": "^1.1.4",
"@pagopa/ts-commons": "^10.10.0",
"@react-native-async-storage/async-storage": "^1.17.10",
Expand Down
8 changes: 8 additions & 0 deletions ts/sagas/startup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ import { watchMessageAttachmentsSaga } from "../features/messages/saga/attachmen
import { watchPnSaga } from "../features/pn/store/sagas/watchPnSaga";
import { watchIDPayWalletSaga } from "../features/idpay/wallet/saga";
import { idpayInitiativeDetailsSaga } from "../features/idpay/initiative/details/saga";
import { isLollipopEnabledSelector } from "../store/reducers/backendStatus";
import {
startAndReturnIdentificationResult,
watchIdentification
Expand Down Expand Up @@ -137,6 +138,7 @@ import { completeOnboardingSaga } from "./startup/completeOnboardingSaga";
import { watchLoadMessageById } from "./messages/watchLoadMessageById";
import { watchThirdPartyMessageSaga } from "./messages/watchThirdPartyMessageSaga";
import { checkNotificationsPreferencesSaga } from "./startup/checkNotificationsPreferencesSaga";
import { generateCryptoKeyPair } from "./startup/generateCryptoKeyPair";

const WAIT_INITIALIZE_SAGA = 5000 as Millisecond;
const navigatorPollingTime = 125 as Millisecond;
Expand Down Expand Up @@ -338,6 +340,12 @@ export function* initializeApplicationSaga(): Generator<
// check if the user expressed preference about mixpanel, if not ask for it
yield* call(askMixpanelOptIn);

// generate crypto key
const isLollipopEnabled = yield* select(isLollipopEnabledSelector);
if (isLollipopEnabled) {
yield* call(generateCryptoKeyPair);
}

if (hasPreviousSessionAndPin) {
// We have to retrieve the pin here and not on the previous if-condition (same guard)
// otherwise the typescript compiler will complain of an unassigned variable later on
Expand Down
44 changes: 44 additions & 0 deletions ts/sagas/startup/generateCryptoKeyPair.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {
generate,
deleteKey,
CryptoError
} from "@pagopa/io-react-native-crypto";
import { call } from "typed-redux-saga/macro";
import {
checkPublicKeyExists,
isKeyAlreadyGenerated,
setKeyAlreadyGenerated
} from "../../utils/crypto";
import { mixpanelTrack } from "./../../mixpanel";

const KEY_NAME = "lp-temp-key";

export function* generateCryptoKeyPair() {
try {
const keyAlreadyExistsOnKeystore = yield* call(
checkPublicKeyExists,
KEY_NAME
);
const keyHasBeenAlreadyGenerated = yield* call(
isKeyAlreadyGenerated,
KEY_NAME
);
const shouldWeGenerateKey = !(
keyHasBeenAlreadyGenerated || keyAlreadyExistsOnKeystore
);

if (shouldWeGenerateKey) {
const key = yield* call(generate, KEY_NAME);
void mixpanelTrack("LOLLIPOP_KEY_GENERATION_SUCCESS", {
kty: key.kty
});
yield* call(setKeyAlreadyGenerated, KEY_NAME, key.kty);
yield* call(deleteKey, KEY_NAME);
}
} catch (e) {
const errorMessage = (e as CryptoError).message;
void mixpanelTrack("LOLLIPOP_KEY_GENERATION_FAILURE", {
reason: errorMessage
});
}
}
14 changes: 14 additions & 0 deletions ts/store/reducers/backendStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,20 @@ export const bancomatPayConfigSelector = createSelector(
)
);

/**
* return the remote config about LolliPOP enabled/disabled
* if there is no data, false is the default value -> (LolliPOP disabled)
*/
export const isLollipopEnabledSelector = createSelector(
backendStatusSelector,
(backendStatus): boolean =>
pipe(
backendStatus,
O.map(bs => bs.config.lollipop.enabled),
O.getOrElse(() => false)
)
);

/**
* return the remote config about CGN enabled/disabled
* if there is no data, false is the default value -> (CGN disabled)
Expand Down
35 changes: 35 additions & 0 deletions ts/utils/crypto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import AsyncStorage from "@react-native-async-storage/async-storage";
import { pipe } from "fp-ts/lib/function";
import * as T from "fp-ts/lib/Task";
import * as TE from "fp-ts/lib/TaskEither";
import { getPublicKey } from "@pagopa/io-react-native-crypto";

export const setKeyAlreadyGenerated = async (keyTag: string, value: string) =>
pipe(
TE.tryCatch(
() => AsyncStorage.setItem(keyTag, value),
() => false
),
TE.map(_ => true),
TE.getOrElse(() => T.of(false))
)();

export const isKeyAlreadyGenerated = async (keyTag: string) =>
pipe(
TE.tryCatch(
() => AsyncStorage.getItem(keyTag),
() => false
),
TE.map(value => value !== null),
TE.getOrElse(() => T.of(false))
)();

export const checkPublicKeyExists = (keyId: string) =>
pipe(
TE.tryCatch(
() => getPublicKey(keyId),
() => false
),
TE.map(_ => true),
TE.getOrElse(() => T.of(false))
)();
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3052,6 +3052,11 @@
fp-ts "^2.12.1"
io-ts "^2.2.16"

"@pagopa/io-react-native-crypto@^0.2.1":
version "0.2.1"
resolved "https://registry.yarnpkg.com/@pagopa/io-react-native-crypto/-/io-react-native-crypto-0.2.1.tgz#3d62b0f0cf45b2a878e4ee0652239ea69089988e"
integrity sha512-J+VP1kLXl1lQSJJYFMa+ljW9fWgMIYQskBJZFaVKPrtrZr8MJyrhNzlFUf2/EGwxm3kA+7o7budq6fPqdfVvvg==

"@pagopa/openapi-codegen-ts@^12.0.2":
version "12.0.2"
resolved "https://registry.yarnpkg.com/@pagopa/openapi-codegen-ts/-/openapi-codegen-ts-12.0.2.tgz#1913ba4fefe3d28f5a4f8497d8f824cdd9844cd0"
Expand Down

0 comments on commit 7938ce2

Please sign in to comment.