jimmytousergo commited on
Commit
12e817a
·
verified ·
1 Parent(s): fe54a8d

Sync from GitHub via hub-sync

Browse files
Files changed (1) hide show
  1. server.ts +88 -0
server.ts CHANGED
@@ -1,5 +1,6 @@
1
  import express from 'express';
2
  import path from 'path';
 
3
  import { fileURLToPath } from 'url';
4
  import dotenv from 'dotenv';
5
 
@@ -898,6 +899,93 @@ async function startServer() {
898
  next();
899
  });
900
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
901
  // API: Search Odoo + PrestaShop contacts
902
  app.get('/api/search', async (req, res) => {
903
  const phone = String(req.query.phone || '');
 
1
  import express from 'express';
2
  import path from 'path';
3
+ import crypto from 'crypto';
4
  import { fileURLToPath } from 'url';
5
  import dotenv from 'dotenv';
6
 
 
899
  next();
900
  });
901
 
902
+ // ==========================================
903
+ // PROTECTION PAR MOT DE PASSE PARTAGE
904
+ // ==========================================
905
+ const APP_PASSWORD = process.env.APP_PASSWORD || '';
906
+ const AUTH_SECRET = crypto
907
+ .createHash('sha256')
908
+ .update('tousergo-crm-' + APP_PASSWORD)
909
+ .digest('hex');
910
+ const AUTH_COOKIE_NAME = 'crm_auth';
911
+
912
+ function parseCookies(req: express.Request): Record<string, string> {
913
+ const header = req.headers.cookie;
914
+ const out: Record<string, string> = {};
915
+ if (!header) return out;
916
+ header.split(';').forEach((part) => {
917
+ const idx = part.indexOf('=');
918
+ if (idx === -1) return;
919
+ const key = part.slice(0, idx).trim();
920
+ const value = part.slice(idx + 1).trim();
921
+ out[key] = decodeURIComponent(value);
922
+ });
923
+ return out;
924
+ }
925
+
926
+ function isAuthenticated(req: express.Request): boolean {
927
+ if (!APP_PASSWORD) return true; // si aucun mot de passe configure, ne bloque rien
928
+ const cookies = parseCookies(req);
929
+ return cookies[AUTH_COOKIE_NAME] === AUTH_SECRET;
930
+ }
931
+
932
+ app.use(express.urlencoded({ extended: true }));
933
+
934
+ app.post('/login', (req, res) => {
935
+ const submitted = String(req.body?.password || '');
936
+ const redirectTo = String(req.body?.redirect || '/');
937
+ if (APP_PASSWORD && submitted === APP_PASSWORD) {
938
+ res.setHeader(
939
+ 'Set-Cookie',
940
+ `${AUTH_COOKIE_NAME}=${encodeURIComponent(AUTH_SECRET)}; Path=/; Max-Age=2592000; HttpOnly; SameSite=Lax`
941
+ );
942
+ return res.redirect(302, redirectTo || '/');
943
+ }
944
+ return res.send(renderLoginPage(redirectTo, true));
945
+ });
946
+
947
+ function renderLoginPage(redirectTo: string, showError: boolean): string {
948
+ return `<!DOCTYPE html>
949
+ <html lang="fr">
950
+ <head>
951
+ <meta charset="UTF-8" />
952
+ <title>CRM Levee de Fiche - Connexion</title>
953
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
954
+ <style>
955
+ body { font-family: -apple-system, sans-serif; background: #f1f5f9; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; }
956
+ .box { background: white; padding: 32px; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); width: 320px; }
957
+ h1 { font-size: 16px; margin: 0 0 16px; color: #26295A; }
958
+ input { width: 100%; padding: 10px; border: 1px solid #cbd5e1; border-radius: 8px; box-sizing: border-box; margin-bottom: 12px; font-size: 14px; }
959
+ button { width: 100%; padding: 10px; background: #B63E19; color: white; border: none; border-radius: 8px; font-weight: bold; cursor: pointer; }
960
+ .error { color: #B63E19; font-size: 12px; margin-bottom: 12px; }
961
+ </style>
962
+ </head>
963
+ <body>
964
+ <div class="box">
965
+ <h1>CRM Service Client - Acces protege</h1>
966
+ ${showError ? '<div class="error">Mot de passe incorrect.</div>' : ''}
967
+ <form method="POST" action="/login">
968
+ <input type="hidden" name="redirect" value="${redirectTo.replace(/"/g, '&quot;')}" />
969
+ <input type="password" name="password" placeholder="Mot de passe" autofocus />
970
+ <button type="submit">Se connecter</button>
971
+ </form>
972
+ </div>
973
+ </body>
974
+ </html>`;
975
+ }
976
+
977
+ app.use((req, res, next) => {
978
+ if (req.path === '/login') return next();
979
+ if (isAuthenticated(req)) return next();
980
+
981
+ if (req.path.startsWith('/api/')) {
982
+ return res.status(401).json({ error: 'Non authentifie' });
983
+ }
984
+
985
+ const originalUrl = req.originalUrl || '/';
986
+ return res.send(renderLoginPage(originalUrl, false));
987
+ });
988
+
989
  // API: Search Odoo + PrestaShop contacts
990
  app.get('/api/search', async (req, res) => {
991
  const phone = String(req.query.phone || '');