From f45e9985d63e84546995ff7f5e60cac037592889 Mon Sep 17 00:00:00 2001 From: Rick B Date: Wed, 8 Feb 2023 17:44:44 -0700 Subject: [PATCH] feat(api): enhance multitenancy support --- src/amt/ConnectedDevice.ts | 4 +- src/amt/connectedDevice.test.ts | 2 +- src/custom.d.ts | 1 + src/data/postgres/tables/device.test.ts | 28 ++++++------- src/data/postgres/tables/device.ts | 27 +++++++++--- src/middleware/custom/example.ts | 6 +++ src/models/Config.d.ts | 2 + src/routes/devices/create.test.ts | 8 ++-- src/routes/devices/create.ts | 2 +- src/routes/devices/delete.ts | 4 +- src/routes/devices/get.test.ts | 42 ++++++++++++++++++- src/routes/devices/get.ts | 15 +++++-- src/routes/devices/getAll.test.ts | 13 +++--- src/routes/devices/getAll.ts | 8 ++-- src/routes/devices/stats.ts | 4 +- src/routes/devices/tags.ts | 2 +- src/routes/devices/update.ts | 3 +- src/server/mpsserver.ts | 2 +- src/server/webserver.ts | 2 + .../collections/MPS.postman_collection.json | 15 ++----- src/test/helper/config.ts | 2 + src/utils/wsRedirect.test.ts | 2 +- 22 files changed, 131 insertions(+), 63 deletions(-) diff --git a/src/amt/ConnectedDevice.ts b/src/amt/ConnectedDevice.ts index 338012881..e21e8bba6 100644 --- a/src/amt/ConnectedDevice.ts +++ b/src/amt/ConnectedDevice.ts @@ -12,11 +12,13 @@ export class ConnectedDevice { ciraSocket: CIRASocket limiter: Bottleneck kvmConnect: boolean + tenantId: string - constructor (ciraSocket: CIRASocket, readonly username: string, readonly password: string) { + constructor (ciraSocket: CIRASocket, readonly username: string, readonly password: string, tenantId: string) { this.ciraSocket = ciraSocket this.httpHandler = new HttpHandler() this.kvmConnect = false + this.tenantId = tenantId this.limiter = new Bottleneck({ maxConcurrent: 3, minTime: 250 diff --git a/src/amt/connectedDevice.test.ts b/src/amt/connectedDevice.test.ts index ddae629c1..23b300ec7 100644 --- a/src/amt/connectedDevice.test.ts +++ b/src/amt/connectedDevice.test.ts @@ -10,7 +10,7 @@ const socket: CIRASocket = null describe('Connected Device', () => { it('should initialize', () => { - const device = new ConnectedDevice(socket, 'admin', 'P@ssw0rd') + const device = new ConnectedDevice(socket, 'admin', 'P@ssw0rd', '') expect(device.ciraSocket).toBeNull() expect(device.httpHandler).toBeDefined() }) diff --git a/src/custom.d.ts b/src/custom.d.ts index 1e8da4c54..de77fab77 100644 --- a/src/custom.d.ts +++ b/src/custom.d.ts @@ -14,5 +14,6 @@ declare module 'express' { certs: certificatesType db: IDB deviceAction: DeviceAction + tenantId: string } } diff --git a/src/data/postgres/tables/device.test.ts b/src/data/postgres/tables/device.test.ts index 0e77695b4..781d61f13 100644 --- a/src/data/postgres/tables/device.test.ts +++ b/src/data/postgres/tables/device.test.ts @@ -102,8 +102,7 @@ describe('device tests', () => { const device: Device = await deviceTable.getById('4c4c4544-004b-4210-8033-b6c04f504633') expect(device).toBe(null) expect(querySpy).toBeCalledTimes(1) - expect(querySpy).toBeCalledWith(` - SELECT + expect(querySpy).toBeCalledWith(`SELECT guid as "guid", hostname as "hostname", tags as "tags", @@ -113,8 +112,8 @@ describe('device tests', () => { tenantid as "tenantId", friendlyname as "friendlyName", dnssuffix as "dnsSuffix" - FROM devices - WHERE guid = $1 and tenantid = $2`, ['4c4c4544-004b-4210-8033-b6c04f504633', '']) + FROM devices + WHERE guid = $1`, ['4c4c4544-004b-4210-8033-b6c04f504633']) }) test('should get count of connected devices when exists', async () => { @@ -153,17 +152,16 @@ describe('device tests', () => { const result: Device = await deviceTable.getById('4c4c4544-004b-4210-8033-b6c04f504633', 'tenantId') expect(result).toBe(device) expect(querySpy).toBeCalledTimes(1) - expect(querySpy).toBeCalledWith(` - SELECT - guid as "guid", - hostname as "hostname", - tags as "tags", - mpsinstance as "mpsInstance", - connectionstatus as "connectionStatus", - mpsusername as "mpsusername", - tenantid as "tenantId", - friendlyname as "friendlyName", - dnssuffix as "dnsSuffix" + expect(querySpy).toBeCalledWith(`SELECT + guid as "guid", + hostname as "hostname", + tags as "tags", + mpsinstance as "mpsInstance", + connectionstatus as "connectionStatus", + mpsusername as "mpsusername", + tenantid as "tenantId", + friendlyname as "friendlyName", + dnssuffix as "dnsSuffix" FROM devices WHERE guid = $1 and tenantid = $2`, ['4c4c4544-004b-4210-8033-b6c04f504633', 'tenantId']) }) diff --git a/src/data/postgres/tables/device.ts b/src/data/postgres/tables/device.ts index 2cb82eeb7..7b7dd7d5b 100644 --- a/src/data/postgres/tables/device.ts +++ b/src/data/postgres/tables/device.ts @@ -72,9 +72,22 @@ export class DeviceTable implements IDeviceTable { * @param {string} guid * @returns {Device} Device object */ - async getById (id: string, tenantId: string = ''): Promise { - const results = await this.db.query(` - SELECT + async getById (id: string, tenantId?: string): Promise { + let query = `SELECT + guid as "guid", + hostname as "hostname", + tags as "tags", + mpsinstance as "mpsInstance", + connectionstatus as "connectionStatus", + mpsusername as "mpsusername", + tenantid as "tenantId", + friendlyname as "friendlyName", + dnssuffix as "dnsSuffix" + FROM devices + WHERE guid = $1 and tenantid = $2` + let params = [id, tenantId] + if (tenantId == null) { + query = `SELECT guid as "guid", hostname as "hostname", tags as "tags", @@ -84,9 +97,11 @@ export class DeviceTable implements IDeviceTable { tenantid as "tenantId", friendlyname as "friendlyName", dnssuffix as "dnsSuffix" - FROM devices - WHERE guid = $1 and tenantid = $2`, [id, tenantId]) - + FROM devices + WHERE guid = $1` + params = [id] + } + const results = await this.db.query(query, params) return results.rowCount > 0 ? results.rows[0] : null } diff --git a/src/middleware/custom/example.ts b/src/middleware/custom/example.ts index 87c8cad95..c5dfaabd5 100644 --- a/src/middleware/custom/example.ts +++ b/src/middleware/custom/example.ts @@ -16,6 +16,12 @@ exports = module.exports = function (req, res, next) { // For setting the tenantId use req.tenantId // req.tenantId = req.headers['x-tenant-id-token'] + // Be sure to reject requests that do not have access to the tenant + // if (req.tenantId === .tenantId) { + // next() + // } else { + // res.send(401).end() + // } // ensure next is called when appropriate, or return an error code using res next() diff --git a/src/models/Config.d.ts b/src/models/Config.d.ts index aff8a5996..7b3d6272f 100644 --- a/src/models/Config.d.ts +++ b/src/models/Config.d.ts @@ -38,6 +38,8 @@ export interface configType { instance_name: string redirection_expiration_time: number web_auth_enabled: boolean + jwt_token_header: string + jwt_tenant_property: string } export interface certificatesType { diff --git a/src/routes/devices/create.test.ts b/src/routes/devices/create.test.ts index 3f369d49a..c8f83cfd3 100644 --- a/src/routes/devices/create.test.ts +++ b/src/routes/devices/create.test.ts @@ -62,7 +62,7 @@ describe('create', () => { } } as any await insertDevice(req, res as any) - expect(req.db.devices.getById).toHaveBeenCalledWith(guidFromRequest) + expect(req.db.devices.getById).toHaveBeenCalledWith(guidFromRequest, tenantIdFromRequest) expect(statusSpy).toHaveBeenCalledWith(200) expect(jsonSpy).toHaveBeenCalledWith(expectedUpdateResultFromDb) expect(req.db.devices.update).toHaveBeenCalledWith(expectedUpdateResultFromDb) @@ -110,7 +110,7 @@ describe('create', () => { } } as any await insertDevice(req, res as any) - expect(req.db.devices.getById).toHaveBeenCalledWith(guidFromRequest) + expect(req.db.devices.getById).toHaveBeenCalledWith(guidFromRequest, null) expect(statusSpy).toHaveBeenCalledWith(200) expect(jsonSpy).toHaveBeenCalledWith(expectedUpdateResultFromDb) expect(req.db.devices.update).toHaveBeenCalledWith(expectedUpdateResultFromDb) @@ -154,7 +154,7 @@ describe('create', () => { } } as any await insertDevice(req, res as any) - expect(req.db.devices.getById).toHaveBeenCalledWith(guidFromRequest) + expect(req.db.devices.getById).toHaveBeenCalledWith(guidFromRequest, tenantIdFromRequest) expect(statusSpy).toHaveBeenCalledWith(201) expect(jsonSpy).toHaveBeenCalledWith(expectedInsertResultFromDb) expect(req.db.devices.insert).toHaveBeenCalledWith(expectedInsertResultFromDb) @@ -198,7 +198,7 @@ describe('create', () => { } } as any await insertDevice(req, res as any) - expect(req.db.devices.getById).toHaveBeenCalledWith(guidFromRequest) + expect(req.db.devices.getById).toHaveBeenCalledWith(guidFromRequest, null) expect(statusSpy).toHaveBeenCalledWith(201) expect(jsonSpy).toHaveBeenCalledWith(expectedInsertResultFromDb) expect(req.db.devices.insert).toHaveBeenCalledWith(expectedInsertResultFromDb) diff --git a/src/routes/devices/create.ts b/src/routes/devices/create.ts index 0ec8b6c43..6af4a63da 100644 --- a/src/routes/devices/create.ts +++ b/src/routes/devices/create.ts @@ -11,7 +11,7 @@ import { type Request, type Response } from 'express' export async function insertDevice (req: Request, res: Response): Promise { let device: Device try { - device = await req.db.devices.getById(req.body.guid) + device = await req.db.devices.getById(req.body.guid, req.body.tenantId) if (device != null) { device.hostname = req.body.hostname ?? device.hostname device.tags = req.body.tags ?? device.tags diff --git a/src/routes/devices/delete.ts b/src/routes/devices/delete.ts index 762a08b3a..b5143ccc8 100644 --- a/src/routes/devices/delete.ts +++ b/src/routes/devices/delete.ts @@ -8,11 +8,11 @@ import { logger, messages } from '../../logging' export async function deleteDevice (req: Request, res: Response): Promise { try { - const device = await req.db.devices.getById(req.params.guid) + const device = await req.db.devices.getById(req.params.guid, req.tenantId) if (device == null) { res.status(404).json({ error: 'NOT FOUND', message: `Device ID ${req.params.guid} not found` }).end() } else { - const results = await req.db.devices.delete(req.params.guid) + const results = await req.db.devices.delete(req.params.guid, req.tenantId) if (results) { res.status(204).end() } diff --git a/src/routes/devices/get.test.ts b/src/routes/devices/get.test.ts index 819fd6ba9..ea811d73a 100644 --- a/src/routes/devices/get.test.ts +++ b/src/routes/devices/get.test.ts @@ -24,9 +24,13 @@ beforeEach(() => { describe('guid get', () => { const req = { + tenantId: 'tenantxyz', params: { guid: '00000000-0000-0000-0000-000000000000' }, + query: { + tenantId: '' + }, db: { devices: { getById: () => {} @@ -35,8 +39,14 @@ describe('guid get', () => { } as any const logSpy = jest.spyOn(logger, 'error') - it('should set status to 200 and get result if device exists in DB', async () => { - req.db.devices.getById = jest.fn().mockReturnValue({}) + it('should set status to 200 and get result if device exists in DB with tenant', async () => { + req.db.devices.getById = jest.fn().mockReturnValue({ + guid: '00000000-0000-0000-0000-000000000000', + hostname: 'hostname', + tags: [], + mpsusername: 'admin', + tenantId: 'tenantxyz' + }) await getDevice(req, res as any) expect(req.db.devices.getById).toHaveBeenCalledWith(req.params.guid) expect(statusSpy).toHaveBeenCalledWith(200) @@ -44,6 +54,15 @@ describe('guid get', () => { expect(endSpy).toHaveBeenCalled() }) + it('should set status to 204 and get result if device exists in DB', async () => { + req.db.devices.getById = jest.fn().mockReturnValue({}) + await getDevice(req, res as any) + expect(req.db.devices.getById).toHaveBeenCalledWith(req.params.guid) + expect(statusSpy).toHaveBeenCalledWith(204) + expect(jsonSpy).not.toHaveBeenCalledWith(null) + expect(endSpy).toHaveBeenCalled() + }) + it('should set status to 404 if device does not exist in DB', async () => { req.db.devices.getById = jest.fn().mockReturnValue(null) await getDevice(req, res as any) @@ -64,4 +83,23 @@ describe('guid get', () => { expect(endSpy).toHaveBeenCalled() expect(logSpy).toHaveBeenCalled() }) + + it('should set status to 204 and get tenantId from req.query', async () => { + req.tenantId = '' + req.query.tenantId = 'test' + + req.db.devices.getById = jest.fn().mockReturnValue({ + guid: '00000000-0000-0000-0000-000000000000', + hostname: 'hostname', + tags: [], + mpsusername: 'admin', + tenantId: 'tenantxyz' + }) + await getDevice(req, res as any) + expect(req.db.devices.getById).toHaveBeenCalledWith(req.params.guid) + expect(statusSpy).toHaveBeenCalledWith(204) + expect(jsonSpy).not.toHaveBeenCalledWith(null) + expect(endSpy).toHaveBeenCalled() + }) + }) diff --git a/src/routes/devices/get.ts b/src/routes/devices/get.ts index b1e26caf6..24dc4c557 100644 --- a/src/routes/devices/get.ts +++ b/src/routes/devices/get.ts @@ -8,9 +8,18 @@ import { type Request, type Response } from 'express' export async function getDevice (req: Request, res: Response): Promise { try { - const results = await req.db.devices.getById(req.params.guid) - if (results != null) { - res.status(200).json(results).end() + let tenantId = req.tenantId + const tentantIdInQuery = req.query?.tenantId + if ((tenantId == null || tenantId === '') && (tentantIdInQuery != null || tentantIdInQuery !== '')) { + tenantId = tentantIdInQuery as string + } + const result = await req.db.devices.getById(req.params.guid) + if (result != null) { + if (result.tenantId === tenantId) { + res.status(200).json(result).end() + } else { + res.status(204).end() + } } else { res.status(404).end() } diff --git a/src/routes/devices/getAll.test.ts b/src/routes/devices/getAll.test.ts index 44a1b2783..88b6dcad0 100644 --- a/src/routes/devices/getAll.test.ts +++ b/src/routes/devices/getAll.test.ts @@ -42,6 +42,7 @@ describe('getAll', () => { $skip: 0, status: false }, + tenantId: '', db: { devices: { @@ -52,7 +53,7 @@ describe('getAll', () => { } await getAllDevices(req as any, res as any) const tags = req.query.tags.split(',') - expect(req.db.devices.getByTags).toHaveBeenCalledWith(tags, req.query.method, req.query.$top, req.query.$skip) + expect(req.db.devices.getByTags).toHaveBeenCalledWith(tags, req.query.method, req.query.$top, req.query.$skip, req.tenantId) expect(statusSpy).toHaveBeenCalledWith(200) }) @@ -67,6 +68,7 @@ describe('getAll', () => { $skip: 0, status: null }, + tenantId: '', db: { devices: { @@ -75,7 +77,7 @@ describe('getAll', () => { } } await getAllDevices(req as any, res as any) - expect(req.db.devices.get).toHaveBeenCalledWith(req.query.$top, req.query.$skip) + expect(req.db.devices.get).toHaveBeenCalledWith(req.query.$top, req.query.$skip, req.tenantId) expect(statusSpy).toHaveBeenCalledWith(200) expect(jsonSpy).toHaveBeenCalledWith(deviceList) }) @@ -110,6 +112,7 @@ describe('getAll', () => { query: { hostname: 'test' }, + tenantId: '', db: { devices: { getById: () => {} @@ -121,7 +124,7 @@ describe('getAll', () => { it('should set status to 200 and get result if device exists in DB', async () => { req.db.devices.getByHostname = jest.fn().mockReturnValue([{}]) await getAllDevices(req, res as any) - expect(req.db.devices.getByHostname).toHaveBeenCalledWith(req.query.hostname) + expect(req.db.devices.getByHostname).toHaveBeenCalledWith(req.query.hostname, req.tenantId) expect(statusSpy).toHaveBeenCalledWith(200) expect(jsonSpy).toHaveBeenCalledWith([{}]) expect(endSpy).toHaveBeenCalled() @@ -130,7 +133,7 @@ describe('getAll', () => { it('should set status to 404 if device does not exist in DB', async () => { req.db.devices.getByHostname = jest.fn().mockReturnValue([]) await getAllDevices(req, res as any) - expect(req.db.devices.getByHostname).toHaveBeenCalledWith(req.query.hostname) + expect(req.db.devices.getByHostname).toHaveBeenCalledWith(req.query.hostname, req.tenantId) expect(statusSpy).toHaveBeenCalledWith(200) expect(jsonSpy).toHaveBeenCalledWith([]) expect(endSpy).toHaveBeenCalled() @@ -141,7 +144,7 @@ describe('getAll', () => { throw new TypeError('fake error') }) await getAllDevices(req, res as any) - expect(req.db.devices.getByHostname).toHaveBeenCalledWith(req.query.hostname) + expect(req.db.devices.getByHostname).toHaveBeenCalledWith(req.query.hostname, req.tenantId) expect(statusSpy).toHaveBeenCalledWith(500) expect(jsonSpy).not.toHaveBeenCalled() expect(endSpy).toHaveBeenCalled() diff --git a/src/routes/devices/getAll.ts b/src/routes/devices/getAll.ts index 8594798b9..75664082d 100644 --- a/src/routes/devices/getAll.ts +++ b/src/routes/devices/getAll.ts @@ -14,12 +14,12 @@ export async function getAllDevices (req: Request, res: Response): Promise let list: Device[] = [] if (req.query.hostname != null) { - list = await req.db.devices.getByHostname(req.query.hostname as string) + list = await req.db.devices.getByHostname(req.query.hostname as string, req.tenantId) } else if (req.query.tags != null) { const tags = (req.query.tags as string).split(',') - list = await req.db.devices.getByTags(tags, req.query.method as string, req.query.$top as any, req.query.$skip as any) + list = await req.db.devices.getByTags(tags, req.query.method as string, req.query.$top as any, req.query.$skip as any, req.tenantId) } else { - list = await req.db.devices.get(req.query.$top as any, req.query.$skip as any) + list = await req.db.devices.get(req.query.$top as any, req.query.$skip as any, req.tenantId) } if (req.query.status != null) { list = list.filter(x => { @@ -28,7 +28,7 @@ export async function getAllDevices (req: Request, res: Response): Promise }) } if (count != null && count) { - const count: number = await req.db.devices.getCount() + const count: number = await req.db.devices.getCount(req.tenantId) const dataWithCount: DataWithCount = { data: list, totalCount: count diff --git a/src/routes/devices/stats.ts b/src/routes/devices/stats.ts index 3f1b3d672..466717c18 100644 --- a/src/routes/devices/stats.ts +++ b/src/routes/devices/stats.ts @@ -9,8 +9,8 @@ import { messages } from '../../logging/messages' export async function stats (req: Request, res: Response): Promise { try { - const connectedCount = await req.db.devices.getConnectedDevices() - const totalCount = await req.db.devices.getCount() + const connectedCount = await req.db.devices.getConnectedDevices(req.tenantId) + const totalCount = await req.db.devices.getCount(req.tenantId) res.json({ totalCount, connectedCount, diff --git a/src/routes/devices/tags.ts b/src/routes/devices/tags.ts index e0f8edeaa..2d5fec3c1 100644 --- a/src/routes/devices/tags.ts +++ b/src/routes/devices/tags.ts @@ -8,7 +8,7 @@ import { type Request, type Response } from 'express' export async function getDistinctTags (req: Request, res: Response): Promise { try { - const results = await req.db.devices.getDistinctTags() + const results = await req.db.devices.getDistinctTags(req.tenantId) if (results != null) { res.status(200).json(results).end() } else { diff --git a/src/routes/devices/update.ts b/src/routes/devices/update.ts index 9a5ea87e4..138457249 100644 --- a/src/routes/devices/update.ts +++ b/src/routes/devices/update.ts @@ -10,12 +10,11 @@ import { type Request, type Response } from 'express' export async function updateDevice (req: Request, res: Response): Promise { const guid: string = req.body.guid try { - let device = await req.db.devices.getById(guid) + let device = await req.db.devices.getById(guid, req.tenantId) if (device == null) { res.status(404).json({ error: 'NOT FOUND', message: `Device ID ${guid} not found` }).end() } else { device = { ...device, ...req.body } - device.tenantId = '' // ensure from token and not overwritten const results = await req.db.devices.update(device) res.status(200).json(results).end() } diff --git a/src/server/mpsserver.ts b/src/server/mpsserver.ts index b604af23a..4e8cf692d 100644 --- a/src/server/mpsserver.ts +++ b/src/server/mpsserver.ts @@ -108,7 +108,7 @@ export class MPSServer { logger.debug(`${messages.MPS_CIRA_AUTHENTICATION_SUCCESS} for: ${username}`) const cred = await this.secrets.getAMTCredentials(socket.tag.SystemId) - devices[socket.tag.SystemId] = new ConnectedDevice(socket, cred[0], cred[1]) + devices[socket.tag.SystemId] = new ConnectedDevice(socket, cred[0], cred[1], device.tenantId) this.events.emit('connected', socket.tag.SystemId) await this.handleDeviceConnect(socket.tag.SystemId) APFProcessor.SendUserAuthSuccess(socket) // Notify the auth success on the CIRA connection diff --git a/src/server/webserver.ts b/src/server/webserver.ts index f796a7811..d5f8ac047 100644 --- a/src/server/webserver.ts +++ b/src/server/webserver.ts @@ -142,6 +142,8 @@ export class WebServer { async useAPIv1 (req: Request, res: Response, next: NextFunction): Promise { const newDB = new DbCreatorFactory() + console.log(req.headers) + req.db = await newDB.getDb() req.secrets = this.secrets req.certs = this.certs diff --git a/src/test/collections/MPS.postman_collection.json b/src/test/collections/MPS.postman_collection.json index 345754320..1c700c5fa 100644 --- a/src/test/collections/MPS.postman_collection.json +++ b/src/test/collections/MPS.postman_collection.json @@ -362,18 +362,9 @@ "listen": "test", "script": { "exec": [ - "pm.test(\"Status code is 200\", function () {\r", - " pm.response.to.have.status(200);\r", - "});\r", - "\r", - "pm.test(\"Expect to return device info\",function(){\r", - " var jsonData = pm.response.json();\r", - " pm.expect(jsonData.guid).to.be.equal(\"143e4567-e89b-12d3-a456-426614174000\")\r", - " pm.expect(jsonData.hostname).to.be.equal(\"hostname\")\r", - " pm.expect(jsonData.tags.length).to.be.equal(0) \r", - " pm.expect(jsonData.mpsInstance).to.be.equal(null)\r", - " pm.expect(jsonData.connectionStatus).to.be.equal(false)\r", - "})" + "pm.test(\"Status code is 204\", function () {\r", + " pm.response.to.have.status(204);\r", + "});\r" ], "type": "text/javascript" } diff --git a/src/test/helper/config.ts b/src/test/helper/config.ts index 456ea2618..6da3a69e1 100644 --- a/src/test/helper/config.ts +++ b/src/test/helper/config.ts @@ -29,6 +29,8 @@ export const config: configType = { db_provider: 'postgres', connection_string: 'postgresql://:@localhost:5432/mpsdb?sslmode=no-verify', instance_name: 'localhost', + jwt_token_header: '', + jwt_tenant_property: '', mps_tls_config: { key: '../private/mpsserver-cert-private.key', cert: '../private/mpsserver-cert-public.crt', diff --git a/src/utils/wsRedirect.test.ts b/src/utils/wsRedirect.test.ts index 4def968cf..435779215 100644 --- a/src/utils/wsRedirect.test.ts +++ b/src/utils/wsRedirect.test.ts @@ -45,7 +45,7 @@ describe('WsRedirect tests', () => { url: `https://iotg.com?tls=0&host=${fakeGuid}` } - devices[fakeGuid] = new ConnectedDevice(null, 'admin', 'P@ssw0rd') + devices[fakeGuid] = new ConnectedDevice(null, 'admin', 'P@ssw0rd', '') const setNormalTCPSpy = jest.spyOn(wsRedirect, 'setNormalTCP').mockReturnValue() const publishEventSpy = jest.spyOn(MqttProvider, 'publishEvent')