diff --git a/client/src/App.tsx b/client/src/App.tsx index 5199afa..3fad6fd 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -28,6 +28,7 @@ import OAuthCallback from './pages/AuthManager/callback/AuthCallback'; const App: React.FC = () => { const [isAuthenticated, setIsAuthenticated] = useState(ApiService.isLoggedIn()); const [isTeacherAuthenticated, setIsTeacherAuthenticated] = useState(ApiService.isLoggedInTeacher()); + const [isRoomRequireAuthentication, setRoomsRequireAuth] = useState(null); const location = useLocation(); // Check login status every time the route changes @@ -37,7 +38,13 @@ const App: React.FC = () => { setIsTeacherAuthenticated(ApiService.isLoggedInTeacher()); }; + const fetchAuthenticatedRooms = async () => { + const data = await ApiService.getRoomsRequireAuth(); + setRoomsRequireAuth(data); + }; + checkLoginStatus(); + fetchAuthenticatedRooms(); }, [location]); const handleLogout = () => { @@ -76,7 +83,7 @@ const App: React.FC = () => { {/* Pages espace étudiant */} : } + element={( !isRoomRequireAuthentication || isAuthenticated ) ? : } /> {/* Pages authentification */} diff --git a/client/src/pages/AuthManager/callback/AuthCallback.tsx b/client/src/pages/AuthManager/callback/AuthCallback.tsx index 6ba290d..046abc7 100644 --- a/client/src/pages/AuthManager/callback/AuthCallback.tsx +++ b/client/src/pages/AuthManager/callback/AuthCallback.tsx @@ -9,9 +9,11 @@ const OAuthCallback: React.FC = () => { useEffect(() => { const searchParams = new URLSearchParams(location.search); const user = searchParams.get('user'); + const username = searchParams.get('username'); if (user) { apiService.saveToken(user); + apiService.saveUsername(username || ""); navigate('/'); } else { navigate('/login'); diff --git a/client/src/pages/Student/JoinRoom/JoinRoom.tsx b/client/src/pages/Student/JoinRoom/JoinRoom.tsx index e29bfb7..75516b0 100644 --- a/client/src/pages/Student/JoinRoom/JoinRoom.tsx +++ b/client/src/pages/Student/JoinRoom/JoinRoom.tsx @@ -15,9 +15,11 @@ import LoadingButton from '@mui/lab/LoadingButton'; import LoginContainer from '../../../components/LoginContainer/LoginContainer' +import ApiService from '../../../services/ApiService' + const JoinRoom: React.FC = () => { const [roomName, setRoomName] = useState(''); - const [username, setUsername] = useState(''); + const [username, setUsername] = useState(ApiService.getUsername()); const [socket, setSocket] = useState(null); const [isWaitingForTeacher, setIsWaitingForTeacher] = useState(false); const [question, setQuestion] = useState(); diff --git a/client/src/services/ApiService.tsx b/client/src/services/ApiService.tsx index d5c0b28..b63bbdd 100644 --- a/client/src/services/ApiService.tsx +++ b/client/src/services/ApiService.tsx @@ -105,7 +105,43 @@ class ApiService { } } + public saveUsername(username: string): void { + if (!username || username.length === 0) { + return; + } + + const object = { + username: username + } + + localStorage.setItem("username", JSON.stringify(object)); + } + + public getUsername(): string { + const objectStr = localStorage.getItem("username"); + + if (!objectStr) { + return ""; + } + + const object = JSON.parse(objectStr) + + return object.username; + } + + // Route to know if rooms need authentication to join + public async getRoomsRequireAuth(): Promise { + const url: string = this.constructRequestUrl(`/auth/getRoomsRequireAuth`); + const result: AxiosResponse = await axios.get(url); + + if (result.status == 200) { + return result.data.roomsRequireAuth; + } + return false; + } + public logout(): void { + localStorage.removeItem("username"); return localStorage.removeItem("jwt"); } diff --git a/docker-compose.yaml b/docker-compose.yaml index 898a78a..770f6db 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -30,6 +30,7 @@ services: SITE_URL: http://localhost FRONTEND_PORT: 5173 USE_PORTS: false + AUTHENTICATED_ROOMS: false volumes: - ./server/auth_config.json:/usr/src/app/serveur/config/auth_config.json depends_on: diff --git a/server/.env.example b/server/.env.example index 8553a4b..3ab7212 100644 --- a/server/.env.example +++ b/server/.env.example @@ -19,3 +19,5 @@ SESSION_Secret='session_secret' SITE_URL=http://localhost FRONTEND_PORT=5173 USE_PORTS=false + +AUTHENTICATED_ROOMS=false diff --git a/server/__tests__/auth.test.js b/server/__tests__/auth.test.js index 0099d03..f3f92d5 100644 --- a/server/__tests__/auth.test.js +++ b/server/__tests__/auth.test.js @@ -205,3 +205,40 @@ describe( }); }) ); + +describe( + "Rooms requiring authentication", () => { + // Making a copy of env variables to restore them later + const OLD_ENV_VARIABLES = process.env; + + let authConfigInstance; + + beforeAll(() => { + authConfigInstance = new AuthConfig(); + }); + + // Clearing cache just in case + beforeEach(() => { + jest.resetModules(); + process.env = { ...OLD_ENV_VARIABLES }; + }); + + // Resetting the old values + afterAll(() => { + process.env = OLD_ENV_VARIABLES; + }); + + // tests cases as [environment variable value, expected value] + const cases = [["true", true], ["false", false], ["", false], ["other_than_true_false", false]]; + test.each(cases)( + "Given %p as AUTHENTICATED_ROOMS environment variable value, returns %p", + (envVarArg, expectedResult) => { + process.env.AUTHENTICATED_ROOMS = envVarArg; + const isAuthRequired = authConfigInstance.getRoomsRequireAuth(); + + expect(isAuthRequired).toEqual(expectedResult); + } + ); + + } +) diff --git a/server/auth/auth-manager.js b/server/auth/auth-manager.js index fce031e..27082f9 100644 --- a/server/auth/auth-manager.js +++ b/server/auth/auth-manager.js @@ -44,7 +44,7 @@ class AuthManager{ async login(userInfo,req,res,next){ const tokenToSave = jwt.create(userInfo.email, userInfo._id,userInfo.roles); - res.redirect(`/auth/callback?user=${tokenToSave}`); + res.redirect(`/auth/callback?user=${tokenToSave}&username=${userInfo.name}`); console.info(`L'utilisateur '${userInfo.name}' vient de se connecter`) } diff --git a/server/config/auth.js b/server/config/auth.js index 8f4605e..2b7c4df 100644 --- a/server/config/auth.js +++ b/server/config/auth.js @@ -175,6 +175,17 @@ class AuthConfig { } } + // Check if students must be authenticated to join a room + getRoomsRequireAuth() { + const roomRequireAuth = process.env.AUTHENTICATED_ROOMS; + + if (!roomRequireAuth || roomRequireAuth !== "true") { + return false; + } + + return true; + } + } diff --git a/server/controllers/auth.js b/server/controllers/auth.js index 21fa3b1..76769fb 100644 --- a/server/controllers/auth.js +++ b/server/controllers/auth.js @@ -20,6 +20,17 @@ class authController { } } + async getRoomsRequireAuth(req, res, next) { + const authC = new AuthConfig(); + const roomsRequireAuth = authC.getRoomsRequireAuth(); + + const response = { + roomsRequireAuth + } + + return res.json(response); + } + } module.exports = new authController; \ No newline at end of file diff --git a/server/routers/auth.js b/server/routers/auth.js index c560864..7260669 100644 --- a/server/routers/auth.js +++ b/server/routers/auth.js @@ -5,5 +5,6 @@ const jwt = require('../middleware/jwtToken.js'); const authController = require('../controllers/auth.js') router.get("/getActiveAuth",authController.getActive); +router.get("/getRoomsRequireAuth", authController.getRoomsRequireAuth); module.exports = router; \ No newline at end of file