Compare commits

..

8 Commits

Author SHA1 Message Date
09dec2071e 1.1.65 2020-09-29 19:42:38 +00:00
a1443deafe fix(core): update 2020-09-29 19:42:38 +00:00
9eac5ad336 1.1.64 2020-09-29 19:37:49 +00:00
cf607a79d5 fix(core): update 2020-09-29 19:37:49 +00:00
8426c976bf 1.1.63 2020-09-29 18:58:10 +00:00
1086065000 fix(core): update 2020-09-29 18:58:09 +00:00
72196ec383 1.1.62 2020-09-29 17:21:08 +00:00
c6ad490a6f fix(core): update 2020-09-29 17:21:08 +00:00
12 changed files with 533 additions and 691 deletions

111
README.md
View File

@ -1,111 +0,0 @@
# @pushrocks/smartsocket
easy and secure websocket communication
## Availabililty and Links
* [npmjs.org (npm package)](https://www.npmjs.com/package/@pushrocks/smartsocket)
* [gitlab.com (source)](https://gitlab.com/pushrocks/smartsocket)
* [github.com (source mirror)](https://github.com/pushrocks/smartsocket)
* [docs (typedoc)](https://pushrocks.gitlab.io/smartsocket/)
## Status for master
[![build status](https://gitlab.com/pushrocks/smartsocket/badges/master/build.svg)](https://gitlab.com/pushrocks/smartsocket/commits/master)
[![coverage report](https://gitlab.com/pushrocks/smartsocket/badges/master/coverage.svg)](https://gitlab.com/pushrocks/smartsocket/commits/master)
[![npm downloads per month](https://img.shields.io/npm/dm/@pushrocks/smartsocket.svg)](https://www.npmjs.com/package/@pushrocks/smartsocket)
[![Known Vulnerabilities](https://snyk.io/test/npm/@pushrocks/smartsocket/badge.svg)](https://snyk.io/test/npm/@pushrocks/smartsocket)
[![TypeScript](https://img.shields.io/badge/TypeScript->=%203.x-blue.svg)](https://nodejs.org/dist/latest-v10.x/docs/api/)
[![node](https://img.shields.io/badge/node->=%2010.x.x-blue.svg)](https://nodejs.org/dist/latest-v10.x/docs/api/)
[![JavaScript Style Guide](https://img.shields.io/badge/code%20style-prettier-ff69b4.svg)](https://prettier.io/)
## Usage
Use TypeScript for best in class instellisense.
Under the hood we use socket.io and shortid for managed data exchange.
### Serverside
```typescript
import * as smartsocket from 'smartsocket';
import * as q from q; // q is a promise library
// The "Smartsocket" listens on a port and can receive new "SocketConnection" requests.
let mySmartsocket = new smartsocket.Smartsocket({
port: 3000 // the port smartsocket will listen on
});
// optional:
// run this with anothoer existing server like express
declare var someExpressServer; // read the express docs about how express actually works
mySmartsocket.setServer(someExpressServer);
// A "SocketRole" can be referenced by "SocketFunction"s.
// All "SocketRequest"s carry authentication data for a specific "SocketRole".
// "SocketFunction"s know which "SocketRole"s are allowed to execute them
let mySocketRole = new smartsocket.SocketRole({
name: 'someRoleName',
passwordHash: 'someHashedString'
});
// A "SocketFunction" executes a referenced function and passes in any data of the corresponding "SocketRequest".
// The referenced function must return a promise and resolve with data of type any.
// Any "SocketRequest" carries a unique identifier. If the referenced function's promise resolved any passed on argument will be returned to the requesting party
let testSocketFunction1 = new smartsocket.SocketFunction({
funcName: 'testSocketFunction1',
funcDef: data => {
console.log('testSocketFunction1 executed successfully!');
},
allowedRoles: [mySocketRole] // all roles that have access to a specific function
});
// A "Smartsocket" exposes a .clientCall() that gets
// 1. the name of the "SocketFunction" on the client side
// 2. the data to pass in
// 3. And a target "SocketConnection" (there can be multiple connections at once)
// any unique id association is done internally
mySmartsocket.clientCall('restart', data, someTargetConnection).then(responseData => {});
```
#### Client side
```typescript
import * as smartsocket from 'smartsocket';
// A "SmartsocketClient" is different from a "Smartsocket" in that it doesn't expose any public address.
// Thus any new "SocketConnection"s must be innitiated from a "SmartsocketClient".
let testSmartsocketClient = new smartsocket.SmartsocketClient({
port: testConfig.port,
url: 'http://localhost',
password: 'testPassword',
alias: 'testClient1',
role: 'testRole1'
});
// You can .connect() and .disconnect() from a "Smartsocket"
testSmartsocketClient.connect().then(() => {
done();
});
// The client can also specify "SocketFunction"s. It can also specify "SocketRole"s in case a client connects to multiple servers at once
let testSocketFunction2 = new smartsocket.SocketFunction({
funcName: 'testSocketFunction2',
funcDef: data => {}, // the function to execute, has to return promise
allowedRoles: []
});
// A "SmartsocketClient" can call functions on the serverside using .serverCall() analog to the "Smartsocket"'s .clientCall method.
mySmartsocketClient.serverCall('function', functionCallData).then(functionResponseData => {
// the functionResponseData comes from the server... awesome, right?
});
```
> **NOTE:**
> you can easily chain dependent requests on either the server or client side with promises.
> `data` is always a js object that you can design for your specific needs.
> It supports buffers for large binary data network exchange.
For further information read the linked docs at the top of this readme.
> MIT licensed | **©** [Lossless GmbH](https://lossless.gmbh)
| By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy)
[![repo-footer](https://lossless.gitlab.io/publicrelations/repofooter.svg)](https://maintainedby.lossless.com)

1009
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "@pushrocks/smartsocket",
"version": "1.1.61",
"version": "1.1.65",
"description": "easy and secure websocket communication",
"main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts",
@ -20,14 +20,16 @@
"homepage": "https://gitlab.com/pushrocks/smartsocket#README",
"dependencies": {
"@apiglobal/typedrequest-interfaces": "^1.0.15",
"@pushrocks/isohash": "^1.0.2",
"@pushrocks/isounique": "^1.0.4",
"@pushrocks/lik": "^4.0.17",
"@pushrocks/smartdelay": "^2.0.10",
"@pushrocks/smartenv": "^4.0.15",
"@pushrocks/smartexpress": "^3.0.76",
"@pushrocks/smarthash": "^2.1.6",
"@pushrocks/smartlog": "^2.0.39",
"@pushrocks/smartpromise": "^3.0.6",
"@pushrocks/smartrx": "^2.0.19",
"@pushrocks/smartunique": "^3.0.3",
"@pushrocks/smarttime": "^3.0.35",
"@types/socket.io": "^2.1.11",
"@types/socket.io-client": "^1.4.33",
"socket.io": "^2.3.0",
@ -36,7 +38,7 @@
"devDependencies": {
"@gitzone/tsbuild": "^2.1.25",
"@gitzone/tsrun": "^1.2.12",
"@gitzone/tstest": "^1.0.44",
"@gitzone/tstest": "^1.0.48",
"@pushrocks/tapbundle": "^3.2.9",
"@types/node": "^14.11.2",
"tslint": "^6.1.3",

View File

@ -1,4 +1,5 @@
import * as plugins from './smartsocket.plugins';
import * as pluginsTyped from './smartsocket.pluginstyped';
// classes
import { SocketConnection } from './smartsocket.classes.socketconnection';
@ -11,8 +12,6 @@ import { SocketRequest } from './smartsocket.classes.socketrequest';
import { SocketRole } from './smartsocket.classes.socketrole';
import { SocketServer } from './smartsocket.classes.socketserver';
// socket.io
import * as SocketIO from 'socket.io';
import { logger } from './smartsocket.logging';
export interface ISmartsocketConstructorOptions {
@ -23,9 +22,10 @@ export class Smartsocket {
/**
* a unique id to detect server restarts
*/
public shortId = plugins.smartunique.shortId();
public shortId = plugins.isounique.uni();
public smartenv = new plugins.smartenv.Smartenv();
public options: ISmartsocketConstructorOptions;
public io: SocketIO.Server;
public io: pluginsTyped.socketIo.Server;
public socketConnections = new plugins.lik.ObjectMap<SocketConnection>();
public socketRoles = new plugins.lik.ObjectMap<SocketRole>();
public socketFunctions = new plugins.lik.ObjectMap<SocketFunction<any>>();
@ -46,7 +46,8 @@ export class Smartsocket {
* starts smartsocket
*/
public async start() {
this.io = plugins.socketIo(this.socketServer.getServerForSocketIo());
const socketIoModule = this.smartenv.getSafeNodeModule('socket.io');
this.io = socketIoModule(this.socketServer.getServerForSocketIo());
await this.socketServer.start();
this.io.on('connection', (socketArg) => {
this._handleSocketConnection(socketArg);
@ -85,7 +86,7 @@ export class Smartsocket {
funcName: functionNameArg,
},
originSocketConnection: targetSocketConnectionArg,
shortId: plugins.smartunique.shortId(),
shortId: plugins.isounique.uni(),
side: 'requesting',
});
const response: ISocketFunctionCallDataResponse<T> = await socketRequest.dispatch();
@ -110,7 +111,7 @@ export class Smartsocket {
/**
* the standard handler for new socket connections
*/
private async _handleSocketConnection(socketArg: plugins.socketIo.Socket) {
private async _handleSocketConnection(socketArg: pluginsTyped.socketIo.Socket) {
const socketConnection: SocketConnection = new SocketConnection({
alias: undefined,
authenticated: false,

View File

@ -1,4 +1,5 @@
import * as plugins from './smartsocket.plugins';
import * as pluginsTyped from './smartsocket.pluginstyped';
import * as interfaces from './interfaces';
import { SocketConnection } from './smartsocket.classes.socketconnection';
@ -24,7 +25,7 @@ export interface ISmartsocketClientOptions {
export class SmartsocketClient {
// a unique id
public shortId = plugins.smartunique.shortId();
public shortId = plugins.isounique.uni();
// the shortId of the remote we connect to
public remoteShortId: string = null;
@ -63,8 +64,16 @@ export class SmartsocketClient {
/**
* connect the client to the server
*/
public connect() {
public async connect() {
const done = plugins.smartpromise.defer();
const smartenvInstance = new plugins.smartenv.Smartenv();
const socketIoClient = await smartenvInstance.getEnvAwareModule({
nodeModuleName: 'socket.io-client',
webUrlArg: 'https://cdn.jsdelivr.net/npm/socket.io-client@2/dist/socket.io.js',
getFunction: () => {
return globalThis.io;
},
});
logger.log('info', 'trying to connect...');
const socketUrl = `${this.serverUrl}:${this.serverPort}`;
this.socketConnection = new SocketConnection({
@ -73,7 +82,7 @@ export class SmartsocketClient {
role: this.socketRole,
side: 'client',
smartsocketHost: this,
socket: plugins.socketIoClient(socketUrl, {
socket: await socketIoClient.connect(socketUrl, {
multiplex: false,
reconnectionAttempts: 5,
}),
@ -175,7 +184,7 @@ export class SmartsocketClient {
const socketRequest = new SocketRequest<T>(this, {
side: 'requesting',
originSocketConnection: this.socketConnection,
shortId: plugins.smartunique.shortId(),
shortId: plugins.isounique.uni(),
funcCallData: {
funcName: functionNameArg,
funcDataArg: dataArg,

View File

@ -92,7 +92,7 @@ export class SocketConnection {
this.socket.on('dataAuth', async (dataArg: ISocketConnectionAuthenticationObject) => {
logger.log('info', 'received authentication data. now hashing and comparing...');
this.socket.removeListener('dataAuth', () => {});
if (SocketRole.checkPasswordForRole(dataArg, this.smartsocketRef)) {
if (await SocketRole.checkPasswordForRole(dataArg, this.smartsocketRef)) {
// TODO: authenticate password
this.alias = dataArg.alias;
this.authenticated = true;
@ -123,14 +123,14 @@ export class SocketConnection {
if (this.authenticated) {
this.socket.on('function', (dataArg: ISocketRequestDataObject<any>) => {
// check if requested function is available to the socket's scope
logger.log('info', 'function request received');
// logger.log('info', 'function request received');
const referencedFunction: SocketFunction<any> = this.role.allowedFunctions.find(
(socketFunctionArg) => {
return socketFunctionArg.name === dataArg.funcCallData.funcName;
}
);
if (referencedFunction) {
logger.log('ok', 'function in access scope');
// logger.log('ok', 'function in access scope');
const localSocketRequest = new SocketRequest(this.smartsocketRef, {
side: 'responding',
originSocketConnection: this,

View File

@ -107,8 +107,7 @@ export class SocketRequest<T extends plugins.typedrequestInterfaces.ITypedReques
);
if (!targetSocketFunction) {
logger.log('warn', `There is no SocketFunction defined for ${this.funcCallData.funcName}`);
logger.log('warn', `So now response is being sent.`);
logger.log('error', `There is no SocketFunction defined for ${this.funcCallData.funcName}`);
return;
}
logger.log('info', `invoking ${targetSocketFunction.name}`);

View File

@ -28,13 +28,13 @@ export class SocketRole {
});
}
public static checkPasswordForRole(
public static async checkPasswordForRole(
dataArg: ISocketConnectionAuthenticationObject,
referenceSmartsocket: Smartsocket | SmartsocketClient
): boolean {
): Promise<boolean> {
const targetPasswordHash = SocketRole.getSocketRoleByName(referenceSmartsocket, dataArg.role)
.passwordHash;
const computedCompareHash = plugins.smarthash.sha256FromStringSync(dataArg.password);
const computedCompareHash = await plugins.isohash.sha256FromString(dataArg.password);
return targetPasswordHash === computedCompareHash;
}

View File

@ -1,8 +1,7 @@
import * as plugins from './smartsocket.plugins';
import * as pluginsTyped from './smartsocket.pluginstyped';
// used in case no other server is supplied
import * as http from 'http';
import * as https from 'https';
import { Smartsocket } from './smartsocket.classes.smartsocket';
import { logger } from './smartsocket.logging';
@ -12,7 +11,7 @@ import { logger } from './smartsocket.logging';
*/
export class SocketServer {
private smartsocket: Smartsocket;
private httpServer: http.Server | https.Server;
private httpServer: pluginsTyped.http.Server | pluginsTyped.https.Server;
// wether httpServer is standalone
private standaloneServer = false;
private expressServer: any;
@ -27,7 +26,7 @@ export class SocketServer {
*/
public async setExternalServer(
serverType: 'smartexpress',
serverArg: plugins.smartexpress.Server
serverArg: pluginsTyped.smartexpress.Server
) {
await serverArg.startedPromise;
this.httpServer = serverArg.httpServer;
@ -40,7 +39,8 @@ export class SocketServer {
if (this.httpServer) {
return this.httpServer;
} else {
this.httpServer = new http.Server();
const httpModule = this.smartsocket.smartenv.getSafeNodeModule('http');
this.httpServer = new httpModule.Server();
this.standaloneServer = true;
return this.httpServer;
}

View File

@ -0,0 +1,3 @@
import * as plugins from './smartsocket.plugins';
export class SocketStats {}

View File

@ -4,30 +4,24 @@ import * as typedrequestInterfaces from '@apiglobal/typedrequest-interfaces';
export { typedrequestInterfaces };
// pushrocks scope
import * as isohash from '@pushrocks/isohash';
import * as isounique from '@pushrocks/isounique';
import * as lik from '@pushrocks/lik';
import * as smartenv from '@pushrocks/smartenv';
import * as smartlog from '@pushrocks/smartlog';
import * as smarthash from '@pushrocks/smarthash';
import * as smartdelay from '@pushrocks/smartdelay';
import * as smartexpress from '@pushrocks/smartexpress';
import * as smartpromise from '@pushrocks/smartpromise';
import * as smarttime from '@pushrocks/smarttime';
import * as smartunique from '@pushrocks/smartunique';
import * as smartrx from '@pushrocks/smartrx';
export {
isohash,
isounique,
lik,
smartenv,
smartlog,
smarthash,
smartdelay,
smartexpress,
smartpromise,
smarttime,
smartunique,
smartrx,
};
// third party scope
import socketIo from 'socket.io';
import socketIoClient from 'socket.io-client';
export { socketIo, socketIoClient };

View File

@ -0,0 +1,16 @@
// node native
import type http from 'http';
import type https from 'https';
export { http, https };
// pushrocks scope
import type * as smartexpress from '@pushrocks/smartexpress';
export { smartexpress };
// third party scope
import type socketIo from 'socket.io';
import type socketIoClient from 'socket.io-client';
export { socketIo, socketIoClient };