github client geree
This commit is contained in:
+35
-3
@@ -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
|
||||
};
|
||||
query,
|
||||
ensureOauthClient
|
||||
};
|
||||
|
||||
+10
-3
@@ -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();
|
||||
startServer();
|
||||
|
||||
@@ -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;
|
||||
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(`<!doctype html><html><body><script>window.opener && window.opener.postMessage({token: '${token}'}, '*'); window.close();</script></body></html>`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).send('GitHub OAuth error');
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user