@@ -2,12 +2,10 @@ import { ValidationError } from "@pagopa/handler-kit";
22import { FiscalCode , NonEmptyString } from "@pagopa/ts-commons/lib/strings" ;
33import { createPublicKey } from "crypto" ;
44import * as E from "fp-ts/Either" ;
5- import { identity , pipe } from "fp-ts/function" ;
5+ import { pipe } from "fp-ts/function" ;
66import * as J from "fp-ts/Json" ;
7- import { Separated } from "fp-ts/lib/Separated" ;
87import * as O from "fp-ts/Option" ;
98import * as RA from "fp-ts/ReadonlyArray" ;
10- import * as T from "fp-ts/Task" ;
119import * as TE from "fp-ts/TaskEither" ;
1210import { JwkPublicKey } from "io-wallet-common/jwk" ;
1311import { calculateJwkThumbprint } from "jose" ;
@@ -21,10 +19,17 @@ import {
2119} from "@/attestation-service" ;
2220
2321import {
22+ parseAndroidAttestation ,
23+ parseGoogleAppCredentials ,
2424 validateAndroidAssertion ,
2525 validateAndroidAttestation ,
2626} from "./android" ;
27- import { validateiOSAssertion , validateiOSAttestation } from "./ios" ;
27+ import {
28+ parseIosAssertion ,
29+ parseIosAttestation ,
30+ validateiOSAssertion ,
31+ validateiOSAttestation ,
32+ } from "./ios" ;
2833
2934export class IntegrityCheckError extends Error {
3035 name = "IntegrityCheckError" ;
@@ -36,18 +41,6 @@ export class IntegrityCheckError extends Error {
3641const toIntegrityCheckError = ( e : Error | ValidationError ) : Error =>
3742 e instanceof ValidationError ? new IntegrityCheckError ( e . violations ) : e ;
3843
39- const getErrorsOrFirstValidValue = (
40- // eslint-disable-next-line @typescript-eslint/no-explicit-any
41- validated : Separated < readonly Error [ ] , readonly any [ ] > ,
42- ) =>
43- pipe (
44- validated . right ,
45- RA . head ,
46- E . fromOption (
47- ( ) => new IntegrityCheckError ( validated . left . map ( ( el ) => el . message ) ) ,
48- ) ,
49- ) ;
50-
5144export class MobileAttestationService implements AttestationService {
5245 #configuration: AttestationServiceConfiguration ;
5346
@@ -87,41 +80,55 @@ export class MobileAttestationService implements AttestationService {
8780 TE . tryCatch ( ( ) => calculateJwkThumbprint ( jwk , "sha256" ) , E . toError ) ,
8881 TE . chainEitherKW ( ( jwk_thumbprint ) =>
8982 pipe (
90- {
91- challenge : nonce ,
92- jwk_thumbprint,
93- } ,
83+ { challenge : nonce , jwk_thumbprint } ,
9484 J . stringify ,
9585 E . mapLeft ( ( ) => new ValidationError ( [ "Unable to create clientData" ] ) ) ,
9686 ) ,
9787 ) ,
9888 TE . chainW ( ( clientData ) =>
9989 pipe (
100- [
90+ parseIosAssertion ( {
91+ hardwareSignature,
92+ integrityAssertion,
93+ } ) ,
94+ TE . fromEither ,
95+ TE . chainW ( ( decodedAssertion ) =>
10196 validateiOSAssertion (
102- integrityAssertion ,
103- hardwareSignature ,
97+ decodedAssertion ,
10498 clientData ,
10599 hardwareKey ,
106100 signCount ,
107101 this . #configuration. iosBundleIdentifiers ,
108102 this . #configuration. iOsTeamIdentifier ,
109103 this . #configuration. skipSignatureValidation ,
110104 ) ,
111- validateAndroidAssertion (
112- integrityAssertion ,
113- hardwareSignature ,
114- clientData ,
115- hardwareKey ,
116- this . #configuration. androidBundleIdentifiers ,
117- this . #configuration. androidPlayStoreCertificateHash ,
118- this . #configuration. googleAppCredentialsEncoded ,
119- this . #configuration. androidPlayIntegrityUrl ,
120- this . allowDevelopmentEnvironmentForUser ( user ) ,
105+ ) ,
106+ TE . orElseW ( ( iosErr ) =>
107+ pipe (
108+ parseGoogleAppCredentials (
109+ this . #configuration. googleAppCredentialsEncoded ,
110+ ) ,
111+ TE . fromEither ,
112+ TE . chain ( ( googleAppCredentials ) =>
113+ validateAndroidAssertion (
114+ integrityAssertion ,
115+ hardwareSignature ,
116+ clientData ,
117+ hardwareKey ,
118+ this . #configuration. androidBundleIdentifiers ,
119+ this . #configuration. androidPlayStoreCertificateHash ,
120+ googleAppCredentials ,
121+ this . #configuration. androidPlayIntegrityUrl ,
122+ this . allowDevelopmentEnvironmentForUser ( user ) ,
123+ ) ,
124+ ) ,
125+ TE . orElseW ( ( androidErr ) =>
126+ TE . left (
127+ new IntegrityCheckError ( [ iosErr . message , androidErr . message ] ) ,
128+ ) ,
129+ ) ,
121130 ) ,
122- ] ,
123- RA . wilt ( T . ApplicativePar ) ( identity ) ,
124- T . map ( getErrorsOrFirstValidValue ) ,
131+ ) ,
125132 ) ,
126133 ) ,
127134 ) ;
@@ -140,32 +147,44 @@ export class MobileAttestationService implements AttestationService {
140147 TE . fromEither ,
141148 TE . chainW ( ( data ) =>
142149 pipe (
143- [
150+ parseIosAttestation ( data ) ,
151+ TE . fromEither ,
152+ TE . chainW ( ( decoded ) =>
144153 validateiOSAttestation (
145- data ,
154+ decoded ,
146155 nonce ,
147156 hardwareKeyTag ,
148157 this . #configuration. iosBundleIdentifiers ,
149158 this . #configuration. iOsTeamIdentifier ,
150159 this . #configuration. appleRootCertificate ,
151160 this . allowDevelopmentEnvironmentForUser ( user ) ,
152161 ) ,
162+ ) ,
163+ TE . orElseW ( ( iosErr ) =>
153164 pipe (
154- validateAndroidAttestation (
155- data ,
156- nonce ,
157- this . #configuration. androidBundleIdentifiers ,
158- this . #configuration. googlePublicKeys ,
159- this . #configuration. androidCrlUrl ,
160- this . #configuration. httpRequestTimeout ,
165+ parseAndroidAttestation ( data ) ,
166+ TE . fromEither ,
167+ TE . chainW ( ( x509Chain ) =>
168+ validateAndroidAttestation (
169+ x509Chain ,
170+ nonce ,
171+ this . #configuration. androidBundleIdentifiers ,
172+ this . #configuration. googlePublicKeys ,
173+ this . #configuration. androidCrlUrl ,
174+ this . #configuration. httpRequestTimeout ,
175+ ) ,
161176 ) ,
162177 TE . mapLeft ( toIntegrityCheckError ) ,
178+ TE . orElseW ( ( androidErr ) =>
179+ TE . left (
180+ new IntegrityCheckError ( [ iosErr . message , androidErr . message ] ) ,
181+ ) ,
182+ ) ,
163183 ) ,
164- ] ,
165- RA . wilt ( T . ApplicativeSeq ) ( identity ) ,
166- T . map ( getErrorsOrFirstValidValue ) ,
184+ ) ,
167185 ) ,
168186 ) ,
169187 ) ;
170188}
189+
171190export { ValidatedAttestation } ;
0 commit comments