70 lines
2.2 KiB
TypeScript
70 lines
2.2 KiB
TypeScript
import WebSocket from "ws";
|
|
import {IncomingMessage} from "http";
|
|
import WebSocketListener from "../../WebSocketListener";
|
|
import MagicLink from "../models/MagicLink";
|
|
import Application from "../../Application";
|
|
|
|
export default class MagicLinkWebSocketListener<A extends Application> extends WebSocketListener<A> {
|
|
private readonly connections: { [p: string]: (() => void)[] | undefined } = {};
|
|
|
|
public refreshMagicLink(sessionId: string): void {
|
|
const fs = this.connections[sessionId];
|
|
if (fs) {
|
|
fs.forEach(f => f());
|
|
}
|
|
}
|
|
|
|
public async handle(socket: WebSocket, request: IncomingMessage, session: Express.Session | null): Promise<void> {
|
|
// Drop if requested without session
|
|
if (!session) {
|
|
socket.close(1002, 'Session is required for this request.');
|
|
return;
|
|
}
|
|
|
|
// Refuse any incoming data
|
|
socket.on('message', () => {
|
|
socket.close(1003);
|
|
});
|
|
|
|
// Get magic link
|
|
const magicLink = await MagicLink.select()
|
|
.where('session_id', session.id)
|
|
.sortBy('authorized')
|
|
.first();
|
|
|
|
// Refresh if immediately applicable
|
|
if (!magicLink || !await magicLink.isValid() || await magicLink.isAuthorized()) {
|
|
socket.send('refresh');
|
|
socket.close(1000);
|
|
return;
|
|
}
|
|
|
|
const validityTimeout = setTimeout(() => {
|
|
socket.send('refresh');
|
|
socket.close(1000);
|
|
}, magicLink.getExpirationDate().getTime() - new Date().getTime());
|
|
|
|
const f = () => {
|
|
clearTimeout(validityTimeout);
|
|
socket.send('refresh');
|
|
socket.close(1000);
|
|
};
|
|
|
|
socket.on('close', () => {
|
|
const connections = this.connections[session.id];
|
|
if (connections) {
|
|
this.connections[session.id] = connections.filter(f => f !== f);
|
|
if (connections.length === 0) delete this.connections[session.id];
|
|
}
|
|
});
|
|
|
|
let connections = this.connections[session.id];
|
|
if (!connections) connections = this.connections[session.id] = [];
|
|
connections.push(f);
|
|
}
|
|
|
|
public path(): string {
|
|
return '/magic-link';
|
|
}
|
|
}
|