From 70797f6215b9f70ee688652764364eba0706fb4c Mon Sep 17 00:00:00 2001 From: bitsearch Date: Fri, 16 Jan 2026 16:55:57 +0100 Subject: [PATCH] github client geree --- srcs/backend/db.js | 38 ++++++++++++++++++++++-- srcs/backend/index.js | 13 +++++++-- srcs/backend/routes/auth.js | 58 +++++++++++++++++++++++++++++++++++-- srcs/frontend/src/login.js | 21 +++++++++++--- 4 files changed, 118 insertions(+), 12 deletions(-) diff --git a/srcs/backend/db.js b/srcs/backend/db.js index 88e3557..57ca20f 100644 --- a/srcs/backend/db.js +++ b/srcs/backend/db.js @@ -59,6 +59,16 @@ async function createTables() FOREIGN KEY (id_user1) REFERENCES users(id) ON DELETE CASCADE, FOREIGN KEY (id_user2) REFERENCES users(id) ON DELETE CASCADE ); + + CREATE TABLE IF NOT EXISTS oauth_clients ( + id SERIAL PRIMARY KEY, + provider VARCHAR(50) NOT NULL, + client_id VARCHAR(200) NOT NULL, + client_secret TEXT, + redirect_uri VARCHAR(255), + created_at TIMESTAMP DEFAULT NOW(), + UNIQUE(provider, client_id) + ); `); console.log('Tables created!'); } @@ -73,9 +83,31 @@ async function query(text, params) return (pool.query(text, params)); } -module.exports = +async function ensureOauthClient(provider, client_id, client_secret, redirect_uri) { + try + { + const res = await pool.query( + `SELECT id FROM oauth_clients WHERE provider = $1 AND client_id = $2`, [provider, client_id] + ); + if (res.rows.length > 0) + return res.rows[0]; + const insert = await pool.query( + `INSERT INTO oauth_clients (provider, client_id, client_secret, redirect_uri) VALUES ($1, $2, $3, $4) RETURNING id`, + [provider, client_id, client_secret, redirect_uri] + ); + return insert.rows[0]; + } + catch (err) + { + console.error('Error ensuring oauth client:', err); + throw err; + } +} + +module.exports = { waitForDb, createTables, - query -}; \ No newline at end of file + query, + ensureOauthClient +}; diff --git a/srcs/backend/index.js b/srcs/backend/index.js index 9f26624..ae61e83 100644 --- a/srcs/backend/index.js +++ b/srcs/backend/index.js @@ -4,13 +4,13 @@ const cors = require('cors'); const {Server} = require('socket.io'); const authRouter = require('./routes/auth'); const chatRouter = require('./routes/global_chat'); -const {waitForDb, createTables} = require('./db'); +const {waitForDb, createTables, ensureOauthClient} = require('./db'); const setupSocketIO = require('./services/socket'); const app = express(); const server = http.createServer(app); const io = new Server(server, -{ + { cors: { origin: "*", @@ -28,6 +28,13 @@ async function startServer() await waitForDb(); await createTables(); + // Ensure GitHub OAuth client is registered in DB + try { + await ensureOauthClient('github', process.env.GITHUB_CLIENT_ID, process.env.GITHUB_CLIENT_SECRET, process.env.GITHUB_CALLBACK_URL || process.env.GITHUB_REDIRECT_URI); + } catch (e) { + console.warn('OAuth client might already exist or failed to register:', e.message); + } + app.use('/api/auth', authRouter); app.use('/api/global_chat', chatRouter); app.get('/api', (req, res) => res.send('Backend running')); @@ -38,4 +45,4 @@ async function startServer() }); } -startServer(); \ No newline at end of file +startServer(); diff --git a/srcs/backend/routes/auth.js b/srcs/backend/routes/auth.js index 2e42b28..3e01953 100644 --- a/srcs/backend/routes/auth.js +++ b/srcs/backend/routes/auth.js @@ -2,6 +2,9 @@ const express = require('express'); const router = express.Router(); const authService = require('../services/auth'); const fetch = require('node-fetch'); +const bcrypt = require('bcrypt'); +const jwt = require('jsonwebtoken'); +const {query} = require('../db'); router.post('/register', async(req, res) => { @@ -24,10 +27,61 @@ router.post('/login', async(req, res) => router.get('/github', (req, res) => { const githubAuthUrl = `https://github.com/login/oauth/authorize?` + `client_id=${process.env.GITHUB_CLIENT_ID}&` + - `redirect_uri=${encodeURIComponent(process.env.GITHUB_REDIRECT_URI)}&` + + `redirect_uri=${encodeURIComponent(process.env.GITHUB_CALLBACK_URL || process.env.GITHUB_REDIRECT_URI)}&` + `scope=user:email`; res.redirect(githubAuthUrl); }); -module.exports = router; \ No newline at end of file +router.get('/github/callback', async (req, res) => { + const code = req.query.code; + if (!code) { + return res.status(400).send('Missing code'); + } + try { + const tokenResponse = await fetch('https://github.com/login/oauth/access_token', { + method: 'POST', + headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, + body: JSON.stringify({ + client_id: process.env.GITHUB_CLIENT_ID, + client_secret: process.env.GITHUB_CLIENT_SECRET, + code: code + }) + }); + const tokenData = await tokenResponse.json(); + const accessToken = tokenData.access_token; + if (!accessToken) throw new Error('No access token'); + + + const userResponse = await fetch('https://api.github.com/user', { + headers: { 'Authorization': `Bearer ${accessToken}`, 'User-Agent': 'Transcendence' } + }); + const ghUser = await userResponse.json(); + const ghUsername = ghUser.login || `github_${ghUser.id}`; + + + let result = await query(`SELECT id FROM users WHERE username = $1`, [ghUsername]); + let userId; + if (result.rows.length > 0) { + userId = result.rows[0].id; + } else { + const crypto = require('crypto'); + const randomPwd = crypto.randomBytes(16).toString('hex'); + const passwordHash = await bcrypt.hash(randomPwd, 10); + await query(`INSERT INTO users (username, password_hash) VALUES ($1, $2)`, [ghUsername, passwordHash]); + const inserted = await query(`SELECT id FROM users WHERE username = $1`, [ghUsername]); + userId = inserted.rows[0].id; + } + + // Issue JWT + const token = jwt.sign({ userId: userId, username: ghUsername }, process.env.JWT_SECRET, { expiresIn: '1h' }); + + // Send token to opener window and close popup + res.send(``); + } catch (err) { + console.error(err); + res.status(500).send('GitHub OAuth error'); + } +}); + +module.exports = router; diff --git a/srcs/frontend/src/login.js b/srcs/frontend/src/login.js index 0d61945..c452296 100644 --- a/srcs/frontend/src/login.js +++ b/srcs/frontend/src/login.js @@ -40,12 +40,25 @@ export class LoginWindow extends fenetre { this.githubBtn.style.backgroundColor = "#24292e"; this.githubBtn.style.color = "white"; this.githubBtn.onclick = () => { - window.location.href = "/api/auth/github"; + // Ouvre le OAuth GitHub dans une popup et reçoit le token via postMessage + const w = 600; + const h = 700; + const left = (screen.width - w) / 2; + const top = (screen.height - h) / 2; + const popup = window.open('/api/auth/github', 'githubOAuth', `width=${w},height=${h},left=${left},top=${top}`); + const listener = (ev) => { + if (ev.data && ev.data.token) { + localStorage.setItem('auth_token', ev.data.token); + this.message.innerText = 'Connexion GitHub réussie ! Bienvenue.'; + this.message.style.color = '#3cff01'; + window.removeEventListener('message', listener); + if (popup) popup.close(); + } + }; + window.addEventListener('message', listener, {once: true}); }; this.body.appendChild(this.githubBtn); - - this.checkIfAlreadyLoggedIn(); //verifie si l'utilisateur est connecté au démarrage } @@ -152,4 +165,4 @@ export class LoginWindow extends fenetre { this.switch.innerText = "S'inscrire"; } } -} \ No newline at end of file +}