From 7e15d2e5caf01cc01535fbd81829b34eb166c8eb Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Mon, 24 Jul 2023 14:18:17 +0200 Subject: [PATCH] File uploads also use Angular's HTTP service #9696 Previously file upload where sent via outside of Angular. By keeping everything within Angular, we simplify the HTTP interceptors that work out of the box for normal XHR and file uploads. --- .../cart/services/datatrans.service.ts | 9 +- .../app/shared/config/apolloDefaultOptions.ts | 82 ++++--------------- package.json | 8 +- yarn.lock | 63 +++++++------- 4 files changed, 51 insertions(+), 111 deletions(-) diff --git a/client/app/front-office/modules/cart/services/datatrans.service.ts b/client/app/front-office/modules/cart/services/datatrans.service.ts index e36f818f..25a43ed8 100644 --- a/client/app/front-office/modules/cart/services/datatrans.service.ts +++ b/client/app/front-office/modules/cart/services/datatrans.service.ts @@ -1,5 +1,6 @@ import {Inject, Injectable} from '@angular/core'; -import CryptoES from 'crypto-es'; +import {HmacSHA256} from 'crypto-es/lib/sha256'; +import {Hex} from 'crypto-es/lib/core'; import {DOCUMENT} from '@angular/common'; import {fromEvent, Subject} from 'rxjs'; import {takeUntil} from 'rxjs/operators'; @@ -287,9 +288,9 @@ export class DatatransService { } const valueToSign = aliasCC + merchandId + amount + currency + refno; - const wordKey = CryptoES.enc.Hex.parse(hexaKey); - const wordSig = CryptoES.HmacSHA256(valueToSign, wordKey); + const wordKey = Hex.parse(hexaKey); + const wordSig = HmacSHA256(valueToSign, wordKey); - return CryptoES.enc.Hex.stringify(wordSig); + return Hex.stringify(wordSig); } } diff --git a/client/app/shared/config/apolloDefaultOptions.ts b/client/app/shared/config/apolloDefaultOptions.ts index 095d0062..e442e11d 100644 --- a/client/app/shared/config/apolloDefaultOptions.ts +++ b/client/app/shared/config/apolloDefaultOptions.ts @@ -1,4 +1,4 @@ -import {HttpBatchLink} from 'apollo-angular/http'; +import {HttpBatchLink, HttpLink} from 'apollo-angular/http'; import { ApolloClientOptions, ApolloLink, @@ -7,12 +7,10 @@ import { NormalizedCacheObject, } from '@apollo/client/core'; import {onError} from '@apollo/client/link/error'; -import {hasFilesAndProcessDate, NaturalAlertService, isMutation} from '@ecodev/natural'; -import {createUploadLink} from 'apollo-upload-client'; +import {createHttpLink, NaturalAlertService} from '@ecodev/natural'; import {NetworkActivityService} from '../services/network-activity.service'; -import {isPlatformBrowser} from '@angular/common'; import {APOLLO_OPTIONS} from 'apollo-angular'; -import {PLATFORM_ID, Provider} from '@angular/core'; +import {inject, PLATFORM_ID, Provider} from '@angular/core'; export const apolloDefaultOptions: DefaultOptions = { query: { @@ -54,82 +52,32 @@ function createErrorLink( }); } -/** - * Create a simple Apollo link for server side rendering without network activity, nor upload, nor error alerts - * - * This function will only be executed in Node environment, so we can access `process` - */ -function createApolloLinkForServer(httpBatchLink: HttpBatchLink): ApolloLink { - const hostname = process.cwd().split('/').pop() || 'dev.larevuedurable.com'; - - const options = { - uri: 'https://' + hostname + '/graphql', // Must be absolute URL - credentials: 'include', - }; - - // We must allow connecting to self-signed certificate for development environment - // Unfortunately, this is only possible to do it globally for the entire process, instead of specifically to our API endpoint - // See https://github.com/apollographql/apollo-angular/issues/1354#issue-503860648 - if (hostname.match(/\.lan$/)) { - process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; - } - - return httpBatchLink.create(options); -} - function createApolloLink( networkActivityService: NetworkActivityService, alertService: NaturalAlertService, + httpLink: HttpLink, httpBatchLink: HttpBatchLink, ): ApolloLink { - const options = { - uri: '/graphql', - credentials: 'include', - }; - - const uploadInterceptor = new ApolloLink((operation, forward) => { - networkActivityService.increase(); - - if (forward) { - return forward(operation).map(response => { - networkActivityService.decrease(); - return response; - }); - } else { - return null; - } - }); - - // If query has no file, batch it, otherwise upload only that query - const httpLink = ApolloLink.split( - operation => hasFilesAndProcessDate(operation.variables) || isMutation(operation.query), - uploadInterceptor.concat(createUploadLink(options)), - httpBatchLink.create(options), - ); - const errorLink = createErrorLink(networkActivityService, alertService); - return errorLink.concat(httpLink); + return errorLink.concat( + createHttpLink(httpLink, httpBatchLink, { + uri: '/graphql', + }), + ); } -function apolloOptionsFactory( - networkActivityService: NetworkActivityService, - alertService: NaturalAlertService, - httpBatchLink: HttpBatchLink, - // eslint-disable-next-line @typescript-eslint/ban-types - platformId: Object, -): ApolloClientOptions { - // tells if it's browser or server - const isBrowser = isPlatformBrowser(platformId); +function apolloOptionsFactory(): ApolloClientOptions { + const networkActivityService = inject(NetworkActivityService); + const alertService = inject(NaturalAlertService); + const httpLink = inject(HttpLink); + const httpBatchLink = inject(HttpBatchLink); - const link = isBrowser - ? createApolloLink(networkActivityService, alertService, httpBatchLink) - : createApolloLinkForServer(httpBatchLink); + const link = createApolloLink(networkActivityService, alertService, httpLink, httpBatchLink); return { link: link, cache: new InMemoryCache(), defaultOptions: apolloDefaultOptions, - ssrMode: !isBrowser, }; } diff --git a/package.json b/package.json index 70363704..539cba6c 100644 --- a/package.json +++ b/package.json @@ -28,17 +28,16 @@ "@angular/router": "^16.1.2", "@apollo/client": "^3.7.16", "@ecodev/fab-speed-dial": "^15.0.0", - "@ecodev/natural": "^53.0.0", - "@ecodev/natural-editor": "^53.0.0", + "@ecodev/natural": "^54.0.0", + "@ecodev/natural-editor": "^54.0.0", "@graphql-codegen/cli": "^4.0.1", "@graphql-codegen/typescript-apollo-angular": "^3.5.6", "@graphql-codegen/typescript-operations": "^4.0.1", "@graphql-tools/mock": "^9.0.0", "@ngbracket/ngx-layout": "^16.0.0", "apollo-angular": "^5.0.0", - "apollo-upload-client": "^17.0.0", "big.js": "^6.2.1", - "crypto-es": "^1.2.7", + "crypto-es": "^2.0.3", "graphql": "^16.7.1", "lodash-es": "^4.17.21", "lodash.template": "^4.5.0", @@ -59,7 +58,6 @@ "@angular/compiler-cli": "^16.1.2", "@nguniversal/builders": "^16.1.0", "@playwright/test": "^1.35.1", - "@types/apollo-upload-client": "^17.0.2", "@types/big.js": "^6.1.6", "@types/express": "^4.17.17", "@types/jasmine": "~4.3.4", diff --git a/yarn.lock b/yarn.lock index cfeaebe8..f9b7e06f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -348,7 +348,7 @@ dependencies: tslib "^2.3.0" -"@apollo/client@^3.7.0", "@apollo/client@^3.7.16": +"@apollo/client@^3.7.16": version "3.7.16" resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.7.16.tgz#418cb23566a6d52e9e22d34484167149269efd40" integrity sha512-rdhoc7baSD7ZzcjavEpYN8gZJle1KhjEKj4SJeMgBpcnO4as7oXUVU4LtFpotzZdFlo57qaLrNzfvppSTsKvZQ== @@ -1470,10 +1470,10 @@ dependencies: tslib "^2.5.3" -"@ecodev/natural-editor@^53.0.0": - version "53.0.0" - resolved "https://registry.yarnpkg.com/@ecodev/natural-editor/-/natural-editor-53.0.0.tgz#b183bd967ee5d110f38ff1bc9300a4a0876fb3b9" - integrity sha512-aF3lj/lfPaBD7fQhAB94dJq8M+g+JETl8afDI1TN4AR9dkZzqIc28s5hwL3uAGuJVHwFpeqX9QwufIub8aMFuw== +"@ecodev/natural-editor@^54.0.0": + version "54.0.0" + resolved "https://registry.yarnpkg.com/@ecodev/natural-editor/-/natural-editor-54.0.0.tgz#ba825a0f60593233cf562b2bc4dd9b4918465450" + integrity sha512-J37xVR1NEvcPoacbYuDYpw/D1NcmlSCnGGOA0LFwGf3x9igplOeHYY9MF9X2+RSBF7Vip9lMmRIxGFsbQbMqZw== dependencies: prosemirror-commands "^1.5.2" prosemirror-dropcursor "^1.8.1" @@ -1490,11 +1490,13 @@ prosemirror-view "^1.31.5" tslib "^2.5.3" -"@ecodev/natural@^53.0.0": - version "53.0.0" - resolved "https://registry.yarnpkg.com/@ecodev/natural/-/natural-53.0.0.tgz#f518c368fbe89ca0451a9ee02bc38c0bb72c5e45" - integrity sha512-k+s1Whb26l8GdEmiObKJzh5xeo8jStdhsMu3GECTG4GHCsKQ/9f2AKiEm820Y6bKyS2hEtF9XVNcnuLE4oXygA== +"@ecodev/natural@^54.0.0": + version "54.0.0" + resolved "https://registry.yarnpkg.com/@ecodev/natural/-/natural-54.0.0.tgz#11772b9f7b4702c9991970125315439036fbc9ca" + integrity sha512-Fas2+8C3sD7pszdfGiry72zFudORDFxwtidpSAoMwdrb00+z94vfkCwYGJ7AAc/Ofzfrb0XOOlYmfJtruk/UnQ== dependencies: + crypto-es "^2.0.3" + extract-files "^13.0.0" tslib "^2.5.3" "@esbuild/android-arm64@0.17.19": @@ -3230,15 +3232,6 @@ "@tufjs/canonical-json" "1.0.0" minimatch "^9.0.0" -"@types/apollo-upload-client@^17.0.2": - version "17.0.2" - resolved "https://registry.yarnpkg.com/@types/apollo-upload-client/-/apollo-upload-client-17.0.2.tgz#15dc737663928be27c768117603dfc23c21514bb" - integrity sha512-NphAiBqzZv3iY8Cq+qWyi0QUFFzJ+nVd7QKI/iKV8RfILrpYDL69F/vlhjn4BNxKlmc3LxJHymcf3gFzLBwuZQ== - dependencies: - "@apollo/client" "^3.7.0" - "@types/extract-files" "*" - graphql "14 - 16" - "@types/big.js@^6.1.6": version "6.1.6" resolved "https://registry.yarnpkg.com/@types/big.js/-/big.js-6.1.6.tgz#3d417e758483d55345a03a087f7e0c87137ca444" @@ -3327,11 +3320,6 @@ "@types/qs" "*" "@types/serve-static" "*" -"@types/extract-files@*": - version "8.1.1" - resolved "https://registry.yarnpkg.com/@types/extract-files/-/extract-files-8.1.1.tgz#11b67e795ad2c8b483431e8d4f190db2fd22944b" - integrity sha512-dMJJqBqyhsfJKuK7p7HyyNmki7qj1AlwhUKWx6KrU7i1K2T2SPsUsSUTWFmr/sEM1q8rfR8j5IyUmYrDbrhfjQ== - "@types/http-errors@*": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.1.tgz#20172f9578b225f6c7da63446f56d4ce108d5a65" @@ -4043,13 +4031,6 @@ apollo-angular@^5.0.0: dependencies: tslib "^2.0.0" -apollo-upload-client@^17.0.0: - version "17.0.0" - resolved "https://registry.yarnpkg.com/apollo-upload-client/-/apollo-upload-client-17.0.0.tgz#d9baaff8d14e54510de9f2855b487e75ca63b392" - integrity sha512-pue33bWVbdlXAGFPkgz53TTmxVMrKeQr0mdRcftNY+PoHIdbGZD0hoaXHvO6OePJAkFz7OiCFUf98p1G/9+Ykw== - dependencies: - extract-files "^11.0.0" - "aproba@^1.0.3 || ^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" @@ -5009,10 +4990,10 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -crypto-es@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/crypto-es/-/crypto-es-1.2.7.tgz#754a6d52319a94fb4eb1f119297f17196b360f88" - integrity sha512-UUqiVJ2gUuZFmbFsKmud3uuLcNP2+Opt+5ysmljycFCyhA0+T16XJmo1ev/t5kMChMqWh7IEvURNCqsg+SjZGQ== +crypto-es@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/crypto-es/-/crypto-es-2.0.3.tgz#ca95e0bd017c4febfe6e09194e51b291c0e3739d" + integrity sha512-/VAp8U1txXXEV8AmXw2J/zBRSc1TheAeN6wikI3J7aX7jl2V9WhH7X+IabAH3PkwqboEAZ47yROSvDCp3/Fgaw== css-loader@6.8.1: version "6.8.1" @@ -5814,6 +5795,13 @@ extract-files@^11.0.0: resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-11.0.0.tgz#b72d428712f787eef1f5193aff8ab5351ca8469a" integrity sha512-FuoE1qtbJ4bBVvv94CC7s0oTnKUGvQs+Rjf1L2SJFfS+HTVVjhPFtehPdQ0JiGPqVNfSSZvL5yzHHQq2Z4WNhQ== +extract-files@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-13.0.0.tgz#9065073dedbcfb5e2ae8a90988cf609834b217ec" + integrity sha512-FXD+2Tsr8Iqtm3QZy1Zmwscca7Jx3mMC5Crr+sEP1I303Jy1CYMuYCm7hRTplFNg3XdUavErkxnTzpaqdSoi6g== + dependencies: + is-plain-obj "^4.1.0" + fast-decode-uri-component@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543" @@ -6335,7 +6323,7 @@ graphql-ws@5.14.0: resolved "https://registry.yarnpkg.com/graphql-ws/-/graphql-ws-5.14.0.tgz#766f249f3974fc2c48fae0d1fb20c2c4c79cd591" integrity sha512-itrUTQZP/TgswR4GSSYuwWUzrE/w5GhbwM2GX3ic2U7aw33jgEsayfIlvaj7/GcIvZgNMzsPTrE5hqPuFUiE5g== -"graphql@14 - 16", graphql@^16.7.1: +graphql@^16.7.1: version "16.7.1" resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.7.1.tgz#11475b74a7bff2aefd4691df52a0eca0abd9b642" integrity sha512-DRYR9tf+UGU0KOsMcKAlXeFfX89UiiIZ0dRU3mR0yJfu6OjZqUcp68NnFLnqQU5RexygFoDy1EW+ccOYcPfmHg== @@ -6912,6 +6900,11 @@ is-plain-obj@^3.0.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== +is-plain-obj@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" + integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== + is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"