69 lines
2.3 KiB
TypeScript
69 lines
2.3 KiB
TypeScript
import {Session} from "express-session";
|
|
import {IncomingMessage} from "http";
|
|
import WebSocket from "ws";
|
|
|
|
import Application from "../../Application.js";
|
|
import SessionWebSocketListener from "../../SessionWebSocketListener.js";
|
|
import MagicLink from "../models/MagicLink.js";
|
|
|
|
export default class MagicLinkWebSocketListener<A extends Application> extends SessionWebSocketListener<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 handleSessionSocket(socket: WebSocket, request: IncomingMessage, session: Session): Promise<void> {
|
|
// 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');
|
|
const reason = magicLink ?
|
|
'Magic link state changed.' :
|
|
'Magic link not found for session ' + session.id;
|
|
socket.close(1000, reason);
|
|
return;
|
|
}
|
|
|
|
const validityTimeout = setTimeout(() => {
|
|
socket.send('refresh');
|
|
socket.close(1000, 'Timed out');
|
|
}, magicLink.getExpirationDate().getTime() - new Date().getTime());
|
|
|
|
const f = () => {
|
|
clearTimeout(validityTimeout);
|
|
socket.send('refresh');
|
|
socket.close(1000, 'Closed by server');
|
|
};
|
|
|
|
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';
|
|
}
|
|
}
|