diff --git a/Dockerfile b/Dockerfile index 92bc5bc..99168e0 100755 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,12 @@ -FROM python:3.9-slim -WORKDIR /app -COPY app/requirements.txt . -RUN pip install --no-cache-dir -r requirements.txt -COPY app/ . -EXPOSE 8000 -CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file +# Dockerfile.nginx (Frontend) +FROM nginx:alpine + +# Copie vos fichiers statiques (index.html, etc.) +COPY ./app /usr/share/nginx/html + +# Force les droits Linux corrects pour Nginx (évite le 403 Forbidden) +RUN chown -R nginx:nginx /usr/share/nginx/html && \ + chmod -R 755 /usr/share/nginx/html + +# Nginx écoute par défaut sur le port 80 dans le conteneur +EXPOSE 80 \ No newline at end of file diff --git a/app/icons/icon-192.png b/app/icons/icon-192.png new file mode 100644 index 0000000..4641197 Binary files /dev/null and b/app/icons/icon-192.png differ diff --git a/app/icons/icon-512.png b/app/icons/icon-512.png new file mode 100644 index 0000000..127b4f9 Binary files /dev/null and b/app/icons/icon-512.png differ diff --git a/app/index.html b/app/index.html index 6775709..7d00fa6 100755 --- a/app/index.html +++ b/app/index.html @@ -1,265 +1,844 @@ - + - - - Cyberusgate - Démonstration - - - - - - + + + + + + +SafeAccess + + + + + + - -
+ - - - -
-
-

Cyberusgate

-

Console d'administration centralisée

-
+ +
+
+ + + +
+ +
- -
-
-

Utilisateurs Actifs

- -
-
- - - - - - - - - - - - -
NomRôleStatutAction
-
-
+ +
+
+
+ +
+

Vérification 2FA

+

Code TOTP (renouvelle toutes les 30s)

+
------
+
+

Entrez le code de votre application d'authentification :

+
+
+ + + +
+ + +
+
- -
-

Journal d'Événements en Temps Réel

-
- -
-
+ +
+
+
+
AD
+
+

Alice Dupont

+

AC-0012 · Niveau 3

+
+
+
+ + +
+
+ + + + +
+
+
+
NFC disponible
Votre téléphone est détecté compatible NFC
+
+
+
+
AD
+
+

Alice Dupont

+

Technicien Réseau Senior

+
ID: AC-0012 · Émis le 01/01/2025
+
+
+ PRÊT À SCANNER +
- - - - -
-
-

Simulateur de Porte

- - -
-
-

CYBERUSGATE

-
- -
-
- -
- - -
- -
- -
-
+
+
+
+ +
+
+
SafeAccess system · NFC/QR
+
+
+
+ +
+
En attente d'un lecteur NFC
+
Approchez votre téléphone du lecteur
+
+
+ + +
+
+
+ + +
+
+
Tous
+
NFC
+
RFID
+
QR Code
+
Bluetooth
+
+
Mes badges (4)
+
+
+ + +
+ +
+
+ + +
+
Tableau de bord
+
+
Utilisateurs
17
actifs ce mois
+
Zones
16
zones actives
+
Accès aujourd'hui
143
autorisés
+
Alertes
0
incidents actifs
+
+
Gestion des zones
+
+
Logs récents
+
+
+ + +
+
Sécurité
+
+
+
+
Double authentification (2FA)
TOTP activé · App Authenticator
+
+
+
+
+
Biométrie
Empreinte / Face ID
+
+
+
+
+
Code PIN
Modifier le code PIN de secours
+
+
- - - - + +function selectMFA(btn, method) { + document.querySelectorAll('.mfa-method-btn').forEach(b => b.classList.remove('active')); + btn.classList.add('active'); + if(method === 'sms') showToast('SMS envoyé au +33 6 ** ** ** 42'); + if(method === 'email') showToast('Email envoyé à a.dupont@****'); +} + +function verifyMFA() { + const inputs = document.querySelectorAll('.mfa-digit'); + let code = ''; + inputs.forEach(i => code += i.value); + if(code.length < 6) { showToast('Entrez les 6 chiffres'); return; } + if(code === currentCode || code === correctCode) { + if(totpInterval) clearInterval(totpInterval); + showToast('✓ Authentification réussie !'); + setTimeout(() => { + goTo('screen-app'); + renderQR(); + renderBadgeList(); + renderHistory(); + renderDashboard(); + }, 800); + } else { + showToast('❌ Code incorrect, réessayez'); + buildMFAInputs(); + } +} + +// ===== QR CODE ===== +function renderQR() { + const canvas = document.getElementById('qr-canvas'); + const ctx = canvas.getContext('2d'); + const size = 154; + const data = 'SAFEACCESS:AC-0012:' + Date.now(); + drawQR(ctx, data, size); + setInterval(() => { + const newData = 'SAFEACCESS:AC-0012:' + Date.now(); + drawQR(ctx, newData, size); + }, 60000); +} + +function drawQR(ctx, data, size) { + ctx.clearRect(0, 0, size, size); + ctx.fillStyle = '#fff'; + ctx.fillRect(0, 0, size, size); + const cells = 25; + const cellSize = Math.floor(size / cells); + const hash = Array.from(data).reduce((a, c) => ((a << 5) - a + c.charCodeAt(0)) | 0, 0); + for(let r = 0; r < cells; r++) { + for(let c = 0; c < cells; c++) { + const seed = (r * 31 + c * 17 + hash + r*c) % 100; + const shouldFill = seed < 45 || (r < 7 && c < 7) || (r < 7 && c > cells-8) || (r > cells-8 && c < 7); + if(shouldFill) { + ctx.fillStyle = '#0D2B5E'; + ctx.fillRect(c * cellSize + 1, r * cellSize + 1, cellSize - 1, cellSize - 1); + } + } + } + // Finder patterns + [[0,0],[0,cells-7],[cells-7,0]].forEach(([row,col]) => { + ctx.strokeStyle = '#0D2B5E'; ctx.lineWidth = 2; + ctx.strokeRect(col*cellSize+1, row*cellSize+1, 6*cellSize, 6*cellSize); + ctx.fillStyle = '#0D2B5E'; + ctx.fillRect((col+2)*cellSize, (row+2)*cellSize, 3*cellSize, 3*cellSize); + }); +} + +// ===== NFC SIMULATION ===== +function simulateNFC() { + const ring = document.getElementById('nfc-ring'); + const status = document.getElementById('nfc-status-text'); + ring.style.borderColor = '#FBC02D'; + ring.style.animation = 'nfc-pulse 0.8s ease-in-out infinite'; + status.textContent = 'Lecture NFC en cours...'; + status.style.color = '#E65100'; + setTimeout(() => { + ring.style.borderColor = '#4CAF50'; + ring.style.animation = 'none'; + status.textContent = '✓ Accès autorisé — Bureau Principal'; + status.style.color = '#2E7D32'; + showToast('✓ Accès autorisé — Bureau Principal'); + setTimeout(() => { + ring.style.borderColor = 'var(--blue-light)'; + ring.style.animation = 'nfc-pulse 2.5s ease-in-out infinite'; + status.textContent = 'En attente d\'un lecteur NFC'; + status.style.color = 'var(--blue-main)'; + }, 3000); + }, 1800); +} + +// ===== BADGE LIST ===== +const techIcons = { + nfc: ``, + rfid: ``, + qr: ``, + bt: ``, +}; + +function renderBadgeList() { + const list = document.getElementById('badge-list'); + list.innerHTML = badges.map(b => ` +
+
${techIcons[b.tech]}
+
+
${b.name}
+
${b.uid} · ${b.zones.join(', ')}
+
+
+ ${b.tech.toUpperCase()} +
+
+
+ `).join(''); +} + +// ===== HISTORY ===== +const inIcon = ``; +const outIcon = ``; +const refIcon = ``; + +function renderHistory(filter = '') { + const list = document.getElementById('history-list'); + const filtered = history.filter(h => !filter || h.loc.toLowerCase().includes(filter.toLowerCase())); + let html = ''; + let lastDate = ''; + filtered.forEach(h => { + if(h.date !== lastDate) { + html += `
${h.date}
`; + lastDate = h.date; + } + const iconType = h.status === 'refused' ? 'refused' : h.type === 'in' ? 'in' : 'out'; + const icon = h.status === 'refused' ? refIcon : h.type === 'in' ? inIcon : outIcon; + const typeLabel = h.type === 'in' ? 'Entrée' : 'Sortie'; + html += ` +
+
${icon}
+
+
${typeLabel} · ${h.loc}
+
${h.sub}
+
+
+ ${h.status === 'ok' ? 'AUTORISÉ' : 'REFUSÉ'} +
${h.date.split(',')[1] || ''}
+
+
`; + }); + list.innerHTML = html || '
Aucun résultat
'; +} + +document.getElementById('history-search').addEventListener('input', e => renderHistory(e.target.value)); + +// ===== DASHBOARD ===== +function renderDashboard() { + const zl = document.getElementById('zone-list'); + zl.innerHTML = zones.map(z => ` +
+
${z.name}
${z.level}
+ ${z.risk === 'high' ? 'Restreint' : z.risk === 'medium' ? 'Modéré' : 'Public'} +
`).join(''); + + const dl = document.getElementById('dash-logs'); + dl.innerHTML = history.slice(0,4).map(h => ` +
+
${h.status === 'refused' ? refIcon : h.type === 'in' ? inIcon : outIcon}
+
${h.loc}
${h.sub}
+
${h.status === 'ok' ? 'OK' : 'REFUSÉ'}
+
`).join(''); +} + +// ===== ADD BADGE MODAL ===== +function showAddBadgeModal() { + document.getElementById('modal-add').classList.add('open'); +} +function closeModal() { + document.getElementById('modal-add').classList.remove('open'); +} +function addBadge(tech) { + closeModal(); + const newBadge = { + id: 'B00' + (badges.length + 1), + name: 'Nouveau badge ' + tech, + tech: tech.toLowerCase() === 'nfc' ? 'nfc' : tech.toLowerCase() === 'rfid' ? 'rfid' : tech.toLowerCase() === 'qr code' ? 'qr' : 'bt', + uid: 'NEW-' + Math.random().toString(36).substr(2,8).toUpperCase(), + zones: ['Bureau Principal'], + active: true, + }; + badges.push(newBadge); + if(currentTab === 'mes-badges') renderBadgeList(); + showToast('✓ Badge ' + tech + ' ajouté'); +} + +// ===== TOAST ===== +function showToast(msg) { + const t = document.getElementById('toast'); + t.textContent = msg; + t.classList.add('show'); + setTimeout(() => t.classList.remove('show'), 2500); +} + +// ===== INIT ===== +document.getElementById('fab-btn').style.display = 'none'; + diff --git a/app/manifest.json b/app/manifest.json new file mode 100644 index 0000000..3bf5d84 --- /dev/null +++ b/app/manifest.json @@ -0,0 +1,17 @@ +{ + "name": "SafeAccess — Gestion de badges", + "short_name": "SafeAccess", + "description": "Gestion de badges d'accès NFC, RFID, QR Code et Bluetooth avec 2FA", + "start_url": "/index.html", + "display": "standalone", + "background_color": "#0D2B5E", + "theme_color": "#1565C0", + "orientation": "portrait", + "icons": [ + { "src": "icons/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any maskable" }, + { "src": "icons/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any maskable" } + ], + "categories": ["security", "utilities", "business"], + "lang": "fr", + "scope": "/" +} diff --git a/app/sw.js b/app/sw.js new file mode 100644 index 0000000..efd1f5c --- /dev/null +++ b/app/sw.js @@ -0,0 +1,12 @@ +const CACHE = 'safeaccess-v1'; +const ASSETS = ['/', '/index.html', '/manifest.json']; + +self.addEventListener('install', e => { + e.waitUntil(caches.open(CACHE).then(c => c.addAll(ASSETS))); +}); + +self.addEventListener('fetch', e => { + e.respondWith( + caches.match(e.request).then(r => r || fetch(e.request)).catch(() => caches.match('/index.html')) + ); +}); diff --git a/docker-compose.yml b/docker-compose.yml index a7a3910..07a481e 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,20 +1,9 @@ services: - backend: - build: - context: . - dockerfile: Dockerfile - container_name: cyberusgate_backend - ports: - - "8000:8000" - environment: - - PYTHONUNBUFFERED=1 - networks: - - cyberusgate-network frontend: build: context: . - dockerfile: Dockerfile.nginx + dockerfile: Dockerfile container_name: cyberusgate_frontend ports: - "8888:80" diff --git a/old/Dockerfile b/old/Dockerfile new file mode 100644 index 0000000..92bc5bc --- /dev/null +++ b/old/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.9-slim +WORKDIR /app +COPY app/requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt +COPY app/ . +EXPOSE 8000 +CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file diff --git a/Dockerfile.nginx b/old/Dockerfile.nginx similarity index 100% rename from Dockerfile.nginx rename to old/Dockerfile.nginx diff --git a/old/app/apple-touch-icon.png b/old/app/apple-touch-icon.png new file mode 100644 index 0000000..f319dce Binary files /dev/null and b/old/app/apple-touch-icon.png differ diff --git a/old/app/favicon-16x16.png b/old/app/favicon-16x16.png new file mode 100644 index 0000000..5e7b212 Binary files /dev/null and b/old/app/favicon-16x16.png differ diff --git a/old/app/favicon-32x32.png b/old/app/favicon-32x32.png new file mode 100644 index 0000000..2d77783 Binary files /dev/null and b/old/app/favicon-32x32.png differ diff --git a/old/app/index.html b/old/app/index.html new file mode 100644 index 0000000..6775709 --- /dev/null +++ b/old/app/index.html @@ -0,0 +1,265 @@ + + + + + + Cyberusgate - Démonstration + + + + + + + + +
+ + + + +
+
+

Cyberusgate

+

Console d'administration centralisée

+
+ + +
+
+

Utilisateurs Actifs

+ +
+
+ + + + + + + + + + + + +
NomRôleStatutAction
+
+
+ + +
+

Journal d'Événements en Temps Réel

+
+ +
+
+
+ + + + +
+
+

Simulateur de Porte

+ + +
+
+

CYBERUSGATE

+
+ +
+
+ +
+ + +
+ +
+ +
+
+
+
+ + + + + + + diff --git a/app/main.py b/old/app/main.py old mode 100755 new mode 100644 similarity index 100% rename from app/main.py rename to old/app/main.py diff --git a/app/requirements.txt b/old/app/requirements.txt old mode 100755 new mode 100644 similarity index 100% rename from app/requirements.txt rename to old/app/requirements.txt diff --git a/old/app/site.webmanifest b/old/app/site.webmanifest new file mode 100644 index 0000000..45dc8a2 --- /dev/null +++ b/old/app/site.webmanifest @@ -0,0 +1 @@ +{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/old/docker-compose.yml b/old/docker-compose.yml new file mode 100644 index 0000000..a7a3910 --- /dev/null +++ b/old/docker-compose.yml @@ -0,0 +1,26 @@ +services: + backend: + build: + context: . + dockerfile: Dockerfile + container_name: cyberusgate_backend + ports: + - "8000:8000" + environment: + - PYTHONUNBUFFERED=1 + networks: + - cyberusgate-network + + frontend: + build: + context: . + dockerfile: Dockerfile.nginx + container_name: cyberusgate_frontend + ports: + - "8888:80" + networks: + - cyberusgate-network + +networks: + cyberusgate-network: + driver: bridge \ No newline at end of file