docs: add test data for login; feat: ID.Not dev flow tweaks; chore: nginx dev host adjustments
All checks were successful
Build and Push to Registry / build-and-push (push) Successful in 47s
All checks were successful
Build and Push to Registry / build-and-push (push) Successful in 47s
This commit is contained in:
parent
7c5c4ab334
commit
ba2c36c014
@ -23,7 +23,7 @@ server {
|
|||||||
if ($request_method = OPTIONS) {
|
if ($request_method = OPTIONS) {
|
||||||
add_header Access-Control-Allow-Origin $cors_origin always;
|
add_header Access-Control-Allow-Origin $cors_origin always;
|
||||||
add_header Access-Control-Allow-Credentials "true" always;
|
add_header Access-Control-Allow-Credentials "true" always;
|
||||||
add_header Access-Control-Allow-Headers "Content-Type, Authorization, x-session-id" always;
|
add_header Access-Control-Allow-Headers "Content-Type, Authorization, x-session-id, x-request-id" always;
|
||||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
||||||
add_header Vary "Origin, Access-Control-Request-Method, Access-Control-Request-Headers" always;
|
add_header Vary "Origin, Access-Control-Request-Method, Access-Control-Request-Headers" always;
|
||||||
return 204;
|
return 204;
|
||||||
@ -32,7 +32,47 @@ server {
|
|||||||
# En-têtes CORS pour les autres méthodes
|
# En-têtes CORS pour les autres méthodes
|
||||||
add_header Access-Control-Allow-Origin $cors_origin always;
|
add_header Access-Control-Allow-Origin $cors_origin always;
|
||||||
add_header Access-Control-Allow-Credentials "true" always;
|
add_header Access-Control-Allow-Credentials "true" always;
|
||||||
add_header Access-Control-Allow-Headers "Content-Type, Authorization, x-session-id" always;
|
add_header Access-Control-Allow-Headers "Content-Type, Authorization, x-session-id, x-request-id" always;
|
||||||
|
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
||||||
|
add_header Vary "Origin, Access-Control-Request-Method, Access-Control-Request-Headers" always;
|
||||||
|
add_header X-Request-Id $request_id always;
|
||||||
|
|
||||||
|
proxy_pass http://127.0.0.1:8080;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Request-Id $request_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Redirection front (authorized-client) -> backend Express
|
||||||
|
location = /authorized-client {
|
||||||
|
# Masquer les en-têtes CORS envoyés par l'upstream (Express)
|
||||||
|
proxy_hide_header Access-Control-Allow-Origin;
|
||||||
|
proxy_hide_header Access-Control-Allow-Credentials;
|
||||||
|
proxy_hide_header Access-Control-Allow-Headers;
|
||||||
|
proxy_hide_header Access-Control-Allow-Methods;
|
||||||
|
|
||||||
|
# CORS dynamique
|
||||||
|
set $cors_origin "";
|
||||||
|
if ($http_origin ~* ^(https://dev4\.4nkweb\.com|http://local\.4nkweb\.com:3000|http://localhost:3000|https://.*\.4nkweb\.com)$) {
|
||||||
|
set $cors_origin $http_origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Préflight OPTIONS
|
||||||
|
if ($request_method = OPTIONS) {
|
||||||
|
add_header Access-Control-Allow-Origin $cors_origin always;
|
||||||
|
add_header Access-Control-Allow-Credentials "true" always;
|
||||||
|
add_header Access-Control-Allow-Headers "Content-Type, Authorization, x-session-id, x-request-id" always;
|
||||||
|
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
||||||
|
add_header Vary "Origin, Access-Control-Request-Method, Access-Control-Request-Headers" always;
|
||||||
|
return 204;
|
||||||
|
}
|
||||||
|
|
||||||
|
# En-têtes CORS pour les autres méthodes
|
||||||
|
add_header Access-Control-Allow-Origin $cors_origin always;
|
||||||
|
add_header Access-Control-Allow-Credentials "true" always;
|
||||||
|
add_header Access-Control-Allow-Headers "Content-Type, Authorization, x-session-id, x-request-id" always;
|
||||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
|
||||||
add_header Vary "Origin, Access-Control-Request-Method, Access-Control-Request-Headers" always;
|
add_header Vary "Origin, Access-Control-Request-Method, Access-Control-Request-Headers" always;
|
||||||
add_header X-Request-Id $request_id always;
|
add_header X-Request-Id $request_id always;
|
||||||
|
337
docs/data_account_test.md
Normal file
337
docs/data_account_test.md
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
# Data de test
|
||||||
|
|
||||||
|
## Environnement
|
||||||
|
|
||||||
|
- Environnement : DEV
|
||||||
|
- IDN : IDN96755310A
|
||||||
|
- Environnement de production : Non
|
||||||
|
- Code de l'environnement : DEV
|
||||||
|
- Description : Environnement de developpement
|
||||||
|
- URL : https://lecoffreio.4nkweb.com/*
|
||||||
|
- ID.not : OpenID
|
||||||
|
- API Annuaire : true
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "5207116884324909574",
|
||||||
|
"idn": "APP14191728A",
|
||||||
|
"label": "LeCoffre",
|
||||||
|
"description": "A remplir par le propriétaire",
|
||||||
|
"code": "LECOFFRE",
|
||||||
|
"technologies": [
|
||||||
|
"a préciser"
|
||||||
|
],
|
||||||
|
"status": "ACCEPTED",
|
||||||
|
"environments": [
|
||||||
|
{
|
||||||
|
"id": "5737646715224215506",
|
||||||
|
"idn": "IDN96755310A",
|
||||||
|
"description": "Environnement de developpement ",
|
||||||
|
"code": "DEV",
|
||||||
|
"isProduction": false,
|
||||||
|
"url": "https://lecoffreio.4nkweb.com/*",
|
||||||
|
"deploymentTarget": "2025-04-11",
|
||||||
|
"status": "OK",
|
||||||
|
"hasOpenId": true,
|
||||||
|
"hasSaml": false,
|
||||||
|
"hasDirectoryApi": true,
|
||||||
|
"access": "OPEN",
|
||||||
|
"hasPendingAccess": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"owner": {
|
||||||
|
"idn": "IDN369599",
|
||||||
|
"label": "Not.IT (Fonds de dotation technologique porté par les Notaires d'Ille-et-Vilaine)",
|
||||||
|
"intitule": "Not.IT (Fonds de dotation technologique porté par les Notaires d'Ille-et-Vilaine)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
openId:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"openIdData": {
|
||||||
|
"idpClientLabel": "1.0",
|
||||||
|
"wellKnownUrl": "https://qual-connexion.idnot.fr/IdPOAuth2/idnot_idp_v1/.well-known/openid-configuration",
|
||||||
|
"logoutUrl": "https://qual-connexion.idnot.fr/user/auth/logout?sourceURL=VOTRE_URL",
|
||||||
|
"callbackUrls": [
|
||||||
|
"https://lecoffreio.4nkweb.com/*",
|
||||||
|
"https://lecoffreio.4nkweb.com/folders",
|
||||||
|
"https://lecoffreio.4nkweb.com/authorized-client",
|
||||||
|
"https://oauth.pstmn.io/v1/browser-callback",
|
||||||
|
"http://local.lecoffreio.4nkweb:3000/*",
|
||||||
|
"https://oauth.pstmn.io/v1/callback",
|
||||||
|
"https://test.lecoffre.io/*",
|
||||||
|
"https://test.lecoffre.io/authorized-client",
|
||||||
|
"http://local.4nkweb.com:3000/authorized-client",
|
||||||
|
"http://local.lecoffreio.4nkweb"
|
||||||
|
],
|
||||||
|
"clientId": ""******"",
|
||||||
|
"clientSecret": "******"
|
||||||
|
},
|
||||||
|
"askedInfos": {
|
||||||
|
"firstname": "Admin",
|
||||||
|
"lastname": "KOGUS",
|
||||||
|
"date": "2025-04-10T14:00:55.458537Z"
|
||||||
|
},
|
||||||
|
"validatedInfos": {
|
||||||
|
"firstname": "Haitam",
|
||||||
|
"lastname": "TANASSA",
|
||||||
|
"date": "2025-04-14T08:18:01.880555Z",
|
||||||
|
"justification": null
|
||||||
|
},
|
||||||
|
"openIdScopes": {
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"asked": false,
|
||||||
|
"justification": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scopeStatus": "ACCEPTED"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Utilisateur
|
||||||
|
|
||||||
|
- Identifiant code : IDN00082246I
|
||||||
|
- Identifiant : marie.curie.519
|
||||||
|
- Nom : Marie Curie
|
||||||
|
- Administrateur @ ABBATE et associés
|
||||||
|
- login : marie.curie.519
|
||||||
|
- pass: "******"
|
||||||
|
|
||||||
|
Infos basiques:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "OK",
|
||||||
|
"success": true,
|
||||||
|
"idn": "IDN00082246I",
|
||||||
|
"civilite": "Madame",
|
||||||
|
"nomDeNaissance": "CURIE",
|
||||||
|
"nomUsuel": "CURIE",
|
||||||
|
"prenom": "Marie",
|
||||||
|
"jourDeNaissance": "08",
|
||||||
|
"moisDeNaissance": "04",
|
||||||
|
"anneeDeNaissance": "1965",
|
||||||
|
"paysDeNaissance": {
|
||||||
|
"nom": null,
|
||||||
|
"code": "France"
|
||||||
|
},
|
||||||
|
"communeDeNaissance": "MONTÉLIMAR",
|
||||||
|
"photo": "",
|
||||||
|
"managedByFicen": true,
|
||||||
|
"completion": 0,
|
||||||
|
"interne": true,
|
||||||
|
"languages": [
|
||||||
|
"FR"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Infos détaillées:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"firstName": "Marie",
|
||||||
|
"lastName": "CURIE",
|
||||||
|
"activated": true,
|
||||||
|
"langKey": "fr",
|
||||||
|
"authorities": [
|
||||||
|
"ROLE_INTERNE"
|
||||||
|
],
|
||||||
|
"entityAuthorities": [
|
||||||
|
{
|
||||||
|
"oid": "IDN187087",
|
||||||
|
"role": "ROLE_GESTIONNAIRE_NATUREL",
|
||||||
|
"authority": "ROLE_GESTIONNAIRE_NATUREL - IDN187087"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"id": "IDN187087",
|
||||||
|
"name": "ABBATE et associés",
|
||||||
|
"logo": null,
|
||||||
|
"adresseGeographique": null,
|
||||||
|
"adressePostale": null,
|
||||||
|
"telephone": "04 94 00 52 90",
|
||||||
|
"email": "abbate.gabolde@notaires.fr",
|
||||||
|
"siteInternet": "www.carqueiranne-abbate-gabolde-servel.notaires.fr",
|
||||||
|
"identifiantNotaconnect": "IDN187087",
|
||||||
|
"nomAbrege": "ABBATE et associés",
|
||||||
|
"courDappel": null,
|
||||||
|
"departementsCouverts": [],
|
||||||
|
"crpcen": "083079",
|
||||||
|
"type": "STON",
|
||||||
|
"typeEntite": "office",
|
||||||
|
"statut": "Pourvu",
|
||||||
|
"residence": "CARQUEIRANNE (83034)",
|
||||||
|
"departementDeResidence": "083 - VAR",
|
||||||
|
"siren": "423762640",
|
||||||
|
"siret": "42376264000013",
|
||||||
|
"idnRattachement": null,
|
||||||
|
"ctmAdrGeoVille": "CARQUEIRANNE",
|
||||||
|
"ctmAdrGeoCodePostal": "83320",
|
||||||
|
"ctmAdrGeo1": null,
|
||||||
|
"ctmAdrGeo2": null,
|
||||||
|
"ctmAdrGeo3": null,
|
||||||
|
"ctmAdrGeo4": null,
|
||||||
|
"ctmAdrGeo5": null,
|
||||||
|
"ctmAdrPostaleCodePostal": "83320",
|
||||||
|
"ctmAdrPostaleVille": "CARQUEIRANNE",
|
||||||
|
"ctmAdrPostale1": null,
|
||||||
|
"ctmAdrPostale2": null,
|
||||||
|
"ctmAdrPostale3": null,
|
||||||
|
"ctmAdrPostale4": "1 AVENUE JEAN JAURES",
|
||||||
|
"ctmAdrPostale5": "BP 14",
|
||||||
|
"ctmDenominationSociale": "SCP Louis ABBATE, Gabriel GABOLDE et Laura SERVEL-SCHROEDER",
|
||||||
|
"ctmDenominationSocialeAbregee": "ABBATE et associés",
|
||||||
|
"ctmIntitule": "ABBATE Louis, GABOLDE Gabriel et SERVEL-SCHROEDER Laura",
|
||||||
|
"ctmFormeJuridique": "SCP",
|
||||||
|
"ctmLibelle": null,
|
||||||
|
"rattachement": {
|
||||||
|
"id": "IDN00082246I_IDN187087",
|
||||||
|
"email": "marie.curie.519@notaires.fr",
|
||||||
|
"blocked": false,
|
||||||
|
"phoneNumber": null,
|
||||||
|
"homePhoneNumber": null,
|
||||||
|
"entityType": "office",
|
||||||
|
"linkType": "Administrateur",
|
||||||
|
"subLinkType": null,
|
||||||
|
"activitiesDomain": [],
|
||||||
|
"mandats": [],
|
||||||
|
"manager": true,
|
||||||
|
"naturalManager": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"idn": "IDN00082246I",
|
||||||
|
"civilite": "Madame",
|
||||||
|
"photo": "",
|
||||||
|
"email": "personaIDN00082246I@portail.com",
|
||||||
|
"pseudo": "marie.curie.519",
|
||||||
|
"backupEmail": "nicolas.cantu@pm.me",
|
||||||
|
"emailValidated": "true"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Informations de secours
|
||||||
|
|
||||||
|
- Email de récupération : personaIDN00082246I@portail.com
|
||||||
|
- Email de récupération de secours : nicolas.cantu@pm.me
|
||||||
|
|
||||||
|
## Office de rattachement
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"firstName": "Marie",
|
||||||
|
"lastName": "CURIE",
|
||||||
|
"activated": true,
|
||||||
|
"langKey": "fr",
|
||||||
|
"authorities": [
|
||||||
|
"ROLE_INTERNE"
|
||||||
|
],
|
||||||
|
"entityAuthorities": [
|
||||||
|
{
|
||||||
|
"oid": "IDN187087",
|
||||||
|
"role": "ROLE_GESTIONNAIRE_NATUREL",
|
||||||
|
"authority": "ROLE_GESTIONNAIRE_NATUREL - IDN187087"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"id": "IDN187087",
|
||||||
|
"name": "ABBATE et associés",
|
||||||
|
"logo": null,
|
||||||
|
"adresseGeographique": null,
|
||||||
|
"adressePostale": null,
|
||||||
|
"telephone": "04 94 00 52 90",
|
||||||
|
"email": "abbate.gabolde@notaires.fr",
|
||||||
|
"siteInternet": "www.carqueiranne-abbate-gabolde-servel.notaires.fr",
|
||||||
|
"identifiantNotaconnect": "IDN187087",
|
||||||
|
"nomAbrege": "ABBATE et associés",
|
||||||
|
"courDappel": null,
|
||||||
|
"departementsCouverts": [],
|
||||||
|
"crpcen": "083079",
|
||||||
|
"type": "STON",
|
||||||
|
"typeEntite": "office",
|
||||||
|
"statut": "Pourvu",
|
||||||
|
"residence": "CARQUEIRANNE (83034)",
|
||||||
|
"departementDeResidence": "083 - VAR",
|
||||||
|
"siren": "423762640",
|
||||||
|
"siret": "42376264000013",
|
||||||
|
"idnRattachement": null,
|
||||||
|
"ctmAdrGeoVille": "CARQUEIRANNE",
|
||||||
|
"ctmAdrGeoCodePostal": "83320",
|
||||||
|
"ctmAdrGeo1": null,
|
||||||
|
"ctmAdrGeo2": null,
|
||||||
|
"ctmAdrGeo3": null,
|
||||||
|
"ctmAdrGeo4": null,
|
||||||
|
"ctmAdrGeo5": null,
|
||||||
|
"ctmAdrPostaleCodePostal": "83320",
|
||||||
|
"ctmAdrPostaleVille": "CARQUEIRANNE",
|
||||||
|
"ctmAdrPostale1": null,
|
||||||
|
"ctmAdrPostale2": null,
|
||||||
|
"ctmAdrPostale3": null,
|
||||||
|
"ctmAdrPostale4": "1 AVENUE JEAN JAURES",
|
||||||
|
"ctmAdrPostale5": "BP 14",
|
||||||
|
"ctmDenominationSociale": "SCP Louis ABBATE, Gabriel GABOLDE et Laura SERVEL-SCHROEDER",
|
||||||
|
"ctmDenominationSocialeAbregee": "ABBATE et associés",
|
||||||
|
"ctmIntitule": "ABBATE Louis, GABOLDE Gabriel et SERVEL-SCHROEDER Laura",
|
||||||
|
"ctmFormeJuridique": "SCP",
|
||||||
|
"ctmLibelle": null,
|
||||||
|
"rattachement": {
|
||||||
|
"id": "IDN00082246I_IDN187087",
|
||||||
|
"email": "marie.curie.519@notaires.fr",
|
||||||
|
"blocked": false,
|
||||||
|
"phoneNumber": null,
|
||||||
|
"homePhoneNumber": null,
|
||||||
|
"entityType": "office",
|
||||||
|
"linkType": "Administrateur",
|
||||||
|
"subLinkType": null,
|
||||||
|
"activitiesDomain": [],
|
||||||
|
"mandats": [],
|
||||||
|
"manager": true,
|
||||||
|
"naturalManager": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"idn": "IDN00082246I",
|
||||||
|
"civilite": "Madame",
|
||||||
|
"photo": "",
|
||||||
|
"email": "personaIDN00082246I@portail.com",
|
||||||
|
"pseudo": "marie.curie.519",
|
||||||
|
"backupEmail": "nicolas.cantu@pm.me",
|
||||||
|
"emailValidated": "true"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Identifants
|
||||||
|
|
||||||
|
- Identifiant : ID.NOT IDN187087
|
||||||
|
- Type : STON
|
||||||
|
- CRPCEN : 083079
|
||||||
|
- Forme juridique : SCP
|
||||||
|
- Statut : Pourvu
|
||||||
|
- Département de résidence : 083 - VAR
|
||||||
|
- Résidence : CARQUEIRANNE (83034)
|
||||||
|
|
||||||
|
### Contact
|
||||||
|
|
||||||
|
- Téléphone : 0494005290
|
||||||
|
- Email : abbate.gabolde@notaires.fr
|
||||||
|
- Site internet : www.carqueiranne-abbate-gabolde-servel.notaires.fr
|
||||||
|
|
||||||
|
### Adresse géographique
|
||||||
|
|
||||||
|
- Numéro et libellé de la voie : 1 AVENUE JEAN JAURES
|
||||||
|
- Code postal : 83320
|
||||||
|
- Ville : CARQUEIRANNE
|
||||||
|
|
||||||
|
### Adresse postale
|
||||||
|
|
||||||
|
- Numéro et libellé de la voie : 1 AVENUE JEAN JAURES
|
||||||
|
- Complément d'adresse : BP 14
|
||||||
|
- Code postal : 83320
|
||||||
|
- Ville : CARQUEIRANNE
|
@ -97,49 +97,21 @@ export class IdNotController {
|
|||||||
Logger.info('IdNot authentication initiated', { codePrefix: code.substring(0, 8) + '...' });
|
Logger.info('IdNot authentication initiated', { codePrefix: code.substring(0, 8) + '...' });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Development fallback: allow authentication without contacting IdNot
|
// Mock désactivé: suppression du bypass IDNOT_MOCK
|
||||||
if (process.env.IDNOT_MOCK === '1') {
|
|
||||||
Logger.warn('IDNOT_MOCK enabled - returning mocked IdNot user without external calls');
|
|
||||||
const idNotUser: IdNotUser = {
|
|
||||||
idNot: 'IDN187087',
|
|
||||||
office: {
|
|
||||||
idNot: 'IDN187087',
|
|
||||||
name: 'STON - CARQUEIRANNE',
|
|
||||||
crpcen: '083079',
|
|
||||||
office_status: 'ACTIVATED' as any,
|
|
||||||
address: { address: 'CARQUEIRANNE', city: 'CARQUEIRANNE', zip_code: 83034 },
|
|
||||||
status: 'ACTIVE'
|
|
||||||
},
|
|
||||||
role: { name: 'admin' },
|
|
||||||
contact: {
|
|
||||||
first_name: 'Test',
|
|
||||||
last_name: 'User',
|
|
||||||
email: 'test@lecoffre.io',
|
|
||||||
phone_number: '+33400000000',
|
|
||||||
cell_phone_number: '+33600000000',
|
|
||||||
civility: 'Monsieur' as any
|
|
||||||
},
|
|
||||||
office_role: { name: 'Notaire' }
|
|
||||||
};
|
|
||||||
|
|
||||||
const authToken = uuidv4();
|
|
||||||
const tokenData: AuthToken = {
|
|
||||||
idNot: idNotUser.idNot,
|
|
||||||
authToken,
|
|
||||||
idNotUser,
|
|
||||||
pairingId: null,
|
|
||||||
defaultStorage: null,
|
|
||||||
createdAt: Date.now(),
|
|
||||||
expiresAt: Date.now() + (24 * 60 * 60 * 1000)
|
|
||||||
};
|
|
||||||
authTokens.push(tokenData);
|
|
||||||
|
|
||||||
return { idNotUser, authToken };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exchange code for tokens
|
// Exchange code for tokens
|
||||||
const tokens = await IdNotService.exchangeCodeForTokens(code);
|
const tokens = await IdNotService.exchangeCodeForTokens(code);
|
||||||
|
|
||||||
|
// Optional diagnostic: fetch userinfo to validate access_token
|
||||||
|
try {
|
||||||
|
if (tokens.access_token) {
|
||||||
|
const userinfo = await IdNotService.getUserInfo(tokens.access_token);
|
||||||
|
Logger.info('Userinfo fetched', { userinfoKeys: Object.keys(userinfo || {}) });
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
Logger.warn('Userinfo fetch failed (non-blocking)', { error: e instanceof Error ? e.message : String(e) });
|
||||||
|
}
|
||||||
|
|
||||||
Logger.info('Token exchange successful', {
|
Logger.info('Token exchange successful', {
|
||||||
hasAccessToken: !!tokens.access_token,
|
hasAccessToken: !!tokens.access_token,
|
||||||
hasIdToken: !!tokens.id_token,
|
hasIdToken: !!tokens.id_token,
|
||||||
|
@ -40,20 +40,18 @@ export class IdNotCallbackHandlers {
|
|||||||
|
|
||||||
const payload = StateService.verifyState(state);
|
const payload = StateService.verifyState(state);
|
||||||
|
|
||||||
// If external IdNot access is unavailable, allow mock bypass when enabled
|
// Mock désactivé: suppression du bypass IDNOT_MOCK
|
||||||
const mockEnabled = process.env.IDNOT_MOCK === '1';
|
|
||||||
if (mockEnabled) {
|
|
||||||
const { authToken } = await IdNotController.authenticate(code);
|
|
||||||
const url = new URL(payload.next_url);
|
|
||||||
const hash = url.hash ? url.hash.replace(/^#/, '') + `&authToken=${encodeURIComponent(authToken)}` : `authToken=${encodeURIComponent(authToken)}`;
|
|
||||||
const redirectTo = `${url.origin}${url.pathname}${url.search}#${hash}`;
|
|
||||||
return res.redirect(302, redirectTo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exchange code using existing controller logic to build auth and user
|
// Exchange code using existing controller logic to build auth and user
|
||||||
const { authToken } = await IdNotController.authenticate(code);
|
const { authToken } = await IdNotController.authenticate(code);
|
||||||
|
|
||||||
const url = new URL(payload.next_url);
|
const url = new URL(payload.next_url);
|
||||||
|
// Normalisation du chemin pour dev4: forcer le préfixe /lecoffre si absent
|
||||||
|
try {
|
||||||
|
if (url.hostname === 'dev4.4nkweb.com' && url.pathname === '/authorized-client') {
|
||||||
|
url.pathname = '/lecoffre/authorized-client';
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
// Prefer fragment to avoid leaking in server logs
|
// Prefer fragment to avoid leaking in server logs
|
||||||
const hash = url.hash ? url.hash.replace(/^#/, '') + `&authToken=${encodeURIComponent(authToken)}` : `authToken=${encodeURIComponent(authToken)}`;
|
const hash = url.hash ? url.hash.replace(/^#/, '') + `&authToken=${encodeURIComponent(authToken)}` : `authToken=${encodeURIComponent(authToken)}`;
|
||||||
const redirectTo = `${url.origin}${url.pathname}${url.search}#${hash}`;
|
const redirectTo = `${url.origin}${url.pathname}${url.search}#${hash}`;
|
||||||
@ -61,5 +59,3 @@ export class IdNotCallbackHandlers {
|
|||||||
res.redirect(302, redirectTo);
|
res.redirect(302, redirectTo);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,12 +78,57 @@ export class IdNotService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
try {
|
||||||
|
const contentType = response.headers.get('content-type') || '';
|
||||||
|
const bodyText = await (response as any).text().catch(() => undefined);
|
||||||
|
const snippet = bodyText ? bodyText.slice(0, 200) : undefined;
|
||||||
|
Logger.error('IdNot token exchange non-OK response', {
|
||||||
|
url: IDNOT_TOKEN_URL,
|
||||||
|
status: response.status,
|
||||||
|
statusText: response.statusText,
|
||||||
|
contentType,
|
||||||
|
bodySnippet: snippet
|
||||||
|
});
|
||||||
|
} catch {}
|
||||||
throw new Error(`Token exchange failed: ${response.status} ${response.statusText}`);
|
throw new Error(`Token exchange failed: ${response.status} ${response.statusText}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.json();
|
return response.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async getUserInfo(accessToken: string) {
|
||||||
|
const { IDNOT_USERINFO_URL } = process.env;
|
||||||
|
if (!IDNOT_USERINFO_URL) {
|
||||||
|
throw new Error('Missing IDNOT_USERINFO_URL');
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(IDNOT_USERINFO_URL, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Authorization': `Bearer ${accessToken}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
try {
|
||||||
|
const contentType = response.headers.get('content-type') || '';
|
||||||
|
const bodyText = await (response as any).text().catch(() => undefined);
|
||||||
|
const snippet = bodyText ? bodyText.slice(0, 200) : undefined;
|
||||||
|
Logger.error('IdNot userinfo non-OK response', {
|
||||||
|
url: IDNOT_USERINFO_URL,
|
||||||
|
status: response.status,
|
||||||
|
statusText: response.statusText,
|
||||||
|
contentType,
|
||||||
|
bodySnippet: snippet
|
||||||
|
});
|
||||||
|
} catch {}
|
||||||
|
throw new ExternalServiceError('IdNot', `Failed to fetch userinfo: ${response.status} ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await IdNotService.parseJsonOrThrow(response as any, 'getUserInfo');
|
||||||
|
}
|
||||||
|
|
||||||
static async getUserRattachements(idNot: string) {
|
static async getUserRattachements(idNot: string) {
|
||||||
const { IDNOT_API_KEY, IDNOT_ANNUARY_BASE_URL } = process.env;
|
const { IDNOT_API_KEY, IDNOT_ANNUARY_BASE_URL } = process.env;
|
||||||
|
|
||||||
@ -139,10 +184,10 @@ export class IdNotService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async getUserData(profileIdn: string) {
|
static async getUserData(profileIdn: string) {
|
||||||
const { IDNOT_API_KEY, IDNOT_API_BASE_URL } = process.env;
|
const { IDNOT_API_KEY, IDNOT_ANNUARY_BASE_URL } = process.env;
|
||||||
|
|
||||||
if (!IDNOT_API_KEY || !IDNOT_API_BASE_URL) {
|
if (!IDNOT_API_KEY || !IDNOT_ANNUARY_BASE_URL) {
|
||||||
throw new Error('Missing IDnot API key or base URL');
|
throw new Error('Missing IDnot API key or annuary base URL');
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchParams = new URLSearchParams({
|
const searchParams = new URLSearchParams({
|
||||||
@ -155,8 +200,24 @@ export class IdNotService {
|
|||||||
if (process.env.IDNOT_CONTEXT_HEADER && process.env.IDNOT_CONTEXT_VALUE) {
|
if (process.env.IDNOT_CONTEXT_HEADER && process.env.IDNOT_CONTEXT_VALUE) {
|
||||||
headers[process.env.IDNOT_CONTEXT_HEADER] = process.env.IDNOT_CONTEXT_VALUE;
|
headers[process.env.IDNOT_CONTEXT_HEADER] = process.env.IDNOT_CONTEXT_VALUE;
|
||||||
}
|
}
|
||||||
const response = await fetch(`${IDNOT_API_BASE_URL}/api/pp/v2/rattachements/${profileIdn}?` + searchParams, { method: 'GET', headers });
|
const fullUrl = `${IDNOT_ANNUARY_BASE_URL}/api/pp/v2/rattachements/${profileIdn}?` + searchParams;
|
||||||
|
const response = await fetch(fullUrl, { method: 'GET', headers });
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
try {
|
||||||
|
const contentType = response.headers.get('content-type') || '';
|
||||||
|
const bodyText = await (response as any).text().catch(() => undefined);
|
||||||
|
const snippet = bodyText ? bodyText.slice(0, 200) : undefined;
|
||||||
|
const safeUrl = fullUrl.replace(/(key=)[^&]+/i, '$1***');
|
||||||
|
Logger.error('IdNot getUserData non-OK response', {
|
||||||
|
context: 'getUserData',
|
||||||
|
profileIdn,
|
||||||
|
url: safeUrl,
|
||||||
|
status: response.status,
|
||||||
|
statusText: response.statusText,
|
||||||
|
contentType,
|
||||||
|
bodySnippet: snippet
|
||||||
|
});
|
||||||
|
} catch {}
|
||||||
throw new ExternalServiceError('IdNot', `Failed to fetch user data: ${response.status} ${response.statusText}`);
|
throw new ExternalServiceError('IdNot', `Failed to fetch user data: ${response.status} ${response.statusText}`);
|
||||||
}
|
}
|
||||||
return await IdNotService.parseJsonOrThrow(response as any, 'getUserData');
|
return await IdNotService.parseJsonOrThrow(response as any, 'getUserData');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user