From 7994adbd0bb4a3e372a324c3138c5465b164b09b Mon Sep 17 00:00:00 2001 From: Xavier Jp Date: Thu, 4 Apr 2024 16:54:43 +0200 Subject: [PATCH 1/4] refactor: dysyncronize view from user rights (#959) * feat: dysyncronize view from user rights * chore: types and imports * refactor: use method instead of direct access to session * fix: UI glitch in header and colors * fix: minor glitches and bugs --- .../entreprise/[slug]/page.tsx | 4 +- .../_components/connection-france-connect.tsx | 3 +- .../_components/index.tsx | 3 +- app/(header-minimal)/formulaire/nps/page.tsx | 12 ++-- .../espace-agent/conformite/[slug]/route.ts | 4 +- .../espace-agent/documents/[slug]/route.ts | 4 +- .../non-diffusible.tsx | 17 +++-- components-ui/alerts/index.tsx | 2 +- .../documents/document-actes.tsx | 8 ++- .../documents/document-bilans.tsx | 8 ++- .../summary-section.tsx | 5 +- .../etablissement-description/index.tsx | 2 +- .../etablissement-liste-section/index.tsx | 2 +- components/etablissement-section/index.tsx | 2 +- components/finances-section/societe/index.tsx | 4 +- components/header/header-core/index.tsx | 5 +- .../header/header-core/styles.module.css | 4 +- components/immatriculations/index.tsx | 2 +- components/immatriculations/insee.tsx | 2 +- .../justificatifs/extrait-rne-link/index.tsx | 6 +- .../labels-and-certificates/rge/index.tsx | 2 +- components/load-bar/index.tsx | 8 ++- components/matomo-event/init.tsx | 10 +-- components/title-section/alerts.tsx | 14 +--- .../title-section/etablissement/index.tsx | 2 +- components/title-section/index.tsx | 2 +- components/unite-legale-description/index.tsx | 2 +- components/unite-legale-section/index.tsx | 2 +- hooks/use-session.ts | 2 +- middleware.ts | 9 ++- models/core/statut-diffusion.ts | 5 +- models/user/rights.ts | 36 ++++++++++ models/user/scopes.ts | 21 ++++++ models/user/session.ts | 30 ++++++++ pages/_app.tsx | 2 +- pages/annonces/[slug].tsx | 5 +- pages/api/auth/agent-connect/callback.ts | 39 ++-------- .../download/espace-agent/documents/[slug].ts | 4 +- pages/dirigeants/[slug].tsx | 5 +- pages/documents/[slug].tsx | 9 +-- pages/donnees-financieres/[slug].tsx | 3 +- .../helpers/formatting/unite-legale-label.ts | 2 +- utils/helpers/is-super-agent.ts | 7 ++ utils/server-side-helper/app/get-session.ts | 3 +- utils/server-side-helper/app/with-anti-bot.ts | 2 +- .../page/post-server-side-props.ts | 3 +- utils/session/index.ts | 72 ++----------------- utils/session/with-session.ts | 3 +- 48 files changed, 211 insertions(+), 192 deletions(-) create mode 100644 models/user/rights.ts create mode 100644 models/user/scopes.ts create mode 100644 models/user/session.ts diff --git a/app/(header-default)/entreprise/[slug]/page.tsx b/app/(header-default)/entreprise/[slug]/page.tsx index a8c02816e..2f5dd661d 100644 --- a/app/(header-default)/entreprise/[slug]/page.tsx +++ b/app/(header-default)/entreprise/[slug]/page.tsx @@ -20,6 +20,7 @@ import { estNonDiffusible } from '#models/core/statut-diffusion'; import { isAssociation, isCollectiviteTerritoriale } from '#models/core/types'; import { getUniteLegaleFromSlug } from '#models/core/unite-legale'; import { getServicePublicByUniteLegale } from '#models/service-public'; +import { EScope, hasRights } from '#models/user/rights'; import { extractSirenOrSiretSlugFromUrl, shouldNotIndex, @@ -31,7 +32,6 @@ import extractParamsAppRouter, { } from '#utils/server-side-helper/app/extract-params'; import getSession from '#utils/server-side-helper/app/get-session'; import withErrorHandler from '#utils/server-side-helper/app/with-error-handler'; -import { isSuperAgent } from '#utils/session'; const cachedGetUniteLegale = cache( async (slug: string, page: number, isBot: boolean) => { @@ -93,7 +93,7 @@ export default withErrorHandler(async function UniteLegalePage( ) : ( <> - {isSuperAgent(session) && ( + {hasRights(session, EScope.isAgent) && ( {
- {isAgent(session) ? ( + {isLoggedIn(session) ? ( ) : ( @@ -176,7 +172,7 @@ const FeedBackPage: NextPageWithLayout = async () => { id="email" name="email" type="email" - defaultValue={isAgent(session) ? session?.user?.email : ''} + defaultValue={isLoggedIn(session) ? session?.user?.email : ''} />
diff --git a/app/api/data-fetching/espace-agent/conformite/[slug]/route.ts b/app/api/data-fetching/espace-agent/conformite/[slug]/route.ts index 74eba1d52..51c1e18f6 100644 --- a/app/api/data-fetching/espace-agent/conformite/[slug]/route.ts +++ b/app/api/data-fetching/espace-agent/conformite/[slug]/route.ts @@ -1,10 +1,10 @@ import { HttpForbiddenError } from '#clients/exceptions'; import { getDonneesRestreintesEntreprise } from '#models/espace-agent/donnees-restreintes-entreprise'; import { FetchRessourceException } from '#models/exceptions'; +import { EScope, hasRights } from '#models/user/rights'; import { extractSirenFromSiret, verifySiret } from '#utils/helpers'; import { logFatalErrorInSentry } from '#utils/sentry'; import getSession from '#utils/server-side-helper/app/get-session'; -import { isSuperAgent } from '#utils/session'; export async function GET( _request: Request, @@ -13,7 +13,7 @@ export async function GET( const session = await getSession(); const slug = params.slug; try { - if (!isSuperAgent(session)) { + if (!hasRights(session, EScope.conformite)) { throw new HttpForbiddenError('Unauthorized account'); } diff --git a/app/api/data-fetching/espace-agent/documents/[slug]/route.ts b/app/api/data-fetching/espace-agent/documents/[slug]/route.ts index c921e5a8d..b05d1c3f5 100644 --- a/app/api/data-fetching/espace-agent/documents/[slug]/route.ts +++ b/app/api/data-fetching/espace-agent/documents/[slug]/route.ts @@ -2,10 +2,10 @@ import { clientDocuments } from '#clients/api-proxy/rne/documents'; import { HttpForbiddenError, HttpNotFound } from '#clients/exceptions'; import { EAdministration } from '#models/administrations/EAdministration'; import { FetchRessourceException } from '#models/exceptions'; +import { EScope, hasRights } from '#models/user/rights'; import { verifySiren } from '#utils/helpers'; import logErrorInSentry from '#utils/sentry'; import getSession from '#utils/server-side-helper/app/get-session'; -import { isAgent } from '#utils/session'; export async function GET( _request: Request, @@ -14,7 +14,7 @@ export async function GET( const session = await getSession(); const slug = params.slug; try { - if (!isAgent(session)) { + if (!hasRights(session, EScope.documentsRne)) { throw new HttpForbiddenError('Unauthorized account'); } diff --git a/components-ui/alerts-with-explanations/non-diffusible.tsx b/components-ui/alerts-with-explanations/non-diffusible.tsx index a582879ca..e728847e9 100644 --- a/components-ui/alerts-with-explanations/non-diffusible.tsx +++ b/components-ui/alerts-with-explanations/non-diffusible.tsx @@ -1,5 +1,6 @@ import { ISTATUTDIFFUSION, estDiffusible } from '#models/core/statut-diffusion'; -import { ISession, isAgent } from '#utils/session'; +import { EScope, hasRights } from '#models/user/rights'; +import { ISession } from '#models/user/session'; import { Info, ProtectedData } from '../alerts'; const DefaultNonDiffusibleAlert = () => ( @@ -42,12 +43,14 @@ export default function NonDiffusibleAlert({ if (estDiffusible({ statutDiffusion })) { return null; } - if (isAgent(session)) { - - Les informations de cette structure ne sont pas accessibles au grand - public mais vous pouvez voir ses informations grâce à votre compte{' '} - agent-public. - ; + if (hasRights(session, EScope.nonDiffusible)) { + return ( + + Les informations de cette structure ne sont pas accessibles au grand + public mais vous pouvez voir ses informations grâce à votre compte{' '} + agent-public. + + ); } if (statutDiffusion === ISTATUTDIFFUSION.PROTECTED) { diff --git a/components-ui/alerts/index.tsx b/components-ui/alerts/index.tsx index d7726633c..080f85e19 100644 --- a/components-ui/alerts/index.tsx +++ b/components-ui/alerts/index.tsx @@ -5,7 +5,7 @@ import constants from '#models/constants'; import styles from './styles.module.css'; const colors = { - info: ['#0078f3', '#f4f6ff'], + info: ['#0078f3', '#e5f3ff'], success: ['#18753c', '#dffee6'], error: ['#ce0500', '#fff4f4'], warning: ['#ff9c00', '#fff3e0'], diff --git a/components/espace-agent-components/documents/document-actes.tsx b/components/espace-agent-components/documents/document-actes.tsx index 1ecbefb68..bb0a696e0 100644 --- a/components/espace-agent-components/documents/document-actes.tsx +++ b/components/espace-agent-components/documents/document-actes.tsx @@ -10,6 +10,8 @@ import { isAssociation, isServicePublic, } from '#models/core/types'; +import { EScope, hasRights } from '#models/user/rights'; +import { ISession } from '#models/user/session'; import { formatDateLong } from '#utils/helpers'; import useFetchActesRNE from 'hooks/fetch/actes-RNE'; import AgentWallDocuments from '../agent-wall/documents'; @@ -86,9 +88,9 @@ const AgentComponent: React.FC<{ const DocumentActesSection: React.FC<{ uniteLegale: IUniteLegale; - isAgent: boolean; -}> = ({ uniteLegale, isAgent }) => { - if (!isAgent) { + session: ISession | null; +}> = ({ uniteLegale, session }) => { + if (!hasRights(session, EScope.actesRne)) { return ( = ({ uniteLegale, isAgent }) => { - if (!isAgent) { + session: ISession | null; +}> = ({ uniteLegale, session }) => { + if (!hasRights(session, EScope.bilansRne)) { return ( = ({ Télécharger les bilans , ], - ...(isSuperAgent(session) + ...(hasRights(session, EScope.conformite) ? [ ['',
], [ diff --git a/components/etablissement-description/index.tsx b/components/etablissement-description/index.tsx index 2832d855c..e556adea3 100644 --- a/components/etablissement-description/index.tsx +++ b/components/etablissement-description/index.tsx @@ -7,6 +7,7 @@ import { getNomComplet, } from '#models/core/statut-diffusion'; import { IEtablissement, IUniteLegale } from '#models/core/types'; +import { ISession } from '#models/user/session'; import { formatAge, formatDateLong, @@ -14,7 +15,6 @@ import { uniteLegaleLabel, uniteLegaleLabelWithPronounContracted, } from '#utils/helpers'; -import { ISession } from '#utils/session'; type IProps = { etablissement: IEtablissement; diff --git a/components/etablissement-liste-section/index.tsx b/components/etablissement-liste-section/index.tsx index 103ef318e..1706d874a 100644 --- a/components/etablissement-liste-section/index.tsx +++ b/components/etablissement-liste-section/index.tsx @@ -15,8 +15,8 @@ import { getNomComplet, } from '#models/core/statut-diffusion'; import { IEtablissement, IUniteLegale } from '#models/core/types'; +import { ISession } from '#models/user/session'; import { Siret, formatDate, formatSiret } from '#utils/helpers'; -import { ISession } from '#utils/session'; const EtablissementTable: React.FC<{ label?: string; diff --git a/components/etablissement-section/index.tsx b/components/etablissement-section/index.tsx index 0456374c7..d463651c2 100644 --- a/components/etablissement-section/index.tsx +++ b/components/etablissement-section/index.tsx @@ -21,13 +21,13 @@ import { getNomComplet, } from '#models/core/statut-diffusion'; import { IEtablissement, IUniteLegale } from '#models/core/types'; +import { ISession } from '#models/user/session'; import { formatDate, formatSiret, uniteLegaleLabelWithPronounContracted, } from '#utils/helpers'; import { libelleTrancheEffectif } from '#utils/helpers/formatting/codes-effectifs'; -import { ISession } from '#utils/session'; type IProps = { session: ISession | null; diff --git a/components/finances-section/societe/index.tsx b/components/finances-section/societe/index.tsx index 5942f7254..934555ae0 100644 --- a/components/finances-section/societe/index.tsx +++ b/components/finances-section/societe/index.tsx @@ -7,8 +7,8 @@ import { FullTable } from '#components/table/full'; import { EAdministration } from '#models/administrations/EAdministration'; import constants from '#models/constants'; import { IUniteLegale } from '#models/core/types'; +import { EScope, hasRights } from '#models/user/rights'; import { formatCurrency, formatDate, formatDateYear } from '#utils/helpers'; -import { isAgent } from '#utils/session'; import { useFetchFinancesSociete } from 'hooks'; import useSession from 'hooks/use-session'; @@ -36,7 +36,7 @@ export const FinancesSocieteSection: React.FC<{ if ( bilans.find((e) => e.confidentiality !== 'Public') && - !isAgent(session) + !hasRights(session, EScope.bilansRne) ) { return ( diff --git a/components/header/header-core/index.tsx b/components/header/header-core/index.tsx index 5b4caaa66..499edda24 100644 --- a/components/header/header-core/index.tsx +++ b/components/header/header-core/index.tsx @@ -5,7 +5,8 @@ import { InfoBanner } from '#components/banner/info-banner'; import LoadBar from '#components/load-bar'; import SearchBar from '#components/search-bar'; import constants from '#models/constants'; -import { ISession, isLoggedIn } from '#utils/session'; +import { isLoggedIn } from '#models/user/rights'; +import { ISession } from '#models/user/session'; import styles from './styles.module.css'; type IProps = { @@ -35,8 +36,8 @@ export const HeaderCore: React.FC = ({ className="fr-header" style={{ filter: !useSearchBar ? 'none' : undefined }} > + -
a:hover { - background-color: #f8f8f8; + background-color: #f8f8f8 !important; } .menuLogout:hover > a { diff --git a/components/immatriculations/index.tsx b/components/immatriculations/index.tsx index 765d500e3..0aa772f49 100644 --- a/components/immatriculations/index.tsx +++ b/components/immatriculations/index.tsx @@ -13,7 +13,7 @@ import { import { isAssociation, isServicePublic } from '#models/core/types'; import { IImmatriculation } from '#models/immatriculation'; import { IJustificatifs } from '#models/justificatifs'; -import { ISession } from '#utils/session'; +import { ISession } from '#models/user/session'; import ImmatriculationRNE from './rne'; const isNotFound = ( diff --git a/components/immatriculations/insee.tsx b/components/immatriculations/insee.tsx index 432696637..5141a4f15 100644 --- a/components/immatriculations/insee.tsx +++ b/components/immatriculations/insee.tsx @@ -12,8 +12,8 @@ import { getAdresseEtablissement, } from '#models/core/statut-diffusion'; import { IEtablissement, IUniteLegale } from '#models/core/types'; +import { ISession } from '#models/user/session'; import { formatSiret } from '#utils/helpers'; -import { ISession } from '#utils/session'; const AvisSituationTable: React.FC<{ etablissements: IEtablissement[]; diff --git a/components/justificatifs/extrait-rne-link/index.tsx b/components/justificatifs/extrait-rne-link/index.tsx index 8446f8d76..97a27ed35 100644 --- a/components/justificatifs/extrait-rne-link/index.tsx +++ b/components/justificatifs/extrait-rne-link/index.tsx @@ -4,13 +4,15 @@ import { nonDiffusibleDataFormatter, } from '#models/core/statut-diffusion'; import { IUniteLegale } from '#models/core/types'; -import { ISession, isAgent } from '#utils/session'; +import { EScope, hasRights } from '#models/user/rights'; +import { ISession } from '#models/user/session'; const ExtraitRNELink: React.FC<{ uniteLegale: IUniteLegale; session: ISession | null; }> = ({ uniteLegale, session }) => { - return estDiffusible(uniteLegale) || isAgent(session) ? ( + return estDiffusible(uniteLegale) || + hasRights(session, EScope.nonDiffusible) ? ( { diff --git a/components/load-bar/index.tsx b/components/load-bar/index.tsx index 6d76d7b01..eccc79e8b 100644 --- a/components/load-bar/index.tsx +++ b/components/load-bar/index.tsx @@ -2,8 +2,10 @@ import { useEffect } from 'react'; import constants from '#models/constants'; +import { EScope, hasRights } from '#models/user/rights'; +import { ISession } from '#models/user/session'; -export default function LoadBar({ isAgent }: { isAgent: boolean }) { +export default function LoadBar({ session }: { session: ISession | null }) { useEffect(() => { const loadBar = loadBarFactory(); if (typeof window !== 'undefined') { @@ -14,7 +16,9 @@ export default function LoadBar({ isAgent }: { isAgent: boolean }) {
- {isAgent(session) && ( + {hasRights(session, EScope.isAgent) && ( Vous êtes connecté avec un compte agent public. Ce @@ -35,14 +35,6 @@ export default function TitleAlerts({ Réservé aux agents publics ” . -
-
- Ce service est en beta test. Il est possible - que vous recontriez des bugs ou des erreurs. Si cela arrive,{' '} -
- n’hésitez pas à nous contacter - - . )} diff --git a/components/title-section/etablissement/index.tsx b/components/title-section/etablissement/index.tsx index cb5a5be56..f647fdd9f 100644 --- a/components/title-section/etablissement/index.tsx +++ b/components/title-section/etablissement/index.tsx @@ -10,12 +10,12 @@ import { getNomComplet, } from '#models/core/statut-diffusion'; import { IEtablissement, IUniteLegale } from '#models/core/types'; +import { ISession } from '#models/user/session'; import { formatIntFr, formatSiret, uniteLegaleLabelWithPronounContracted, } from '#utils/helpers'; -import { ISession } from '#utils/session'; import { INSEE } from '../../administrations'; import TitleAlerts from '../alerts'; import { FICHE, Tabs } from '../tabs'; diff --git a/components/title-section/index.tsx b/components/title-section/index.tsx index 772980cf6..0d822159f 100644 --- a/components/title-section/index.tsx +++ b/components/title-section/index.tsx @@ -12,8 +12,8 @@ import { getNomComplet, } from '#models/core/statut-diffusion'; import { IUniteLegale } from '#models/core/types'; +import { ISession } from '#models/user/session'; import { formatIntFr } from '#utils/helpers'; -import { ISession } from '#utils/session'; import TitleAlerts from './alerts'; import styles from './styles.module.css'; import { FICHE, Tabs } from './tabs'; diff --git a/components/unite-legale-description/index.tsx b/components/unite-legale-description/index.tsx index ab51d969e..533b299a1 100644 --- a/components/unite-legale-description/index.tsx +++ b/components/unite-legale-description/index.tsx @@ -5,6 +5,7 @@ import { getNomComplet, } from '#models/core/statut-diffusion'; import { IUniteLegale } from '#models/core/types'; +import { ISession } from '#models/user/session'; import { capitalize, formatAge, @@ -13,7 +14,6 @@ import { } from '#utils/helpers'; import { libelleCategorieEntrepriseForDescription } from '#utils/helpers/formatting/categories-entreprise'; import { libelleEffectifForDescription } from '#utils/helpers/formatting/codes-effectifs'; -import { ISession } from '#utils/session'; import { UniteLegaleEtablissementCountDescription } from './etablissement-count-description'; export const UniteLegaleDescription: React.FC<{ diff --git a/components/unite-legale-section/index.tsx b/components/unite-legale-section/index.tsx index 23fd29ae5..9dedcc535 100644 --- a/components/unite-legale-section/index.tsx +++ b/components/unite-legale-section/index.tsx @@ -18,10 +18,10 @@ import { isAssociation, isServicePublic, } from '#models/core/types'; +import { ISession } from '#models/user/session'; import { formatDate, formatIntFr, formatSiret } from '#utils/helpers'; import { libelleCategorieEntreprise } from '#utils/helpers/formatting/categories-entreprise'; import { libelleTrancheEffectif } from '#utils/helpers/formatting/codes-effectifs'; -import { ISession } from '#utils/session'; import { LabelsAndCertificatesBadgesSection, checkHasLabelsAndCertificates, diff --git a/hooks/use-session.ts b/hooks/use-session.ts index 4bafbb515..ce3c47448 100644 --- a/hooks/use-session.ts +++ b/hooks/use-session.ts @@ -1,7 +1,7 @@ 'use client'; import { createContext, useContext } from 'react'; -import { ISession } from '#utils/session'; +import { ISession } from '#models/user/session'; const sessionContext = createContext(null); diff --git a/middleware.ts b/middleware.ts index f6df49677..6724ed444 100644 --- a/middleware.ts +++ b/middleware.ts @@ -1,8 +1,9 @@ import { getIronSession } from 'iron-session'; import type { NextRequest } from 'next/server'; import { NextResponse } from 'next/server'; -import { sessionOptions, setVisitTimestamp } from '#utils/session'; +import { ISession } from '#models/user/session'; import { extractSirenOrSiretSlugFromUrl } from '#utils/helpers'; +import { sessionOptions, setVisitTimestamp } from '#utils/session'; // This function can be marked `async` if using `await` inside export async function middleware(request: NextRequest) { @@ -37,7 +38,11 @@ export async function middleware(request: NextRequest) { headers: requestHeaders, }, }); - const session = await getIronSession(request, response, sessionOptions); + const session = await getIronSession( + request, + response, + sessionOptions + ); await setVisitTimestamp(session); return response; } diff --git a/models/core/statut-diffusion.ts b/models/core/statut-diffusion.ts index 2b96c8305..29d94bacd 100644 --- a/models/core/statut-diffusion.ts +++ b/models/core/statut-diffusion.ts @@ -1,4 +1,5 @@ -import { ISession, isAgent } from '#utils/session'; +import { EScope, hasRights } from '#models/user/rights'; +import { ISession } from '#models/user/session'; import { IEtablissement, IUniteLegale } from './types'; export enum ISTATUTDIFFUSION { @@ -9,7 +10,7 @@ export enum ISTATUTDIFFUSION { } const canSeeNonDiffusible = (session: ISession | null) => - session && isAgent(session); + hasRights(session, EScope.nonDiffusible); /** * Only diffusible. Exclude partially diffusible and non-diffusible diff --git a/models/user/rights.ts b/models/user/rights.ts new file mode 100644 index 000000000..4850439ed --- /dev/null +++ b/models/user/rights.ts @@ -0,0 +1,36 @@ +import { ISession } from './session'; + +export enum EScope { + actesRne = 'rne', + bilansRne = 'rne', + documentsRne = 'rne', + conformite = 'conformite', + nonDiffusible = 'nonDiffusible', + isAgent = 'isAgent', +} + +/** + * Has rights to access a view + */ +export function hasRights(session: ISession | null, rightScope: EScope) { + const userScopes = session?.user?.scopes || []; + + switch (rightScope) { + case EScope.actesRne: + case EScope.bilansRne: + case EScope.documentsRne: + return userScopes.includes('rne'); + case EScope.conformite: + return userScopes.includes('conformite'); + case EScope.nonDiffusible: + return userScopes.includes('nonDiffusible'); + case EScope.isAgent: + return userScopes.includes('agent'); + default: + return false; + } +} + +export function isLoggedIn(session: ISession | null) { + return (session?.user?.scopes || []).length > 0; +} diff --git a/models/user/scopes.ts b/models/user/scopes.ts new file mode 100644 index 000000000..81f930a8b --- /dev/null +++ b/models/user/scopes.ts @@ -0,0 +1,21 @@ +import { checkIsSuperAgent } from '#utils/helpers/is-super-agent'; + +export type IScope = 'rne' | 'nonDiffusible' | 'conformite' | 'agent'; + +export const getUserScopes = async ( + userEmail: string +): Promise<{ scopes: IScope[]; userType: string }> => { + const isSuperAgent = await checkIsSuperAgent(userEmail); + + if (isSuperAgent) { + return { + scopes: ['agent', 'nonDiffusible', 'conformite', 'rne'], + userType: 'Super-agent connecté', + }; + } + + return { + scopes: ['agent', 'nonDiffusible', 'rne'], + userType: 'Agent connecté', + }; +}; diff --git a/models/user/session.ts b/models/user/session.ts new file mode 100644 index 000000000..9afe375ee --- /dev/null +++ b/models/user/session.ts @@ -0,0 +1,30 @@ +import { IScope } from './scopes'; + +export type ISession = { + lastVisitTimestamp?: number; + user?: { + email?: string; + familyName?: string; + firstName?: string; + fullName?: string; + siret?: string; + userType?: string; + scopes?: IScope[]; + }; + + // agent connect + state?: string; + nonce?: string; + idToken?: string; + // connexion + pathFrom?: string; + + // FranceConnect hide personal data request + hidePersonalDataRequestFC?: { + firstName?: string; + familyName?: string; + birthdate?: string; + tokenId: string; + sub: string; + }; +}; diff --git a/pages/_app.tsx b/pages/_app.tsx index c3832cdfa..4882608f4 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -4,7 +4,7 @@ import type { ReactElement, ReactNode } from 'react'; import { BrowserIsOutdatedBanner } from '#components/banner/browser-is-outdated'; import ErrorBoundary from '#components/error-boundary/index'; import { LayoutDefault } from '#components/layouts/layout-default'; -import { ISession } from '#utils/session'; +import { ISession } from '#models/user/session'; import { marianne } from 'app/fonts'; import { SessionProvider } from 'hooks/use-session'; import '../style/dsfr.min.css'; diff --git a/pages/annonces/[slug].tsx b/pages/annonces/[slug].tsx index b2f423e41..09898750a 100644 --- a/pages/annonces/[slug].tsx +++ b/pages/annonces/[slug].tsx @@ -8,6 +8,7 @@ import { FICHE } from '#components/title-section/tabs'; import { estDiffusible } from '#models/core/statut-diffusion'; import { IUniteLegale, isAssociation } from '#models/core/types'; import { getUniteLegaleFromSlug } from '#models/core/unite-legale'; +import { EScope, hasRights } from '#models/user/rights'; import { uniteLegalePageDescription, uniteLegalePageTitle, @@ -17,7 +18,6 @@ import { IPropsWithMetadata, postServerSideProps, } from '#utils/server-side-helper/page/post-server-side-props'; -import { isAgent } from '#utils/session'; import { NextPageWithLayout } from 'pages/_app'; interface IProps extends IPropsWithMetadata { @@ -45,7 +45,8 @@ const Annonces: NextPageWithLayout = ({ uniteLegale={uniteLegale} session={session} /> - {estDiffusible(uniteLegale) || isAgent(session) ? ( + {estDiffusible(uniteLegale) || + hasRights(session, EScope.nonDiffusible) ? ( ) : ( diff --git a/pages/api/auth/agent-connect/callback.ts b/pages/api/auth/agent-connect/callback.ts index a6e54fa19..684c42c89 100644 --- a/pages/api/auth/agent-connect/callback.ts +++ b/pages/api/auth/agent-connect/callback.ts @@ -1,51 +1,24 @@ -import { - IAgentConnectUserInfo, - agentConnectAuthenticate, -} from '#clients/auth/agent-connect/strategy'; +import { agentConnectAuthenticate } from '#clients/auth/agent-connect/strategy'; import { HttpForbiddenError } from '#clients/exceptions'; import { Exception } from '#models/exceptions'; -import { checkIsSuperAgent } from '#utils/helpers/is-super-agent'; +import { getUserScopes } from '#models/user/scopes'; import { logFatalErrorInSentry } from '#utils/sentry'; -import { - ISessionPrivilege, - cleanPathFrom, - getPathFrom, - setAgentSession, -} from '#utils/session'; +import { cleanPathFrom, getPathFrom, setAgentSession } from '#utils/session'; import withSession from '#utils/session/with-session'; -const getUserPrivileges = async ( - userInfo: IAgentConnectUserInfo -): Promise => { - const isTestAccount = - userInfo.email === 'user@yopmail.com' && - process.env.NODE_ENV !== 'production'; - - const isSuperAgent = await checkIsSuperAgent(userInfo.email); - if (isTestAccount || isSuperAgent) { - return 'super-agent'; - } - - // agent connect only connect agents - return 'agent'; -}; - export default withSession(async function callbackRoute(req, res) { try { const userInfo = await agentConnectAuthenticate(req); - const userPrivilege = await getUserPrivileges(userInfo); + const { scopes, userType } = await getUserScopes(userInfo?.email); const session = req.session; - if (userPrivilege === 'unkown') { - throw new HttpForbiddenError(`Unauthorized account : ${userInfo.email}`); - } - await setAgentSession( userInfo.email, userInfo.family_name ?? '', userInfo.given_name ?? '', userInfo.siret ?? '', - userPrivilege, + scopes, + userType, session ); diff --git a/pages/api/download/espace-agent/documents/[slug].ts b/pages/api/download/espace-agent/documents/[slug].ts index baf6fa624..e4b6ff31a 100644 --- a/pages/api/download/espace-agent/documents/[slug].ts +++ b/pages/api/download/espace-agent/documents/[slug].ts @@ -5,8 +5,8 @@ import { import { HttpBadRequestError, HttpForbiddenError } from '#clients/exceptions'; import { EAdministration } from '#models/administrations/EAdministration'; import { FetchRessourceException } from '#models/exceptions'; +import { EScope, hasRights } from '#models/user/rights'; import logErrorInSentry from '#utils/sentry'; -import { isAgent } from '#utils/session'; import withSession from '#utils/session/with-session'; export default withSession(async function download(req, res) { @@ -16,7 +16,7 @@ export default withSession(async function download(req, res) { } = req; try { - if (!isAgent(session)) { + if (!hasRights(session, EScope.documentsRne)) { throw new HttpForbiddenError('Unauthorized account'); } diff --git a/pages/dirigeants/[slug].tsx b/pages/dirigeants/[slug].tsx index f8003fad5..820018f48 100644 --- a/pages/dirigeants/[slug].tsx +++ b/pages/dirigeants/[slug].tsx @@ -16,6 +16,7 @@ import { IServicePublic, getServicePublicByUniteLegale, } from '#models/service-public'; +import { EScope, hasRights } from '#models/user/rights'; import { uniteLegalePageDescription, uniteLegalePageTitle, @@ -25,7 +26,6 @@ import { IPropsWithMetadata, postServerSideProps, } from '#utils/server-side-helper/page/post-server-side-props'; -import { isAgent } from '#utils/session'; import { useFetchImmatriculationRNE } from 'hooks'; import useSession from 'hooks/use-session'; import { NextPageWithLayout } from 'pages/_app'; @@ -76,7 +76,8 @@ function DirigeantInformation({ uniteLegale }: { uniteLegale: IUniteLegale }) { uniteLegale={uniteLegale} immatriculationRNE={immatriculationRNE} /> - {estDiffusible(uniteLegale) || isAgent(session) ? ( + {estDiffusible(uniteLegale) || + hasRights(session, EScope.nonDiffusible) ? ( <> = ({ ficheType={FICHE.DOCUMENTS} session={session} /> - {isSuperAgent(session) && ( + {hasRights(session, EScope.conformite) && ( <> )} - +
); diff --git a/pages/donnees-financieres/[slug].tsx b/pages/donnees-financieres/[slug].tsx index 377cc53c5..12ef738cf 100644 --- a/pages/donnees-financieres/[slug].tsx +++ b/pages/donnees-financieres/[slug].tsx @@ -15,7 +15,6 @@ import { IPropsWithMetadata, postServerSideProps, } from '#utils/server-side-helper/page/post-server-side-props'; -import { isAgent } from '#utils/session'; import { NextPageWithLayout } from 'pages/_app'; interface IProps extends IPropsWithMetadata { @@ -49,7 +48,7 @@ const FinancePage: NextPageWithLayout = ({ )} diff --git a/utils/helpers/formatting/unite-legale-label.ts b/utils/helpers/formatting/unite-legale-label.ts index 0bcefe8e9..0d25889d1 100644 --- a/utils/helpers/formatting/unite-legale-label.ts +++ b/utils/helpers/formatting/unite-legale-label.ts @@ -11,7 +11,7 @@ import { isCollectiviteTerritoriale, isServicePublic, } from '#models/core/types'; -import { ISession } from '#utils/session'; +import { ISession } from '#models/user/session'; import { formatSiret } from '../siren-and-siret'; import { capitalize, formatIntFr } from './formatting'; diff --git a/utils/helpers/is-super-agent.ts b/utils/helpers/is-super-agent.ts index d9250f529..9fe672ad6 100644 --- a/utils/helpers/is-super-agent.ts +++ b/utils/helpers/is-super-agent.ts @@ -29,6 +29,13 @@ class SuperAgentsList { const superAgents = new SuperAgentsList(); export const checkIsSuperAgent = async (agentMail: string) => { + const isTestAccount = + agentMail === 'user@yopmail.com' && process.env.NODE_ENV !== 'production'; + + if (isTestAccount) { + return true; + } + const superAgentList = await superAgents.getList(); if (superAgentList.indexOf(agentMail) > -1) { return true; diff --git a/utils/server-side-helper/app/get-session.ts b/utils/server-side-helper/app/get-session.ts index 2f6678b6a..ce8448525 100644 --- a/utils/server-side-helper/app/get-session.ts +++ b/utils/server-side-helper/app/get-session.ts @@ -1,6 +1,7 @@ import { getIronSession } from 'iron-session'; import { cookies } from 'next/headers'; -import { ISession, sessionOptions } from '#utils/session'; +import { ISession } from '#models/user/session'; +import { sessionOptions } from '#utils/session'; export default async function getSession(): Promise { return await getIronSession(cookies(), sessionOptions); diff --git a/utils/server-side-helper/app/with-anti-bot.ts b/utils/server-side-helper/app/with-anti-bot.ts index e187c52e2..94dc861c7 100644 --- a/utils/server-side-helper/app/with-anti-bot.ts +++ b/utils/server-side-helper/app/with-anti-bot.ts @@ -1,7 +1,7 @@ import { userAgent } from 'next/server'; import { Information } from '#models/exceptions'; +import { ISession } from '#models/user/session'; import { logInfoInSentry } from '#utils/sentry'; -import { ISession } from '../../session'; import getSession from './get-session'; /** diff --git a/utils/server-side-helper/page/post-server-side-props.ts b/utils/server-side-helper/page/post-server-side-props.ts index b17c3572f..c34db079e 100644 --- a/utils/server-side-helper/page/post-server-side-props.ts +++ b/utils/server-side-helper/page/post-server-side-props.ts @@ -1,7 +1,8 @@ import { getIronSession } from 'iron-session'; import { GetServerSidePropsContext } from 'next'; +import { ISession } from '#models/user/session'; import { IReqWithSession } from '#utils/session/with-session'; -import { ISession, sessionOptions, setVisitTimestamp } from '../../session'; +import { sessionOptions, setVisitTimestamp } from '../../session'; import { errorRedirection } from '../redirection'; import { getContext } from './error-context'; diff --git a/utils/session/index.ts b/utils/session/index.ts index 728018959..bb99dc5b4 100644 --- a/utils/session/index.ts +++ b/utils/session/index.ts @@ -1,34 +1,6 @@ import type { IronSession, SessionOptions } from 'iron-session'; - -export type ISessionPrivilege = 'unkown' | 'agent' | 'super-agent'; - -export type ISession = { - lastVisitTimestamp?: number; - user?: { - email?: string; - familyName?: string; - firstName?: string; - fullName?: string; - privilege?: ISessionPrivilege; - siret?: string; - }; - - // agent connect - state?: string; - nonce?: string; - idToken?: string; - // connexion - pathFrom?: string; - - // FranceConnect hide personal data request - hidePersonalDataRequestFC?: { - firstName?: string; - familyName?: string; - birthdate?: string; - tokenId: string; - sub: string; - }; -}; +import { IScope } from '#models/user/scopes'; +import { ISession } from '#models/user/session'; export const sessionOptions: SessionOptions = { password: process.env.IRON_SESSION_PWD as string, @@ -49,7 +21,8 @@ export const setAgentSession = async ( familyName: string, firstName: string, siret: string, - privilege: ISessionPrivilege, + scopes: IScope[], + userType: string, session: IronSession ) => { session.user = { @@ -57,8 +30,9 @@ export const setAgentSession = async ( firstName, familyName, fullName: familyName ? `${firstName} ${familyName}` : undefined, - privilege, siret, + userType, + scopes, }; await session.save(); }; @@ -122,37 +96,3 @@ export function getHidePersonalDataRequestFCSession( NonNullable >; } - -/** - * Verify if user is loggedin - * - * @param session - * @returns - */ -export const isLoggedIn = (session: ISession | null) => { - return !!session?.user?.email; -}; - -/** - * Verify if user session has agent privileges - * - * @param session - * @returns - */ -export const isBasicAgent = (session: ISession | null) => { - return session?.user?.privilege === 'agent'; -}; - -/** - * Verify if user session has super-agent privileges - */ -export const isSuperAgent = (session: ISession | null) => { - return session?.user?.privilege === 'super-agent'; -}; - -/** - * Verify if user session has super-agent or agent privileges - */ -export const isAgent = (session: ISession | null) => { - return isBasicAgent(session) || isSuperAgent(session); -}; diff --git a/utils/session/with-session.ts b/utils/session/with-session.ts index d928dac5a..df27ed150 100644 --- a/utils/session/with-session.ts +++ b/utils/session/with-session.ts @@ -1,6 +1,7 @@ import { IronSession, getIronSession } from 'iron-session'; import { NextApiRequest, NextApiResponse } from 'next'; -import { ISession, sessionOptions } from '.'; +import { ISession } from '#models/user/session'; +import { sessionOptions } from '.'; export type IReqWithSession = NextApiRequest & { session: IronSession; From b69ec4c8eaf1d7ed4ceef5731925fb05f539cf0a Mon Sep 17 00:00:00 2001 From: Xavier Jp Date: Fri, 5 Apr 2024 09:59:02 +0200 Subject: [PATCH 2/4] content: update banner --- components/banner/info-banner.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/banner/info-banner.tsx b/components/banner/info-banner.tsx index 7e2087245..b2512e5b3 100644 --- a/components/banner/info-banner.tsx +++ b/components/banner/info-banner.tsx @@ -18,11 +18,9 @@ export const InfoBanner: React.FC<{}> = () => ( }} >
- ⚠️ Une mise à jour est en cours et les données affichées sur notre site - peuvent ne pas être à jour. + ⚠️ Une mise à jour est en cours et les données de la base Sirene n’ont pas été mises à jour sur notre site depuis le 22 mars 2024.
- Cette situation est susceptible de perdurer jusqu’au vendredi 05 avril. - Veuillez nous excuser pour la gêne occasionnée. + Cette situation est susceptible de perdurer jusqu’à ce que les données soient disponibles. Veuillez nous excuser pour la gêne occasionnée.
From 2fd0960c91a8d4d70ee79cd48aee3dec5defa0f1 Mon Sep 17 00:00:00 2001 From: Xavier Jp Date: Sun, 7 Apr 2024 18:02:19 +0200 Subject: [PATCH 3/4] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ccf0f0733..ac8c766cf 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![CI (lint, unit-tests, end2end, a11y)](https://github.com/etalab/annuaire-entreprises.data.gouv.fr/actions/workflows/pre-merge.yml/badge.svg)](https://github.com/etalab/annuaire-entreprises.data.gouv.fr/actions/workflows/pre-merge.yml) [![External API check](https://github.com/etalab/annuaire-entreprises-site/actions/workflows/external-api-test.yml/badge.svg)](https://github.com/etalab/annuaire-entreprises-site/actions/workflows/external-api-test.yml) [![Deploy cluster](https://github.com/etalab/annuaire-entreprises-site/actions/workflows/deploy-cluster.yml/badge.svg)](https://github.com/etalab/annuaire-entreprises-site/actions/workflows/deploy-cluster.yml) -Partenaires Badge +Partenaires Badge Sources de données Badge Statut des API Badge Changelog Badge @@ -16,7 +16,7 @@ Dépôt du site [Annuaire des Entreprises](https://annuaire-entreprises.data.gou Ce site met à disposition des citoyens et des agents les données ouvertes (open-data) des entreprises, associations et administrations dotées d'un n° SIREN/SIRET. -Ce site ré-utilise les données des différentes administrations partenaires : +Ce site ré-utilise les données des différentes [administrations partenaires](https://annuaire-entreprises.data.gouv.fr/administration). ## Contenu From 029439649238b5725fea325081f1b95a607426b3 Mon Sep 17 00:00:00 2001 From: Xavier Jp Date: Sun, 7 Apr 2024 18:04:08 +0200 Subject: [PATCH 4/4] Fix: wrong year date --- data/changelog.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/changelog.yml b/data/changelog.yml index 22b5c82b0..3c0977533 100644 --- a/data/changelog.yml +++ b/data/changelog.yml @@ -1,7 +1,7 @@ --- -- date: 24/03/2023 +- date: 24/03/2024 title: 'Nouvelle source de donnée : les Entreprises Sociales Inclusives' -- date: 24/02/2023 +- date: 24/02/2024 title: Ajout du filtre géographique EPCI - date: 14/02/2024 title: 'Nouvelle source de donnée, [l’Annuaire du service public](https://lannuaire.service-public.fr/) :'