-
Notifications
You must be signed in to change notification settings - Fork 97
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into IOCOM-905-router
- Loading branch information
Showing
27 changed files
with
648 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,292 @@ | ||
/* eslint-disable complexity */ | ||
export type HttpBaseConfig = { | ||
followRedirects?: boolean; | ||
headers?: Record<string, string>; | ||
url: string; | ||
}; | ||
export type HttpGetConfig = HttpBaseConfig & { verb: "get" }; | ||
export type HttpPostConfig = HttpBaseConfig & { | ||
verb: "post"; | ||
body?: Record<string, string>; | ||
}; | ||
export type HttpCallConfig = HttpGetConfig | HttpPostConfig; | ||
|
||
export type HttpClientSuccessResponse = { | ||
type: "success"; | ||
status: number; | ||
body: string; | ||
headers: Record<string, string>; | ||
}; | ||
export type HttpClientFailureResponse = { | ||
type: "failure"; | ||
code: number; | ||
message: string; | ||
}; | ||
export type HttpClientResponse = | ||
| HttpClientSuccessResponse | ||
| HttpClientFailureResponse; | ||
|
||
const fakeAsyncHttpCall = (callback: () => HttpClientResponse) => | ||
new Promise<HttpClientSuccessResponse>((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<string, FakeCookie>(); | ||
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}_X-IO-Federation-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<string, string>) => { | ||
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(); | ||
} | ||
}; | ||
|
||
// eslint-disable-next-line sonarjs/cognitive-complexity | ||
export const mockHttpNativeCall = (config: HttpCallConfig) => { | ||
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: "<html><head><title>Welcome User!</title></head><body>You are now authenticated</body></html>", | ||
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` | ||
})); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* eslint-disable no-console */ | ||
import { call } from "typed-redux-saga/macro"; | ||
import { | ||
HttpCallConfig, | ||
RPInitialUrl, | ||
FakeBaseUrl, | ||
mockHttpNativeCall, | ||
mockSetNativeCookie | ||
} from "./mockFIMSCallbacks"; | ||
|
||
export function* mockFIMSSaga() { | ||
try { | ||
mockSetNativeCookie(FakeBaseUrl, "X-IO-Federation-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"]; | ||
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; | ||
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; | ||
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)}`); | ||
} | ||
} |
Oops, something went wrong.