diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 402360535c3..b95bda40a62 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -142,7 +142,7 @@ PODS: - OpenSSL-Universal (1.1.1100) - pagopa-io-react-native-crypto (0.3.0): - React-Core - - pagopa-io-react-native-http-client (1.0.0): + - pagopa-io-react-native-http-client (1.0.2): - Alamofire (~> 5.9.1) - React-Core - pagopa-io-react-native-jwt (1.2.0): @@ -952,7 +952,7 @@ SPEC CHECKSUMS: nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5 OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c pagopa-io-react-native-crypto: 6aa9f33e4bf64ef420ad97c720c1ad0f876cd470 - pagopa-io-react-native-http-client: 973ebbdfc3d62c885a849b94c362148760ed61a7 + pagopa-io-react-native-http-client: 0799ed85dfe45c56765a394ab1f39aa2fb56f09d pagopa-io-react-native-jwt: f89a378bbc5ebfd93c24ec5993e97545a4815157 pagopa-io-react-native-login-utils: 442a5e2ab8db2c476fed2cff6d7ad16388ff1f21 pagopa-react-native-zendesk: e4a63ee0745a567b641110f7ff78e457086ab7a3 diff --git a/package.json b/package.json index b2118222603..ba51957f24b 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "@pagopa/io-app-design-system": "1.36.14", "@pagopa/io-pagopa-commons": "^3.1.0", "@pagopa/io-react-native-crypto": "^0.3.0", - "@pagopa/io-react-native-http-client": "1.0.0", + "@pagopa/io-react-native-http-client": "1.0.2", "@pagopa/io-react-native-jwt": "^1.2.0", "@pagopa/io-react-native-login-utils": "^1.0.0", "@pagopa/io-react-native-wallet": "^0.11.1", diff --git a/ts/features/fims/__mocks__/mockFIMSCallbacks.ts b/ts/features/fims/__mocks__/mockFIMSCallbacks.ts deleted file mode 100644 index 095697d2ca2..00000000000 --- a/ts/features/fims/__mocks__/mockFIMSCallbacks.ts +++ /dev/null @@ -1,294 +0,0 @@ -/* eslint-disable complexity */ -export type HttpBaseConfig = { - followRedirects?: boolean; - headers?: Record; - url: string; -}; -export type HttpGetConfig = HttpBaseConfig & { verb: "get" }; -export type HttpPostConfig = HttpBaseConfig & { - verb: "post"; - body?: Record; -}; -export type HttpCallConfig = HttpGetConfig | HttpPostConfig; - -export type HttpClientSuccessResponse = { - type: "success"; - status: number; - body: string; - headers: Record; -}; -export type HttpClientFailureResponse = { - type: "failure"; - code: number; - message: string; -}; -export type HttpClientResponse = - | HttpClientSuccessResponse - | HttpClientFailureResponse; - -const fakeAsyncHttpCall = (callback: () => HttpClientResponse) => - new Promise((resolve, reject) => { - setTimeout(() => { - const result = callback(); - if (result.type === "success") { - resolve(result); - } else { - reject(result); - } - }, 750 + Math.floor(Math.random() * 1750)); - }); - -export const FakeBaseUrl = "http://localhost:3000"; -export const RPInitialUrl = `${FakeBaseUrl}/fims/relyingParty/1/landingPage`; -const RPRedirectUrl = `${FakeBaseUrl}/fims/relyingParty/1/redirectUri`; -const RPRedirectUrlWithData = `${RPRedirectUrl}?authorization_code=1234567890&nonce=0b4c4749-5c0d-4ea2-925a-00d2f61db8c1&state=aebc026d-b045-448e-a51f-39a2cad2fdee`; -const RPInAppBrowserUrl = `https://www.google.com`; - -const ProviderFirstUrl = `${FakeBaseUrl}/fims/provider/oauth/authorize?client_id=1&scope=openid%20profile&response_type=id_token&redirect_uri=${RPRedirectUrl}&response_mode=form_post&nonce=0b4c4749-5c0d-4ea2-925a-00d2f61db8c1&state=aebc026d-b045-448e-a51f-39a2cad2fdee`; -const ProviderSecondUrl = `${FakeBaseUrl}/fims/provider/interaction/3f57b355-be53-4490-b0d0-1c55e805bc2e`; -const ProviderThirdUrl = `${FakeBaseUrl}/fims/provider/oauth/authorize/3f57b355-be53-4490-b0d0-1c55e805bc2e`; -const ProviderFourthUrl = `${FakeBaseUrl}/fims/provider/interaction/a589e42b-4a7d-4ca9-9de0-47036aca71a4`; - -const ProviderAcceptFirstUrl = `${FakeBaseUrl}/fims/provider/interaction/a589e42b-4a7d-4ca9-9de0-47036aca71a4/confirm`; -const ProviderAcceptSecondUrl = `${FakeBaseUrl}/fims/provider/oauth/authorize/a589e42b-4a7d-4ca9-9de0-47036aca71a4`; - -type FakeCookie = { - domain: string; - name: string; - value: string; -}; -const removeTrailingSlash = (str: string) => - str.endsWith("/") ? str.slice(0, -1) : str; -const fakeCookieStorage = new Map(); -export const mockSetNativeCookie = ( - domain: string, - name: string, - value: string -) => - fakeCookieStorage.set(`${removeTrailingSlash(domain)}_${name}`, { - domain, - name, - value - }); -export const mockClearNativeCookie = (domain: string, name: string) => - fakeCookieStorage.delete(`${domain}_${name}`); -export const mockClearAllCookies = () => fakeCookieStorage.clear(); - -const hasValidFIMSToken = () => { - const fimsCookie = fakeCookieStorage.get( - `${FakeBaseUrl}/fims/provider__io_fims_token` - ); - return fimsCookie && fimsCookie.value.trim().length > 0; -}; - -const missingFIMSTokenResponse = () => - fakeAsyncHttpCall(() => ({ - type: "failure", - code: 401, - message: "Missing or Invalid FIMS token" - })); - -const lollipopSignatureFailedResponse = () => - fakeAsyncHttpCall(() => ({ - type: "failure", - code: 403, - message: "No lollipop data found" - })); - -const grantsResponse = () => - fakeAsyncHttpCall(() => ({ - type: "success", - status: 200, - body: JSON.stringify({ grants: ["name", "surname", "email"] }), - headers: { - "confirm-url": ProviderAcceptFirstUrl, - "deny-url": "TODO :)" - } - })); - -const getLollipopDataErrorIfAny = (headers?: Record) => { - if (!headers) { - return "No lollipop data found"; - } - if ((headers.signature?.trim().length ?? 0) === 0) { - return "Missing 'signature' lollipop header"; - } - if ((headers["signature-input"]?.trim().length ?? 0) === 0) { - return "Missing 'signature-input' lollipop header"; - } - if ( - (headers["x-pagopa-lollipop-original-method"]?.trim().length ?? 0) === 0 - ) { - return "Missing 'x-pagopa-lollipop-original-method' lollipop header"; - } - if ((headers["x-pagopa-lollipop-original-url"]?.trim().length ?? 0) === 0) { - return "Missing 'x-pagopa-lollipop-original-url' lollipop header"; - } - if ( - (headers["x-pagopa-lollipop-custom-authorization_code"]?.trim().length ?? - 0) === 0 - ) { - return "Missing 'x-pagopa-lollipop-custom-authorization_code' lollipop header"; - } - return null; -}; - -const fastForwardToGrantResponse = () => { - if (hasValidFIMSToken()) { - return grantsResponse(); - } else { - return missingFIMSTokenResponse(); - } -}; - -export const mockHttpNativeCall = ( - config: HttpCallConfig - // eslint-disable-next-line sonarjs/cognitive-complexity -): Promise => { - const verb = config.verb; - const url = config.url; - - if (url === RPInitialUrl && verb === "get") { - if (config.followRedirects) { - return fastForwardToGrantResponse(); - } else { - return fakeAsyncHttpCall(() => ({ - type: "success", - status: 303, - body: "", - headers: { - "Content-Type": "text/plain; charset=utf-8", - Location: ProviderFirstUrl - } - })); - } - } else if (url === ProviderFirstUrl && verb === "get") { - if (hasValidFIMSToken()) { - if (config.followRedirects) { - return fastForwardToGrantResponse(); - } else { - return fakeAsyncHttpCall(() => ({ - type: "success", - status: 303, - body: "", - headers: { - "Content-Type": "text/plain; charset=utf-8", - Location: ProviderSecondUrl.replace(FakeBaseUrl, "") - } - })); - } - } else { - return missingFIMSTokenResponse(); - } - } else if (url === ProviderSecondUrl && verb === "get") { - if (hasValidFIMSToken()) { - if (config.followRedirects) { - return fastForwardToGrantResponse(); - } else { - return fakeAsyncHttpCall(() => ({ - type: "success", - status: 303, - body: "", - headers: { - "Content-Type": "text/plain; charset=utf-8", - Location: ProviderThirdUrl.replace(FakeBaseUrl, "") - } - })); - } - } else { - return missingFIMSTokenResponse(); - } - } else if (url === ProviderThirdUrl && verb === "get") { - if (hasValidFIMSToken()) { - if (config.followRedirects) { - return fastForwardToGrantResponse(); - } else { - return fakeAsyncHttpCall(() => ({ - type: "success", - status: 303, - body: "", - headers: { - "Content-Type": "text/plain; charset=utf-8", - Location: ProviderFourthUrl.replace(FakeBaseUrl, "") - } - })); - } - } else { - return missingFIMSTokenResponse(); - } - } else if (url === ProviderFourthUrl && verb === "get") { - return fastForwardToGrantResponse(); - } else if (url === ProviderAcceptFirstUrl && verb === "post") { - if (hasValidFIMSToken()) { - if (config.followRedirects) { - return lollipopSignatureFailedResponse(); - } else { - return fakeAsyncHttpCall(() => ({ - type: "success", - status: 303, - body: "", - headers: { - "Content-Type": "text/plain; charset=utf-8", - Location: ProviderAcceptSecondUrl - } - })); - } - } else { - return missingFIMSTokenResponse(); - } - } else if (url === ProviderAcceptSecondUrl && verb === "get") { - if (hasValidFIMSToken()) { - if (config.followRedirects) { - return lollipopSignatureFailedResponse(); - } else { - return fakeAsyncHttpCall(() => ({ - type: "success", - status: 303, - body: "", - headers: { - "Content-Type": "text/plain; charset=utf-8", - Location: RPRedirectUrlWithData - } - })); - } - } else { - return missingFIMSTokenResponse(); - } - } else if (url === RPRedirectUrlWithData && verb === "get") { - const lollipopError = getLollipopDataErrorIfAny(config.headers); - if (lollipopError) { - return fakeAsyncHttpCall(() => ({ - type: "failure", - code: 403, - message: lollipopError - })); - } else { - if (config.followRedirects) { - return fakeAsyncHttpCall(() => ({ - type: "success", - status: 200, - body: "Welcome User!You are now authenticated", - headers: { - "Content-Type": "text/html; charset=utf-8" - } - })); - } else { - return fakeAsyncHttpCall(() => ({ - type: "success", - status: 302, - body: "", - headers: { - "Content-Type": "text/plain; charset=utf-8", - Location: RPInAppBrowserUrl - } - })); - } - } - } - - return fakeAsyncHttpCall(() => ({ - type: "failure", - code: 404, - message: `Url (${url}) does not exist` - })); -}; diff --git a/ts/features/fims/__mocks__/mockFIMSSaga.ts b/ts/features/fims/__mocks__/mockFIMSSaga.ts deleted file mode 100644 index 5fc16f405d7..00000000000 --- a/ts/features/fims/__mocks__/mockFIMSSaga.ts +++ /dev/null @@ -1,68 +0,0 @@ -/* eslint-disable no-console */ -import { call } from "typed-redux-saga/macro"; -import { - HttpCallConfig, - RPInitialUrl, - FakeBaseUrl, - mockHttpNativeCall as nativeCall, - mockSetNativeCookie, - HttpClientSuccessResponse -} from "./mockFIMSCallbacks"; - -// since we are hardwiring mocks, we are sure that the response is always successful -- no need for error handling -const mockHttpNativeCall = nativeCall as ( - config: HttpCallConfig -) => Promise; - -export function* mockFIMSSaga() { - try { - mockSetNativeCookie(FakeBaseUrl, "_io_fims_token", "asd"); - const config: HttpCallConfig = { - verb: "get", - url: RPInitialUrl, - headers: {}, - followRedirects: true - }; - const consents = yield* call(mockHttpNativeCall, config); - console.log(`=== ${JSON.stringify(consents)}`); - - const confirmUrl = consents.headers["confirm-url"] as string; - const config2: HttpCallConfig = { - verb: "post", - url: confirmUrl, - headers: {}, - followRedirects: false, - body: {} - }; - const output2 = yield* call(mockHttpNativeCall, config2); - console.log(`=== ${JSON.stringify(output2)}`); - - const nextUrl = output2.headers.Location as string; - const config3: HttpCallConfig = { - verb: "get", - url: nextUrl, - headers: {}, - followRedirects: false - }; - const output3 = yield* call(mockHttpNativeCall, config3); - console.log(`=== ${JSON.stringify(output3)}`); - - const nextUrl4 = output3.headers.Location as string; - const config4: HttpCallConfig = { - verb: "get", - url: nextUrl4, - headers: { - signature: "asd", - "signature-input": "asd", - "x-pagopa-lollipop-original-method": "asd", - "x-pagopa-lollipop-original-url": "asd", - "x-pagopa-lollipop-custom-authorization_code": "asd" - }, - followRedirects: false - }; - const output4 = yield* call(mockHttpNativeCall, config4); - console.log(`=== ${JSON.stringify(output4)}`); - } catch (e) { - console.log(`=== ERROR ${JSON.stringify(e)}`); - } -} diff --git a/ts/features/fims/saga/index.tsx b/ts/features/fims/saga/index.tsx index ff528a75270..89892ce6a03 100644 --- a/ts/features/fims/saga/index.tsx +++ b/ts/features/fims/saga/index.tsx @@ -1,13 +1,24 @@ +import { + HttpCallConfig, + HttpClientFailureResponse, + HttpClientResponse, + HttpClientSuccessResponse, + nativeRequest, + setCookie +} from "@pagopa/io-react-native-http-client"; import { openAuthenticationSession } from "@pagopa/io-react-native-login-utils"; import { StackActions } from "@react-navigation/native"; import * as E from "fp-ts/Either"; +import { identity, pipe } from "fp-ts/lib/function"; import { URL } from "react-native-url-polyfill"; import { SagaIterator } from "redux-saga"; import { call, put, select, takeLatest } from "typed-redux-saga"; import { ActionType } from "typesafe-actions"; +import { mixpanelTrack } from "../../../mixpanel"; import NavigationService from "../../../navigation/NavigationService"; import { fimsTokenSelector } from "../../../store/reducers/authentication"; import { fimsDomainSelector } from "../../../store/reducers/backendStatus"; +import { buildEventProperties } from "../../../utils/analytics"; import { LollipopConfig } from "../../lollipop"; import { generateKeyInfo } from "../../lollipop/saga"; import { @@ -15,19 +26,12 @@ import { lollipopPublicKeySelector } from "../../lollipop/store/reducers/lollipop"; import { lollipopRequestInit } from "../../lollipop/utils/fetch"; -import { - HttpCallConfig, - HttpClientFailureResponse, - HttpClientResponse, - HttpClientSuccessResponse, - mockHttpNativeCall, - mockSetNativeCookie -} from "../__mocks__/mockFIMSCallbacks"; import { fimsGetConsentsListAction, fimsGetRedirectUrlAndOpenIABAction } from "../store/actions"; import { fimsCTAUrlSelector } from "../store/reducers"; +import { ConsentData } from "../types"; export function* watchFimsSaga(): SagaIterator { yield* takeLatest( @@ -47,32 +51,54 @@ function* handleFimsGetConsentsList() { if (!fimsToken || !oidcProviderUrl || !fimsCTAUrl) { // TODO:: proper error handling + logToMixPanel( + `missing FIMS data: fimsToken: ${!!fimsToken}, oidcProviderUrl: ${!!oidcProviderUrl}, fimsCTAUrl: ${!!fimsCTAUrl}` + ); + yield* put( fimsGetConsentsListAction.failure(new Error("missing FIMS data")) ); return; } - yield* call( - mockSetNativeCookie, - oidcProviderUrl, - "_io_fims_token", - fimsToken - ); + yield* call(setCookie, oidcProviderUrl, "/", "_io_fims_token", fimsToken); + + // TODO:: use with future BE lang implementation -- const lang = getLocalePrimaryWithFallback(); - const getConsentsResult = yield* call(mockHttpNativeCall, { + const getConsentsResult = yield* call(nativeRequest, { verb: "get", followRedirects: true, - url: fimsCTAUrl + url: fimsCTAUrl, + headers: { + "Accept-Language": "it-IT" + } }); if (getConsentsResult.type === "failure") { + logToMixPanel( + `consent data fetch error: ${JSON.stringify(getConsentsResult)}` + ); yield* put( fimsGetConsentsListAction.failure(new Error("consent data fetch error")) ); return; } - yield* put(fimsGetConsentsListAction.success(getConsentsResult)); + + yield pipe( + getConsentsResult.body, + E.tryCatchK(JSON.parse, identity), + E.map(ConsentData.decode), + E.flatten, + E.foldW( + () => { + logToMixPanel(`could not decode: ${getConsentsResult.body}`); + return put( + fimsGetConsentsListAction.failure(new Error("could not decode")) + ); + }, + decodedConsents => put(fimsGetConsentsListAction.success(decodedConsents)) + ) + ); } // note: IAB => InAppBrowser @@ -81,6 +107,7 @@ function* handleFimsGetRedirectUrlAndOpenIAB( ) { const oidcProviderDomain = yield* select(fimsDomainSelector); if (!oidcProviderDomain) { + logToMixPanel(`missing FIMS, domain is ${oidcProviderDomain}`); yield* put( fimsGetRedirectUrlAndOpenIABAction.failure( new Error("missing FIMS domain") @@ -88,8 +115,13 @@ function* handleFimsGetRedirectUrlAndOpenIAB( ); return; } - const { acceptUrl } = action.payload; + const maybeAcceptUrl = action.payload.acceptUrl; + + const acceptUrl = buildAbsoluteUrl(maybeAcceptUrl ?? "", oidcProviderDomain); if (!acceptUrl) { + logToMixPanel( + `unable to accept grants, could not buld url. obtained URL: ${maybeAcceptUrl}` + ); yield* put( fimsGetRedirectUrlAndOpenIABAction.failure( new Error("unable to accept grants: invalid URL") @@ -98,14 +130,19 @@ function* handleFimsGetRedirectUrlAndOpenIAB( return; } - const rpUrl = yield* call( + const rpRedirectResponse = yield* call( recurseUntilRPUrl, { url: acceptUrl, verb: "post" }, oidcProviderDomain ); // --------------- lolliPoP ----------------- - if (rpUrl.type === "failure") { + if (rpRedirectResponse.type === "failure") { + logToMixPanel( + `could not get RelyingParty redirect URL, ${JSON.stringify( + rpRedirectResponse + )}` + ); yield* put( fimsGetRedirectUrlAndOpenIABAction.failure( new Error("could not get RelyingParty redirect URL") @@ -113,13 +150,16 @@ function* handleFimsGetRedirectUrlAndOpenIAB( ); return; } - const relyingPartyRedirectUrl = rpUrl.headers.Location; + const relyingPartyRedirectUrl = rpRedirectResponse.headers.location; const [authCode, lollipopNonce] = getQueryParamsFromUrlString( relyingPartyRedirectUrl ); if (!authCode || !lollipopNonce) { + logToMixPanel( + `could not extract auth data from RelyingParty URL, auth code: ${!!authCode}, nonce: ${!!lollipopNonce}` + ); yield* put( fimsGetRedirectUrlAndOpenIABAction.failure( new Error("could not extract auth data from RelyingParty URL") @@ -149,6 +189,7 @@ function* handleFimsGetRedirectUrlAndOpenIAB( ); if (E.isLeft(lollipopEither)) { + logToMixPanel(`could not sign request with LolliPoP`); yield* put( fimsGetRedirectUrlAndOpenIABAction.failure( new Error("could not sign request with LolliPoP") @@ -158,7 +199,7 @@ function* handleFimsGetRedirectUrlAndOpenIAB( } const lollipopInit = lollipopEither.right; - const inAppBrowserUrl = yield* call(mockHttpNativeCall, { + const inAppBrowserUrlResponse = yield* call(nativeRequest, { verb: "get", url: relyingPartyRedirectUrl, headers: lollipopInit.headers as Record, @@ -166,11 +207,19 @@ function* handleFimsGetRedirectUrlAndOpenIAB( }); const inAppBrowserRedirectUrl = extractValidRedirect( - inAppBrowserUrl, + inAppBrowserUrlResponse, relyingPartyRedirectUrl ); if (!inAppBrowserRedirectUrl) { + logToMixPanel( + `IAB url call failed or without a valid redirect, code: ${ + inAppBrowserUrlResponse.type === "failure" + ? // eslint-disable-next-line sonarjs/no-nested-template-literals + `${inAppBrowserUrlResponse.code}, message: ${inAppBrowserUrlResponse.message}` + : inAppBrowserUrlResponse.status + }` + ); yield* put( fimsGetRedirectUrlAndOpenIABAction.failure( new Error("IAB url call failed or without a valid redirect") @@ -201,7 +250,7 @@ const nonThrowingLollipopRequestInit = async ( interface SuccessResponseWithLocationHeader extends HttpClientSuccessResponse { headers: { - Location: string; + location: string; }; } @@ -210,17 +259,10 @@ const isValidRedirectResponse = ( ): res is SuccessResponseWithLocationHeader => res.type === "success" && isRedirect(res.status) && - !!res.headers.Location && - res.headers.Location.trim().length > 0; + !!res.headers.location && + res.headers.location.trim().length > 0; -const extractValidRedirect = ( - data: HttpClientResponse, - originalRequestUrl: string -) => { - if (!isValidRedirectResponse(data)) { - return undefined; - } - const redirect = data.headers.Location; +const buildAbsoluteUrl = (redirect: string, originalRequestUrl: string) => { try { const redirectUrl = new URL(redirect); return redirectUrl.href; @@ -239,6 +281,14 @@ const extractValidRedirect = ( } }; +const extractValidRedirect = ( + data: HttpClientResponse, + originalRequestUrl: string +) => + isValidRedirectResponse(data) + ? buildAbsoluteUrl(data.headers.location, originalRequestUrl) + : undefined; + const getQueryParamsFromUrlString = (url: string) => { try { const constructedUrl = new URL(url); @@ -256,7 +306,7 @@ const recurseUntilRPUrl = async ( httpClientConfig: HttpCallConfig, oidcDomain: string ): Promise => { - const res = await mockHttpNativeCall({ + const res = await nativeRequest({ ...httpClientConfig, followRedirects: false }); @@ -271,7 +321,8 @@ const recurseUntilRPUrl = async ( const response: HttpClientFailureResponse = { code: res.status, type: "failure", - message: `malformed HTTP redirect response, location header value: ${res.headers.Location}` + message: `malformed HTTP redirect response, location header value: ${res.headers.location}`, + headers: res.headers }; return response; } @@ -285,12 +336,19 @@ const recurseUntilRPUrl = async ( } else { return await recurseUntilRPUrl( { + ...httpClientConfig, verb: "get", url: redirectUrl, - followRedirects: false, - headers: httpClientConfig.headers + followRedirects: false }, oidcDomain ); } }; + +const logToMixPanel = (toLog: string) => { + void mixpanelTrack( + "FIMS_TECH_TEMP_ERROR", + buildEventProperties("TECH", undefined, { message: toLog }) + ); +}; diff --git a/ts/features/fims/screens/FimsFlowHandlerScreen.tsx b/ts/features/fims/screens/FimsFlowHandlerScreen.tsx index 040748554de..555af5d0458 100644 --- a/ts/features/fims/screens/FimsFlowHandlerScreen.tsx +++ b/ts/features/fims/screens/FimsFlowHandlerScreen.tsx @@ -69,18 +69,19 @@ const FimsFlowSuccessBody = () => { if (consents === undefined) { return ; } - // TODO:: will be handled somewhere else - const parsedGrants: Array = JSON.parse(consents.body).grants; return ( item.display_name) + .join(",")} ?`} action={{ label: "accept", onPress: () => dispatch( fimsGetRedirectUrlAndOpenIABAction.request({ - acceptUrl: consents.headers["confirm-url"] + // eslint-disable-next-line no-underscore-dangle + acceptUrl: consents._links.confirm.href }) ) }} diff --git a/ts/features/fims/store/actions/index.ts b/ts/features/fims/store/actions/index.ts index 21e2fa8f72b..44123793998 100644 --- a/ts/features/fims/store/actions/index.ts +++ b/ts/features/fims/store/actions/index.ts @@ -1,5 +1,5 @@ import { ActionType, createAsyncAction } from "typesafe-actions"; -import { HttpClientSuccessResponse } from "../../__mocks__/mockFIMSCallbacks"; +import { ConsentData } from "../../types"; type FimsGetConsentsListRequestType = { ctaUrl: string; @@ -13,7 +13,7 @@ export const fimsGetConsentsListAction = createAsyncAction( "FIMS_GET_CONSENTS_LIST_REQUEST", "FIMS_GET_CONSENTS_LIST_SUCCESS", "FIMS_GET_CONSENTS_LIST_FAILURE" -)(); +)(); // note: IAB==InAppBrowser export const fimsGetRedirectUrlAndOpenIABAction = createAsyncAction( diff --git a/ts/features/fims/store/reducers/index.ts b/ts/features/fims/store/reducers/index.ts index 2e7f0d777bc..c1302a5d9e8 100644 --- a/ts/features/fims/store/reducers/index.ts +++ b/ts/features/fims/store/reducers/index.ts @@ -3,14 +3,14 @@ import * as O from "fp-ts/Option"; import { getType } from "typesafe-actions"; import { Action } from "../../../../store/actions/types"; import { GlobalState } from "../../../../store/reducers/types"; -import { HttpClientSuccessResponse } from "../../__mocks__/mockFIMSCallbacks"; import { fimsGetConsentsListAction, fimsGetRedirectUrlAndOpenIABAction } from "../actions"; +import { ConsentData } from "../../types"; export type FimsState = { ctaUrl?: string; - consentsData: pot.Pot; + consentsData: pot.Pot; errorState: O.Option; }; diff --git a/ts/features/fims/types/index.ts b/ts/features/fims/types/index.ts new file mode 100644 index 00000000000..2105a66ea18 --- /dev/null +++ b/ts/features/fims/types/index.ts @@ -0,0 +1,28 @@ +import * as t from "io-ts"; + +const confirmType = t.interface({ + href: t.string +}); + +const linksType = t.interface({ + confirm: confirmType +}); + +const claimType = t.interface({ + name: t.string, + display_name: t.string +}); + +const redirectionType = t.interface({ + display_name: t.string +}); + +export const ConsentData = t.interface({ + _links: linksType, + service_id: t.string, + redirection: redirectionType, + type: t.string, + claims: t.readonlyArray(claimType) +}); + +export type ConsentData = t.TypeOf; diff --git a/yarn.lock b/yarn.lock index 931874a1a8f..29e1fc71d17 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3306,10 +3306,10 @@ resolved "https://registry.yarnpkg.com/@pagopa/io-react-native-crypto/-/io-react-native-crypto-0.3.0.tgz#4181a53e36d4cd142b93ef133d3d227d9d360f96" integrity sha512-3H5CqJwpEYX14QNUhqbSizJBFBeIQRFv8Bw/46+YILTZpvCloVDjfSrPDsKNLZdC1d05wfUSTGGRncMQOB2kMg== -"@pagopa/io-react-native-http-client@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@pagopa/io-react-native-http-client/-/io-react-native-http-client-1.0.0.tgz#92d91d9c8d9f75f5dd303199cbe81b6e4c6316e0" - integrity sha512-tVHh3HJYZPV9at9Y7RBI9tOONxU8orOLQExd2Q9LNcyV8c8vjUj/VIYQWN159iETDIOR8QbSzvrlvldHxBLbpA== +"@pagopa/io-react-native-http-client@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@pagopa/io-react-native-http-client/-/io-react-native-http-client-1.0.2.tgz#8d92a7ea920f1fe01f5632ccb939bb7961392bd6" + integrity sha512-UVd0S8gV8RUf6ZlHhQDb2jvEyMlc+XQ76j44ewRiP4xGNDX9QmYGfr+QNUmg0PwJ55OoeH6j5lbWiW2Mh1QCtQ== dependencies: auto-changelog "^2.4.0"