mirror of
https://github.com/pavlobu/deskreen.git
synced 2025-05-28 05:10:09 -07:00
Merge pull request #6 from pavlobu/test-for-darkwire
tests for darkwire.io code
This commit is contained in:
commit
279a358242
134
app/server/darkwireSocket.spec.ts
Normal file
134
app/server/darkwireSocket.spec.ts
Normal file
@ -0,0 +1,134 @@
|
||||
/* eslint-disable class-methods-use-this */
|
||||
/* eslint-disable no-new */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import Io from 'socket.io';
|
||||
import http from 'http';
|
||||
import Koa from 'koa';
|
||||
import DarkwireSocket from './darkwireSocket';
|
||||
|
||||
const protocol = http;
|
||||
|
||||
class MockConnectSocket {
|
||||
testObservers: any;
|
||||
|
||||
constructor() {
|
||||
this.testObservers = {};
|
||||
}
|
||||
|
||||
join() {}
|
||||
|
||||
on(type: string, callback: any) {
|
||||
this.testObservers[type] = callback;
|
||||
}
|
||||
|
||||
emit(type: string) {
|
||||
if (this.testObservers[type] !== undefined) {
|
||||
this.testObservers[type]();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe('DarkwireSocket tests', () => {
|
||||
const TEST_ROOM_ID = '123';
|
||||
const TEST_ROOM_ID_HASH = '123321';
|
||||
const makeTestSocketOPTS = (socket: Io.Socket) => {
|
||||
return {
|
||||
roomIdOriginal: TEST_ROOM_ID,
|
||||
roomId: TEST_ROOM_ID_HASH,
|
||||
socket,
|
||||
room: {
|
||||
id: TEST_ROOM_ID_HASH,
|
||||
users: [],
|
||||
isLocked: false,
|
||||
createdAt: Date.now(),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
let app: Koa<Koa.DefaultState, Koa.DefaultContext>;
|
||||
let server: http.Server;
|
||||
let io: Io.Server;
|
||||
let socket: Io.Socket;
|
||||
|
||||
beforeEach(() => {
|
||||
app = new Koa();
|
||||
server = protocol.createServer(app.callback());
|
||||
io = Io(server, {
|
||||
pingInterval: 20000,
|
||||
pingTimeout: 5000,
|
||||
serveClient: false,
|
||||
});
|
||||
|
||||
io.on('connection', (receivedSocket) => {
|
||||
socket = receivedSocket;
|
||||
});
|
||||
});
|
||||
|
||||
it('should set internal socket same as passed in constructor', () => {
|
||||
io.emit('connection', {
|
||||
join: () => {},
|
||||
});
|
||||
const customSocket = new DarkwireSocket(makeTestSocketOPTS(socket));
|
||||
|
||||
expect(customSocket.socket).toBe(socket);
|
||||
});
|
||||
|
||||
it('should emit "ROOM_LOCKED" on internal socket object when .sendRoomLocked() is called', () => {
|
||||
const mockEmitProperty = jest.fn();
|
||||
io.emit('connection', {
|
||||
emit: mockEmitProperty,
|
||||
join: () => {},
|
||||
});
|
||||
const customSocket = new DarkwireSocket(makeTestSocketOPTS(socket));
|
||||
|
||||
customSocket.sendRoomLocked();
|
||||
|
||||
expect(mockEmitProperty).toBeCalledWith('ROOM_LOCKED');
|
||||
});
|
||||
|
||||
it('should call .joinRoom() when socket is created and pass roomId as argument', () => {
|
||||
const mockJoinProperty = jest.fn();
|
||||
io.emit('connection', {
|
||||
join: mockJoinProperty,
|
||||
});
|
||||
const testSocketOPTS = makeTestSocketOPTS(socket);
|
||||
const { roomId } = testSocketOPTS;
|
||||
|
||||
new DarkwireSocket(testSocketOPTS);
|
||||
|
||||
expect(mockJoinProperty).toBeCalledWith(roomId, expect.anything());
|
||||
});
|
||||
|
||||
it('should call handleDisconnect when socket.on("disconnect") happened', async () => {
|
||||
const mockDisconnectProperty = jest.fn();
|
||||
io.emit('connection', new MockConnectSocket());
|
||||
const darkwireSocket = new DarkwireSocket(makeTestSocketOPTS(socket));
|
||||
Object.defineProperty(darkwireSocket, 'handleDisconnect', {
|
||||
value: mockDisconnectProperty,
|
||||
});
|
||||
|
||||
await darkwireSocket.handleSocket(socket);
|
||||
socket.emit('disconnect');
|
||||
|
||||
expect(mockDisconnectProperty).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should set TOGGLE_LOCK_ROOM, USER_DISCONNECT, USER_ENTER callbacks on socket when handleSocket is called', async () => {
|
||||
io.emit('connection', new MockConnectSocket());
|
||||
const darkwireSocket = new DarkwireSocket(makeTestSocketOPTS(socket));
|
||||
|
||||
await darkwireSocket.handleSocket(socket);
|
||||
|
||||
expect(
|
||||
((socket as unknown) as MockConnectSocket).testObservers
|
||||
).toHaveProperty('TOGGLE_LOCK_ROOM');
|
||||
|
||||
expect(
|
||||
((socket as unknown) as MockConnectSocket).testObservers
|
||||
).toHaveProperty('USER_ENTER');
|
||||
|
||||
expect(
|
||||
((socket as unknown) as MockConnectSocket).testObservers
|
||||
).toHaveProperty('USER_DISCONNECT');
|
||||
});
|
||||
});
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* original JS code from darkwire.io
|
||||
* translated to typescript for Deskreen app
|
||||
* */
|
||||
|
||||
/* eslint-disable no-async-promise-executor */
|
||||
import _ from 'lodash';
|
||||
import Io from 'socket.io';
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* original JS code from darkwire.io
|
||||
* translated to typescript for Deskreen app
|
||||
* */
|
||||
|
||||
/* eslint-disable no-console */
|
||||
import getStore from './store';
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* original JS code from darkwire.io
|
||||
* translated to typescript for Deskreen app
|
||||
* */
|
||||
|
||||
/* eslint-disable no-console */
|
||||
import http, { Server } from 'http';
|
||||
import express from 'express';
|
||||
@ -10,7 +15,7 @@ import koaStatic from 'koa-static';
|
||||
import koaSend from 'koa-send';
|
||||
import getPort from 'get-port';
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import Socket from './socket';
|
||||
import DarkwireSocket from './darkwireSocket';
|
||||
import pollForInactiveRooms from './inactiveRooms';
|
||||
import getStore from './store';
|
||||
|
||||
@ -26,8 +31,6 @@ try {
|
||||
isDev = true;
|
||||
}
|
||||
|
||||
require('dotenv').config();
|
||||
|
||||
const app = new Koa();
|
||||
|
||||
const router = new Router();
|
||||
@ -93,7 +96,7 @@ io.on('connection', async (socket) => {
|
||||
room = JSON.parse(room || '{}');
|
||||
|
||||
// eslint-disable-next-line no-new
|
||||
new Socket({
|
||||
new DarkwireSocket({
|
||||
roomIdOriginal: roomId,
|
||||
roomId: roomIdHash,
|
||||
socket,
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
/*
|
||||
* got original code from darkwire.io
|
||||
* translated code to typescript for Deskreen
|
||||
* original JS code from darkwire.io
|
||||
* translated to typescript for Deskreen app
|
||||
* */
|
||||
|
||||
interface MemoryStoreParams {
|
||||
|
@ -9,19 +9,9 @@ export default class Crypto {
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
bytes[i] = str.charCodeAt(i);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// convertArrayBufferViewToString(buffer) {
|
||||
// let str = '';
|
||||
// for (let i = 0; i < buffer.byteLength; i++) {
|
||||
// str += String.fromCharCode(buffer[i]);
|
||||
// }
|
||||
|
||||
// return str;
|
||||
// }
|
||||
|
||||
createEncryptDecryptKeys() {
|
||||
return new Promise<forge.pki.rsa.KeyPair>((resolve) => {
|
||||
const keypair = forge.pki.rsa.generateKeyPair({
|
||||
@ -109,10 +99,7 @@ export default class Crypto {
|
||||
});
|
||||
}
|
||||
|
||||
wrapKeyWithForge(
|
||||
keyToWrap: string,
|
||||
publicKeyToWrapWith: forge.pki.rsa.PublicKey
|
||||
) {
|
||||
wrapKey(keyToWrap: string, publicKeyToWrapWith: forge.pki.rsa.PublicKey) {
|
||||
return publicKeyToWrapWith.encrypt(keyToWrap, 'RSA-OAEP');
|
||||
}
|
||||
|
||||
|
56
app/utils/message.spec.ts
Normal file
56
app/utils/message.spec.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { prepare, process } from './message';
|
||||
import getTestPublickKeyPem from './mocks/getTestPublickKeyPem';
|
||||
import getTestPrivateKeyPem from './mocks/getTestPrivateKeyPem';
|
||||
|
||||
interface TestPayload {
|
||||
text: string;
|
||||
}
|
||||
|
||||
interface TestDecryptedPayload {
|
||||
payload: TestPayload;
|
||||
}
|
||||
describe('message.ts tests for proper encryption and decryption functionality', () => {
|
||||
const TEST_TEXT = 'some test text here';
|
||||
const TEST_TEXT_AS_URL = 'some%20test%20text%20here';
|
||||
const testPayloadToEncrypt = {
|
||||
payload: {
|
||||
text: TEST_TEXT,
|
||||
},
|
||||
};
|
||||
|
||||
const testUser = {
|
||||
username: 'testUsername',
|
||||
id: 'testId',
|
||||
};
|
||||
|
||||
const testPartner = {
|
||||
publicKey: getTestPublickKeyPem(),
|
||||
};
|
||||
it('should create encrypted payload with prepare() method', async () => {
|
||||
const encryptedPayload = await prepare(
|
||||
testPayloadToEncrypt,
|
||||
testUser,
|
||||
testPartner
|
||||
);
|
||||
|
||||
expect(encryptedPayload.toSend.payload).not.toContain(TEST_TEXT);
|
||||
expect(encryptedPayload.toSend.payload).not.toContain(TEST_TEXT_AS_URL);
|
||||
});
|
||||
|
||||
it('should decrypt encrypted payload with process() method', async () => {
|
||||
const encryptedPayload = await prepare(
|
||||
testPayloadToEncrypt,
|
||||
testUser,
|
||||
testPartner
|
||||
);
|
||||
|
||||
const decryptedPayload = await process(
|
||||
encryptedPayload.toSend,
|
||||
getTestPrivateKeyPem()
|
||||
);
|
||||
|
||||
expect((decryptedPayload as TestDecryptedPayload).payload.text).toContain(
|
||||
TEST_TEXT_AS_URL
|
||||
);
|
||||
});
|
||||
});
|
@ -7,8 +7,25 @@ import Crypto from './crypto';
|
||||
|
||||
const crypto = new Crypto();
|
||||
|
||||
interface EncryptedPayloadToSend {
|
||||
payload: string;
|
||||
signature: string;
|
||||
iv: string;
|
||||
keys: EncryptedKeys[];
|
||||
}
|
||||
|
||||
interface EncryptedKeys {
|
||||
sessionKey: string;
|
||||
signingKey: string;
|
||||
}
|
||||
|
||||
interface ProcessedPayload {
|
||||
toSend: EncryptedPayloadToSend;
|
||||
original: any;
|
||||
}
|
||||
|
||||
export const process = (payload: any, privateKeyString: string) =>
|
||||
new Promise(async (resolve, reject) => {
|
||||
new Promise(async (resolve) => {
|
||||
const privateKey = (await crypto.importEncryptDecryptKey(
|
||||
privateKeyString
|
||||
)) as forge.pki.rsa.PrivateKey;
|
||||
@ -41,9 +58,9 @@ export const process = (payload: any, privateKeyString: string) =>
|
||||
);
|
||||
|
||||
if (!verified) {
|
||||
console.error("recreated signature doesn't match with payload.signature");
|
||||
reject();
|
||||
return;
|
||||
throw new Error(
|
||||
"recreated signature doesn't match with payload.signature"
|
||||
);
|
||||
}
|
||||
|
||||
const decryptedPayload = await crypto.decryptMessage(
|
||||
@ -57,7 +74,7 @@ export const process = (payload: any, privateKeyString: string) =>
|
||||
});
|
||||
|
||||
export const prepare = (payload: any, user: any, partner: any) =>
|
||||
new Promise(async (resolve) => {
|
||||
new Promise<ProcessedPayload>(async (resolve) => {
|
||||
const myUsername = user.username;
|
||||
const myId = user.id;
|
||||
const members = [partner];
|
||||
@ -92,8 +109,8 @@ export const prepare = (payload: any, user: any, partner: any) =>
|
||||
member.publicKey
|
||||
)) as forge.pki.rsa.PublicKey;
|
||||
const enc = await Promise.all([
|
||||
crypto.wrapKeyWithForge(secretKeyRandomAES, memberPublicKey),
|
||||
crypto.wrapKeyWithForge(secretKeyRandomHMAC, memberPublicKey),
|
||||
crypto.wrapKey(secretKeyRandomAES, memberPublicKey),
|
||||
crypto.wrapKey(secretKeyRandomHMAC, memberPublicKey),
|
||||
]);
|
||||
|
||||
return {
|
||||
|
29
app/utils/mocks/getTestPrivateKeyPem.ts
Normal file
29
app/utils/mocks/getTestPrivateKeyPem.ts
Normal file
@ -0,0 +1,29 @@
|
||||
export default function getTestPrivateKeyPem() {
|
||||
return `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAoQ8+vdVAerEyaxGaffzrTTv+sgpQ3xToBFYkxrT6f+zP4MqV
|
||||
nTIy2+UMlEGGryMFgJWyurqv+NyoVf7vIFOxQcxJko1BL/oIt/e5YZ/fMIw9AhgP
|
||||
0A0oZyFKNbGesCY3zMdpZqPE0brzfhjr/lu5VzioZI9vxocOSSc3+S8w1EXqujgO
|
||||
X3PWXgZrD6Y//Oo+8BgNQta/e5PUyc9yNchU/W3ddzBdE0iUXTdQt7yFvzy4vTbS
|
||||
ywUxoNNJnD6dUJ6dZ4c24VGvrvhJ5mzNqQjibAhtkPFbvhn0e0BHl0BZ876fLHGg
|
||||
zpHgmmiWbKwBYl1ydv8fW9W3r5nQoW0RThYJjwIDAQABAoIBAHqOrUGrGsvCNwl+
|
||||
db9VTICTHLbCXtPChuN14bpLUSszOuRlhAAAiO8HltDiI+j1j2RPhZfOI8YNsxLt
|
||||
UW2aAhJ9r6aTUn19mFDVcv20uBOrQ2lqge3hdVM049GD/asxCdkMDUqLaGPoDQ1x
|
||||
TXNavOiANrN+6qF5eAd2joNRw6hi7osyWqfpgM9y58kiYYazKHKlI/er19JsD2t5
|
||||
hgRiFti+oN9nqhhVzJI/GYU9JugXnB/Z0uFvqOyt/3YDHPpOC07WYpfA3yzshBkW
|
||||
TiiMp1eJNX/sRh4JHzRI9/MQe9ajlAS7T74HwCkclzaS8ZY6t+dfVZ097/ug77eQ
|
||||
NwY4DAECgYEA0hWv7hpookKKcl0srfxbx+FbtBhzXqz+Tfy3H5do6uXRc0aUwQ25
|
||||
PZLs7UAT3zjt+4aYu1xgkp3cUx5FNr/FAPYLtjXw1/6fmt3HX8820SpCMjIzS1bU
|
||||
UwJvmAut70YA+n2eKwO1qJNeLcpNCDebbIXwj0lKDh5HQDyoswuz7I8CgYEAxEKV
|
||||
N4Ma6GqZ0hgdQlO71oSuftHUI80Iz+Riorrp4AA8hp5A3V6Fd9QDy8PYLz1kD9pM
|
||||
uWdCLqaxdOVDtLVnjNVZH1SI+wSBDA/0OtdvPaONL1JKRA21kol049f0M8wkulAw
|
||||
6lfi2aQwZ3KWyEAfDy5iPdVROnQWqUcLmxO0kwECgYAGpSr4dBtlLoekkG/uXPIm
|
||||
Q2mcK73Se9RbcSf1tttZusVCSTRBWwbF/NTDuGgogmt8rkg8fPKNELM8adO0pKI9
|
||||
oorCS7h/jI1N38ADttE8EoMfhVj8BBYZPhV7kLsCu4siYUDUiXyAhZDQD/sZzHB9
|
||||
IUt3rNDL24dTb9fCOheJ3wKBgGRgpY7Z2DZM51VkDfrxdp3WCKVGTljtMfeaGLSg
|
||||
IqP1mv9DC2vtPxg1cKeUCArJPFc7UIh2/ot7qEFgTQusyERojgePJew0tofj1QcP
|
||||
To7ZConMbb12wYosEYPC3NxtKc+82ffRcW3dIwCVw/axjPEnyQlVBBGAdGKpuo7b
|
||||
Oj0BAoGAMs2zuAJfJB4xE1UZdLXk9uHWPAzgUNDzHuS5mMWuloGvKX+19yck6o2J
|
||||
ZA/iq6GwOgvD2y9MC0mV4WkmwZpVXwPVpZD8GVQXZf2xZgh/q2e3IObAd80NLnaG
|
||||
v86qN98DRTh9L+47Nsaf1J5vDDaAfH2Ir8UgAQ5ZMEFDm7P0hUQ=
|
||||
-----END RSA PRIVATE KEY-----`;
|
||||
}
|
11
app/utils/mocks/getTestPublickKeyPem.ts
Normal file
11
app/utils/mocks/getTestPublickKeyPem.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export default function getTestPublicKeyPem() {
|
||||
return `-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoQ8+vdVAerEyaxGaffzr
|
||||
TTv+sgpQ3xToBFYkxrT6f+zP4MqVnTIy2+UMlEGGryMFgJWyurqv+NyoVf7vIFOx
|
||||
QcxJko1BL/oIt/e5YZ/fMIw9AhgP0A0oZyFKNbGesCY3zMdpZqPE0brzfhjr/lu5
|
||||
VzioZI9vxocOSSc3+S8w1EXqujgOX3PWXgZrD6Y//Oo+8BgNQta/e5PUyc9yNchU
|
||||
/W3ddzBdE0iUXTdQt7yFvzy4vTbSywUxoNNJnD6dUJ6dZ4c24VGvrvhJ5mzNqQji
|
||||
bAhtkPFbvhn0e0BHl0BZ876fLHGgzpHgmmiWbKwBYl1ydv8fW9W3r5nQoW0RThYJ
|
||||
jwIDAQAB
|
||||
-----END PUBLIC KEY-----`;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user