Ajout de la présentation
This commit is contained in:
Generated
+26
-65
@@ -84,6 +84,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
|
||||||
"integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
|
"integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.29.7",
|
"@babel/code-frame": "^7.29.7",
|
||||||
"@babel/generator": "^7.29.7",
|
"@babel/generator": "^7.29.7",
|
||||||
@@ -1486,6 +1487,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz",
|
||||||
"integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==",
|
"integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
@@ -1566,29 +1568,6 @@
|
|||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@emnapi/core": {
|
|
||||||
"version": "1.10.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
|
|
||||||
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@emnapi/wasi-threads": "1.2.1",
|
|
||||||
"tslib": "^2.4.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@emnapi/runtime": {
|
|
||||||
"version": "1.10.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
|
|
||||||
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
|
||||||
"tslib": "^2.4.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@emnapi/wasi-threads": {
|
"node_modules/@emnapi/wasi-threads": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
|
||||||
@@ -3083,6 +3062,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.3.4.tgz",
|
||||||
"integrity": "sha512-zyAqFLeZuaakerMMnhYqBeGAzJ+WFQUTgezP3FxSlXNwFq5XxnjP28vi2XHGqm4zg4pGWls9Ay4JKshIHUOpwA==",
|
"integrity": "sha512-zyAqFLeZuaakerMMnhYqBeGAzJ+WFQUTgezP3FxSlXNwFq5XxnjP28vi2XHGqm4zg4pGWls9Ay4JKshIHUOpwA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/core": "^7.21.2",
|
"@react-navigation/core": "^7.21.2",
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
@@ -3282,6 +3262,7 @@
|
|||||||
"integrity": "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==",
|
"integrity": "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
@@ -3352,6 +3333,7 @@
|
|||||||
"integrity": "sha512-sPhE4iHuJDSvoAiec+Ro8JyXw8f0ql13HFR82P99nCm9GwTEKG0KYLvDe6REk8BCXuit6vJAv/Yxg5ABaNS2rA==",
|
"integrity": "sha512-sPhE4iHuJDSvoAiec+Ro8JyXw8f0ql13HFR82P99nCm9GwTEKG0KYLvDe6REk8BCXuit6vJAv/Yxg5ABaNS2rA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.62.1",
|
"@typescript-eslint/scope-manager": "8.62.1",
|
||||||
"@typescript-eslint/types": "8.62.1",
|
"@typescript-eslint/types": "8.62.1",
|
||||||
@@ -3714,9 +3696,6 @@
|
|||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -3731,9 +3710,6 @@
|
|||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"musl"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -3748,9 +3724,6 @@
|
|||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -3765,9 +3738,6 @@
|
|||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"musl"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -3782,9 +3752,6 @@
|
|||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -3799,9 +3766,6 @@
|
|||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -3816,9 +3780,6 @@
|
|||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"musl"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -3833,9 +3794,6 @@
|
|||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -3850,9 +3808,6 @@
|
|||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -3867,9 +3822,6 @@
|
|||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"libc": [
|
|
||||||
"musl"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -4013,6 +3965,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz",
|
||||||
"integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==",
|
"integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -4673,6 +4626,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.10.38",
|
"baseline-browser-mapping": "^2.10.38",
|
||||||
"caniuse-lite": "^1.0.30001799",
|
"caniuse-lite": "^1.0.30001799",
|
||||||
@@ -5668,6 +5622,7 @@
|
|||||||
"integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==",
|
"integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.8.0",
|
"@eslint-community/eslint-utils": "^4.8.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
@@ -5864,6 +5819,7 @@
|
|||||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rtsao/scc": "^1.1.0",
|
"@rtsao/scc": "^1.1.0",
|
||||||
"array-includes": "^3.1.9",
|
"array-includes": "^3.1.9",
|
||||||
@@ -6078,6 +6034,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/expo/-/expo-54.0.35.tgz",
|
"resolved": "https://registry.npmjs.org/expo/-/expo-54.0.35.tgz",
|
||||||
"integrity": "sha512-E+tXpQwjGm5fK/uwa55p0Xx/kuo5dXDKfVJ95IargTNa5KiFt26lSTXXa9KnHbI4EDLwFD38/xTKZvzPTlGTdg==",
|
"integrity": "sha512-E+tXpQwjGm5fK/uwa55p0Xx/kuo5dXDKfVJ95IargTNa5KiFt26lSTXXa9KnHbI4EDLwFD38/xTKZvzPTlGTdg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.0",
|
"@babel/runtime": "^7.20.0",
|
||||||
"@expo/cli": "54.0.25",
|
"@expo/cli": "54.0.25",
|
||||||
@@ -6130,6 +6087,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.13.tgz",
|
||||||
"integrity": "sha512-FnZn12E1dRYKDHlAdIyNFhBurKTS3F9CrfrBDJI5m3D7U17KBHMQ6JEfYlSj7LG7t+Ulr+IKaj58L1k5gBwTcQ==",
|
"integrity": "sha512-FnZn12E1dRYKDHlAdIyNFhBurKTS3F9CrfrBDJI5m3D7U17KBHMQ6JEfYlSj7LG7t+Ulr+IKaj58L1k5gBwTcQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/config": "~12.0.13",
|
"@expo/config": "~12.0.13",
|
||||||
"@expo/env": "~2.0.8"
|
"@expo/env": "~2.0.8"
|
||||||
@@ -6144,6 +6102,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/expo-font/-/expo-font-14.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/expo-font/-/expo-font-14.0.12.tgz",
|
||||||
"integrity": "sha512-QQzunE2Mxk45AsCWm3tK7OpVljbtVnKD58q4/qliev+cbye1IOduUnRIdD+P7DyButw17G9MTX795kgaQiz5hQ==",
|
"integrity": "sha512-QQzunE2Mxk45AsCWm3tK7OpVljbtVnKD58q4/qliev+cbye1IOduUnRIdD+P7DyButw17G9MTX795kgaQiz5hQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fontfaceobserver": "^2.1.0"
|
"fontfaceobserver": "^2.1.0"
|
||||||
},
|
},
|
||||||
@@ -6184,6 +6143,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-8.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-8.0.12.tgz",
|
||||||
"integrity": "sha512-FpXeIpFgZuxihwT9lBo86YD3y6LphBuAhN680MMxm/Y7fmsc57vimn2d3vFu68VI0+Z9w457t494mu2wvlgWTQ==",
|
"integrity": "sha512-FpXeIpFgZuxihwT9lBo86YD3y6LphBuAhN680MMxm/Y7fmsc57vimn2d3vFu68VI0+Z9w457t494mu2wvlgWTQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"expo-constants": "~18.0.13",
|
"expo-constants": "~18.0.13",
|
||||||
"invariant": "^2.2.4"
|
"invariant": "^2.2.4"
|
||||||
@@ -8762,9 +8722,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -8785,9 +8742,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"libc": [
|
|
||||||
"musl"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -8808,9 +8762,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"libc": [
|
|
||||||
"glibc"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -8831,9 +8782,6 @@
|
|||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"libc": [
|
|
||||||
"musl"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -10392,6 +10340,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
|
||||||
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
|
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -10411,6 +10360,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
|
||||||
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
|
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.26.0"
|
"scheduler": "^0.26.0"
|
||||||
},
|
},
|
||||||
@@ -10447,6 +10397,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.81.5.tgz",
|
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.81.5.tgz",
|
||||||
"integrity": "sha512-1w+/oSjEXZjMqsIvmkCRsOc8UBYv163bTWKTI8+1mxztvQPhCRYGTvZ/PL1w16xXHneIj/SLGfxWg2GWN2uexw==",
|
"integrity": "sha512-1w+/oSjEXZjMqsIvmkCRsOc8UBYv163bTWKTI8+1mxztvQPhCRYGTvZ/PL1w16xXHneIj/SLGfxWg2GWN2uexw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jest/create-cache-key-function": "^29.7.0",
|
"@jest/create-cache-key-function": "^29.7.0",
|
||||||
"@react-native/assets-registry": "0.81.5",
|
"@react-native/assets-registry": "0.81.5",
|
||||||
@@ -10504,6 +10455,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.28.0.tgz",
|
||||||
"integrity": "sha512-0msfJ1vRxXKVgTgvL+1ZOoYw3/0z1R+Ked0+udoJhyplC2jbVKIJ8Z1bzWdpQRCV3QcQ87Op0zJVE5DhKK2A0A==",
|
"integrity": "sha512-0msfJ1vRxXKVgTgvL+1ZOoYw3/0z1R+Ked0+udoJhyplC2jbVKIJ8Z1bzWdpQRCV3QcQ87Op0zJVE5DhKK2A0A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@egjs/hammerjs": "^2.0.17",
|
"@egjs/hammerjs": "^2.0.17",
|
||||||
"hoist-non-react-statics": "^3.3.0",
|
"hoist-non-react-statics": "^3.3.0",
|
||||||
@@ -10529,6 +10481,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.1.7.tgz",
|
||||||
"integrity": "sha512-Q4H6xA3Tn7QL0/E/KjI86I1KK4tcf+ErRE04LH34Etka2oVQhW6oXQ+Q8ZcDCVxiWp5vgbBH6XcH8BOo4w/Rhg==",
|
"integrity": "sha512-Q4H6xA3Tn7QL0/E/KjI86I1KK4tcf+ErRE04LH34Etka2oVQhW6oXQ+Q8ZcDCVxiWp5vgbBH6XcH8BOo4w/Rhg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react-native-is-edge-to-edge": "^1.2.1",
|
"react-native-is-edge-to-edge": "^1.2.1",
|
||||||
"semver": "^7.7.2"
|
"semver": "^7.7.2"
|
||||||
@@ -10556,6 +10509,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.2.tgz",
|
||||||
"integrity": "sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg==",
|
"integrity": "sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "*",
|
"react": "*",
|
||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
@@ -10566,6 +10520,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.16.0.tgz",
|
||||||
"integrity": "sha512-yIAyh7F/9uWkOzCi1/2FqvNvK6Wb9Y1+Kzn16SuGfN9YFJDTbwlzGRvePCNTOX0recpLQF3kc2FmvMUhyTCH1Q==",
|
"integrity": "sha512-yIAyh7F/9uWkOzCi1/2FqvNvK6Wb9Y1+Kzn16SuGfN9YFJDTbwlzGRvePCNTOX0recpLQF3kc2FmvMUhyTCH1Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react-freeze": "^1.0.0",
|
"react-freeze": "^1.0.0",
|
||||||
"react-native-is-edge-to-edge": "^1.2.1",
|
"react-native-is-edge-to-edge": "^1.2.1",
|
||||||
@@ -10581,6 +10536,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.2.tgz",
|
||||||
"integrity": "sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==",
|
"integrity": "sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.18.6",
|
"@babel/runtime": "^7.18.6",
|
||||||
"@react-native/normalize-colors": "^0.74.1",
|
"@react-native/normalize-colors": "^0.74.1",
|
||||||
@@ -10613,6 +10569,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.15.0.tgz",
|
||||||
"integrity": "sha512-Vzjgy8mmxa/JO6l5KZrsTC7YemSdq+qB01diA0FqjUTaWGAGwuykpJ73MDj3+mzBSlaDxAEugHzTtkUQkQEQeQ==",
|
"integrity": "sha512-Vzjgy8mmxa/JO6l5KZrsTC7YemSdq+qB01diA0FqjUTaWGAGwuykpJ73MDj3+mzBSlaDxAEugHzTtkUQkQEQeQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
"invariant": "2.2.4"
|
"invariant": "2.2.4"
|
||||||
@@ -10627,6 +10584,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.5.1.tgz",
|
||||||
"integrity": "sha512-lJG6Uk9YuojjEX/tQrCbcbmpdLCSFxDK1rJlkDhgqkVi1KZzG7cdcBFQRqyNOOzR9Y0CXNuldmtWTGOyM0k0+w==",
|
"integrity": "sha512-lJG6Uk9YuojjEX/tQrCbcbmpdLCSFxDK1rJlkDhgqkVi1KZzG7cdcBFQRqyNOOzR9Y0CXNuldmtWTGOyM0k0+w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/plugin-transform-arrow-functions": "^7.0.0-0",
|
"@babel/plugin-transform-arrow-functions": "^7.0.0-0",
|
||||||
"@babel/plugin-transform-class-properties": "^7.0.0-0",
|
"@babel/plugin-transform-class-properties": "^7.0.0-0",
|
||||||
@@ -10737,6 +10695,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
|
||||||
"integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==",
|
"integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -12041,6 +12000,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -12247,6 +12207,7 @@
|
|||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
|
|||||||
Regular → Executable
@@ -9,6 +9,16 @@ services:
|
|||||||
- "8888:80"
|
- "8888:80"
|
||||||
networks:
|
networks:
|
||||||
- cyberusgate-network
|
- cyberusgate-network
|
||||||
|
|
||||||
|
frontend_presentation:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.presentation
|
||||||
|
container_name: cyberusgate_presentation
|
||||||
|
ports:
|
||||||
|
- "7854:80"
|
||||||
|
networks:
|
||||||
|
- cyberusgate-network
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
cyberusgate-network:
|
cyberusgate-network:
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
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"]
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 53 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 902 B |
Binary file not shown.
|
Before Width: | Height: | Size: 2.7 KiB |
@@ -1,265 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr" class="h-full bg-gray-50">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Cyberusgate - Démonstration</title>
|
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
|
||||||
<link rel="manifest" href="/site.webmanifest">
|
|
||||||
<!-- Utilisation de Tailwind CSS via CDN pour un prototypage rapide -->
|
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
|
||||||
</head>
|
|
||||||
<body class="h-full">
|
|
||||||
<div class="flex flex-col md:flex-row w-full h-full min-h-screen font-sans">
|
|
||||||
|
|
||||||
<!-- ======================================= -->
|
|
||||||
<!-- PANNEAU 1: CONSOLE D'ADMIN -->
|
|
||||||
<!-- ======================================= -->
|
|
||||||
<div class="w-full md:w-2/3 lg:w-3/5 bg-white p-6 md:p-8 border-r border-gray-200">
|
|
||||||
<header class="mb-8">
|
|
||||||
<h1 class="text-3xl font-bold text-gray-800">Cyberusgate</h1>
|
|
||||||
<p class="text-gray-500">Console d'administration centralisée</p>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<!-- Section de gestion des utilisateurs -->
|
|
||||||
<div class="mb-8">
|
|
||||||
<div class="flex justify-between items-center mb-4">
|
|
||||||
<h2 class="text-xl font-semibold text-gray-700">Utilisateurs Actifs</h2>
|
|
||||||
<button onclick="createEphemeralPass()" class="px-4 py-2 bg-blue-600 text-white rounded-lg shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50 transition">
|
|
||||||
Créer un pass éphémère
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="overflow-x-auto">
|
|
||||||
<table class="min-w-full bg-white border border-gray-200 rounded-lg">
|
|
||||||
<thead class="bg-gray-50">
|
|
||||||
<tr>
|
|
||||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Nom</th>
|
|
||||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Rôle</th>
|
|
||||||
<th class="px-6 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">Statut</th>
|
|
||||||
<th class="px-6 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">Action</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="user-table-body" class="divide-y divide-gray-200">
|
|
||||||
<!-- Les lignes des utilisateurs seront injectées ici par JavaScript -->
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Section du journal d'événements -->
|
|
||||||
<div>
|
|
||||||
<h2 class="text-xl font-semibold text-gray-700 mb-4">Journal d'Événements en Temps Réel</h2>
|
|
||||||
<div id="log-container" class="h-64 bg-gray-800 text-white font-mono text-sm p-4 rounded-lg overflow-y-auto flex flex-col-reverse">
|
|
||||||
<!-- Les logs seront injectés ici par JavaScript -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- ======================================= -->
|
|
||||||
<!-- PANNEAU 2: SIMULATEUR DE PORTE -->
|
|
||||||
<!-- ======================================= -->
|
|
||||||
<div class="w-full md:w-1/3 lg:w-2/5 bg-gray-100 p-6 md:p-8 flex flex-col justify-center items-center">
|
|
||||||
<div class="w-full max-w-sm text-center">
|
|
||||||
<h2 class="text-xl font-semibold text-gray-700 mb-4">Simulateur de Porte</h2>
|
|
||||||
|
|
||||||
<!-- Le "lecteur" visuel -->
|
|
||||||
<div id="access-reader" class="relative w-48 h-64 bg-gray-700 rounded-lg shadow-2xl mx-auto flex flex-col justify-center items-center p-4 transition-all duration-300">
|
|
||||||
<div id="access-light" class="w-12 h-12 rounded-full bg-gray-500 mb-4 transition-colors duration-300"></div>
|
|
||||||
<p class="text-white font-bold text-lg">CYBERUSGATE</p>
|
|
||||||
<div id="access-result" class="absolute bottom-4 inset-x-0 text-white text-lg font-bold opacity-0 transition-opacity duration-300">
|
|
||||||
<!-- Résultat: "AUTORISÉ" ou "REFUSÉ" -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-8">
|
|
||||||
<label for="user-selector" class="block text-sm font-medium text-gray-700 mb-2">Qui tente d'accéder ?</label>
|
|
||||||
<select id="user-selector" class="w-full p-2 border border-gray-300 rounded-lg shadow-sm focus:ring-indigo-500 focus:border-indigo-500">
|
|
||||||
<!-- Les options seront injectées ici -->
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-6">
|
|
||||||
<button onclick="simulateScan()" class="w-full px-6 py-4 bg-indigo-600 text-white font-bold rounded-lg shadow-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-opacity-75 transition transform hover:scale-105">
|
|
||||||
Simuler un scan de badge
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- ======================================= -->
|
|
||||||
<!-- LOGIQUE JAVASCRIPT -->
|
|
||||||
<!-- ======================================= -->
|
|
||||||
<script>
|
|
||||||
// Production URLs
|
|
||||||
const API_BASE_URL = 'https://cyberusgate.api.guillaume-sanchez.fr';
|
|
||||||
const WEBSOCKET_URL = 'ws://cyberusgate.api.guillaume-sanchez.fr/ws/logs';
|
|
||||||
// Dev URLs
|
|
||||||
// const API_BASE_URL = 'http://192.168.10.10:8000';
|
|
||||||
// const WEBSOCKET_URL = 'ws://192.168.10.10:8000/ws/logs';
|
|
||||||
|
|
||||||
cyberusgate.api
|
|
||||||
|
|
||||||
// --- Éléments du DOM ---
|
|
||||||
const userTableBody = document.getElementById('user-table-body');
|
|
||||||
const userSelector = document.getElementById('user-selector');
|
|
||||||
const logContainer = document.getElementById('log-container');
|
|
||||||
const accessReader = document.getElementById('access-reader');
|
|
||||||
const accessLight = document.getElementById('access-light');
|
|
||||||
const accessResult = document.getElementById('access-result');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Au chargement de la page, on initialise les données et la connexion WebSocket.
|
|
||||||
*/
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
fetchUsersAndPopulate();
|
|
||||||
connectWebSocket();
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Récupère les utilisateurs depuis l'API et met à jour l'interface (tableau et sélecteur).
|
|
||||||
*/
|
|
||||||
async function fetchUsersAndPopulate() {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${API_BASE_URL}/users`);
|
|
||||||
const users = await response.json();
|
|
||||||
|
|
||||||
// Vide les listes actuelles
|
|
||||||
userTableBody.innerHTML = '';
|
|
||||||
userSelector.innerHTML = '';
|
|
||||||
|
|
||||||
// Remplit le tableau et le sélecteur
|
|
||||||
users.forEach(user => {
|
|
||||||
// Pour le tableau d'admin
|
|
||||||
const accessStatus = user.has_access
|
|
||||||
? '<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">Actif</span>'
|
|
||||||
: '<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800">Révoqué</span>';
|
|
||||||
|
|
||||||
const revokeButton = user.has_access
|
|
||||||
? `<button onclick="revokeAccess('${user.id}')" class="text-red-600 hover:text-red-900 font-medium">Révoquer</button>`
|
|
||||||
: `<span class="text-gray-400">N/A</span>`;
|
|
||||||
|
|
||||||
const tableRow = `
|
|
||||||
<tr id="user-row-${user.id}">
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap"><div class="text-sm font-medium text-gray-900">${user.name}</div></td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap"><div class="text-sm text-gray-500">${user.role}</div></td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-center">${accessStatus}</td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-center text-sm">${revokeButton}</td>
|
|
||||||
</tr>`;
|
|
||||||
userTableBody.innerHTML += tableRow;
|
|
||||||
|
|
||||||
// Pour le sélecteur du simulateur
|
|
||||||
const selectorOption = `<option value="${user.id}">${user.name}</option>`;
|
|
||||||
userSelector.innerHTML += selectorOption;
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Erreur lors de la récupération des utilisateurs:", error);
|
|
||||||
logMessage("Erreur: Impossible de joindre le serveur backend.", 'error');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Établit la connexion WebSocket pour recevoir les logs en temps réel.
|
|
||||||
*/
|
|
||||||
function connectWebSocket() {
|
|
||||||
const socket = new WebSocket(WEBSOCKET_URL);
|
|
||||||
|
|
||||||
socket.onmessage = (event) => {
|
|
||||||
logMessage(event.data, 'info');
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.onclose = () => {
|
|
||||||
console.log("WebSocket déconnecté. Tentative de reconnexion dans 5s...");
|
|
||||||
logMessage("Serveur de logs déconnecté. Reconnexion...", 'error');
|
|
||||||
setTimeout(connectWebSocket, 5000); // Tente de se reconnecter
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.onerror = () => {
|
|
||||||
console.error("Erreur WebSocket.");
|
|
||||||
logMessage("Erreur de connexion au serveur de logs.", 'error');
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Affiche un message dans la console de logs.
|
|
||||||
*/
|
|
||||||
function logMessage(message, type = 'info') {
|
|
||||||
const logEntry = document.createElement('p');
|
|
||||||
logEntry.textContent = message;
|
|
||||||
if (message.includes("REFUSÉ")) {
|
|
||||||
logEntry.className = 'text-red-400';
|
|
||||||
} else if (message.includes("AUTORISÉ")) {
|
|
||||||
logEntry.className = 'text-green-400';
|
|
||||||
} else if (message.includes("ACTION ADMIN")) {
|
|
||||||
logEntry.className = 'text-yellow-400';
|
|
||||||
} else if (type === 'error') {
|
|
||||||
logEntry.className = 'text-red-500 font-bold';
|
|
||||||
}
|
|
||||||
logContainer.prepend(logEntry); // prepend pour avoir le plus récent en haut
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Appelle l'API pour révoquer l'accès d'un utilisateur.
|
|
||||||
*/
|
|
||||||
async function revokeAccess(userId) {
|
|
||||||
if (!confirm(`Êtes-vous sûr de vouloir révoquer l'accès pour cet utilisateur ?`)) return;
|
|
||||||
await fetch(`${API_BASE_URL}/users/revoke/${userId}`, { method: 'POST' });
|
|
||||||
// On rafraîchit la liste pour mettre à jour le statut visuel partout
|
|
||||||
fetchUsersAndPopulate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Appelle l'API pour créer un nouvel utilisateur éphémère.
|
|
||||||
*/
|
|
||||||
async function createEphemeralPass() {
|
|
||||||
await fetch(`${API_BASE_URL}/users/create_ephemeral`, { method: 'POST' });
|
|
||||||
fetchUsersAndPopulate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simule le scan de badge en appelant l'API.
|
|
||||||
*/
|
|
||||||
async function simulateScan() {
|
|
||||||
const selectedUserId = userSelector.value;
|
|
||||||
const response = await fetch(`${API_BASE_URL}/access/simulate`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ user_id: selectedUserId })
|
|
||||||
});
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
// Met à jour l'interface du lecteur
|
|
||||||
updateReaderUI(result.status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Met à jour l'UI du lecteur (lumière et texte) après une tentative d'accès.
|
|
||||||
*/
|
|
||||||
function updateReaderUI(status) {
|
|
||||||
// Réinitialise d'abord l'état
|
|
||||||
accessLight.classList.remove('bg-green-500', 'bg-red-500');
|
|
||||||
accessResult.classList.remove('opacity-100');
|
|
||||||
accessResult.textContent = '';
|
|
||||||
|
|
||||||
if (status === 'authorized') {
|
|
||||||
accessLight.classList.add('bg-green-500');
|
|
||||||
accessResult.textContent = 'AUTORISÉ';
|
|
||||||
accessResult.classList.add('opacity-100');
|
|
||||||
} else {
|
|
||||||
accessLight.classList.add('bg-red-500');
|
|
||||||
accessResult.textContent = 'REFUSÉ';
|
|
||||||
accessResult.classList.add('opacity-100');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Revient à l'état initial après quelques secondes
|
|
||||||
setTimeout(() => {
|
|
||||||
accessLight.classList.remove('bg-green-500', 'bg-red-500');
|
|
||||||
accessResult.classList.remove('opacity-100');
|
|
||||||
}, 2500);
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
-131
@@ -1,131 +0,0 @@
|
|||||||
# main.py : Backend pour le POC Cyberusgate avec FastAPI
|
|
||||||
import asyncio
|
|
||||||
import datetime
|
|
||||||
import uuid
|
|
||||||
from typing import Dict, List
|
|
||||||
|
|
||||||
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
|
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
|
||||||
|
|
||||||
# --- Initialisation de l'application FastAPI ---
|
|
||||||
app = FastAPI(
|
|
||||||
title="Cyberusgate POC API",
|
|
||||||
description="API pour la démonstration de la solution de badge digital."
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- Configuration CORS ---
|
|
||||||
# Permet au frontend (ouvert depuis un fichier local) de communiquer avec le backend.
|
|
||||||
app.add_middleware(
|
|
||||||
CORSMiddleware,
|
|
||||||
allow_origins=["*"], # Attention : En production, restreindre à l'URL du frontend.
|
|
||||||
allow_credentials=True,
|
|
||||||
allow_methods=["*"],
|
|
||||||
allow_headers=["*"],
|
|
||||||
)
|
|
||||||
|
|
||||||
# --- "Base de données" en mémoire ---
|
|
||||||
# Utilisation d'un dictionnaire pour simuler une base de données d'utilisateurs.
|
|
||||||
# La clé est l'ID de l'utilisateur, la valeur contient ses informations.
|
|
||||||
users_db: Dict[str, Dict] = {
|
|
||||||
"user-001": {"id": "user-001", "name": "Alice Martin", "role": "Collaborateur", "has_access": True},
|
|
||||||
"user-002": {"id": "user-002", "name": "Bob Dubois", "role": "Prestataire", "has_access": True},
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- Gestion des connexions WebSocket pour les logs en temps réel ---
|
|
||||||
class ConnectionManager:
|
|
||||||
def __init__(self):
|
|
||||||
self.active_connections: List[WebSocket] = []
|
|
||||||
|
|
||||||
async def connect(self, websocket: WebSocket):
|
|
||||||
await websocket.accept()
|
|
||||||
self.active_connections.append(websocket)
|
|
||||||
|
|
||||||
def disconnect(self, websocket: WebSocket):
|
|
||||||
self.active_connections.remove(websocket)
|
|
||||||
|
|
||||||
async def broadcast(self, message: str):
|
|
||||||
""" Diffuse un message à tous les clients connectés. """
|
|
||||||
for connection in self.active_connections:
|
|
||||||
await connection.send_text(message)
|
|
||||||
|
|
||||||
manager = ConnectionManager()
|
|
||||||
|
|
||||||
async def log_and_broadcast(message: str):
|
|
||||||
""" Formate un message de log avec un timestamp et le diffuse. """
|
|
||||||
timestamp = datetime.datetime.now().strftime("%H:%M:%S")
|
|
||||||
log_message = f"[{timestamp}] {message}"
|
|
||||||
print(log_message) # Affiche aussi dans la console du serveur
|
|
||||||
await manager.broadcast(log_message)
|
|
||||||
|
|
||||||
# --- Endpoints de l'API ---
|
|
||||||
|
|
||||||
@app.get("/users", summary="Lister tous les utilisateurs")
|
|
||||||
async def get_users():
|
|
||||||
""" Récupère la liste de tous les utilisateurs enregistrés. """
|
|
||||||
return list(users_db.values())
|
|
||||||
|
|
||||||
@app.post("/access/simulate", summary="Simuler un scan de badge")
|
|
||||||
async def simulate_access(data: Dict):
|
|
||||||
"""
|
|
||||||
Vérifie si un utilisateur a l'accès autorisé et log le résultat.
|
|
||||||
"""
|
|
||||||
user_id = data.get("user_id")
|
|
||||||
if not user_id or user_id not in users_db:
|
|
||||||
await log_and_broadcast(f"ERREUR: Tentative d'accès avec un ID inconnu '{user_id}'.")
|
|
||||||
return {"status": "refused", "reason": "Utilisateur inconnu"}
|
|
||||||
|
|
||||||
user = users_db[user_id]
|
|
||||||
if user["has_access"]:
|
|
||||||
await log_and_broadcast(f"ACCÈS AUTORISÉ: {user['name']} ({user['role']}) à la porte principale.")
|
|
||||||
return {"status": "authorized", "user_name": user['name']}
|
|
||||||
else:
|
|
||||||
await log_and_broadcast(f"ACCÈS REFUSÉ: {user['name']} ({user['role']}) - Droits révoqués.")
|
|
||||||
return {"status": "refused", "user_name": user['name'], "reason": "Accès révoqué"}
|
|
||||||
|
|
||||||
@app.post("/users/revoke/{user_id}", summary="Révoquer l'accès d'un utilisateur")
|
|
||||||
async def revoke_access(user_id: str):
|
|
||||||
""" Désactive les droits d'accès pour un utilisateur donné. """
|
|
||||||
if user_id in users_db:
|
|
||||||
users_db[user_id]["has_access"] = False
|
|
||||||
user_name = users_db[user_id]['name']
|
|
||||||
await log_and_broadcast(f"ACTION ADMIN: Accès révoqué pour {user_name}.")
|
|
||||||
return {"status": "success", "user_id": user_id, "has_access": False}
|
|
||||||
return {"status": "error", "message": "Utilisateur non trouvé"}
|
|
||||||
|
|
||||||
@app.post("/users/create_ephemeral", summary="Créer un pass éphémère")
|
|
||||||
async def create_ephemeral_pass():
|
|
||||||
""" Crée un nouvel utilisateur 'Prestataire' avec un accès temporaire. """
|
|
||||||
new_id = f"guest-{uuid.uuid4().hex[:4]}"
|
|
||||||
new_user = {
|
|
||||||
"id": new_id,
|
|
||||||
"name": f"Visiteur {new_id}",
|
|
||||||
"role": "Pass Éphémère",
|
|
||||||
"has_access": True,
|
|
||||||
}
|
|
||||||
users_db[new_id] = new_user
|
|
||||||
await log_and_broadcast(f"ACTION ADMIN: Pass éphémère créé pour {new_user['name']}.")
|
|
||||||
return new_user
|
|
||||||
|
|
||||||
# --- Endpoint WebSocket pour les logs ---
|
|
||||||
|
|
||||||
@app.websocket("/ws/logs")
|
|
||||||
async def websocket_endpoint(websocket: WebSocket):
|
|
||||||
"""
|
|
||||||
Point de connexion pour les clients qui veulent recevoir les logs en temps réel.
|
|
||||||
"""
|
|
||||||
await manager.connect(websocket)
|
|
||||||
await log_and_broadcast("INFO: Un client de la console d'admin s'est connecté.")
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
# On maintient la connexion ouverte pour envoyer des messages
|
|
||||||
# Le serveur n'attend pas de message du client ici.
|
|
||||||
await asyncio.sleep(1)
|
|
||||||
except WebSocketDisconnect:
|
|
||||||
manager.disconnect(websocket)
|
|
||||||
await log_and_broadcast("INFO: Un client de la console d'admin s'est déconnecté.")
|
|
||||||
|
|
||||||
# --- Point d'entrée pour lancer le serveur (avec uvicorn) ---
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import uvicorn
|
|
||||||
print("Lancement du serveur de l'API Cyberusgate sur http://0.0.0.0:8000")
|
|
||||||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
fastapi==0.111.0
|
|
||||||
uvicorn[standard]==0.29.0
|
|
||||||
python-multipart==0.0.9
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"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"}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
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
|
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user