additon of custom channel conditional eval, though it desperately needs sanitization and/or a framework to work upon. further optimisations and addition of direct messaging
This commit is contained in:
parent
33d1886599
commit
fb5533ce7a
@ -8,11 +8,11 @@ import CustomClient from './clients/types/customClient';
|
|||||||
var logger = require('./logger');
|
var logger = require('./logger');
|
||||||
|
|
||||||
class ChannelManager {
|
class ChannelManager {
|
||||||
channels: any = [];
|
channels: any[] = [];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// create default channel...
|
// create default channel...
|
||||||
var channel: PublicChannel = new PublicChannel('default');
|
let channel = new PublicChannel('default');
|
||||||
this.channels.push(channel);
|
this.channels.push(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,13 +56,18 @@ class ChannelManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createByChannelType(data: any) {
|
createByChannelType(data: any) {
|
||||||
var channel_name = data.channel_type + 'Channel'
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var Channel = require(`./channels/types/${channel_name}`);
|
logger.accessLog.info(`attempting to create channel of type ${data.channel_type}, channel id: ${data.channel}...`);
|
||||||
logger.accessLog.info(`attempting to create channel of type ${channel_name}, channel id: ${data.channel}...`);
|
|
||||||
return new Channel(data.channel);
|
if (data.channel_type == 'public') {
|
||||||
|
return new PublicChannel(data.channel)
|
||||||
|
} else if (data.channel_type == 'private') {
|
||||||
|
return new PrivateChannel(data.channel)
|
||||||
|
} else {
|
||||||
|
return new CustomChannel(data.channel, data.custom)
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
logger.errorLog.info(e);
|
logger.errorLog.info(e);
|
||||||
logger.accessLog.info(`creating base channel: ${data.channel}`);
|
logger.accessLog.info(`creating base channel: ${data.channel}`);
|
||||||
return new PublicChannel(data.channel);
|
return new PublicChannel(data.channel);
|
||||||
|
@ -1,23 +1,18 @@
|
|||||||
import PublicClient from '../clients/types/publicClient';
|
import PublicClient from '../clients/types/publicClient';
|
||||||
import PrivateClient from '../clients/types/privateClient';
|
import PrivateClient from '../clients/types/privateClient';
|
||||||
import CustomClient from '../clients/types/customClient';
|
import CustomClient from '../clients/types/customClient';
|
||||||
import * as Joi from 'joi';
|
|
||||||
|
|
||||||
var logger = require('../logger');
|
var logger = require('../logger');
|
||||||
|
|
||||||
class ChannelBase {
|
class ChannelBase {
|
||||||
id: string;
|
id: string;
|
||||||
clients: PrivateClient[]|PublicClient[]|CustomClient[] = [];
|
clients: any[] = [];
|
||||||
|
|
||||||
constructor(id: string) {
|
constructor(id: string) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
logger.accessLog.info('Channel Created', {channelId: id});
|
logger.accessLog.info('Channel Created', {channelId: id});
|
||||||
}
|
}
|
||||||
|
|
||||||
validations() {
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
|
|
||||||
broadcastMessage(from: PublicClient|PrivateClient|CustomClient, message: object) {
|
broadcastMessage(from: PublicClient|PrivateClient|CustomClient, message: object) {
|
||||||
for (let to of this.clients) {
|
for (let to of this.clients) {
|
||||||
if (this.messageTransactionPossible(from, to)) {
|
if (this.messageTransactionPossible(from, to)) {
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
import CustomClient from '../../clients/types/customClient';
|
import CustomClient from '../../clients/types/customClient';
|
||||||
import ChannelBase from '../channelBase';
|
import ChannelBase from '../channelBase';
|
||||||
import * as Joi from 'joi';
|
|
||||||
|
|
||||||
class CustomChannel extends ChannelBase {
|
class CustomChannel extends ChannelBase {
|
||||||
validations() {
|
clients: CustomClient[] = [];
|
||||||
return {
|
custom: any;
|
||||||
test: Joi.alternatives().try(Joi.string(), Joi.object())
|
|
||||||
}
|
constructor(id: string, custom: any) {
|
||||||
|
super(id);
|
||||||
|
this.custom = custom
|
||||||
}
|
}
|
||||||
|
|
||||||
messageTransactionPossible(from: CustomClient, to: CustomClient) {
|
messageTransactionPossible(from: CustomClient, to: CustomClient) {
|
||||||
return true
|
return eval(this.custom.broadcastConditions)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = CustomChannel;
|
|
||||||
export default CustomChannel;
|
export default CustomChannel;
|
||||||
|
@ -4,6 +4,8 @@ import ChannelBase from '../channelBase';
|
|||||||
var logger = require('../../logger');
|
var logger = require('../../logger');
|
||||||
|
|
||||||
class PrivateChannel extends ChannelBase {
|
class PrivateChannel extends ChannelBase {
|
||||||
|
clients: PrivateClient[] = [];
|
||||||
|
|
||||||
messageTransactionPossible(from: PrivateClient, to: PrivateClient) {
|
messageTransactionPossible(from: PrivateClient, to: PrivateClient) {
|
||||||
return (
|
return (
|
||||||
to != from &&
|
to != from &&
|
||||||
@ -13,5 +15,4 @@ class PrivateChannel extends ChannelBase {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = PrivateChannel;
|
|
||||||
export default PrivateChannel;
|
export default PrivateChannel;
|
||||||
|
@ -4,6 +4,8 @@ import ChannelBase from '../channelBase';
|
|||||||
var logger = require('../../logger');
|
var logger = require('../../logger');
|
||||||
|
|
||||||
class PublicChannel extends ChannelBase {
|
class PublicChannel extends ChannelBase {
|
||||||
|
clients: PublicClient[] = [];
|
||||||
|
|
||||||
messageTransactionPossible(from: PublicClient, to: PublicClient) {
|
messageTransactionPossible(from: PublicClient, to: PublicClient) {
|
||||||
return (
|
return (
|
||||||
to != from
|
to != from
|
||||||
@ -11,5 +13,4 @@ class PublicChannel extends ChannelBase {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = PublicChannel;
|
|
||||||
export default PublicChannel;
|
export default PublicChannel;
|
||||||
|
@ -7,7 +7,7 @@ import ChannelManager from './channelManager';
|
|||||||
var logger = require('./logger');
|
var logger = require('./logger');
|
||||||
|
|
||||||
class ClientManager {
|
class ClientManager {
|
||||||
clients: PublicClient[]|PrivateClient[]|CustomClient[] = [];
|
clients: any[] = [];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
//...maybe one day
|
//...maybe one day
|
||||||
@ -68,12 +68,16 @@ class ClientManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getClientType(data: any, channelManager: ChannelManager, ws: WebSocket) {
|
getClientType(data: any, channelManager: ChannelManager, ws: WebSocket) {
|
||||||
var client_type = data.client_type + 'Client'
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var Client = require(`./clients/types/${client_type}`);
|
|
||||||
logger.accessLog.info(`attempting to create client of type ${data.client_type}, client id: ${data.user_id}...`);
|
logger.accessLog.info(`attempting to create client of type ${data.client_type}, client id: ${data.user_id}...`);
|
||||||
return new Client(data, ws, channelManager, this);
|
|
||||||
|
if (data.client_type == 'public') {
|
||||||
|
return new PublicClient(data, ws, channelManager, this)
|
||||||
|
} else if (data.channel_type == 'private') {
|
||||||
|
return new PrivateClient(data, ws, channelManager, this)
|
||||||
|
} else {
|
||||||
|
return new CustomClient(data, ws, channelManager, this)
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.errorLog.info(e);
|
logger.errorLog.info(e);
|
||||||
logger.accessLog.info(`creating base client: ${data.user_id}`);
|
logger.accessLog.info(`creating base client: ${data.user_id}`);
|
||||||
|
@ -4,6 +4,9 @@ import ChannelManager from '../channelManager';
|
|||||||
import PublicChannel from '../channels/types/publicChannel';
|
import PublicChannel from '../channels/types/publicChannel';
|
||||||
import PrivateChannel from '../channels/types/privateChannel';
|
import PrivateChannel from '../channels/types/privateChannel';
|
||||||
import CustomChannel from '../channels/types/customChannel';
|
import CustomChannel from '../channels/types/customChannel';
|
||||||
|
import PublicClient from '../clients/types/publicClient';
|
||||||
|
import PrivateClient from '../clients/types/privateClient';
|
||||||
|
import CustomClient from '../clients/types/customClient';
|
||||||
|
|
||||||
var messageManager = require('../messageManager');
|
var messageManager = require('../messageManager');
|
||||||
var logger = require('../logger');
|
var logger = require('../logger');
|
||||||
@ -27,10 +30,6 @@ class ClientBase {
|
|||||||
this.roles = ['receiver']
|
this.roles = ['receiver']
|
||||||
}
|
}
|
||||||
|
|
||||||
validations() {
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
|
|
||||||
getData() {
|
getData() {
|
||||||
return this.data;
|
return this.data;
|
||||||
}
|
}
|
||||||
@ -46,21 +45,24 @@ class ClientBase {
|
|||||||
connectToChannel(channel: PublicChannel|PrivateChannel|CustomChannel) {
|
connectToChannel(channel: PublicChannel|PrivateChannel|CustomChannel) {
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
|
|
||||||
var messageListener = (message: any) => {
|
var messageListener = (data: any) => {
|
||||||
logger.accessLog.info(`starting message transaction on channel ${channel.id}: `, {message: message});
|
logger.accessLog.info(`starting message transaction on channel ${channel.id}: `, {data: data});
|
||||||
message = messageManager.prepareMessage(message, channel, this);
|
data = messageManager.prepareMessage(data, channel, this);
|
||||||
|
|
||||||
if (!message.error) {
|
if (!data.error) {
|
||||||
if (message['message_type'] == 'broadcast') {
|
if (data.message_type == 'broadcast') {
|
||||||
channel.broadcastMessage(this, message);
|
channel.broadcastMessage(this, data);
|
||||||
} else if (message['message_type'] == 'changeChannel') {
|
} else if (data.message_type == 'direct') {
|
||||||
|
let to = this.clientManager.getClient(data.message.to)
|
||||||
|
to.directMessage(data)
|
||||||
|
} else if (data.message_type == 'changeChannel') {
|
||||||
this.ws.removeListener('message', messageListener);
|
this.ws.removeListener('message', messageListener);
|
||||||
this.channelManager.changeChannel(this, message);
|
this.channelManager.changeChannel(this, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.accessLog.info(`message transaction complete on channel ${channel.id}: `, {message: message});
|
logger.accessLog.info(`message transaction complete on channel ${channel.id}: `, {message: data});
|
||||||
} else {
|
} else {
|
||||||
logger.errorLog.info(`Validation failed, please review schema: ${channel.id}`, {data: {message: message, error: message.error}});
|
logger.errorLog.info(`Validation failed, please review schema: ${channel.id}`, {data: {message: data, error: data.error}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +80,11 @@ class ClientBase {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
directMessage(message: any) {
|
||||||
|
this.ws.send(JSON.stringify(message));
|
||||||
|
logger.accessLog.info(`sent direct message to ${this.id}`, { data: { message: message }});
|
||||||
|
}
|
||||||
|
|
||||||
replaceWebSocket(ws: WebSocket) {
|
replaceWebSocket(ws: WebSocket) {
|
||||||
this.ws.close();
|
this.ws.close();
|
||||||
this.ws = ws;
|
this.ws = ws;
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
import ClientBase from '../clientBase';
|
import ClientBase from '../clientBase';
|
||||||
|
import ClientManager from '../../clientManager';
|
||||||
|
import ChannelManager from '../../channelManager';
|
||||||
|
import * as WebSocket from 'ws';
|
||||||
import * as Joi from 'joi';
|
import * as Joi from 'joi';
|
||||||
|
|
||||||
|
var logger = require('../../logger');
|
||||||
|
|
||||||
class CustomClient extends ClientBase {
|
class CustomClient extends ClientBase {
|
||||||
// validations() {
|
constructor(data: any, ws: WebSocket, channelManager: ChannelManager, clientManager: ClientManager) {
|
||||||
// return {
|
super(data, ws, channelManager, clientManager);
|
||||||
// test: Joi.alternatives().try(Joi.string(), Joi.object())
|
this.roles = data.user_roles
|
||||||
// }
|
logger.accessLog.info('Custom Client Created', {data: data});
|
||||||
// }
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = CustomClient;
|
|
||||||
export default CustomClient;
|
export default CustomClient;
|
||||||
|
|
||||||
|
@ -13,6 +13,5 @@ class PrivateClient extends ClientBase {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = PrivateClient;
|
|
||||||
export default PrivateClient;
|
export default PrivateClient;
|
||||||
|
|
||||||
|
@ -4,6 +4,5 @@ var logger = require('../../logger');
|
|||||||
|
|
||||||
class PublicClient extends ClientBase {};
|
class PublicClient extends ClientBase {};
|
||||||
|
|
||||||
module.exports = PublicClient;
|
|
||||||
export default PublicClient;
|
export default PublicClient;
|
||||||
|
|
||||||
|
@ -15,5 +15,5 @@ module.exports = {
|
|||||||
audience: 'internal',
|
audience: 'internal',
|
||||||
algorithm: ["HS256"]
|
algorithm: ["HS256"]
|
||||||
},
|
},
|
||||||
messageTypes : ['broadcast', 'changeChannel']
|
messageTypes : ['broadcast', 'direct', 'changeChannel']
|
||||||
}
|
}
|
||||||
|
@ -1,31 +1,11 @@
|
|||||||
import * as Joi from 'joi';
|
import * as Joi from 'joi';
|
||||||
import PublicChannel from './channels/types/publicChannel';
|
import Validations from './services/validations';
|
||||||
import PrivateChannel from './channels/types/privateChannel';
|
|
||||||
import CustomChannel from './channels/types/customChannel';
|
|
||||||
import PublicClient from './clients/types/publicClient';
|
|
||||||
import PrivateClient from './clients/types/privateClient';
|
|
||||||
import CustomClient from './clients/types/customClient';
|
|
||||||
|
|
||||||
var logger = require('./logger');
|
|
||||||
var app = require('./config/app');
|
|
||||||
|
|
||||||
let schema = (channel: PublicChannel|PrivateChannel|CustomChannel, client: PublicClient|PrivateClient|CustomClient) => {
|
|
||||||
let validations = {
|
|
||||||
message_type: Joi.string().valid(app.messageTypes).insensitive().required(),
|
|
||||||
channel: Joi.string(),
|
|
||||||
channel_type: Joi.string(),
|
|
||||||
client_type: Joi.string(),
|
|
||||||
user_id: Joi.number().integer(),
|
|
||||||
message: Joi.alternatives().try(Joi.string(), Joi.object())
|
|
||||||
}
|
|
||||||
|
|
||||||
return {...validations, ...channel.validations, ...client.validations}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
prepareMessage: (message: string, channel: PublicChannel|PrivateChannel|CustomChannel, client: PublicClient|PrivateClient|CustomClient) => {
|
prepareMessage: (message: string) => {
|
||||||
var parsed = JSON.parse(message)
|
let validations = new Validations(message)
|
||||||
const result = Joi.validate(parsed, schema(channel, client));
|
let parsed = JSON.parse(message)
|
||||||
|
const result = Joi.validate(parsed, validations.MessageConditions);
|
||||||
|
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
return result
|
return result
|
||||||
|
26
src/services/validations.ts
Normal file
26
src/services/validations.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import PublicChannel from '../channels/types/publicChannel';
|
||||||
|
import PrivateChannel from '../channels/types/privateChannel';
|
||||||
|
import CustomChannel from '../channels/types/customChannel';
|
||||||
|
import * as Joi from 'joi'
|
||||||
|
|
||||||
|
var app = require('../config/app');
|
||||||
|
|
||||||
|
class Validations {
|
||||||
|
MessageConditions = {
|
||||||
|
message_type: Joi.string().valid(app.messageTypes).insensitive().required(),
|
||||||
|
channel: Joi.string(),
|
||||||
|
channel_type: Joi.string(),
|
||||||
|
client_type: Joi.string(),
|
||||||
|
user_id: Joi.number().integer(),
|
||||||
|
message: Joi.alternatives().try(Joi.string(), Joi.object()),
|
||||||
|
custom: Joi.object()
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(message: any) {
|
||||||
|
if (message.channel_type == 'custom') {
|
||||||
|
let conditions = message.conditions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Validations;
|
@ -40,7 +40,7 @@ describe('ChannelBase', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not broadcast a message to self', function () {
|
it('should not broadcast a message to self', function () {
|
||||||
var result = channel.broadcastMessage(client, 'test message');
|
var result = channel.broadcastMessage(client, {message: "test message"});
|
||||||
expect(result.status).to.be.equal('success');
|
expect(result.status).to.be.equal('success');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as WebSocket from 'ws';
|
import * as WebSocket from 'ws';
|
||||||
import ClientBase from '../clients/clientBase';
|
import PublicClient from '../clients/types/publicClient';
|
||||||
import ClientManager from '../clientManager';
|
import ClientManager from '../clientManager';
|
||||||
import ChannelManager from '../channelManager';
|
import ChannelManager from '../channelManager';
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user