diff --git a/.kontinuous/env/preprod/values.yaml b/.kontinuous/env/preprod/values.yaml index 188694183..29266b778 100644 --- a/.kontinuous/env/preprod/values.yaml +++ b/.kontinuous/env/preprod/values.yaml @@ -17,7 +17,7 @@ www: host: cdtn-admin-preprod.dev.fabrique.social.gouv.fr env: - name: "FRONTEND_HOST" - value: https://cdtn-admin-preprod.dev.fabrique.social.gouv.fr + value: cdtn-admin-preprod.dev.fabrique.social.gouv.fr jobs: runs: diff --git a/.kontinuous/env/prod/values.yaml b/.kontinuous/env/prod/values.yaml index f0f78e389..fb6ea866d 100644 --- a/.kontinuous/env/prod/values.yaml +++ b/.kontinuous/env/prod/values.yaml @@ -5,7 +5,7 @@ www: nginx.ingress.kubernetes.io/whitelist-source-range: 185.24.184.196,185.24.185.196,185.24.186.196,185.24.187.196,185.24.187.254,164.131.160.1,164.131.160.2,164.131.160.3,164.131.160.4,164.131.160.5,164.131.160.6,164.131.160.17,164.131.160.18,164.131.160.19,164.131.160.20,164.131.160.21,164.131.160.22,164.131.160.33,164.131.160.34,164.131.160.35,164.131.160.36,164.131.160.37,164.131.160.38,164.131.160.49,164.131.160.50,164.131.160.51,164.131.160.52,164.131.160.53,164.131.160.54 env: - name: "FRONTEND_HOST" - value: https://cdtn-admin.fabrique.social.gouv.fr + value: cdtn-admin.fabrique.social.gouv.fr resources: limits: cpu: "200m" @@ -34,18 +34,18 @@ contributions: export: resources: limits: - cpu: '1500m' - memory: '4096Mi' + cpu: "1500m" + memory: "4096Mi" requests: - cpu: '1000m' - memory: '896Mi' + cpu: "1000m" + memory: "896Mi" hasura: replicas: 2 resources: limits: - cpu: '2000m' - memory: '4Gi' + cpu: "2000m" + memory: "4Gi" requests: - cpu: '1000m' - memory: '1Gi' + cpu: "1000m" + memory: "1Gi" diff --git a/.node-version b/.node-version index 2edeafb09..7639d8576 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -20 \ No newline at end of file +20.3.1 \ No newline at end of file diff --git a/targets/frontend/next.config.js b/targets/frontend/next.config.js index d639a2102..4a1386d32 100644 --- a/targets/frontend/next.config.js +++ b/targets/frontend/next.config.js @@ -1,9 +1,3 @@ -// Use the hidden-source-map option when you don't want the source maps to be -// publicly available on the servers, only to the error reporting -const withSourceMaps = require("@zeit/next-source-maps")(); - -const basePath = ""; - const securityHeaders = [ { key: "X-Frame-Options", @@ -14,7 +8,6 @@ const securityHeaders = [ ]; module.exports = { - basePath, async headers() { return [ { @@ -25,6 +18,9 @@ module.exports = { ]; }, poweredByHeader: false, + httpAgentOptions: { + keepAlive: false, + }, webpack: (config, { isServer, dev }) => { config.module.rules.push({ exclude: /node_modules/, diff --git a/targets/frontend/package.json b/targets/frontend/package.json index 9de3ac775..b5e8958c6 100644 --- a/targets/frontend/package.json +++ b/targets/frontend/package.json @@ -36,7 +36,6 @@ "@tiptap/react": "^2.1.10", "@tiptap/starter-kit": "^2.0.3", "@urql/exchange-auth": "^0.1.6", - "@zeit/next-source-maps": "0.0.4-canary.1", "ace-builds": "^1.4.12", "argon2": "^0.30.3", "cookie": "^0.4.1", @@ -46,12 +45,12 @@ "diff": "^5.0.0", "formidable": "^2.0.0", "graphql": "^16.0.0", - "http-proxy-middleware": "3.0.0-beta.1", + "http-proxy-middleware": "2.0.1", "isomorphic-unfetch": "^3.1.0", "jsonwebtoken": "^8.5.1", "memoizee": "^0.4.15", "micromark": "^2.11.4", - "next": "13.2.4", + "next": "13.5.6", "next-urql": "^3.2.1", "nodemailer": "^6.6.5", "p-limit": "^4.0.0", @@ -85,6 +84,7 @@ "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.5.1", + "@types/cookie": "^0.5.2", "@types/formidable": "^2.0.5", "@types/jest": "^27.4.0", "@types/jsonwebtoken": "^9.0.3", diff --git a/targets/frontend/src/components/editor/CodeEditor.js b/targets/frontend/src/components/editor/CodeEditor.js index 4d0b6da0e..8635fe8c7 100644 --- a/targets/frontend/src/components/editor/CodeEditor.js +++ b/targets/frontend/src/components/editor/CodeEditor.js @@ -7,20 +7,24 @@ import "ace-builds/src-noconflict/theme-github"; export default function CodeEditor({ onChange, value }) { return ( - + <> + {window && ( + + )} + ); } diff --git a/targets/frontend/src/config.ts b/targets/frontend/src/config.ts index c29a5f4ef..89fdc061e 100644 --- a/targets/frontend/src/config.ts +++ b/targets/frontend/src/config.ts @@ -2,7 +2,3 @@ export const ACCOUNT_MAIL_SENDER = "contact@fabrique.social.gouv.fr"; export const JWT_TOKEN_EXPIRES = 15; // 15 min export const REFRESH_TOKEN_EXPIRES = 43200; // 30 days in minutes export const ACTIVATION_TOKEN_EXPIRES = 10080; // 7 days in minutes -export const HASURA_GRAPHQL_JWT_SECRET = - process.env.HASURA_GRAPHQL_JWT_SECRET ?? - '{"type":"HS256","key":"a_pretty_long_secret_key_that_should_be_at_least_32_char"}'; -export const BASE_URL = process.env.FRONTEND_HOST || `http://localhost:3000`; diff --git a/targets/frontend/src/hoc/CustomUrqlClient.js b/targets/frontend/src/hoc/CustomUrqlClient.js index c79a07615..dfd3096f2 100644 --- a/targets/frontend/src/hoc/CustomUrqlClient.js +++ b/targets/frontend/src/hoc/CustomUrqlClient.js @@ -1,5 +1,4 @@ import { withUrqlClient } from "next-urql"; -import { BASE_URL } from "../config"; import { customAuthExchange, customErrorExchange, @@ -9,13 +8,11 @@ import { cacheExchange, dedupExchange, fetchExchange } from "urql"; export const withCustomUrqlClient = (Component) => withUrqlClient( (ssrExchange, ctx) => { - const url = ctx?.req ? `${BASE_URL}/api/graphql` : `/api/graphql`; - console.log( - "[ withUrqlClient ]", - ctx ? (ctx?.req ? "server" : "client") : "no ctx", - ctx?.pathname, - url - ); + const baseUrl = process.env.FRONTEND_HOST + ? `https://www.${process.env.FRONTEND_HOST}` + : `http://localhost:3000`; + const isServer = ctx && ctx.req; + const url = isServer ? `${baseUrl}/api/graphql` : "/api/graphql"; return { exchanges: [ process.env.NODE_ENV !== "production" diff --git a/targets/frontend/src/hoc/UserProvider.js b/targets/frontend/src/hoc/UserProvider.js index 73600585a..8fcd50325 100644 --- a/targets/frontend/src/hoc/UserProvider.js +++ b/targets/frontend/src/hoc/UserProvider.js @@ -20,7 +20,6 @@ export function withUserProvider(WrappedComponent) { static async getInitialProps(ctx) { const token = await auth(ctx); - console.log("[ withUserProvider ] ctx", ctx ? true : false); const componentProps = WrappedComponent.getInitialProps && (await WrappedComponent.getInitialProps(ctx)); diff --git a/targets/frontend/src/lib/auth/cookie.ts b/targets/frontend/src/lib/auth/cookie.ts new file mode 100644 index 000000000..daf5c681c --- /dev/null +++ b/targets/frontend/src/lib/auth/cookie.ts @@ -0,0 +1,56 @@ +import cookie from "cookie"; +import { REFRESH_TOKEN_EXPIRES } from "src/config"; + +export function setJwtCookie( + res: any, + refresh_token?: string, + jwt_token?: string +) { + const cookies = []; + try { + if (refresh_token) { + cookies.push( + cookie.serialize("refresh_token", refresh_token, { + httpOnly: true, + maxAge: REFRESH_TOKEN_EXPIRES * 60, // maxAge in second + path: "/", + sameSite: "strict", + secure: process.env.NODE_ENV === "production", + }) + ); + } + if (jwt_token) { + cookies.push( + cookie.serialize("jwt", jwt_token, { + httpOnly: true, + path: "/", + sameSite: "strict", + secure: process.env.NODE_ENV === "production", + }) + ); + } + if (cookies.length > 0) res.setHeader("Set-Cookie", cookies); + } catch (err) { + console.error("[setJwtCookie]", err); + } +} + +export function removeJwtCookie(res: any) { + const cookies = [ + cookie.serialize("refresh_token", "", { + httpOnly: true, + maxAge: -1, + path: "/", + sameSite: "strict", + secure: process.env.NODE_ENV === "production", + }), + cookie.serialize("jwt", "", { + httpOnly: true, + maxAge: -1, + path: "/", + sameSite: "strict", + secure: process.env.NODE_ENV === "production", + }), + ]; + res.setHeader("Set-Cookie", cookies); +} diff --git a/targets/frontend/src/lib/auth/exchanges.js b/targets/frontend/src/lib/auth/exchanges.js index 0b173e88d..08c414cbe 100644 --- a/targets/frontend/src/lib/auth/exchanges.js +++ b/targets/frontend/src/lib/auth/exchanges.js @@ -1,6 +1,6 @@ import { errorExchange, makeOperation } from "@urql/core"; import { authExchange } from "@urql/exchange-auth"; -import { auth, getToken, isTokenExpired, setToken } from "src/lib/auth/token"; +import { auth } from "src/lib/auth/token"; import { request } from "../request"; @@ -35,24 +35,6 @@ export function customAuthExchange(ctx) { }, getAuth: async ({ authState }) => { - // for initial launch, fetch the auth state from storage (local storage, async storage etc) - if (!authState) { - const token = getToken() || (await auth(ctx)); - if (token) { - return { token: token.jwt_token }; - } - return null; - } - - /** - * the following code gets executed when an auth error has occurred - * we should refresh the token if possible and return a new auth state - * If refresh fails, we should log out - **/ - - // if your refresh logic is in graphQL, you must use this mutate function to call it - // if your refresh logic is a separate RESTful endpoint, use fetch or similar - setToken(null); const result = await auth(ctx); if (result?.jwt_token) { // return the new tokens @@ -64,7 +46,7 @@ export function customAuthExchange(ctx) { willAuthError: ({ authState }) => { // e.g. check for expiration, existence of auth etc - if (!authState || isTokenExpired()) return true; + if (!authState) return true; return false; }, }); diff --git a/targets/frontend/src/lib/auth/jwt.js b/targets/frontend/src/lib/auth/jwt.js index 949b5c410..5943a0b7d 100644 --- a/targets/frontend/src/lib/auth/jwt.js +++ b/targets/frontend/src/lib/auth/jwt.js @@ -1,12 +1,13 @@ import jwt, { verify } from "jsonwebtoken"; -import { HASURA_GRAPHQL_JWT_SECRET } from "../../config"; - import { JWT_TOKEN_EXPIRES } from "../../config"; let jwtSecret; try { - jwtSecret = JSON.parse(HASURA_GRAPHQL_JWT_SECRET); + jwtSecret = JSON.parse( + process.env.HASURA_GRAPHQL_JWT_SECRET ?? + '{"type":"HS256","key":"a_pretty_long_secret_key_that_should_be_at_least_32_char"}' + ); } catch (error) { console.error("[JWT], HASURA_GRAPHQL_JWT_SECRET is not a valid json"); } diff --git a/targets/frontend/src/lib/auth/setJwtCookie.js b/targets/frontend/src/lib/auth/setJwtCookie.js deleted file mode 100644 index 4a4a4ccdf..000000000 --- a/targets/frontend/src/lib/auth/setJwtCookie.js +++ /dev/null @@ -1,25 +0,0 @@ -import cookie from "cookie"; -import { REFRESH_TOKEN_EXPIRES } from "../../config"; - -export function setJwtCookie(res, refresh_token, jwt_token) { - const cookies = [ - cookie.serialize("refresh_token", refresh_token, { - httpOnly: true, - maxAge: parseInt(REFRESH_TOKEN_EXPIRES, 10) * 60, // maxAge in second - path: "/", - sameSite: "Strict", - secure: process.env.NODE_ENV === "production", - }), - ]; - if (jwt_token) { - cookies.push( - cookie.serialize("jwt", jwt_token, { - httpOnly: true, - path: "/", - sameSite: "Strict", - secure: process.env.NODE_ENV === "production", - }) - ); - } - res.setHeader("Set-Cookie", cookies); -} diff --git a/targets/frontend/src/lib/auth/token.js b/targets/frontend/src/lib/auth/token.js index d33a36756..b054af83b 100644 --- a/targets/frontend/src/lib/auth/token.js +++ b/targets/frontend/src/lib/auth/token.js @@ -1,30 +1,13 @@ import Router from "next/router"; -import { request } from "../request"; -import { setJwtCookie } from "./setJwtCookie"; -import { BASE_URL } from "../../config"; - -let inMemoryToken; - -export function getToken() { - return inMemoryToken || null; -} - -export function setToken(token) { - inMemoryToken = token; -} - -export function isTokenExpired() { - const expired = - !inMemoryToken || Date.now() > new Date(inMemoryToken.jwt_token_expiry); - return expired; -} +import { setJwtCookie, removeJwtCookie } from "./cookie"; +import cookie from "cookie"; export async function auth(ctx) { - console.log("[ auth ] ctx ?", ctx ? true : false); - if (ctx?.token) { - return ctx.token; - } + console.log( + "[auth] - refresh token => is server ?", + ctx && ctx.req ? true : false + ); const cookieHeader = ctx?.req ? { Cookie: ctx.req.headers.cookie } : {}; if ( @@ -32,41 +15,65 @@ export async function auth(ctx) { !ctx.res.writableEnded && !/refresh_token/.test(cookieHeader.Cookie) ) { - console.log("[ auth ] no cookie found -> redirect to login"); + console.log("[auth] no cookie found -> redirect to login"); ctx.res.writeHead(302, { Location: "/login" }); ctx.res.end(); return null; } try { - console.log("[auth] refresh token"); - const tokenData = await request( - ctx?.req ? `${BASE_URL}/api/refresh_token` : "/api/refresh_token", - { - body: {}, - credentials: "include", - headers: { - "Cache-Control": "no-cache", - ...cookieHeader, - }, - mode: "same-origin", + const baseUrl = process.env.FRONTEND_HOST + ? `https://www.${process.env.FRONTEND_HOST}` + : `http://localhost:3000`; + const isServer = ctx && ctx.req; + const url = isServer + ? `${baseUrl}/api/refresh_token` + : "/api/refresh_token"; + + let body = {}; + + if (cookieHeader && cookieHeader.Cookie) { + let cookies = cookie.parse(cookieHeader.Cookie); + if (cookies && cookies.refresh_token) { + body = { + ...cookies, + }; } - ); + } + if (body.length === 0) { + console.log("no token found"); + return; + } + const tokenData = await fetch(url, { + headers: { + "Content-Type": "application/json", + "Cache-Control": "no-cache", + ...cookieHeader, + }, + method: "POST", + cache: "no-cache", + mode: "same-origin", + credentials: "include", + body: JSON.stringify({ + refresh_token: body.refresh_token, + }), + }).then((res) => res.json()); + + if (!tokenData.refresh_token) { + throw new Error("no refresh_token found"); + } + // for ServerSide call, we need to set the Cookie header // to update the refresh_token value - if (ctx?.res) { + if (isServer) { setJwtCookie(ctx.res, tokenData.refresh_token); - // we also store token in context (this is probably a bad idea b) - // to reuse it and avoid refresh token twice - ctx.token = tokenData; } - inMemoryToken = { ...tokenData }; - console.log("[auth] token", inMemoryToken ? "true" : "false"); - return inMemoryToken; + return tokenData; } catch (error) { console.error("[ auth ] refreshToken error ", { error }); // we are on server side and its response is not ended yet if (ctx?.res && !ctx.res.writableEnded) { + removeJwtCookie(ctx.res); ctx.res.writeHead(302, { Location: "/login" }); ctx.res.end(); } else if (ctx && !ctx.req) { diff --git a/targets/frontend/src/lib/duration.js b/targets/frontend/src/lib/duration.js index 0eb8f1380..6ca5488e7 100644 --- a/targets/frontend/src/lib/duration.js +++ b/targets/frontend/src/lib/duration.js @@ -10,7 +10,12 @@ export function toSecond(minutes = 0) { } export function getExpiryDate(minutes = 0) { - return new Date(Date.now() + toMs(minutes)); + try { + return new Date(Date.now() + toMs(minutes)); + } catch (error) { + console.error(error); + return null; + } } export const timeSince = (date) => diff --git a/targets/frontend/src/lib/emails/activateAccount.ts b/targets/frontend/src/lib/emails/activateAccount.ts index 5dc7e370e..71c6d18ef 100644 --- a/targets/frontend/src/lib/emails/activateAccount.ts +++ b/targets/frontend/src/lib/emails/activateAccount.ts @@ -1,9 +1,12 @@ -import { BASE_URL } from "src/config"; import sendmail from "./sendmail"; export function sendActivateAccountEmail(email: string, secret_token: string) { const subject = "Activation de votre compte"; - const activateUrl = `${BASE_URL}/change_password?token=${secret_token}&activate=1`; // todo: dynamic hostname + const activateUrl = `${ + process.env.FRONTEND_HOST + ? `https://www.${process.env.FRONTEND_HOST}` + : `http://localhost:3000` + }/change_password?token=${secret_token}&activate=1`; // todo: dynamic hostname const text = `Bonjour, Vous pouvez activer votre compte ${email} afin d'accéder à l'outil d'administration du cdtn en suivant ce lien : ${activateUrl} diff --git a/targets/frontend/src/lib/emails/lostPassword.js b/targets/frontend/src/lib/emails/lostPassword.js index 35d6bae69..916c240eb 100644 --- a/targets/frontend/src/lib/emails/lostPassword.js +++ b/targets/frontend/src/lib/emails/lostPassword.js @@ -1,8 +1,11 @@ -import { BASE_URL } from "../../config"; import sendmail from "./sendmail"; export function sendLostPasswordEmail(email, secret_token) { - const activateUrl = `${BASE_URL}/change_password?token=${secret_token}`; // todo: dynamic hostname + const activateUrl = `${ + process.env.FRONTEND_HOST + ? `https://www.${process.env.FRONTEND_HOST}` + : `http://localhost:3000` + }/change_password?token=${secret_token}`; // todo: dynamic hostname const subject = "Réinitialisation de votre mot de passe"; const text = ` Bonjour, diff --git a/targets/frontend/src/pages/api/graphql.js b/targets/frontend/src/pages/api/graphql.js index dc9fd13b0..457d0b980 100644 --- a/targets/frontend/src/pages/api/graphql.js +++ b/targets/frontend/src/pages/api/graphql.js @@ -23,7 +23,6 @@ const proxy = createProxyMiddleware({ process.env.HASURA_GRAPHQL_ENDPOINT ?? "http://localhost:8080/v1/graphql", ws: true, xfwd: true, // proxy websockets - headers: { Connection: "keep-alive" }, }); export default proxy; diff --git a/targets/frontend/src/pages/api/login.js b/targets/frontend/src/pages/api/login.js index 5a2bfed2b..a4f87c728 100644 --- a/targets/frontend/src/pages/api/login.js +++ b/targets/frontend/src/pages/api/login.js @@ -4,7 +4,7 @@ import { client } from "@shared/graphql-client"; import { verify } from "argon2"; import { createErrorFor } from "src/lib/apiError"; import { generateJwtToken } from "src/lib/auth/jwt"; -import { setJwtCookie } from "src/lib/auth/setJwtCookie"; +import { setJwtCookie } from "src/lib/auth/cookie"; import { getExpiryDate } from "src/lib/duration"; import { loginQuery, refreshTokenMutation } from "./login.gql"; @@ -69,10 +69,11 @@ export default async function login(req, res) { } const jwt_token = generateJwtToken(user); + const refreshTokenResult = await client .mutation(refreshTokenMutation, { refresh_token_data: { - expires_at: getExpiryDate(parseInt(REFRESH_TOKEN_EXPIRES, 10)), + expires_at: getExpiryDate(REFRESH_TOKEN_EXPIRES), user_id: user.id, }, }) @@ -93,7 +94,7 @@ export default async function login(req, res) { res.json({ jwt_token, - jwt_token_expiry: getExpiryDate(parseInt(JWT_TOKEN_EXPIRES, 10) || 15), + jwt_token_expiry: getExpiryDate(JWT_TOKEN_EXPIRES), refresh_token, }); } diff --git a/targets/frontend/src/pages/api/logout.js b/targets/frontend/src/pages/api/logout.js index eac7d2737..ef530b6a7 100644 --- a/targets/frontend/src/pages/api/logout.js +++ b/targets/frontend/src/pages/api/logout.js @@ -1,9 +1,8 @@ import Boom from "@hapi/boom"; import { z } from "zod"; import { client } from "@shared/graphql-client"; -import cookie from "cookie"; import { createErrorFor } from "src/lib/apiError"; -import { setToken } from "src/lib/auth/token"; +import { removeJwtCookie } from "src/lib/auth/cookie"; export default async function logout(req, res) { const apiError = createErrorFor(res); @@ -26,8 +25,6 @@ export default async function logout(req, res) { const { refresh_token } = value; - // delete JWT (optional) - setToken(null); // delete refresh token passed in data const result = await client .mutation(mutation, { @@ -39,29 +36,8 @@ export default async function logout(req, res) { console.error("logout error", result.error); } - console.log("[ logout ]", { refresh_token }); - res.setHeader( - "Set-Cookie", - cookie.serialize("refresh_token", "deleted", { - httpOnly: true, - maxAge: 0, - path: "/", - sameSite: "lax", - secure: process.env.NODE_ENV === "production", - }) - ); - res.setHeader( - "Set-Cookie", - cookie.serialize("jwt", "deleted", { - httpOnly: true, - maxAge: 0, - path: "/", - sameSite: "lax", - secure: process.env.NODE_ENV === "production", - }) - ); + removeJwtCookie(res); - console.log("[logout]", refresh_token); res.json({ message: "user logout !" }); } diff --git a/targets/frontend/src/pages/api/refresh_token.js b/targets/frontend/src/pages/api/refresh_token.js index 5c574cbe5..4d33a861d 100644 --- a/targets/frontend/src/pages/api/refresh_token.js +++ b/targets/frontend/src/pages/api/refresh_token.js @@ -3,11 +3,10 @@ import { z } from "zod"; import { client } from "@shared/graphql-client"; import { createErrorFor } from "src/lib/apiError"; import { generateJwtToken } from "src/lib/auth/jwt"; -import { setJwtCookie } from "src/lib/auth/setJwtCookie"; import { getExpiryDate } from "src/lib/duration"; import { v4 as uuidv4 } from "uuid"; import { REFRESH_TOKEN_EXPIRES, JWT_TOKEN_EXPIRES } from "../../config"; - +import { setJwtCookie } from "src/lib/auth/cookie"; import { deletePreviousRefreshTokenMutation, getRefreshTokenQuery, @@ -15,78 +14,84 @@ import { export default async function refreshToken(req, res) { const apiError = createErrorFor(res); - const schema = z.object({ - refresh_token: z.string().uuid(), - }); - - let { error, data: value } = schema.safeParse(req.query); - - if (error) { - const temp = schema.safeParse(req.body); - error = temp.error; - value = temp.data; - } - - if (error) { - const temp = schema.safeParse(req.cookies); - error = temp.error; - value = temp.data; - } - - const { refresh_token } = value; - - if (error) { - return apiError(Boom.badRequest(error.details[0].message)); + try { + console.log("[api/refresh_token.js] refreshToken"); + const schema = z.object({ + refresh_token: z.string().uuid(), + }); + + let value; + + let { error, data } = schema.safeParse(req.query); + + value = data; + + if (error) { + const temp = schema.safeParse(req.body); + error = temp.error; + value = temp.data; + } + + if (error) { + const temp = schema.safeParse(req.cookies); + error = temp.error; + value = temp.data; + } + + if (!value.refresh_token) { + return apiError(Boom.unauthorized("Invalid 'refresh_token'")); + } + + const { refresh_token } = value; + + let result = await client + .query(getRefreshTokenQuery, { + current_timestampz: new Date(), + refresh_token, + }) + .toPromise(); + + if (result.error) { + console.error(result.error); + return apiError(Boom.unauthorized("Invalid 'refresh_token'")); + } + + if (result.data.refresh_tokens.length === 0) { + console.error("Incorrect user id or refresh token", refresh_token); + return apiError(Boom.unauthorized("Invalid 'refresh_token'")); + } + + const { user } = result.data[`refresh_tokens`][0]; + + const new_refresh_token = uuidv4(); + + result = await client + .mutation(deletePreviousRefreshTokenMutation, { + new_refresh_token_data: { + expires_at: getExpiryDate(REFRESH_TOKEN_EXPIRES), + refresh_token: new_refresh_token, + user_id: user.id, + }, + old_refresh_token: refresh_token, + }) + .toPromise(); + + if (result.error) { + console.error(result.error); + return apiError(Boom.unauthorized("Invalid 'refresh_token'")); + } + + const jwt_token = generateJwtToken(user); + + setJwtCookie(res, new_refresh_token, jwt_token); + + res.json({ + jwt_token, + jwt_token_expiry: getExpiryDate(JWT_TOKEN_EXPIRES), + refresh_token: new_refresh_token, + }); + } catch (e) { + console.error(e); + return apiError(Boom.badImplementation(e.message)); } - let result = await client - .query(getRefreshTokenQuery, { - current_timestampz: new Date(), - refresh_token, - }) - .toPromise(); - - if (result.error) { - console.error(result.error); - return apiError(Boom.unauthorized("Invalid 'refresh_token'")); - } - - if (result.data.refresh_tokens.length === 0) { - console.error("Incorrect user id or refresh token", refresh_token); - return apiError(Boom.unauthorized("Invalid 'refresh_token'")); - } - - const { user } = result.data[`refresh_tokens`][0]; - - const new_refresh_token = uuidv4(); - - console.log("[ /api/refresh_token ]", "replace", { - new_refresh_token, - refresh_token, - }); - - result = await client - .mutation(deletePreviousRefreshTokenMutation, { - new_refresh_token_data: { - expires_at: getExpiryDate(parseInt(REFRESH_TOKEN_EXPIRES, 10)), - refresh_token: new_refresh_token, - user_id: user.id, - }, - old_refresh_token: refresh_token, - }) - .toPromise(); - - if (result.error) { - console.error(result.error); - return apiError(Boom.unauthorized("Invalid 'refresh_token'")); - } - - const jwt_token = generateJwtToken(user); - - setJwtCookie(res, new_refresh_token, jwt_token); - - res.json({ - jwt_token, - jwt_token_expiry: getExpiryDate(parseInt(JWT_TOKEN_EXPIRES, 10) || 15), - refresh_token: new_refresh_token, - }); } diff --git a/targets/frontend/src/pages/api/reset_password.js b/targets/frontend/src/pages/api/reset_password.js index 89d6676a2..5e0152cc5 100644 --- a/targets/frontend/src/pages/api/reset_password.js +++ b/targets/frontend/src/pages/api/reset_password.js @@ -29,7 +29,7 @@ export default async function reset_password(req, res) { const result = await client .mutation(udpateSecretTokenMutation, { email, - expires: getExpiryDate(parseInt(ACTIVATION_TOKEN_EXPIRES, 10)), + expires: getExpiryDate(ACTIVATION_TOKEN_EXPIRES), secret_token, }) .toPromise(); diff --git a/targets/frontend/src/pages/api/sitemap.ts b/targets/frontend/src/pages/api/sitemap.ts index 9b75eb412..3ae3c4571 100644 --- a/targets/frontend/src/pages/api/sitemap.ts +++ b/targets/frontend/src/pages/api/sitemap.ts @@ -66,7 +66,7 @@ export default async function Sitemap( req: NextApiRequest, res: NextApiResponse ) { - console.log("[ /api/sitemap ]", " request: ", req.query); + console.log("[/api/sitemap]", " request: ", req.query); const startProcessAt = process.hrtime(); const baseUrl = (req.query.baseurl as string) || "https://code.travail.gouv.fr"; @@ -92,7 +92,7 @@ export default async function Sitemap( `); res.end(); const endProcess = process.hrtime(startProcessAt); - console.log("[ /api/sitemap ]", " end in ", endProcess); + console.log("[/api/sitemap]", " end in ", endProcess); } /** diff --git a/targets/frontend/src/pages/api/storage/[path].js b/targets/frontend/src/pages/api/storage/[path].js index 20fef9633..b6a471ac0 100644 --- a/targets/frontend/src/pages/api/storage/[path].js +++ b/targets/frontend/src/pages/api/storage/[path].js @@ -2,14 +2,16 @@ import Boom from "@hapi/boom"; import { verify } from "jsonwebtoken"; import { createErrorFor } from "src/lib/apiError"; import { deleteBlob } from "src/lib/azure"; -import { HASURA_GRAPHQL_JWT_SECRET } from "../../../config"; const container = process.env.STORAGE_CONTAINER ?? "cdtn-dev"; -const jwtSecret = JSON.parse(HASURA_GRAPHQL_JWT_SECRET); +const jwtSecret = JSON.parse( + process.env.HASURA_GRAPHQL_JWT_SECRET ?? + '{"type":"HS256","key":"a_pretty_long_secret_key_that_should_be_at_least_32_char"}' +); export default async function deleteFiles(req, res) { const apiError = createErrorFor(res); - const { token } = req.headers; + const { jwt: token } = req.cookies; if (!token || !verify(token, jwtSecret.key, { algorithms: jwtSecret.type })) { return apiError(Boom.badRequest("wrong token")); diff --git a/targets/frontend/src/pages/api/storage/index.ts b/targets/frontend/src/pages/api/storage/index.ts index b100e7f0b..6c7386d3d 100644 --- a/targets/frontend/src/pages/api/storage/index.ts +++ b/targets/frontend/src/pages/api/storage/index.ts @@ -5,15 +5,17 @@ import { createErrorFor } from "src/lib/apiError"; import { getContainerBlobs, uploadBlob } from "src/lib/azure"; import { isUploadFileSafe } from "src/lib/secu"; import * as stream from "stream"; -import { HASURA_GRAPHQL_JWT_SECRET } from "../../../config"; import { NextApiRequest, NextApiResponse } from "next"; const container = process.env.STORAGE_CONTAINER ?? "cdtn-dev"; -const jwtSecret = JSON.parse(HASURA_GRAPHQL_JWT_SECRET); +const jwtSecret = JSON.parse( + process.env.HASURA_GRAPHQL_JWT_SECRET ?? + '{"type":"HS256","key":"a_pretty_long_secret_key_that_should_be_at_least_32_char"}' +); async function endPoint(req: NextApiRequest, res: NextApiResponse) { const apiError = createErrorFor(res); - const { token }: any = req.headers; + const { jwt: token } = req.cookies; if (!token || !verify(token, jwtSecret.key, { algorithms: jwtSecret.type })) { return apiError(Boom.badRequest("wrong token")); diff --git a/targets/frontend/src/pages/contenus/[id].tsx b/targets/frontend/src/pages/contenus/[id].tsx index 187d75017..4449d5905 100644 --- a/targets/frontend/src/pages/contenus/[id].tsx +++ b/targets/frontend/src/pages/contenus/[id].tsx @@ -1,7 +1,7 @@ import dynamic from "next/dynamic"; import Link from "next/link"; import { useRouter } from "next/router"; -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { Button } from "src/components/button"; import { Layout } from "src/components/layout/auth.layout"; @@ -23,6 +23,7 @@ const CodeWithCodemirror = dynamic(import("src/components/editor/CodeEditor"), { export function DocumentPage() { const router = useRouter(); + const [dataDocument, setDataDocument] = useState(undefined); const [result] = useQuery({ query: getDocumentQuery, @@ -30,12 +31,25 @@ export function DocumentPage() { id: router.query.id, }, }); - const { fetching, error, data: dataDocument } = result; + + useEffect(() => { + return () => { + setDataDocument(undefined); + setJsonData(undefined); + }; + }, []); + + useEffect(() => { + if (result && result.data && result.data.document) { + setDataDocument(result.data.document); + setJsonData(JSON.stringify(result.data.document, undefined, 2)); + } + }, [JSON.stringify(result)]); + + const { fetching, error } = result; const [hasChanged, setHasChanged] = useState(false); - const [jsonData, setJsonData] = useState( - JSON.stringify(dataDocument?.document, undefined, 2) - ); + const [jsonData, setJsonData] = useState(undefined); const [, executeUpdate] = useMutation(updateDocumentMutation); const [, previewContent] = useMutation(previewContentAction); const { handleSubmit } = useForm(); @@ -92,20 +106,19 @@ export function DocumentPage() { ); } return ( - +
- {/* - // @ts-ignore */} - + {jsonData && ( + // @ts-ignore + + )} - {/* - // @ts-ignore */} diff --git a/targets/frontend/src/pages/fichiers.tsx b/targets/frontend/src/pages/fichiers.tsx index ad21fb562..8ab5e5993 100644 --- a/targets/frontend/src/pages/fichiers.tsx +++ b/targets/frontend/src/pages/fichiers.tsx @@ -12,7 +12,6 @@ import { DropZone } from "src/components/storage/DropZone"; import { withCustomUrqlClient } from "src/hoc/CustomUrqlClient"; import { withUserProvider } from "src/hoc/UserProvider"; import { useDebouncedState } from "src/hooks/"; -import { getToken } from "src/lib/auth/token"; import { timeSince } from "src/lib/duration"; import { request } from "src/lib/request"; import useSWR, { mutate } from "swr"; @@ -29,20 +28,15 @@ import { List, } from "@mui/material"; -const listFiles = () => - request(`/api/storage`, { - headers: { token: getToken()?.jwt_token || "" }, - } as any); +const listFiles = () => request(`/api/storage`); const uploadFiles = (formData: any) => request(`/api/storage`, { body: formData, - headers: { token: getToken()?.jwt_token || "" }, } as any); const deleteFile = (path: any) => request(`/api/storage/${path}`, { - headers: { token: getToken()?.jwt_token || "" }, method: "DELETE", } as any); diff --git a/targets/frontend/src/pages/login.js b/targets/frontend/src/pages/login.js index 2e8a20af9..9618720a5 100644 --- a/targets/frontend/src/pages/login.js +++ b/targets/frontend/src/pages/login.js @@ -2,7 +2,6 @@ import Head from "next/head"; import { useRouter } from "next/router"; import { Header } from "src/components/layout/header"; import LoginForm from "src/components/login"; -import { setToken } from "src/lib/auth/token"; import { request } from "src/lib/request"; import { Box } from "@mui/material"; @@ -23,8 +22,6 @@ export default function LoginPage() { headers: { "Cache-Control": "no-cache", }, - }).then((tokenData) => { - setToken(tokenData); }); }; diff --git a/targets/frontend/src/pages/user/new.js b/targets/frontend/src/pages/user/new.js index 10edc24d2..8bcbed35b 100644 --- a/targets/frontend/src/pages/user/new.js +++ b/targets/frontend/src/pages/user/new.js @@ -29,9 +29,7 @@ function prepareMutationData(input) { return { user: { ...input, - secret_token_expires_at: getExpiryDate( - parseInt(ACTIVATION_TOKEN_EXPIRES, 10) - ), + secret_token_expires_at: getExpiryDate(ACTIVATION_TOKEN_EXPIRES), user_roles: { data: { role: input.default_role } }, }, }; diff --git a/yarn.lock b/yarn.lock index 99a696955..bacc0319e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3963,10 +3963,10 @@ __metadata: languageName: node linkType: hard -"@next/env@npm:13.2.4": - version: 13.2.4 - resolution: "@next/env@npm:13.2.4" - checksum: 4123e08a79e66d6144006972027a9ceb8f3fdd782c4a869df1eb3b91b59ad9f4a44082d3f8e421f4df5214c6bc7190b52b94881369452d65eb4580485f33b9e6 +"@next/env@npm:13.5.6": + version: 13.5.6 + resolution: "@next/env@npm:13.5.6" + checksum: 5e8f3f6f987a15dad3cd7b2bcac64a6382c2ec372d95d0ce6ab295eb59c9731222017eebf71ff3005932de2571f7543bce7e5c6a8c90030207fb819404138dc2 languageName: node linkType: hard @@ -4021,20 +4021,6 @@ __metadata: languageName: node linkType: hard -"@next/swc-android-arm-eabi@npm:13.2.4": - version: 13.2.4 - resolution: "@next/swc-android-arm-eabi@npm:13.2.4" - conditions: os=android & cpu=arm - languageName: node - linkType: hard - -"@next/swc-android-arm64@npm:13.2.4": - version: 13.2.4 - resolution: "@next/swc-android-arm64@npm:13.2.4" - conditions: os=android & cpu=arm64 - languageName: node - linkType: hard - "@next/swc-darwin-arm64@npm:11.1.2": version: 11.1.2 resolution: "@next/swc-darwin-arm64@npm:11.1.2" @@ -4042,9 +4028,9 @@ __metadata: languageName: node linkType: hard -"@next/swc-darwin-arm64@npm:13.2.4": - version: 13.2.4 - resolution: "@next/swc-darwin-arm64@npm:13.2.4" +"@next/swc-darwin-arm64@npm:13.5.6": + version: 13.5.6 + resolution: "@next/swc-darwin-arm64@npm:13.5.6" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard @@ -4056,37 +4042,23 @@ __metadata: languageName: node linkType: hard -"@next/swc-darwin-x64@npm:13.2.4": - version: 13.2.4 - resolution: "@next/swc-darwin-x64@npm:13.2.4" +"@next/swc-darwin-x64@npm:13.5.6": + version: 13.5.6 + resolution: "@next/swc-darwin-x64@npm:13.5.6" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@next/swc-freebsd-x64@npm:13.2.4": - version: 13.2.4 - resolution: "@next/swc-freebsd-x64@npm:13.2.4" - conditions: os=freebsd & cpu=x64 - languageName: node - linkType: hard - -"@next/swc-linux-arm-gnueabihf@npm:13.2.4": - version: 13.2.4 - resolution: "@next/swc-linux-arm-gnueabihf@npm:13.2.4" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - -"@next/swc-linux-arm64-gnu@npm:13.2.4": - version: 13.2.4 - resolution: "@next/swc-linux-arm64-gnu@npm:13.2.4" +"@next/swc-linux-arm64-gnu@npm:13.5.6": + version: 13.5.6 + resolution: "@next/swc-linux-arm64-gnu@npm:13.5.6" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@next/swc-linux-arm64-musl@npm:13.2.4": - version: 13.2.4 - resolution: "@next/swc-linux-arm64-musl@npm:13.2.4" +"@next/swc-linux-arm64-musl@npm:13.5.6": + version: 13.5.6 + resolution: "@next/swc-linux-arm64-musl@npm:13.5.6" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard @@ -4098,30 +4070,30 @@ __metadata: languageName: node linkType: hard -"@next/swc-linux-x64-gnu@npm:13.2.4": - version: 13.2.4 - resolution: "@next/swc-linux-x64-gnu@npm:13.2.4" +"@next/swc-linux-x64-gnu@npm:13.5.6": + version: 13.5.6 + resolution: "@next/swc-linux-x64-gnu@npm:13.5.6" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@next/swc-linux-x64-musl@npm:13.2.4": - version: 13.2.4 - resolution: "@next/swc-linux-x64-musl@npm:13.2.4" +"@next/swc-linux-x64-musl@npm:13.5.6": + version: 13.5.6 + resolution: "@next/swc-linux-x64-musl@npm:13.5.6" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@next/swc-win32-arm64-msvc@npm:13.2.4": - version: 13.2.4 - resolution: "@next/swc-win32-arm64-msvc@npm:13.2.4" +"@next/swc-win32-arm64-msvc@npm:13.5.6": + version: 13.5.6 + resolution: "@next/swc-win32-arm64-msvc@npm:13.5.6" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@next/swc-win32-ia32-msvc@npm:13.2.4": - version: 13.2.4 - resolution: "@next/swc-win32-ia32-msvc@npm:13.2.4" +"@next/swc-win32-ia32-msvc@npm:13.5.6": + version: 13.5.6 + resolution: "@next/swc-win32-ia32-msvc@npm:13.5.6" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard @@ -4133,9 +4105,9 @@ __metadata: languageName: node linkType: hard -"@next/swc-win32-x64-msvc@npm:13.2.4": - version: 13.2.4 - resolution: "@next/swc-win32-x64-msvc@npm:13.2.4" +"@next/swc-win32-x64-msvc@npm:13.5.6": + version: 13.5.6 + resolution: "@next/swc-win32-x64-msvc@npm:13.5.6" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -5741,12 +5713,12 @@ __metadata: languageName: node linkType: hard -"@swc/helpers@npm:0.4.14": - version: 0.4.14 - resolution: "@swc/helpers@npm:0.4.14" +"@swc/helpers@npm:0.5.2": + version: 0.5.2 + resolution: "@swc/helpers@npm:0.5.2" dependencies: tslib: ^2.4.0 - checksum: 273fd3f3fc461a92f3790cc551ea054745c6d6959afbe1232e6d7aa1c722bbc114d308aab96bef5c78fc0303c85c7b472ef00e2253251cc89737f3b1af56e5a5 + checksum: 51d7e3d8bd56818c49d6bfbd715f0dbeedc13cf723af41166e45c03e37f109336bbcb57a1f2020f4015957721aeb21e1a7fff281233d797ff7d3dd1f447fa258 languageName: node linkType: hard @@ -6364,6 +6336,13 @@ __metadata: languageName: node linkType: hard +"@types/cookie@npm:^0.5.2": + version: 0.5.2 + resolution: "@types/cookie@npm:0.5.2" + checksum: 4a1e46379d877f5a3cc687a9799dd72e5f7e68c4764d45cb469789dec92b4b4a7a5bb8b10a08c90be15939fa7b9b402f87ed339dfac0cabf43699c5189880e88 + languageName: node + linkType: hard + "@types/cookiejar@npm:*": version: 2.1.2 resolution: "@types/cookiejar@npm:2.1.2" @@ -6470,7 +6449,7 @@ __metadata: languageName: node linkType: hard -"@types/http-proxy@npm:^1.17.10": +"@types/http-proxy@npm:^1.17.5": version: 1.17.12 resolution: "@types/http-proxy@npm:1.17.12" dependencies: @@ -7227,13 +7206,6 @@ __metadata: languageName: node linkType: hard -"@zeit/next-source-maps@npm:0.0.4-canary.1": - version: 0.0.4-canary.1 - resolution: "@zeit/next-source-maps@npm:0.0.4-canary.1" - checksum: 20f476b24eca5f414b1f58effc562dccd3b00efcbc7e3daeebe83b60370c11621cef49e3bac4fd81858f581edb2abbaddbe5dfbb843b00d96844cfdaf8ed6948 - languageName: node - linkType: hard - "@zkochan/js-yaml@npm:0.0.6": version: 0.0.6 resolution: "@zkochan/js-yaml@npm:0.0.6" @@ -8638,6 +8610,15 @@ __metadata: languageName: node linkType: hard +"busboy@npm:1.6.0": + version: 1.6.0 + resolution: "busboy@npm:1.6.0" + dependencies: + streamsearch: ^1.1.0 + checksum: 32801e2c0164e12106bf236291a00795c3c4e4b709ae02132883fe8478ba2ae23743b11c5735a0aae8afe65ac4b6ca4568b91f0d9fed1fdbc32ede824a73746e + languageName: node + linkType: hard + "byte-size@npm:^7.0.0": version: 7.0.1 resolution: "byte-size@npm:7.0.1" @@ -12390,6 +12371,7 @@ __metadata: "@tiptap/pm": ^2.1.10 "@tiptap/react": ^2.1.10 "@tiptap/starter-kit": ^2.0.3 + "@types/cookie": ^0.5.2 "@types/formidable": ^2.0.5 "@types/jest": ^27.4.0 "@types/jsonwebtoken": ^9.0.3 @@ -12398,7 +12380,6 @@ __metadata: "@types/react-dom": ^18.0.11 "@urql/devtools": ^2.0.3 "@urql/exchange-auth": ^0.1.6 - "@zeit/next-source-maps": 0.0.4-canary.1 ace-builds: ^1.4.12 argon2: ^0.30.3 cookie: ^0.4.1 @@ -12411,7 +12392,7 @@ __metadata: formidable: ^2.0.0 graphql: ^16.0.0 graphql-tag: ^2.12.6 - http-proxy-middleware: 3.0.0-beta.1 + http-proxy-middleware: 2.0.1 isomorphic-unfetch: ^3.1.0 jest: ^29.5.0 jest-environment-jsdom: ^29.5.0 @@ -12419,7 +12400,7 @@ __metadata: lint-staged: ^12.0.0 memoizee: ^0.4.15 micromark: ^2.11.4 - next: 13.2.4 + next: 13.5.6 next-urql: ^3.2.1 nodemailer: ^6.6.5 p-limit: ^4.0.0 @@ -13642,6 +13623,19 @@ __metadata: languageName: node linkType: hard +"http-proxy-middleware@npm:2.0.1": + version: 2.0.1 + resolution: "http-proxy-middleware@npm:2.0.1" + dependencies: + "@types/http-proxy": ^1.17.5 + http-proxy: ^1.18.1 + is-glob: ^4.0.1 + is-plain-obj: ^3.0.0 + micromatch: ^4.0.2 + checksum: 0de65bc6644b6efae5d26cd3bec071ceaeb92f26856ffee5ecdde9c702ea1435936e7dfb09da2ac0883eada80fdc993e9925902fc10bf6625565d6365f8cb30f + languageName: node + linkType: hard + "http-proxy-middleware@npm:2.0.6": version: 2.0.6 resolution: "http-proxy-middleware@npm:2.0.6" @@ -13660,20 +13654,6 @@ __metadata: languageName: node linkType: hard -"http-proxy-middleware@npm:3.0.0-beta.1": - version: 3.0.0-beta.1 - resolution: "http-proxy-middleware@npm:3.0.0-beta.1" - dependencies: - "@types/http-proxy": ^1.17.10 - debug: ^4.3.4 - http-proxy: ^1.18.1 - is-glob: ^4.0.1 - is-plain-obj: ^3.0.0 - micromatch: ^4.0.5 - checksum: 683fe0cc27f5f499e9d07311294e3aca1f4f5ec7476fa64fba50bde260ef8d6199d12584b37ef7d4f398727f0763503a13ae47f07519a73fc84b07b85f9e451d - languageName: node - linkType: hard - "http-proxy@npm:^1.18.1": version: 1.18.1 resolution: "http-proxy@npm:1.18.1" @@ -17537,7 +17517,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.1.23, nanoid@npm:^3.3.4": +"nanoid@npm:^3.1.23, nanoid@npm:^3.3.6": version: 3.3.6 resolution: "nanoid@npm:3.3.6" bin: @@ -17747,48 +17727,36 @@ __metadata: languageName: node linkType: hard -"next@npm:13.2.4": - version: 13.2.4 - resolution: "next@npm:13.2.4" - dependencies: - "@next/env": 13.2.4 - "@next/swc-android-arm-eabi": 13.2.4 - "@next/swc-android-arm64": 13.2.4 - "@next/swc-darwin-arm64": 13.2.4 - "@next/swc-darwin-x64": 13.2.4 - "@next/swc-freebsd-x64": 13.2.4 - "@next/swc-linux-arm-gnueabihf": 13.2.4 - "@next/swc-linux-arm64-gnu": 13.2.4 - "@next/swc-linux-arm64-musl": 13.2.4 - "@next/swc-linux-x64-gnu": 13.2.4 - "@next/swc-linux-x64-musl": 13.2.4 - "@next/swc-win32-arm64-msvc": 13.2.4 - "@next/swc-win32-ia32-msvc": 13.2.4 - "@next/swc-win32-x64-msvc": 13.2.4 - "@swc/helpers": 0.4.14 +"next@npm:13.5.6": + version: 13.5.6 + resolution: "next@npm:13.5.6" + dependencies: + "@next/env": 13.5.6 + "@next/swc-darwin-arm64": 13.5.6 + "@next/swc-darwin-x64": 13.5.6 + "@next/swc-linux-arm64-gnu": 13.5.6 + "@next/swc-linux-arm64-musl": 13.5.6 + "@next/swc-linux-x64-gnu": 13.5.6 + "@next/swc-linux-x64-musl": 13.5.6 + "@next/swc-win32-arm64-msvc": 13.5.6 + "@next/swc-win32-ia32-msvc": 13.5.6 + "@next/swc-win32-x64-msvc": 13.5.6 + "@swc/helpers": 0.5.2 + busboy: 1.6.0 caniuse-lite: ^1.0.30001406 - postcss: 8.4.14 + postcss: 8.4.31 styled-jsx: 5.1.1 + watchpack: 2.4.0 peerDependencies: - "@opentelemetry/api": ^1.4.0 - fibers: ">= 3.1.0" - node-sass: ^6.0.0 || ^7.0.0 + "@opentelemetry/api": ^1.1.0 react: ^18.2.0 react-dom: ^18.2.0 sass: ^1.3.0 dependenciesMeta: - "@next/swc-android-arm-eabi": - optional: true - "@next/swc-android-arm64": - optional: true "@next/swc-darwin-arm64": optional: true "@next/swc-darwin-x64": optional: true - "@next/swc-freebsd-x64": - optional: true - "@next/swc-linux-arm-gnueabihf": - optional: true "@next/swc-linux-arm64-gnu": optional: true "@next/swc-linux-arm64-musl": @@ -17806,15 +17774,11 @@ __metadata: peerDependenciesMeta: "@opentelemetry/api": optional: true - fibers: - optional: true - node-sass: - optional: true sass: optional: true bin: next: dist/bin/next - checksum: 8531dee41b60181b582f5ee80858907b102f083ef8808ff9352d589dd39e6b3a96f7a11b3776a03eef3a28430cff768336fa2e3ff2c6f8fcd699fbc891749051 + checksum: c869b0014ae921ada3bf22301985027ec320aebcd6aa9c16e8afbded68bb8def5874cca034c680e8c351a79578f1e514971d02777f6f0a5a1d7290f25970ac0d languageName: node linkType: hard @@ -19454,14 +19418,14 @@ __metadata: languageName: node linkType: hard -"postcss@npm:8.4.14": - version: 8.4.14 - resolution: "postcss@npm:8.4.14" +"postcss@npm:8.4.31": + version: 8.4.31 + resolution: "postcss@npm:8.4.31" dependencies: - nanoid: ^3.3.4 + nanoid: ^3.3.6 picocolors: ^1.0.0 source-map-js: ^1.0.2 - checksum: fe58766ff32e4becf65a7d57678995cfd239df6deed2fe0557f038b47c94e4132e7e5f68b5aa820c13adfec32e523b693efaeb65798efb995ce49ccd83953816 + checksum: 1d8611341b073143ad90486fcdfeab49edd243377b1f51834dc4f6d028e82ce5190e4f11bb2633276864503654fb7cab28e67abdc0fbf9d1f88cad4a0ff0beea languageName: node linkType: hard @@ -22289,6 +22253,13 @@ __metadata: languageName: node linkType: hard +"streamsearch@npm:^1.1.0": + version: 1.1.0 + resolution: "streamsearch@npm:1.1.0" + checksum: 1cce16cea8405d7a233d32ca5e00a00169cc0e19fbc02aa839959985f267335d435c07f96e5e0edd0eadc6d39c98d5435fb5bbbdefc62c41834eadc5622ad942 + languageName: node + linkType: hard + "strict-uri-encode@npm:^2.0.0": version: 2.0.0 resolution: "strict-uri-encode@npm:2.0.0" @@ -24713,6 +24684,16 @@ __metadata: languageName: node linkType: hard +"watchpack@npm:2.4.0": + version: 2.4.0 + resolution: "watchpack@npm:2.4.0" + dependencies: + glob-to-regexp: ^0.4.1 + graceful-fs: ^4.1.2 + checksum: 23d4bc58634dbe13b86093e01c6a68d8096028b664ab7139d58f0c37d962d549a940e98f2f201cecdabd6f9c340338dc73ef8bf094a2249ef582f35183d1a131 + languageName: node + linkType: hard + "wcwidth@npm:^1.0.0, wcwidth@npm:^1.0.1": version: 1.0.1 resolution: "wcwidth@npm:1.0.1"