2022-04-02 13:45:07 +00:00
|
|
|
import express, { RequestHandler } from 'express';
|
|
|
|
import session from 'express-session';
|
|
|
|
import passport from 'passport';
|
|
|
|
import * as redis from 'redis';
|
|
|
|
import * as icynetstrat from 'passport-icynet';
|
|
|
|
import connectRedis from 'connect-redis';
|
|
|
|
|
|
|
|
import http from 'http';
|
|
|
|
import { join } from 'path';
|
|
|
|
import { Server, Socket } from 'socket.io';
|
|
|
|
import { IcyNetUser } from './types/user';
|
|
|
|
import { Canvas } from './object/canvas';
|
|
|
|
import { CanvasRecord, Placement } from '../common/types/canvas';
|
|
|
|
|
|
|
|
import { config } from './config';
|
|
|
|
|
|
|
|
const RedisStore = connectRedis(session);
|
2022-04-02 14:23:36 +00:00
|
|
|
const redisClient = config.redis?.enabled ? redis.createClient() : undefined;
|
2022-04-02 13:45:07 +00:00
|
|
|
|
|
|
|
const sessionMiddleware = session({
|
|
|
|
secret: config.server.sessionSecret,
|
|
|
|
resave: false,
|
|
|
|
saveUninitialized: false,
|
|
|
|
cookie: { secure: process.env.NODE_ENV === 'production', sameSite: 'strict' },
|
2022-04-02 14:23:36 +00:00
|
|
|
store: config.redis?.enabled
|
|
|
|
? new RedisStore({ client: redisClient })
|
|
|
|
: undefined,
|
2022-04-02 13:45:07 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// todo: store less info in session
|
|
|
|
passport.serializeUser((user, done) => {
|
|
|
|
done(null, user);
|
|
|
|
});
|
|
|
|
|
|
|
|
passport.deserializeUser((obj: IcyNetUser, done) => {
|
|
|
|
done(null, obj);
|
|
|
|
});
|
|
|
|
|
|
|
|
passport.use(
|
|
|
|
new icynetstrat.Strategy(
|
|
|
|
{
|
|
|
|
clientID: config.auth.clientID,
|
|
|
|
clientSecret: config.auth.clientSecret,
|
|
|
|
callbackURL: config.auth.callbackURL,
|
|
|
|
scope: [],
|
|
|
|
},
|
|
|
|
function (
|
|
|
|
accessToken: string,
|
|
|
|
refreshToken: string,
|
|
|
|
profile: any,
|
|
|
|
done: Function,
|
|
|
|
) {
|
|
|
|
console.log(profile);
|
|
|
|
process.nextTick(function () {
|
|
|
|
return done(null, profile);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
|
|
|
const app = express();
|
|
|
|
|
|
|
|
if (process.env.NODE_ENV === 'production') {
|
|
|
|
app.enable('trust proxy');
|
|
|
|
}
|
|
|
|
|
|
|
|
const server = http.createServer(app);
|
|
|
|
const io = new Server(server);
|
|
|
|
|
|
|
|
const checkAuth: RequestHandler = (req, res, next) => {
|
|
|
|
if (req.isAuthenticated()) {
|
|
|
|
return next();
|
|
|
|
}
|
|
|
|
res.send('not logged in :(');
|
|
|
|
};
|
|
|
|
|
|
|
|
app.use(sessionMiddleware);
|
|
|
|
|
|
|
|
app.use(passport.initialize());
|
|
|
|
app.use(passport.session());
|
|
|
|
|
|
|
|
app.get(
|
|
|
|
'/login',
|
|
|
|
passport.authenticate('icynet', { scope: [] }),
|
|
|
|
(req, res) => {},
|
|
|
|
);
|
|
|
|
|
|
|
|
app.get(
|
|
|
|
'/callback',
|
|
|
|
passport.authenticate('icynet', { failureRedirect: '/?login=false' }),
|
|
|
|
(req, res) => {
|
|
|
|
res.redirect('/?login=true');
|
|
|
|
}, // auth success
|
|
|
|
);
|
|
|
|
|
|
|
|
app.get('/logout', (req, res) => {
|
|
|
|
req.logout();
|
|
|
|
res.redirect('/');
|
|
|
|
});
|
|
|
|
|
|
|
|
app.get('/info', checkAuth, (req, res) => {
|
|
|
|
res.json(req.user);
|
|
|
|
});
|
|
|
|
|
|
|
|
app.use(express.static(join(__dirname, '..', 'public')));
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
const canvas = new Canvas(config.game.boardSize);
|
|
|
|
const connections: Socket[] = [];
|
|
|
|
const changes: CanvasRecord[] = [];
|
|
|
|
|
|
|
|
io.use((socket, next) =>
|
|
|
|
sessionMiddleware(socket.request as any, {} as any, next as any),
|
|
|
|
);
|
|
|
|
io.on('connection', (socket) => {
|
|
|
|
const session = (socket.request as any).session;
|
|
|
|
const user = session?.passport?.user as IcyNetUser;
|
|
|
|
connections.push(socket);
|
|
|
|
|
|
|
|
socket.emit(
|
|
|
|
'me',
|
|
|
|
user
|
|
|
|
? {
|
|
|
|
username: user.username,
|
|
|
|
display_name: user.display_name,
|
|
|
|
}
|
|
|
|
: null,
|
|
|
|
);
|
|
|
|
|
|
|
|
socket.emit('plane', {
|
|
|
|
size: canvas.size,
|
|
|
|
canvas: Object.values(canvas.getFullPlane()),
|
|
|
|
});
|
|
|
|
|
|
|
|
socket.on('color', ({ c, x, y, t }: Placement) => {
|
|
|
|
if (!user || c > 0xffffff || c < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
canvas.setPixelAt(c, x, y, user.username);
|
|
|
|
socket.emit('colorack', { c, x, y, t });
|
|
|
|
});
|
|
|
|
|
|
|
|
socket.on('disconnect', () => {
|
|
|
|
connections.splice(connections.indexOf(socket), 1);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
canvas.registerChangeHandler((record) => {
|
|
|
|
changes.push(record);
|
|
|
|
});
|
|
|
|
|
|
|
|
setInterval(() => {
|
|
|
|
if (changes.length && connections.length) {
|
|
|
|
connections.forEach((socket) => socket.emit('changes', changes));
|
|
|
|
changes.length = 0;
|
|
|
|
}
|
|
|
|
}, 1000);
|
|
|
|
|
|
|
|
///
|
|
|
|
canvas.initialize().then(() =>
|
|
|
|
server.listen(config.server.port, 'localhost', () => {
|
|
|
|
console.log(`Listening at http://localhost:${config.server.port}/`);
|
|
|
|
}),
|
|
|
|
);
|