diff --git a/apps/endringsmelding-pleiepenger/.env.example b/apps/endringsmelding-pleiepenger/.env.example index 44b55b2bc9..3fdbd3ecdc 100644 --- a/apps/endringsmelding-pleiepenger/.env.example +++ b/apps/endringsmelding-pleiepenger/.env.example @@ -1,21 +1,26 @@ -API_URL_INNSYN=http://localhost:8099 -API_URL_K9_SAK_INNSYN=http://localhost:8099 -API_URL=http://localhost:8099 APP_VERSION=dev -APPSTATUS_DATASET=staging -APPSTATUS_PROJECT_ID=ryujtq87 -DEBUG=false -DEKORATOR_URL=https://www.nav.no/dekoratoren/?simple=true&chatbot=false -DOMAIN_URL=http://localhost:8080 -FRONTEND_API_PATH=http://localhost:8099/ -FRONTEND_INNSYN_API_PATH=http://localhost:8099/api -FRONTEND_K9_SAK_INNSYN_API_PATH=http://localhost:8099/api -FRONTEND_VEDLEGG_URL=http://localhost:8099/api +ENV=dev GITHUB_REF_NAME=some_branch_name -INNSYN_URL=http://localhost:8080 -LOGIN_URL=http://localhost:8099/login?redirect_location=http://localhost:8099 -MINSIDE_URL=http://www.nav.no/minside -MSW=on NODE_ENV=development PUBLIC_PATH=/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger -TILLAT_SN=true \ No newline at end of file + +SIF_PUBLIC_APPSTATUS_DATASET=staging +SIF_PUBLIC_APPSTATUS_PROJECT_ID=ryujtq87 +SIF_PUBLIC_DEKORATOR_URL=https://dekoratoren.ekstern.dev.nav.no/?simple=true&chatbot=false&urlLookupTable=false&logoutUrl=https://endringsmelding-pleiepenger.intern.dev.nav.no/oauth2/logout +SIF_PUBLIC_LOGIN_URL=http://localhost:8081/auth-mock/cookie?subject=mockSubject&redirect_location=http://localhost:8080 +SIF_PUBLIC_MINSIDE_URL=https://www.nav.no/minside +SIF_PUBLIC_FEATURE_NYNORSK=on +SIF_PUBLIC_INNSYN_URL=https://dine-pleiepenger.intern.dev.nav.no/innsyn + +K9_BRUKERDIALOG_PROSESSERING_FRONTEND_PATH=/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger/api/k9-brukerdialog +K9_BRUKERDIALOG_PROSESSERING_API_SCOPE=dev-gcp:dusseldorf:k9-brukerdialog-prosessering +K9_BRUKERDIALOG_PROSESSERING_API_URL=http://k9-brukerdialog-prosessering + +SIF_INNSYN_FRONTEND_PATH=/familie/sykdom-i-familien/soknad/endringsmelding/api/sif-innsyn +SIF_INNSYN_API_URL=http://sif-innsyn-api +SIF_INNSYN_API_SCOPE=dev-gcp:dusseldorf:sif-innsyn-api + +MSW=on +DEBUG=false +NOW=2023-01-01 +USE_AMPLITUDE=false \ No newline at end of file diff --git a/apps/endringsmelding-pleiepenger/CHANGELOG.md b/apps/endringsmelding-pleiepenger/CHANGELOG.md index 57546e5172..5fb40e1ba0 100644 --- a/apps/endringsmelding-pleiepenger/CHANGELOG.md +++ b/apps/endringsmelding-pleiepenger/CHANGELOG.md @@ -1,5 +1,11 @@ # @navikt/endringsmelding-pleiepenger +## 2.32.0 + +### Minor Changes + +- Bruke common server-oppsett + ## 2.31.27 ### Patch Changes diff --git a/apps/endringsmelding-pleiepenger/Dockerfile b/apps/endringsmelding-pleiepenger/Dockerfile index 6593a4d8d5..c09b83051a 100644 --- a/apps/endringsmelding-pleiepenger/Dockerfile +++ b/apps/endringsmelding-pleiepenger/Dockerfile @@ -1,35 +1,79 @@ +FROM node:20.12-alpine AS base -FROM node:18-alpine AS base -RUN apk update && apk add git -RUN apk add --no-cache libc6-compat +ENV APP="endringsmelding-pleiepenger" +ENV SERVER="server" +ENV SCOPE=@navikt/endringsmelding-pleiepenger + +RUN apk fix \ + && apk add --no-cache --update libc6-compat tini \ + && rm -rf /var/cache/apk/* RUN yarn global add turbo +######################################### +# PREPARE DEPS FOR BUILD +######################################### + +FROM base AS prepare WORKDIR /app +COPY ["package.json", ".yarnrc.yml", "yarn.lock", "turbo.json", "./"] +COPY [".yarn/releases/*", ".yarn/releases/"] +COPY packages packages +COPY apps apps +ARG SERVER +COPY ${SERVER} ${SERVER} +RUN find apps \! -name "package.json" -mindepth 2 -maxdepth 2 -print | xargs rm -rf +RUN find packages \! -name "package.json" -mindepth 2 -maxdepth 2 -print | xargs rm -rf +RUN find ${SERVER} \! -name "package.json" -mindepth 2 -maxdepth 2 -print | xargs rm -rf -ENV SCOPE=@navikt/endringsmelding-pleiepenger +######################################### +# BUILDER IMAGE - INSTALL PACKAGES AND COPY SOURCE +######################################### -FROM base AS turbo-builder +FROM prepare AS installer +COPY --from=prepare /app ./ +RUN --mount=type=secret,id=PACKAGES_AUTH_TOKEN \ + PACKAGES_AUTH_TOKEN=$(cat /run/secrets/PACKAGES_AUTH_TOKEN) yarn COPY . . -RUN yarn -RUN yarn turbo run build --filter=${SCOPE} -FROM base AS ws-installer -RUN apk update && apk add git -RUN apk add --no-cache libc6-compat -WORKDIR /app-ws -COPY . . -RUN yarn workspaces focus ${SCOPE} --production - -FROM gcr.io/distroless/nodejs18-debian11:nonroot -WORKDIR /apps/endringsmelding-pleiepenger -COPY --from=ws-installer /app-ws/node_modules ./node_modules/ -COPY --from=turbo-builder /app/apps/endringsmelding-pleiepenger/server.cjs . -COPY --from=turbo-builder /app/apps/endringsmelding-pleiepenger/tokenx.cjs . -COPY --from=turbo-builder /app/apps/endringsmelding-pleiepenger/package.json . -COPY --from=turbo-builder /app/apps/endringsmelding-pleiepenger/src/build/decorator.cjs ./src/build/decorator.cjs -COPY --from=turbo-builder /app/apps/endringsmelding-pleiepenger/src/build/AppSettings.cjs ./src/build/AppSettings.cjs -COPY --from=turbo-builder /app/apps/endringsmelding-pleiepenger/dist ./dist - -EXPOSE 8080 -CMD ["server.cjs"] +######################################### +# BUILD SERVER +######################################### + +FROM installer AS server-build +ARG SERVER +WORKDIR /app/${SERVER} +RUN --mount=type=secret,id=PACKAGES_AUTH_TOKEN \ + PACKAGES_AUTH_TOKEN=$(cat /run/secrets/PACKAGES_AUTH_TOKEN) yarn build + + +######################################### +# Client +######################################### + +FROM installer AS client-build +WORKDIR /app +RUN --mount=type=secret,id=PACKAGES_AUTH_TOKEN \ + PACKAGES_AUTH_TOKEN=$(cat /run/secrets/PACKAGES_AUTH_TOKEN) yarn turbo run build --filter=${SCOPE} +RUN mv /app/apps/${APP}/dist /public + + +######################################### +# Server +######################################### +FROM base AS server +ARG SERVER +WORKDIR /app +COPY --from=server-build /app/${SERVER}/dist ./ +ENTRYPOINT ["/sbin/tini", "--"] + +######################################### +# App +######################################### +FROM server + +COPY --from=client-build /public ./public + +CMD ["node", "index.js"] + + diff --git a/apps/endringsmelding-pleiepenger/dev-server.cjs b/apps/endringsmelding-pleiepenger/dev-server.cjs new file mode 100644 index 0000000000..c592f1774d --- /dev/null +++ b/apps/endringsmelding-pleiepenger/dev-server.cjs @@ -0,0 +1,95 @@ +const { createProxyMiddleware, fixRequestBody } = require('http-proxy-middleware'); +const getAppSettings = require('./e2e/server/AppSettings.cjs'); +const { injectDecoratorServerSide } = require('@navikt/nav-dekoratoren-moduler/ssr/index.js'); +const express = require('express'); +const server = express(); +server.use(express.json()); +const path = require('path'); +const mustacheExpress = require('mustache-express'); +const compression = require('compression'); + +server.disable('x-powered-by'); + +server.use(compression()); + +require('dotenv').config(); +server.set('views', `${__dirname}`); +server.set('view engine', 'mustache'); +server.engine('html', mustacheExpress()); + +server.use((req, res, next) => { + res.removeHeader('X-Powered-By'); + res.set('X-Frame-Options', 'SAMEORIGIN'); + res.set('X-XSS-Protection', '1; mode=block'); + res.set('X-Content-Type-Options', 'nosniff'); + res.set('Referrer-Policy', 'no-referrer'); + res.set('Feature-Policy', "geolocation 'none'; microphone 'none'; camera 'none'"); + next(); +}); + +async function injectDecorator(filePath) { + return injectDecoratorServerSide({ + env: 'dev', + filePath, + params: { + enforceLogin: false, + simple: true, + }, + }); +} + +const startServer = async () => { + server.get('/health/isAlive', (req, res) => res.sendStatus(200)); + server.get('/health/isReady', (req, res) => res.sendStatus(200)); + + const indexHtmlPath = path.resolve(__dirname, 'index.html'); + + const htmlWithDecoratorInjected = await injectDecorator(indexHtmlPath); + + const renderedHtml = htmlWithDecoratorInjected.replaceAll( + '{{{APP_SETTINGS}}}', + JSON.stringify({ + APP_VERSION: `${process.env.APP_VERSION}`, + PUBLIC_PATH: `${process.env.PUBLIC_PATH}`, + ...getAppSettings(), + }), + ); + + const fs = require('fs'); + fs.writeFileSync(path.resolve(__dirname, 'index-decorated.html'), renderedHtml); + + const vite = await require('vite').createServer({ + root: __dirname, + server: { + middlewareMode: true, + port: 8080, + open: './index-decorated.html', + }, + }); + + server.get(/^\/(?!.*dist).*$/, (req, res, next) => { + const ROOT_DIR = path.resolve(__dirname); + const fullPath = path.resolve(ROOT_DIR, decodeURIComponent(req.path.substring(1))); + + if (!fullPath.startsWith(ROOT_DIR)) { + res.status(403).send('Forbidden'); + return; + } + + const fileExists = fs.existsSync(fullPath); + + if ((!fileExists && !req.url.startsWith('/@')) || req.url === '/') { + req.url = '/index-decorated.html'; + } + next(); + }); + + server.use(vite.middlewares); + + const port = process.env.PORT || 8080; + server.listen(port, () => { + console.log(`App listening on port: ${port}`); + }); +}; + +startServer(); diff --git a/apps/endringsmelding-pleiepenger/server-e2e.cjs b/apps/endringsmelding-pleiepenger/e2e-server.cjs similarity index 76% rename from apps/endringsmelding-pleiepenger/server-e2e.cjs rename to apps/endringsmelding-pleiepenger/e2e-server.cjs index 82e9835d69..4303b26ad2 100644 --- a/apps/endringsmelding-pleiepenger/server-e2e.cjs +++ b/apps/endringsmelding-pleiepenger/e2e-server.cjs @@ -3,8 +3,8 @@ const express = require('express'); const server = express(); const path = require('path'); const mustacheExpress = require('mustache-express'); -const getAppSettings = require('./src/build/AppSettings.cjs'); -const getDecorator = require('./src/build/decorator.cjs'); +const getAppSettings = require('./e2e/server/AppSettings.cjs'); +const getDecorator = require('./e2e/server/decorator.cjs'); const compression = require('compression'); require('dotenv').config(); @@ -40,12 +40,14 @@ const renderApp = (decoratorFragments) => }); const startServer = async (html) => { - server.get(`${process.env.PUBLIC_PATH}/health/isAlive`, (_req, res) => res.sendStatus(200)); - server.get(`${process.env.PUBLIC_PATH}/health/isReady`, (_req, res) => res.sendStatus(200)); - server.use(`${process.env.PUBLIC_PATH}/assets`, express.static(path.resolve(__dirname, 'dist/assets'))); - server.use(`**/assets`, express.static(path.resolve(__dirname, 'dist/assets'))); + server.use(`${process.env.PUBLIC_PATH}/assets`, express.static(path.resolve(__dirname, './dist/assets'))); - server.get(/^\/(?!.*api)(?!.*innsynapi)(?!.*dist).*$/, (req, res) => { + server.get('/mockServiceWorker.js', (req, res) => { + const filePath = path.join(__dirname, 'mockServiceWorker.js'); + res.sendFile(filePath); + }); + + server.get(/^\/(?!.*api)(?!.*dist).*$/, (req, res) => { res.send(html); }); diff --git a/apps/endringsmelding-pleiepenger/e2e/playwright/utils/setupMockRoutes.ts b/apps/endringsmelding-pleiepenger/e2e/playwright/utils/setupMockRoutes.ts index 4285868089..6fa1648797 100644 --- a/apps/endringsmelding-pleiepenger/e2e/playwright/utils/setupMockRoutes.ts +++ b/apps/endringsmelding-pleiepenger/e2e/playwright/utils/setupMockRoutes.ts @@ -10,7 +10,7 @@ export const setupScenarioMockRoutes = async (page: Page, scenario: ScenarioType await page.route('**/oppslag/arbeidsgiver**', async (route) => { await route.fulfill({ status: 200, body: JSON.stringify(mockData.arbeidsgiver) }); }); - await page.route('**/api/innsyn/sak', async (route) => { + await page.route('**/innsyn/sak', async (route) => { await route.fulfill({ status: 200, body: JSON.stringify(mockData.sak) }); }); }; diff --git a/apps/endringsmelding-pleiepenger/e2e/server/AppSettings.cjs b/apps/endringsmelding-pleiepenger/e2e/server/AppSettings.cjs new file mode 100644 index 0000000000..2c298c28a6 --- /dev/null +++ b/apps/endringsmelding-pleiepenger/e2e/server/AppSettings.cjs @@ -0,0 +1,31 @@ +require('dotenv').config(); + +const getAppSettings = (isTest) => { + return { + APP_VERSION: `${process.env.APP_VERSION}`, + NODE_ENV: `${process.env.NODE_ENV}`, + PUBLIC_PATH: `${process.env.PUBLIC_PATH}`, + GITHUB_REF_NAME: `${process.env.GITHUB_REF_NAME}`, + + SIF_PUBLIC_APPSTATUS_DATASET: `${process.env.SIF_PUBLIC_APPSTATUS_DATASET}`, + SIF_PUBLIC_APPSTATUS_PROJECT_ID: `${process.env.SIF_PUBLIC_APPSTATUS_PROJECT_ID}`, + SIF_PUBLIC_DEKORATOR_URL: `${process.env.SIF_PUBLIC_DEKORATOR_URL}`, + SIF_PUBLIC_LOGIN_URL: `${process.env.SIF_PUBLIC_LOGIN_URL}`, + SIF_PUBLIC_MINSIDE_URL: `${process.env.SIF_PUBLIC_MINSIDE_URL}`, + SIF_PUBLIC_FEATURE_NYNORSK: `${process.env.SIF_PUBLIC_FEATURE_NYNORSK}`, + SIF_PUBLIC_INNSYN_URL: `${process.env.INNSYN_URL}`, + + K9_BRUKERDIALOG_PROSESSERING_FRONTEND_PATH: `${process.env.K9_BRUKERDIALOG_PROSESSERING_FRONTEND_PATH}`, + K9_BRUKERDIALOG_PROSESSERING_API_URL: `${process.env.K9_BRUKERDIALOG_PROSESSERING_API_URL}`, + SIF_INNSYN_FRONTEND_PATH: `${process.env.SIF_INNSYN_FRONTEND_PATH}`, + SIF_INNSYN_API_URL: `${process.env.SIF_INNSYN_API_URL}`, + + DOMAIN_URL: `${process.env.DOMAIN_URL}`, + MSW: isTest ? 'off' : `${process.env.MSW}`, + E2E_TEST: isTest ? 'true' : false, + SIF_PUBLIC_FEATURE_VELG_SCENARIO: isTest ? 'on' : `${process.env.SIF_PUBLIC_FEATURE_VELG_SCENARIO}`, + NOW: `${process.env.NOW}`, + }; +}; + +module.exports = getAppSettings; diff --git a/apps/endringsmelding-pleiepenger/src/build/decorator.cjs b/apps/endringsmelding-pleiepenger/e2e/server/decorator.cjs similarity index 95% rename from apps/endringsmelding-pleiepenger/src/build/decorator.cjs rename to apps/endringsmelding-pleiepenger/e2e/server/decorator.cjs index 17e6166eb2..1657a548dd 100644 --- a/apps/endringsmelding-pleiepenger/src/build/decorator.cjs +++ b/apps/endringsmelding-pleiepenger/e2e/server/decorator.cjs @@ -27,7 +27,7 @@ const decoratorParams = new URLSearchParams({ const getDecorator = (appSettings) => new Promise((resolve, reject) => { - fetch(`${process.env.DEKORATOR_URL}`, decoratorParams) + fetch(`${process.env.SIF_PUBLIC_DEKORATOR_URL}`, decoratorParams) .then((response) => response.text()) .then((html) => { if (html) { diff --git a/apps/endringsmelding-pleiepenger/index.html b/apps/endringsmelding-pleiepenger/index.html index 2eee2fc93c..4786b17228 100644 --- a/apps/endringsmelding-pleiepenger/index.html +++ b/apps/endringsmelding-pleiepenger/index.html @@ -2,18 +2,16 @@ - + - {{{NAV_SCRIPTS}}} {{{NAV_STYLES}}} - + + -
- {{{NAV_HEADING}}} -
- {{{NAV_FOOTER}}} -
+
diff --git a/apps/endringsmelding-pleiepenger/nais/dev-gcp.json b/apps/endringsmelding-pleiepenger/nais/dev-gcp.json index a03fab1cff..9622c3b076 100644 --- a/apps/endringsmelding-pleiepenger/nais/dev-gcp.json +++ b/apps/endringsmelding-pleiepenger/nais/dev-gcp.json @@ -1,34 +1,38 @@ { "app": "endringsmelding-pleiepenger", + "team": "dusseldorf", "cluster": "dev-gcp", "observabilityEnabled": "true", - "env": { - "API_TOKENX_AUDIENCE": "dev-gcp:dusseldorf:k9-brukerdialog-prosessering", - "API_URL_INNSYN": "http://sif-innsyn-api", - "API_URL": "http://k9-brukerdialog-prosessering", - "APP_VERSION": "dev", - "APPSTATUS_DATASET": "staging", - "APPSTATUS_PROJECT_ID": "ryujtq87", - "DEBUG": "true", - "DEKORATOR_URL": "https://dekoratoren.ekstern.dev.nav.no/?simple=true&chatbot=false&urlLookupTable=false&logoutUrl=https://endringsmelding-pleiepenger.intern.dev.nav.no/oauth2/logout", - "DOMAIN_URL": "https://endringsmelding-pleiepenger.intern.dev.nav.no", - "FRONTEND_API_PATH": "/api", - "FRONTEND_INNSYN_API_PATH": "/innsynapi", - "INNSYN_API_TOKENX_AUDIENCE": "dev-gcp:dusseldorf:sif-innsyn-api", - "INNSYN_URL": "https://dine-pleiepenger.intern.dev.nav.no/innsyn", - "LOGIN_URL": "https://endringsmelding-pleiepenger.intern.dev.nav.no/oauth2/login?redirect=/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger/melding", - "MINSIDE_URL": "https://www.intern.dev.nav.no/minside", - "MSW_MODE": "dev", - "NPM_CONFIG_CACHE": "/tmp", - "PUBLIC_PATH": "/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger" - }, - "externalHosts": ["www.nav.no", "dekoratoren.ekstern.dev.nav.no"], + "externalHosts": ["www.nav.no", "dekoratoren.ekstern.dev.nav.no", "amplitude.nav.no"], "accessPolicyOutApps": ["k9-brukerdialog-prosessering", "sif-innsyn-api"], - "minReplicas": 1, - "maxReplicas": 1, "ingresses": ["https://endringsmelding-pleiepenger.intern.dev.nav.no"], - "livenessPath": "/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger/health/isAlive", + "readinessPath": "/internal/health/isReady", + "livenessPath": "/internal/health/isAlive", "namespace": "dusseldorf", - "readinessPath": "/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger/health/isReady", - "team": "dusseldorf" + "minReplicas": 1, + "maxReplicas": 1, + "env": { + "APP_VERSION": "dev", + "ENV": "dev", + "NODE_ENV": "development", + "PUBLIC_PATH": "/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger", + + "SIF_PUBLIC_APPSTATUS_DATASET": "staging", + "SIF_PUBLIC_APPSTATUS_PROJECT_ID": "ryujtq87", + "SIF_PUBLIC_DEKORATOR_URL": "https://dekoratoren.ekstern.dev.nav.no/?simple=true&chatbot=false&urlLookupTable=false&logoutUrl=https://endringsmelding-pleiepenger.intern.dev.nav.no/oauth2/logout", + "SIF_PUBLIC_DOMAIN_URL": "https://endringsmelding-pleiepenger.intern.dev.nav.no", + "SIF_PUBLIC_LOGIN_URL": "http://localhost:8081/auth-mock/cookie?subject=mockSubject&redirect_location=http://localhost:8080", + "SIF_PUBLIC_INNSYN_URL": "https://dine-pleiepenger.intern.dev.nav.no/innsyn", + "SIF_PUBLIC_MINSIDE_URL": "https://www.nav.no/minside", + "SIF_PUBLIC_FEATURE_VELG_SCENARIO": "on", + + "K9_BRUKERDIALOG_PROSESSERING_FRONTEND_PATH": "/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger/api/k9-brukerdialog", + "K9_BRUKERDIALOG_PROSESSERING_API_SCOPE": "dev-gcp:dusseldorf:k9-brukerdialog-prosessering", + "K9_BRUKERDIALOG_PROSESSERING_API_URL": "http://k9-brukerdialog-prosessering", + + "SIF_INNSYN_FRONTEND_PATH": "/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger/api/sif-innsyn", + "SIF_INNSYN_API_URL": "http://sif-innsyn-api", + "SIF_INNSYN_API_SCOPE": "dev-gcp:dusseldorf:sif-innsyn-api", + "DEBUG": "true" + } } diff --git a/apps/endringsmelding-pleiepenger/nais/prod-gcp.json b/apps/endringsmelding-pleiepenger/nais/prod-gcp.json index ebbaf78b5c..cea7bdfa2b 100644 --- a/apps/endringsmelding-pleiepenger/nais/prod-gcp.json +++ b/apps/endringsmelding-pleiepenger/nais/prod-gcp.json @@ -3,25 +3,27 @@ "cluster": "prod-gcp", "observabilityEnabled": "true", "env": { - "API_TOKENX_AUDIENCE": "prod-gcp:dusseldorf:k9-brukerdialog-prosessering", - "API_URL_INNSYN": "http://sif-innsyn-api", - "API_URL": "http://k9-brukerdialog-prosessering", "APP_VERSION": "prod", - "APPSTATUS_DATASET": "production", - "APPSTATUS_PROJECT_ID": "ryujtq87", - "DEKORATOR_URL": "https://www.nav.no/dekoratoren/?simple=true&chatbot=false&logoutUrl=https://www.nav.no/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger/oauth2/logout", - "DEBUG": "true", - "FRONTEND_API_PATH": "/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger/api", - "FRONTEND_INNSYN_API_PATH": "/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger/innsynapi", - "DOMAIN_URL": "https://www.nav.no", - "INNSYN_API_TOKENX_AUDIENCE": "prod-gcp:dusseldorf:sif-innsyn-api", - "INNSYN_URL": "https://www.nav.no/familie/sykdom-i-familien/soknad/innsyn", - "LOGIN_URL": "https://www.nav.no/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger/oauth2/login?redirect=/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger/melding", - "MINSIDE_URL": "https://www.nav.no/minside", - "NPM_CONFIG_CACHE": "/tmp", - "PUBLIC_PATH": "/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger" + "ENV": "prod", + "NODE_ENV": "production", + "PUBLIC_PATH": "/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger", + "SIF_PUBLIC_APPSTATUS_DATASET": "production", + "SIF_PUBLIC_APPSTATUS_PROJECT_ID": "ryujtq87", + "SIF_PUBLIC_DEKORATOR_URL": "https://www.nav.no/dekoratoren/?simple=true&chatbot=false&logoutUrl=https://www.nav.no/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger/oauth2/logout", + "SIF_PUBLIC_DOMAIN_URL": "https://www.nav.no", + "SIF_PUBLIC_LOGIN_URL": "https://www.nav.no/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger/oauth2/login?redirect=/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger/melding", + "SIF_PUBLIC_INNSYN_URL": "https://www.nav.no/familie/sykdom-i-familien/soknad/innsyn", + "SIF_PUBLIC_MINSIDE_URL": "https://www.nav.no/minside", + + "K9_BRUKERDIALOG_PROSESSERING_FRONTEND_PATH": "/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger/api/k9-brukerdialog", + "K9_BRUKERDIALOG_PROSESSERING_API_SCOPE": "prod-gcp:dusseldorf:k9-brukerdialog-prosessering", + "K9_BRUKERDIALOG_PROSESSERING_API_URL": "http://k9-brukerdialog-prosessering", + + "SIF_INNSYN_FRONTEND_PATH": "/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger/api/sif-innsyn", + "SIF_INNSYN_API_URL": "http://sif-innsyn-api", + "SIF_INNSYN_API_SCOPE": "prod-gcp:dusseldorf:sif-innsyn-api" }, - "externalHosts": ["www.nav.no"], + "externalHosts": ["www.nav.no", "amplitude.nav.no"], "accessPolicyOutApps": ["k9-brukerdialog-prosessering", "sif-innsyn-api"], "minReplicas": 2, "maxReplicas": 2, diff --git a/apps/endringsmelding-pleiepenger/package.json b/apps/endringsmelding-pleiepenger/package.json index d17f14a8ec..2e994fada6 100644 --- a/apps/endringsmelding-pleiepenger/package.json +++ b/apps/endringsmelding-pleiepenger/package.json @@ -5,7 +5,7 @@ "license": "MIT", "name": "@navikt/endringsmelding-pleiepenger", "repository": "https://github.com/navikt/sif-brukerdialog", - "version": "2.31.27", + "version": "2.32.0", "private": true, "dependencies": { "@navikt/ds-css": "7.1.2", @@ -56,6 +56,7 @@ "@babel/preset-typescript": "7.25.7", "@mswjs/data": "0.16.2", "@navikt/ds-tailwind": "7.1.2", + "@navikt/nav-dekoratoren-moduler": "3.1.0", "@playwright/test": "1.47.2", "@sentry/vite-plugin": "2.22.5", "@sif/eslint-config": "*", @@ -98,22 +99,19 @@ "vitest": "2.1.2" }, "scripts": { - "build": "vite build --base=/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger", "build-storybook": "storybook build", + "build": "vite build --base=/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger", "clean": "rm -rf node_modules .dist", "codegen": "playwright codegen", - "playwright-test": "playwright test", - "e2e": "playwright test", "dev-api": "PORT=8089 node ./src/mocks/server.cjs", + "dev": "node ./dev-server.cjs", "lint:eslint": "eslint \"./src/**/*.{js,ts,tsx}\"", "lint:fix": "eslint --quiet --fix './src/**/*.{js,ts,tsx}'", "lint:tsc": "tsc --noEmit", - "dev": "cross-env NODE_ENV=development node ./server.cjs", - "start-e2e-server": "cross-env NODE_ENV=development node ./server-e2e.cjs", - "start-express": "node ./server.cjs", + "playwright-test": "playwright test", + "start-e2e-server": "node ./e2e-server.cjs", "storybook": "storybook dev -p 6006", - "test": "vitest run", - "pw": "playwright test --ui" + "test": "vitest run" }, "eslintConfig": { "overrides": [ diff --git a/apps/endringsmelding-pleiepenger/playwright.config.ts b/apps/endringsmelding-pleiepenger/playwright.config.ts index 827f163647..817dc0680b 100644 --- a/apps/endringsmelding-pleiepenger/playwright.config.ts +++ b/apps/endringsmelding-pleiepenger/playwright.config.ts @@ -25,29 +25,33 @@ export default defineConfig({ reuseExistingServer: true, timeout: 60000, env: { - API_TOKENX_AUDIENCE: 'dev-gcp:dusseldorf:k9-brukerdialog-api', - API_URL_INNSYN: 'http://localhost:8099', - API_URL_K9_SAK_INNSYN: 'http://localhost:8099', - API_URL: 'http://localhost:8099', + SIF_PUBLIC_FEATURE_VELG_SCENARIO: 'on', + NOW: '2023-01-01', APP_VERSION: 'dev', - APPSTATUS_DATASET: 'staging', - APPSTATUS_PROJECT_ID: 'ryujtq87', - DEBUG: 'false', - DEKORATOR_URL: 'https://www.nav.no/dekoratoren/?simple=true&chatbot=false', - DOMAIN_URL: 'http://localhost:8080', - FRONTEND_API_PATH: 'http://localhost:8099/', - FRONTEND_INNSYN_API_PATH: 'http://localhost:8099/api', - FRONTEND_K9_SAK_INNSYN_API_PATH: 'http://localhost:8099/api', - FRONTEND_VEDLEGG_URL: 'http://localhost:8099/api', + ENV: 'dev', GITHUB_REF_NAME: 'some_branch_name', - INNSYN_URL: 'http://localhost:8080', - LOGIN_URL: 'http://localhost:8099/login?redirect_location=http://localhost:8099', - MINSIDE_URL: 'http://www.nav.no/minside', - MSW: 'on', NODE_ENV: 'development', - NOW: '2023-01-01', PUBLIC_PATH: '/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger', - TILLAT_SN: 'false', + + SIF_PUBLIC_APPSTATUS_DATASET: 'staging', + SIF_PUBLIC_APPSTATUS_PROJECT_ID: 'ryujtq87', + SIF_PUBLIC_DEKORATOR_URL: + 'https://dekoratoren.ekstern.dev.nav.no/?simple=true&chatbot=false&urlLookupTable=false&logoutUrl=https://endringsmelding-pleiepenger.intern.dev.nav.no/oauth2/logout', + SIF_PUBLIC_DOMAIN_URL: 'https://endringsmelding-pleiepenger.intern.dev.nav.no', + SIF_PUBLIC_LOGIN_URL: + 'http://localhost:8081/auth-mock/cookie?subject=mockSubject&redirect_location=http://localhost:8080', + SIF_PUBLIC_INNSYN_URL: 'https://dine-pleiepenger.intern.dev.nav.no/innsyn', + SIF_PUBLIC_MINSIDE_URL: 'https://www.nav.no/minside', + SIF_PUBLIC_FEATURE_NYNORSK: 'on', + + K9_BRUKERDIALOG_PROSESSERING_FRONTEND_PATH: + '/familie/sykdom-i-familien/soknad/endringsmelding-pleiepenger/api/k9-brukerdialog', + K9_BRUKERDIALOG_PROSESSERING_API_SCOPE: 'dev-gcp:dusseldorf:k9-brukerdialog-prosessering', + K9_BRUKERDIALOG_PROSESSERING_API_URL: 'http://k9-brukerdialog-prosessering', + + SIF_INNSYN_FRONTEND_PATH: '/familie/sykdom-i-familien/soknad/endringsmelding/api/sif-innsyn', + SIF_INNSYN_API_URL: 'http://sif-innsyn-api', + SIF_INNSYN_API_SCOPE: 'dev-gcp:dusseldorf:sif-innsyn-api', }, }, }); diff --git a/apps/endringsmelding-pleiepenger/server.cjs b/apps/endringsmelding-pleiepenger/server.cjs deleted file mode 100644 index 4313df0bdf..0000000000 --- a/apps/endringsmelding-pleiepenger/server.cjs +++ /dev/null @@ -1,194 +0,0 @@ -/* eslint-disable no-console */ -const express = require('express'); -const path = require('path'); -const mustacheExpress = require('mustache-express'); -const getAppSettings = require('./src/build/AppSettings.cjs'); -const getDecorator = require('./src/build/decorator.cjs'); -const compression = require('compression'); -const cookieParser = require('cookie-parser'); -const jose = require('jose'); -const { v4: uuidv4 } = require('uuid'); -const { createProxyMiddleware } = require('http-proxy-middleware'); -const { initTokenX, exchangeToken } = require('./tokenx.cjs'); -const RateLimit = require('express-rate-limit'); - -const isDev = process.env.NODE_ENV === 'development'; - -if (isDev) { - require('dotenv').config(); -} - -const server = express(); -server.use((_req, res, next) => { - res.removeHeader('X-Powered-By'); - res.set('X-Frame-Options', 'SAMEORIGIN'); - res.set('X-XSS-Protection', '1; mode=block'); - res.set('X-Content-Type-Options', 'nosniff'); - res.set('Referrer-Policy', 'no-referrer'); - res.set('Feature-Policy', "geolocation 'none'; microphone 'none'; camera 'none'"); - next(); -}); -server.use(compression()); -server.use(cookieParser()); - -if (isDev) { - require('dotenv').config(); - server.set('views', `${__dirname}`); -} else { - server.set('views', `${__dirname}/dist`); -} -server.set('view engine', 'mustache'); -server.engine('html', mustacheExpress()); - -const logError = (errorMessage, details) => console.log(errorMessage, details); - -const isExpiredOrNotAuthorized = (token) => { - if (token) { - try { - const exp = jose.decodeJwt(token).exp; - return Date.now() >= exp * 1000; - } catch (err) { - // eslint-disable-next-line no-console - console.error('Feilet med dekoding av token: ', err); - return true; - } - } - return true; -}; - -const getRouterConfig = async (req, audienceInnsyn) => { - { - req.headers['X-Correlation-ID'] = uuidv4(); - - if (process.env.NAIS_CLIENT_ID !== undefined) { - req.headers['X-K9-Brukerdialog'] = process.env.NAIS_CLIENT_ID; - } - - if (req.headers['authorization'] !== undefined) { - const token = req.headers['authorization'].replace('Bearer ', ''); - if (isExpiredOrNotAuthorized(token)) { - return undefined; - } - const exchangedToken = await exchangeToken(token, audienceInnsyn); - if (exchangedToken != null && !exchangedToken.expired() && exchangedToken.access_token) { - req.headers['authorization'] = `Bearer ${exchangedToken.access_token}`; - } - } - - return undefined; - } -}; - -const renderApp = (decoratorFragments) => - new Promise((resolve, reject) => { - server.render('index.html', decoratorFragments, (err, html) => { - if (err) { - reject(err); - } else { - resolve(html); - } - }); - }); - -const setupTokenX = async () => { - if (isDev) { - return Promise.resolve(); - } - return Promise.all([initTokenX()]); -}; - -const startServer = async (html) => { - await setupTokenX(); - - server.get(`${process.env.PUBLIC_PATH}/health/isAlive`, (_req, res) => res.sendStatus(200)); - server.get(`${process.env.PUBLIC_PATH}/health/isReady`, (_req, res) => res.sendStatus(200)); - - server.use( - process.env.FRONTEND_API_PATH, - createProxyMiddleware({ - target: process.env.API_URL, - changeOrigin: true, - pathRewrite: (path) => { - return path.replace(process.env.FRONTEND_API_PATH, ''); - }, - router: async (req) => getRouterConfig(req, false), - secure: true, - xfwd: true, - logLevel: 'info', - }), - ); - - server.use( - process.env.FRONTEND_INNSYN_API_PATH, - createProxyMiddleware({ - target: process.env.API_URL_INNSYN, - changeOrigin: true, - pathRewrite: (path) => { - return path.replace(process.env.FRONTEND_INNSYN_API_PATH, ''); - }, - router: async (req) => getRouterConfig(req, true), - secure: true, - xfwd: true, - logLevel: 'info', - }), - ); - - if (isDev) { - const fs = require('fs'); - fs.writeFileSync(path.resolve(__dirname, 'index-decorated.html'), html); - const vedleggMockStore = './dist/vedlegg'; - - if (!fs.existsSync(vedleggMockStore)) { - fs.mkdirSync(vedleggMockStore); - } - - const vite = await require('vite').createServer({ - root: __dirname, - server: { - middlewareMode: true, - port: 8080, - open: './index-decorated.html', - }, - }); - - server.use( - '/api', - RateLimit({ - windowMs: 15 * 60 * 1000, // 15 minutes - max: 500, // max 100 requests per windowMs - standardHeaders: 'draft-7', - legacyHeaders: false, - }), - ); - - server.get(/^\/(?!.*dist).*$/, (req, _res, next) => { - const fullPath = path.resolve(__dirname, decodeURIComponent(req.path.substring(1))); - const fileExists = fs.existsSync(fullPath); - - if ((!fileExists && !req.url.startsWith('/@')) || req.url === '/') { - req.url = '/index-decorated.html'; - } - next(); - }); - - server.use(vite.middlewares); - } else { - server.use(`${process.env.PUBLIC_PATH}/assets`, express.static(path.resolve(__dirname, 'dist/assets'))); - server.get(/^\/(?!.*api)(?!.*innsynapi)(?!.*dist).*$/, (_req, res) => { - res.send(html); - }); - } - - const port = process.env.PORT || 8080; - server.listen(port, () => { - console.log(`App listening on port: ${port}`); - }); -}; - -getDecorator(getAppSettings()) - .then(renderApp, (error) => { - console.log(error); - logError('Failed to get decorator', error); - process.exit(1); - }) - .then(startServer, (error) => logError('Failed to render app', error)); diff --git a/apps/endringsmelding-pleiepenger/src/app/App.tsx b/apps/endringsmelding-pleiepenger/src/app/App.tsx index 93dac56e73..75d28b5d9d 100644 --- a/apps/endringsmelding-pleiepenger/src/app/App.tsx +++ b/apps/endringsmelding-pleiepenger/src/app/App.tsx @@ -15,7 +15,7 @@ import '@navikt/sif-common-core-ds/src/styles/sif-ds-theme.css'; dayjs.extend(isoWeek); -const container = document.getElementById('app'); +const container = document.getElementById('root'); // eslint-disable-next-line const root = createRoot(container!); const publicPath = getEnvironmentVariable('PUBLIC_PATH'); @@ -29,11 +29,11 @@ function prepare() { if (envNow && getEnvironmentVariable('APP_VERSION') === 'dev') { MockDate.set(new Date(envNow)); } - if (getEnvironmentVariable('MSW') === 'on' && (window as any).isE2E === undefined) { + if (getEnvironmentVariable('MSW') === 'on' && isE2E !== undefined) { return import('../mocks/msw/browser').then(({ worker }) => { worker.start({ onUnhandledRequest: 'bypass', - quiet: true, + quiet: false, }); }); } diff --git a/apps/endringsmelding-pleiepenger/src/app/api/api.ts b/apps/endringsmelding-pleiepenger/src/app/api/api.ts index b47ec0384c..3cbe2f268a 100644 --- a/apps/endringsmelding-pleiepenger/src/app/api/api.ts +++ b/apps/endringsmelding-pleiepenger/src/app/api/api.ts @@ -14,13 +14,13 @@ const axiosConfigCommon: AxiosRequestConfig = { export const axiosConfigPsb: AxiosRequestConfig = { ...axiosConfigCommon, - baseURL: getEnvVariableOrDefault('FRONTEND_API_PATH', 'http://localhost:8080'), + baseURL: getEnvVariableOrDefault('K9_BRUKERDIALOG_PROSESSERING_FRONTEND_PATH', 'http://localhost:8080'), }; const axiosConfigInnsyn: AxiosRequestConfig = { ...axiosConfigCommon, transformResponse: storageParser, - baseURL: getEnvVariableOrDefault('FRONTEND_INNSYN_API_PATH', 'http://localhost:8082'), + baseURL: getEnvVariableOrDefault('SIF_INNSYN_FRONTEND_PATH', 'http://localhost:8082'), }; axios.interceptors.request.use((config) => { diff --git "a/apps/endringsmelding-pleiepenger/src/app/s\303\270knad/S\303\270knad.tsx" "b/apps/endringsmelding-pleiepenger/src/app/s\303\270knad/S\303\270knad.tsx" index caaa442d0a..274c549175 100644 --- "a/apps/endringsmelding-pleiepenger/src/app/s\303\270knad/S\303\270knad.tsx" +++ "b/apps/endringsmelding-pleiepenger/src/app/s\303\270knad/S\303\270knad.tsx" @@ -75,7 +75,7 @@ const Søknad = () => { - {getEnvironmentVariable('MSW') === 'on' && } + {getEnvironmentVariable('SIF_PUBLIC_FEATURE_VELG_SCENARIO') === 'on' && } ); diff --git a/apps/endringsmelding-pleiepenger/src/build/AppSettings.cjs b/apps/endringsmelding-pleiepenger/src/build/AppSettings.cjs deleted file mode 100644 index 33975a0b03..0000000000 --- a/apps/endringsmelding-pleiepenger/src/build/AppSettings.cjs +++ /dev/null @@ -1,25 +0,0 @@ -require('dotenv').config(); - -const getAppSettings = (isTest) => ({ - API_URL_INNSYN: `${process.env.API_URL_INNSYN}`, - API_URL: `${process.env.API_URL}`, - APP_VERSION: `${process.env.APP_VERSION}`, - APPSTATUS_DATASET: `${process.env.APPSTATUS_DATASET}`, - APPSTATUS_PROJECT_ID: `${process.env.APPSTATUS_PROJECT_ID}`, - DEKORATOR_URL: `${process.env.DEKORATOR_URL}`, - DOMAIN_URL: `${process.env.DOMAIN_URL}`, - FRONTEND_API_PATH: `${process.env.FRONTEND_API_PATH}`, - FRONTEND_INNSYN_API_PATH: `${process.env.FRONTEND_INNSYN_API_PATH}`, - GITHUB_REF_NAME: `${process.env.GITHUB_REF_NAME}`, - IMAGE: `${process.env.IMAGE}`, - IMAGE: `${process.env.IMAGE}`, - INNSYN_URL: `${process.env.INNSYN_URL}`, - LOGIN_URL: `${process.env.LOGIN_URL}`, - MINSIDE_URL: `${process.env.MINSIDE_URL}`, - MSW: `${process.env.MSW}`, - PUBLIC_PATH: `${process.env.PUBLIC_PATH}`, - E2E_TEST: isTest ? 'true' : false, - NOW: `${process.env.NOW}`, -}); - -module.exports = getAppSettings; diff --git a/apps/endringsmelding-pleiepenger/tokenx.cjs b/apps/endringsmelding-pleiepenger/tokenx.cjs deleted file mode 100644 index c602f81c02..0000000000 --- a/apps/endringsmelding-pleiepenger/tokenx.cjs +++ /dev/null @@ -1,58 +0,0 @@ -const { Issuer } = require('openid-client'); -let tokenxClient; - -async function initTokenX() { - const tokenxIssuer = await Issuer.discover(process.env.TOKEN_X_WELL_KNOWN_URL); - tokenxClient = new tokenxIssuer.Client( - { - client_id: process.env.TOKEN_X_CLIENT_ID, - token_endpoint_auth_method: 'private_key_jwt', - }, - { - keys: [JSON.parse(process.env.TOKEN_X_PRIVATE_JWK)], - }, - ); -} - -async function getTokenXToken(token, additionalClaims, audienceInnsyn) { - let tokenSet; - try { - tokenSet = await tokenxClient?.grant( - { - grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange', - client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer', - subject_token_type: 'urn:ietf:params:oauth:token-type:jwt', - audience: - audienceInnsyn === true ? process.env.INNSYN_API_TOKENX_AUDIENCE : process.env.API_TOKENX_AUDIENCE, - subject_token: token, - }, - additionalClaims, - ); - } catch (err) { - // eslint-disable-next-line no-console - console.error('Noe gikk galt ved exchange token', err); - } - return tokenSet; -} - -async function exchangeToken(token, audienceInnsyn) { - if (!token) { - // Brukeren er ikke autorisert - return; - } - - const additionalClaims = { - clientAssertionPayload: { - nbf: Math.floor(Date.now() / 1000), - // TokenX only allows a single audience - aud: [tokenxClient?.issuer.metadata.token_endpoint], - }, - }; - - return await getTokenXToken(token, additionalClaims, audienceInnsyn); -} - -module.exports = { - initTokenX, - exchangeToken, -}; diff --git a/server/src/utils/serverConfig.ts b/server/src/utils/serverConfig.ts index 6bc6a53bd6..a0af6bbf2b 100644 --- a/server/src/utils/serverConfig.ts +++ b/server/src/utils/serverConfig.ts @@ -5,16 +5,16 @@ type Proxy = { }; export enum Service { - innsyn = 'innsyn', + sifInnsyn = 'sifInnsyn', k9SakInnsyn = 'k9SakInnsyn', k9BrukerdialogProsessering = 'k9BrukerdialogProsessering', } const proxies = { - [Service.innsyn]: { - frontendPath: process.env.INNSYN_FRONTEND_PATH, - apiScope: process.env.INNSYN_API_SCOPE, - apiUrl: process.env.INNSYN_API_URL, + [Service.sifInnsyn]: { + frontendPath: process.env.SIF_INNSYN_FRONTEND_PATH, + apiScope: process.env.SIF_INNSYN_API_SCOPE, + apiUrl: process.env.SIF_INNSYN_API_URL, }, [Service.k9SakInnsyn]: { frontendPath: process.env.K9_SAK_INNSYN_FRONTEND_PATH, diff --git a/yarn.lock b/yarn.lock index 46cf748a21..dd31999222 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5530,6 +5530,7 @@ __metadata: "@navikt/ds-icons": "npm:3.4.3" "@navikt/ds-react": "npm:7.1.2" "@navikt/ds-tailwind": "npm:7.1.2" + "@navikt/nav-dekoratoren-moduler": "npm:3.1.0" "@navikt/sif-common-amplitude": "npm:*" "@navikt/sif-common-core-ds": "npm:*" "@navikt/sif-common-formik-ds": "npm:*"