Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 5x 5x 5x 5x 5x 4x 4x 4x 4x 4x 4x 5x 5x 5x 5x 1x 4x 4x 3x 3x 3x 1x 2x 24x 24x 1x | import socketIo, {Socket} from 'socket.io';
import debug from 'debug';
import {Car} from '@models';
import {wrapSocketMiddleware} from '@app/util/socket-middleware-wrapper';
import cookieParser from 'cookie-parser';
import jwtCsrf from '@app/routes/auth/jwt/jwt-csrf';
import expressJwt from 'express-jwt';
import config from '@app/config';
import {postLoginJwtValidator} from '@app/routes/auth/jwt/jwt-util';
import {NextFunction, Request, Response} from 'express';
import {MembershipService} from '@app/models';
import {
InternalError,
NotMemberOfGroupError,
UnauthorizedError,
} from '@app/errors';
/**
* Types of updates to the cars of the group.
*/
export enum GroupCarAction {
/**
* A car has been parked.
*/
Park = 'park',
/**
* A client drives a car.
*/
Drive = 'drive',
/**
* A new car is added to the group.
*/
Add = 'add',
/**
* An existing car is deleted.
*/
Delete = 'delete'
}
/**
* Logger.
*/
const log = debug('group-car:group:notification');
/**
* Logger for logging socket details.
*/
const ioLog = debug('group-car:socket');
/**
* Namespace which is used for groups.
*/
let nsp: socketIo.Namespace;
/**
* Socket.io server instance.
*/
let io: socketIo.Server;
/**
* Notification service for group actions.
*/
export const GroupNotificationService = {
/**
* Setter of io server.
* @param _io - io server
*/
setIo(_io: socketIo.Server): void {
io = _io;
nsp = io.of(/^\/group\/\w+/);
nsp.use(this.logConnection.bind(this));
nsp.use(wrapSocketMiddleware(cookieParser()));
nsp.use((socket, next) => {
wrapSocketMiddleware((() => {
const jwtMiddleware = jwtCsrf();
return (req: Request, res: Response, next: NextFunction) => {
/*
* Override res.cookie to throw an error.
* We can expect that thw jwtMiddleware will only
* call this if it tries to set the jwt cookie.
* This should only happen if either the client didn't
* provide the cookie or if the cookie has expired.
*/
// eslint-disable-next-line @typescript-eslint/no-this-alias
res.cookie = function() {
ioLog('Client %s is missing jwt', socket.client.id);
next(new UnauthorizedError('Missing credentials'));
return this;
};
try {
jwtMiddleware(req, res, next);
} catch (e) {
ioLog('Error in jwt csrf middleware: ', e);
next(new InternalError());
}
};
})())(socket, next);
});
nsp.use(wrapSocketMiddleware(expressJwt({
secret: config.jwt.secret,
getToken: config.jwt.getToken,
requestProperty: 'auth',
algorithms: ['HS512'],
})));
nsp.use(wrapSocketMiddleware(postLoginJwtValidator));
nsp.use(this.checkUserAuthorization);
nsp.on('connection', (socket) => {
ioLog(
'Client %s successfully connected to namespace %s',
socket.client.id,
socket.nsp.name,
);
});
},
/**
* Logs the connection of the socket.
* @param socket - The socket
* @param next - Next function
*/
logConnection(socket: Socket, next: NextFunction): void {
ioLog(
'Client %s connecting to namespace %s',
socket.client.id,
socket.nsp.name,
);
next();
},
/**
* Checks if the client is authorized to access the request group.
* @param socket - The socket with client information
* @param next - Next function
*/
async checkUserAuthorization(
socket: Socket,
next: NextFunction,
): Promise<void> {
// Get groupId from namespace
const groupId = parseInt(socket.nsp.name.replace('/group/', ''), 10);
Iif (isNaN(groupId)) {
next(new InternalError('Couldn\'t parse namespace'));
}
if (await MembershipService.isMember(socket.request.user, groupId)) {
next();
} else {
next(new NotMemberOfGroupError());
}
},
/**
* Notifies namespace of the specified group to the specified updateö
* @param groupId - The id of the group
* @param carId - The id of the cdar
* @param type - The type of update
* @param car - Data of the car
*/
notifyCarUpdate(
groupId: number,
carId: number,
type: GroupCarAction,
car: Car,
): void {
log('Notify nsp %s with update to car %d', `/group/${groupId}`, carId);
io.of(`/group/${groupId}`).emit('update', {action: type, car});
},
};
export default GroupNotificationService;
|