diff --git a/federation/package.json b/federation/package.json index 10ad9ea5f..7ceaa1f1e 100644 --- a/federation/package.json +++ b/federation/package.json @@ -15,7 +15,6 @@ "lint": "eslint --max-warnings=0 --ext .js,.ts ." }, "dependencies": { - "@hyperswarm/dht": "^6.3.3", "@types/dotenv": "^8.2.0", "@types/i18n": "^0.13.6", "@types/jsonwebtoken": "^8.5.9", @@ -28,7 +27,7 @@ "dotenv": "10.0.0", "express": "4.17.1", "graphql": "15.5.1", - "i18n": "^0.15.1", + "i18n": "0.15.1", "jsonwebtoken": "^8.5.1", "lodash.clonedeep": "^4.5.0", "log4js": "^6.7.1", diff --git a/federation/src/config/index.ts b/federation/src/config/index.ts index 571ca3bd7..068ffb76a 100644 --- a/federation/src/config/index.ts +++ b/federation/src/config/index.ts @@ -12,7 +12,7 @@ Decimal.set({ const constants = { DB_VERSION: '0058-add_communities_table', - DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 + // DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info LOG_LEVEL: process.env.LOG_LEVEL || 'info', @@ -73,7 +73,7 @@ if ( } const federation = { - FEDERATION_DHT_TOPIC: process.env.FEDERATION_DHT_TOPIC || null, + // FEDERATION_DHT_TOPIC: process.env.FEDERATION_DHT_TOPIC || null, FEDERATION_DHT_SEED: process.env.FEDERATION_DHT_SEED || null, FEDERATION_PORT: process.env.FEDERATION_PORT || 5000, FEDERATION_API: process.env.FEDERATION_API || '1_0', @@ -84,11 +84,7 @@ const CONFIG = { ...constants, ...server, ...database, - //...klicktipp, ...community, - //...email, - //...loginServer, - //...webhook, //...eventProtocol, ...federation, } diff --git a/federation/src/dht_node/@types/@hyperswarm__dht/index.d.ts b/federation/src/dht_node/@types/@hyperswarm__dht/index.d.ts deleted file mode 100644 index efb9ad438..000000000 --- a/federation/src/dht_node/@types/@hyperswarm__dht/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module '@hyperswarm/dht' diff --git a/federation/src/dht_node/index.test.ts b/federation/src/dht_node/index.test.ts deleted file mode 100644 index 235206cf8..000000000 --- a/federation/src/dht_node/index.test.ts +++ /dev/null @@ -1,798 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ - -import { startDHT } from './index' -import DHT from '@hyperswarm/dht' -import CONFIG from '@/config' -import { logger } from '@test/testSetup' -import { Community as DbCommunity } from '@entity/Community' -import { testEnvironment, cleanDB } from '@test/helpers' - -CONFIG.FEDERATION_DHT_SEED = '64ebcb0e3ad547848fef4197c6e2332f' - -jest.mock('@hyperswarm/dht') - -const TEST_TOPIC = 'gradido_test_topic' - -const keyPairMock = { - publicKey: Buffer.from('publicKey'), - secretKey: Buffer.from('secretKey'), -} - -const serverListenSpy = jest.fn() - -const serverEventMocks: { [key: string]: any } = {} - -const serverOnMock = jest.fn().mockImplementation((key: string, callback) => { - serverEventMocks[key] = callback -}) - -const nodeCreateServerMock = jest.fn().mockImplementation(() => { - return { - on: serverOnMock, - listen: serverListenSpy, - } -}) - -const nodeAnnounceMock = jest.fn().mockImplementation(() => { - return { - finished: jest.fn(), - } -}) - -const lookupResultMock = { - token: Buffer.from(TEST_TOPIC), - from: { - id: Buffer.from('somone'), - host: '188.95.53.5', - port: 63561, - }, - to: { id: null, host: '83.53.31.27', port: 55723 }, - peers: [ - { - publicKey: Buffer.from('some-public-key'), - relayAddresses: [], - }, - ], -} - -const nodeLookupMock = jest.fn().mockResolvedValue([lookupResultMock]) - -const socketEventMocks: { [key: string]: any } = {} - -const socketOnMock = jest.fn().mockImplementation((key: string, callback) => { - socketEventMocks[key] = callback -}) - -const socketWriteMock = jest.fn() - -const nodeConnectMock = jest.fn().mockImplementation(() => { - return { - on: socketOnMock, - once: socketOnMock, - write: socketWriteMock, - } -}) - -DHT.hash.mockImplementation(() => { - return Buffer.from(TEST_TOPIC) -}) - -DHT.keyPair.mockImplementation(() => { - return keyPairMock -}) - -DHT.mockImplementation(() => { - return { - createServer: nodeCreateServerMock, - announce: nodeAnnounceMock, - lookup: nodeLookupMock, - connect: nodeConnectMock, - } -}) - -let con: any -let testEnv: any - -beforeAll(async () => { - testEnv = await testEnvironment(logger) - con = testEnv.con - await cleanDB() -}) - -afterAll(async () => { - await cleanDB() - await con.close() -}) - -describe('federation', () => { - beforeAll(() => { - jest.useFakeTimers() - }) - - describe('call startDHT', () => { - const hashSpy = jest.spyOn(DHT, 'hash') - const keyPairSpy = jest.spyOn(DHT, 'keyPair') - beforeEach(async () => { - DHT.mockClear() - jest.clearAllMocks() - await startDHT(TEST_TOPIC) - }) - - it('calls DHT.hash', () => { - expect(hashSpy).toBeCalledWith(Buffer.from(TEST_TOPIC)) - }) - - it('creates a key pair', () => { - expect(keyPairSpy).toBeCalledWith(expect.any(Buffer)) - }) - - it('initializes a new DHT object', () => { - expect(DHT).toBeCalledWith({ keyPair: keyPairMock }) - }) - - describe('DHT node', () => { - it('creates a server', () => { - expect(nodeCreateServerMock).toBeCalled() - }) - - it('listens on the server', () => { - expect(serverListenSpy).toBeCalled() - }) - - describe('timers', () => { - beforeEach(() => { - jest.runOnlyPendingTimers() - }) - - it('announces on topic', () => { - expect(nodeAnnounceMock).toBeCalledWith(Buffer.from(TEST_TOPIC), keyPairMock) - }) - - it('looks up on topic', () => { - expect(nodeLookupMock).toBeCalledWith(Buffer.from(TEST_TOPIC)) - }) - }) - - describe('server connection event', () => { - beforeEach(() => { - serverEventMocks.connection({ - remotePublicKey: Buffer.from('another-public-key'), - on: socketOnMock, - }) - }) - - it('can be triggered', () => { - expect(socketOnMock).toBeCalled() - }) - - describe('socket events', () => { - describe('on data', () => { - describe('with receiving simply a string', () => { - beforeEach(() => { - jest.clearAllMocks() - socketEventMocks.data(Buffer.from('no-json string')) - }) - - it('logs the received data', () => { - expect(logger.info).toBeCalledWith('data: no-json string') - }) - - it('logs an error of unexpected data format and structure', () => { - expect(logger.error).toBeCalledWith( - 'Error on receiving data from socket:', - new SyntaxError('Unexpected token o in JSON at position 1'), - ) - }) - }) - - describe('with receiving array of strings', () => { - beforeEach(() => { - jest.clearAllMocks() - const strArray: string[] = ['invalid type test', 'api', 'url'] - socketEventMocks.data(Buffer.from(strArray.toString())) - }) - - it('logs the received data', () => { - expect(logger.info).toBeCalledWith('data: invalid type test,api,url') - }) - - it('logs an error of unexpected data format and structure', () => { - expect(logger.error).toBeCalledWith( - 'Error on receiving data from socket:', - new SyntaxError('Unexpected token i in JSON at position 0'), - ) - }) - }) - - describe('with receiving array of string-arrays', () => { - beforeEach(async () => { - jest.clearAllMocks() - const strArray: string[][] = [ - [`api`, `url`, `invalid type in array test`], - [`wrong`, `api`, `url`], - ] - await socketEventMocks.data(Buffer.from(strArray.toString())) - }) - - it('logs the received data', () => { - expect(logger.info).toBeCalledWith( - 'data: api,url,invalid type in array test,wrong,api,url', - ) - }) - - it('logs an error of unexpected data format and structure', () => { - expect(logger.error).toBeCalledWith( - 'Error on receiving data from socket:', - new SyntaxError('Unexpected token a in JSON at position 0'), - ) - }) - }) - - describe('with receiving JSON-Array with too much entries', () => { - let jsonArray: { api: string; url: string }[] - beforeEach(async () => { - jest.clearAllMocks() - jsonArray = [ - { api: 'v1_0', url: 'too much versions at the same time test' }, - { api: 'v1_0', url: 'url2' }, - { api: 'v1_0', url: 'url3' }, - { api: 'v1_0', url: 'url4' }, - { api: 'v1_0', url: 'url5' }, - ] - await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - }) - - it('logs the received data', () => { - expect(logger.info).toBeCalledWith( - 'data: [{"api":"v1_0","url":"too much versions at the same time test"},{"api":"v1_0","url":"url2"},{"api":"v1_0","url":"url3"},{"api":"v1_0","url":"url4"},{"api":"v1_0","url":"url5"}]', - ) - }) - - it('logs a warning of too much apiVersion-Definitions', () => { - expect(logger.warn).toBeCalledWith( - `received totaly wrong or too much apiVersions-Definition JSON-String: ${JSON.stringify( - jsonArray, - )}`, - ) - }) - }) - - describe('with receiving wrong but tolerated property data', () => { - let jsonArray: any[] - let result: DbCommunity[] = [] - beforeAll(async () => { - jest.clearAllMocks() - jsonArray = [ - { - wrong: 'wrong but tolerated property test', - api: 'v1_0', - url: 'url1', - }, - { - api: 'v2_0', - url: 'url2', - wrong: 'wrong but tolerated property test', - }, - ] - await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - result = await DbCommunity.find() - }) - - afterAll(async () => { - await cleanDB() - }) - - it('has two Communty entries in database', () => { - expect(result).toHaveLength(2) - }) - - it('has an entry for api version v1_0', () => { - expect(result).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - publicKey: expect.any(Buffer), - apiVersion: 'v1_0', - endPoint: 'url1', - lastAnnouncedAt: expect.any(Date), - createdAt: expect.any(Date), - updatedAt: null, - }), - ]), - ) - }) - - it('has an entry for api version v2_0', () => { - expect(result).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - publicKey: expect.any(Buffer), - apiVersion: 'v2_0', - endPoint: 'url2', - lastAnnouncedAt: expect.any(Date), - createdAt: expect.any(Date), - updatedAt: null, - }), - ]), - ) - }) - }) - - describe('with receiving data but missing api property', () => { - let jsonArray: any[] - beforeEach(async () => { - jest.clearAllMocks() - jsonArray = [ - { test1: 'missing api proterty test', url: 'any url definition as string' }, - { api: 'some api', test2: 'missing url property test' }, - ] - await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - }) - - it('logs the received data', () => { - expect(logger.info).toBeCalledWith(`data: ${JSON.stringify(jsonArray)}`) - }) - - it('logs a warning of invalid apiVersion-Definition', () => { - expect(logger.warn).toBeCalledWith( - `received invalid apiVersion-Definition: ${JSON.stringify(jsonArray[0])}`, - ) - }) - }) - - describe('with receiving data but missing url property', () => { - let jsonArray: any[] - beforeEach(async () => { - jest.clearAllMocks() - jsonArray = [ - { api: 'some api', test2: 'missing url property test' }, - { test1: 'missing api proterty test', url: 'any url definition as string' }, - ] - await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - }) - - it('logs the received data', () => { - expect(logger.info).toBeCalledWith(`data: ${JSON.stringify(jsonArray)}`) - }) - - it('logs a warning of invalid apiVersion-Definition', () => { - expect(logger.warn).toBeCalledWith( - `received invalid apiVersion-Definition: ${JSON.stringify(jsonArray[0])}`, - ) - }) - }) - - describe('with receiving data but wrong type of api property', () => { - let jsonArray: any[] - beforeEach(async () => { - jest.clearAllMocks() - jsonArray = [ - { api: 1, url: 'wrong property type tests' }, - { api: 'urltyptest', url: 2 }, - { api: 1, url: 2 }, - ] - await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - }) - - it('logs the received data', () => { - expect(logger.info).toBeCalledWith(`data: ${JSON.stringify(jsonArray)}`) - }) - - it('logs a warning of invalid apiVersion-Definition', () => { - expect(logger.warn).toBeCalledWith( - `received invalid apiVersion-Definition: ${JSON.stringify(jsonArray[0])}`, - ) - }) - }) - - describe('with receiving data but wrong type of url property', () => { - let jsonArray: any[] - beforeEach(async () => { - jest.clearAllMocks() - jsonArray = [ - { api: 'urltyptest', url: 2 }, - { api: 1, url: 'wrong property type tests' }, - { api: 1, url: 2 }, - ] - await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - }) - - it('logs the received data', () => { - expect(logger.info).toBeCalledWith(`data: ${JSON.stringify(jsonArray)}`) - }) - - it('logs a warning of invalid apiVersion-Definition', () => { - expect(logger.warn).toBeCalledWith( - `received invalid apiVersion-Definition: ${JSON.stringify(jsonArray[0])}`, - ) - }) - }) - - describe('with receiving data but wrong type of both properties', () => { - let jsonArray: any[] - beforeEach(async () => { - jest.clearAllMocks() - jsonArray = [ - { api: 1, url: 2 }, - { api: 'urltyptest', url: 2 }, - { api: 1, url: 'wrong property type tests' }, - ] - await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - }) - - it('logs the received data', () => { - expect(logger.info).toBeCalledWith(`data: ${JSON.stringify(jsonArray)}`) - }) - - it('logs a warning of invalid apiVersion-Definition', () => { - expect(logger.warn).toBeCalledWith( - `received invalid apiVersion-Definition: ${JSON.stringify(jsonArray[0])}`, - ) - }) - }) - - describe('with receiving data but too long api string', () => { - let jsonArray: any[] - beforeEach(async () => { - jest.clearAllMocks() - jsonArray = [ - { api: 'toolong api', url: 'some valid url' }, - { - api: 'valid api', - url: 'this is a too long url definition with exact one character more than the allowed two hundert and fiftyfive characters. and here begins the fill characters with no sense of content menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmic', - }, - { - api: 'toolong api', - url: 'this is a too long url definition with exact one character more than the allowed two hundert and fiftyfive characters. and here begins the fill characters with no sense of content menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmic', - }, - ] - await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - }) - - it('logs the received data', () => { - expect(logger.info).toBeCalledWith(`data: ${JSON.stringify(jsonArray)}`) - }) - - it('logs a warning of invalid apiVersion-Definition', () => { - expect(logger.warn).toBeCalledWith( - `received apiVersion with content longer than max length: ${JSON.stringify( - jsonArray[0], - )}`, - ) - }) - }) - - describe('with receiving data but too long url string', () => { - let jsonArray: any[] - beforeEach(async () => { - jest.clearAllMocks() - jsonArray = [ - { - api: 'api', - url: 'this is a too long url definition with exact one character more than the allowed two hundert and fiftyfive characters. and here begins the fill characters with no sense of content menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmic', - }, - { api: 'toolong api', url: 'some valid url' }, - { - api: 'toolong api', - url: 'this is a too long url definition with exact one character more than the allowed two hundert and fiftyfive characters. and here begins the fill characters with no sense of content menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmic', - }, - ] - await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - }) - - it('logs the received data', () => { - expect(logger.info).toBeCalledWith(`data: ${JSON.stringify(jsonArray)}`) - }) - - it('logs a warning of invalid apiVersion-Definition', () => { - expect(logger.warn).toBeCalledWith( - `received apiVersion with content longer than max length: ${JSON.stringify( - jsonArray[0], - )}`, - ) - }) - }) - - describe('with receiving data but both properties with too long strings', () => { - let jsonArray: any[] - beforeEach(async () => { - jest.clearAllMocks() - jsonArray = [ - { - api: 'toolong api', - url: 'this is a too long url definition with exact one character more than the allowed two hundert and fiftyfive characters. and here begins the fill characters with no sense of content menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmic', - }, - { - api: 'api', - url: 'this is a too long url definition with exact one character more than the allowed two hundert and fiftyfive characters. and here begins the fill characters with no sense of content menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmic', - }, - { api: 'toolong api', url: 'some valid url' }, - ] - await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - }) - - it('logs the received data', () => { - expect(logger.info).toBeCalledWith(`data: ${JSON.stringify(jsonArray)}`) - }) - }) - - describe('with receiving data of exact max allowed properties length', () => { - let jsonArray: any[] - let result: DbCommunity[] = [] - beforeAll(async () => { - jest.clearAllMocks() - jsonArray = [ - { - api: 'valid api', - url: 'this is a valid url definition with exact the max allowed length of two hundert and fiftyfive characters. and here begins the fill characters with no sense of content kuhwarmiga menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmich', - }, - { - api: 'api', - url: 'this is a too long url definition with exact one character more than the allowed two hundert and fiftyfive characters. and here begins the fill characters with no sense of content menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmic', - }, - { api: 'toolong api', url: 'some valid url' }, - ] - await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - result = await DbCommunity.find() - }) - - afterAll(async () => { - await cleanDB() - }) - - it('has one Communty entry in database', () => { - expect(result).toHaveLength(1) - }) - - it(`has an entry with max content length for api and url`, () => { - expect(result).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - publicKey: expect.any(Buffer), - apiVersion: 'valid api', - endPoint: - 'this is a valid url definition with exact the max allowed length of two hundert and fiftyfive characters. and here begins the fill characters with no sense of content kuhwarmiga menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmich', - lastAnnouncedAt: expect.any(Date), - createdAt: expect.any(Date), - updatedAt: null, - }), - ]), - ) - }) - }) - - describe('with receiving data of exact max allowed buffer length', () => { - let jsonArray: any[] - let result: DbCommunity[] = [] - beforeAll(async () => { - jest.clearAllMocks() - jsonArray = [ - { - api: 'valid api1', - url: 'this is a valid url definition with exact the max allowed length of two hundert and fiftyfive characters. and here begins the fill characters with no sense of content kuhwarmiga menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmich', - }, - { - api: 'valid api2', - url: 'this is a valid url definition with exact the max allowed length of two hundert and fiftyfive characters. and here begins the fill characters with no sense of content kuhwarmiga menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmich', - }, - { - api: 'valid api3', - url: 'this is a valid url definition with exact the max allowed length of two hundert and fiftyfive characters. and here begins the fill characters with no sense of content kuhwarmiga menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmich', - }, - { - api: 'valid api4', - url: 'this is a valid url definition with exact the max allowed length of two hundert and fiftyfive characters. and here begins the fill characters with no sense of content kuhwarmiga menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmich', - }, - ] - await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - result = await DbCommunity.find() - }) - - afterAll(async () => { - await cleanDB() - }) - - it('has five Communty entries in database', () => { - expect(result).toHaveLength(4) - }) - - it(`has an entry 'valid api1' with max content length for api and url`, () => { - expect(result).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - publicKey: expect.any(Buffer), - apiVersion: 'valid api1', - endPoint: - 'this is a valid url definition with exact the max allowed length of two hundert and fiftyfive characters. and here begins the fill characters with no sense of content kuhwarmiga menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmich', - lastAnnouncedAt: expect.any(Date), - createdAt: expect.any(Date), - updatedAt: null, - }), - ]), - ) - }) - - it(`has an entry 'valid api2' with max content length for api and url`, () => { - expect(result).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - publicKey: expect.any(Buffer), - apiVersion: 'valid api2', - endPoint: - 'this is a valid url definition with exact the max allowed length of two hundert and fiftyfive characters. and here begins the fill characters with no sense of content kuhwarmiga menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmich', - lastAnnouncedAt: expect.any(Date), - createdAt: expect.any(Date), - updatedAt: null, - }), - ]), - ) - }) - - it(`has an entry 'valid api3' with max content length for api and url`, () => { - expect(result).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - publicKey: expect.any(Buffer), - apiVersion: 'valid api3', - endPoint: - 'this is a valid url definition with exact the max allowed length of two hundert and fiftyfive characters. and here begins the fill characters with no sense of content kuhwarmiga menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmich', - lastAnnouncedAt: expect.any(Date), - createdAt: expect.any(Date), - updatedAt: null, - }), - ]), - ) - }) - - it(`has an entry 'valid api4' with max content length for api and url`, () => { - expect(result).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - publicKey: expect.any(Buffer), - apiVersion: 'valid api4', - endPoint: - 'this is a valid url definition with exact the max allowed length of two hundert and fiftyfive characters. and here begins the fill characters with no sense of content kuhwarmiga menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmich', - lastAnnouncedAt: expect.any(Date), - createdAt: expect.any(Date), - updatedAt: null, - }), - ]), - ) - }) - }) - - describe('with receiving data longer than max allowed buffer length', () => { - let jsonArray: any[] - beforeEach(async () => { - jest.clearAllMocks() - jsonArray = [ - { - api: 'Xvalid api1', - url: 'this is a valid url definition with exact the max allowed length of two hundert and fiftyfive characters. and here begins the fill characters with no sense of content kuhwarmiga menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmich', - }, - { - api: 'valid api2', - url: 'this is a valid url definition with exact the max allowed length of two hundert and fiftyfive characters. and here begins the fill characters with no sense of content kuhwarmiga menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmich', - }, - { - api: 'valid api3', - url: 'this is a valid url definition with exact the max allowed length of two hundert and fiftyfive characters. and here begins the fill characters with no sense of content kuhwarmiga menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmich', - }, - { - api: 'valid api4', - url: 'this is a valid url definition with exact the max allowed length of two hundert and fiftyfive characters. and here begins the fill characters with no sense of content kuhwarmiga menschhabicheinhungerdassichnichtweiswoichheutnachtschlafensollsofriertesmich', - }, - ] - await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - }) - - it('logs the received data', () => { - expect(logger.warn).toBeCalledWith( - `received more than max allowed length of data buffer: ${ - JSON.stringify(jsonArray).length - } against 1141 max allowed`, - ) - }) - }) - - describe('with proper data', () => { - let result: DbCommunity[] = [] - beforeAll(async () => { - jest.clearAllMocks() - await socketEventMocks.data( - Buffer.from( - JSON.stringify([ - { - api: 'v1_0', - url: 'http://localhost:4000/api/v1_0', - }, - { - api: 'v2_0', - url: 'http://localhost:4000/api/v2_0', - }, - ]), - ), - ) - result = await DbCommunity.find() - }) - - afterAll(async () => { - await cleanDB() - }) - - it('has two Communty entries in database', () => { - expect(result).toHaveLength(2) - }) - - it('has an entry for api version v1_0', () => { - expect(result).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - publicKey: expect.any(Buffer), - apiVersion: 'v1_0', - endPoint: 'http://localhost:4000/api/v1_0', - lastAnnouncedAt: expect.any(Date), - createdAt: expect.any(Date), - updatedAt: null, - }), - ]), - ) - }) - - it('has an entry for api version v2_0', () => { - expect(result).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - publicKey: expect.any(Buffer), - apiVersion: 'v2_0', - endPoint: 'http://localhost:4000/api/v2_0', - lastAnnouncedAt: expect.any(Date), - createdAt: expect.any(Date), - updatedAt: null, - }), - ]), - ) - }) - }) - }) - - describe('on open', () => { - beforeEach(() => { - socketEventMocks.open() - }) - - it.skip('calls socket write with own api versions', () => { - expect(socketWriteMock).toBeCalledWith( - Buffer.from( - JSON.stringify([ - { - api: 'v1_0', - url: 'http://localhost:4000/api/v1_0', - }, - { - api: 'v1_1', - url: 'http://localhost:4000/api/v1_1', - }, - { - api: 'v2_0', - url: 'http://localhost:4000/api/v2_0', - }, - ]), - ), - ) - }) - }) - }) - }) - }) - }) -}) diff --git a/federation/src/dht_node/index.ts b/federation/src/dht_node/index.ts deleted file mode 100644 index 7b8095b54..000000000 --- a/federation/src/dht_node/index.ts +++ /dev/null @@ -1,185 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import DHT from '@hyperswarm/dht' -import { federationLogger as logger } from '@/server/logger' -import CONFIG from '@/config' -import { Community as DbCommunity } from '@entity/Community' - -const KEY_SECRET_SEEDBYTES = 32 -const getSeed = (): Buffer | null => - CONFIG.FEDERATION_DHT_SEED ? Buffer.alloc(KEY_SECRET_SEEDBYTES, CONFIG.FEDERATION_DHT_SEED) : null - -const POLLTIME = 20000 -const SUCCESSTIME = 120000 -const ERRORTIME = 240000 -const ANNOUNCETIME = 30000 - -enum ApiVersionType { - V1_0 = 'v1_0', - V1_1 = 'v1_1', - V2_0 = 'v2_0', -} -type CommunityApi = { - api: string - url: string -} - -export const startDHT = async (topic: string): Promise => { - try { - const TOPIC = DHT.hash(Buffer.from(topic)) - const keyPair = DHT.keyPair(getSeed()) - logger.info(`keyPairDHT: publicKey=${keyPair.publicKey.toString('hex')}`) - logger.debug(`keyPairDHT: secretKey=${keyPair.secretKey.toString('hex')}`) - - const ownApiVersions = Object.values(ApiVersionType).map(function (apiEnum) { - const comApi: CommunityApi = { - api: apiEnum, - url: CONFIG.FEDERATION_COMMUNITY_URL + apiEnum, - } - return comApi - }) - logger.debug(`ApiList: ${JSON.stringify(ownApiVersions)}`) - - const node = new DHT({ keyPair }) - - const server = node.createServer() - - server.on('connection', function (socket: any) { - logger.info(`server on... with Remote public key: ${socket.remotePublicKey.toString('hex')}`) - - socket.on('data', async (data: Buffer) => { - try { - if (data.length > 1141) { - logger.warn( - `received more than max allowed length of data buffer: ${data.length} against 1141 max allowed`, - ) - return - } - logger.info(`data: ${data.toString('ascii')}`) - const recApiVersions: CommunityApi[] = JSON.parse(data.toString('ascii')) - - // TODO better to introduce the validation by https://github.com/typestack/class-validato - if (recApiVersions && Array.isArray(recApiVersions) && recApiVersions.length < 5) { - for (const recApiVersion of recApiVersions) { - if ( - !recApiVersion.api || - typeof recApiVersion.api !== 'string' || - !recApiVersion.url || - typeof recApiVersion.url !== 'string' - ) { - logger.warn( - `received invalid apiVersion-Definition: ${JSON.stringify(recApiVersion)}`, - ) - // in a forEach-loop use return instead of continue - return - } - // TODO better to introduce the validation on entity-Level by https://github.com/typestack/class-validator - if (recApiVersion.api.length > 10 || recApiVersion.url.length > 255) { - logger.warn( - `received apiVersion with content longer than max length: ${JSON.stringify( - recApiVersion, - )}`, - ) - // in a forEach-loop use return instead of continue - return - } - - const variables = { - apiVersion: recApiVersion.api, - endPoint: recApiVersion.url, - publicKey: socket.remotePublicKey.toString('hex'), - lastAnnouncedAt: new Date(), - } - logger.debug(`upsert with variables=${JSON.stringify(variables)}`) - // this will NOT update the updatedAt column, to distingue between a normal update and the last announcement - await DbCommunity.createQueryBuilder() - .insert() - .into(DbCommunity) - .values(variables) - .orUpdate({ - conflict_target: ['id', 'publicKey', 'apiVersion'], - overwrite: ['end_point', 'last_announced_at'], - }) - .execute() - logger.info(`federation community upserted successfully...`) - } - } else { - logger.warn( - `received totaly wrong or too much apiVersions-Definition JSON-String: ${JSON.stringify( - recApiVersions, - )}`, - ) - } - } catch (e) { - logger.error('Error on receiving data from socket:', e) - } - }) - }) - - await server.listen() - - setInterval(async () => { - logger.info(`Announcing on topic: ${TOPIC.toString('hex')}`) - await node.announce(TOPIC, keyPair).finished() - }, ANNOUNCETIME) - - let successfulRequests: string[] = [] - let errorfulRequests: string[] = [] - - setInterval(async () => { - logger.info('Refreshing successful nodes') - successfulRequests = [] - }, SUCCESSTIME) - - setInterval(async () => { - logger.info('Refreshing errorful nodes') - errorfulRequests = [] - }, ERRORTIME) - - setInterval(async () => { - const result = await node.lookup(TOPIC) - - const collectedPubKeys: string[] = [] - - for await (const data of result) { - data.peers.forEach((peer: any) => { - const pubKey = peer.publicKey.toString('hex') - if ( - pubKey !== keyPair.publicKey.toString('hex') && - !successfulRequests.includes(pubKey) && - !errorfulRequests.includes(pubKey) && - !collectedPubKeys.includes(pubKey) - ) { - collectedPubKeys.push(peer.publicKey.toString('hex')) - } - }) - } - - logger.info(`Found new peers: ${collectedPubKeys}`) - - collectedPubKeys.forEach((remotePubKey) => { - const socket = node.connect(Buffer.from(remotePubKey, 'hex')) - - // socket.once("connect", function () { - // console.log("client side emitted connect"); - // }); - - // socket.once("end", function () { - // console.log("client side ended"); - // }); - - socket.once('error', (err: any) => { - errorfulRequests.push(remotePubKey) - logger.error(`error on peer ${remotePubKey}: ${err.message}`) - }) - - socket.on('open', function () { - socket.write(Buffer.from(JSON.stringify(ownApiVersions))) - successfulRequests.push(remotePubKey) - }) - }) - }, POLLTIME) - } catch (err) { - logger.error('DHT unexpected error:', err) - } -} diff --git a/federation/src/index.ts b/federation/src/index.ts index 0f791a5ec..32d191990 100644 --- a/federation/src/index.ts +++ b/federation/src/index.ts @@ -1,7 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import createServer from './server/createServer' -import { startDHT } from '@/dht_node/index' // config import CONFIG from './config' @@ -10,7 +9,6 @@ async function main() { // eslint-disable-next-line no-console console.log(`FEDERATION_PORT=${CONFIG.FEDERATION_PORT}`) console.log(`FEDERATION_API=${CONFIG.FEDERATION_API}`) - console.log(`configured: FEDERATION_DHT_TOPIC=${CONFIG.FEDERATION_DHT_TOPIC}`) const { app } = await createServer() app.listen(CONFIG.FEDERATION_PORT, () => { @@ -21,17 +19,6 @@ async function main() { console.log(`GraphIQL available at http://localhost:${CONFIG.FEDERATION_PORT}`) } }) - - // start DHT hyperswarm when DHT_TOPIC is set in .env - if (CONFIG.FEDERATION_DHT_TOPIC) { - // eslint-disable-next-line no-console - console.log( - `starting Federation on ${CONFIG.FEDERATION_DHT_TOPIC} ${ - CONFIG.FEDERATION_DHT_SEED ? 'with seed...' : 'without seed...' - }`, - ) - await startDHT(CONFIG.FEDERATION_DHT_TOPIC) // con, - } } main().catch((e) => { diff --git a/federation/src/server/logger.ts b/federation/src/server/logger.ts index 8af1389bc..d5f4f6b44 100644 --- a/federation/src/server/logger.ts +++ b/federation/src/server/logger.ts @@ -8,11 +8,7 @@ const options = JSON.parse(readFileSync(CONFIG.LOG4JS_CONFIG, 'utf-8')) options.categories.backend.level = CONFIG.LOG_LEVEL options.categories.apollo.level = CONFIG.LOG_LEVEL let filename: string = options.appenders.federation.filename -if(CONFIG.FEDERATION_DHT_TOPIC) { - options.appenders.federation.filename = filename.replace('apiversion-%v', 'dht-'+CONFIG.FEDERATION_DHT_TOPIC).replace('%p', CONFIG.FEDERATION_PORT.toString()) -} else { - options.appenders.federation.filename = filename.replace('%v', CONFIG.FEDERATION_API).replace('%p', CONFIG.FEDERATION_PORT.toString()) -} +options.appenders.federation.filename = filename.replace('%v', CONFIG.FEDERATION_API).replace('%p', CONFIG.FEDERATION_PORT.toString()) filename = options.appenders.access.filename options.appenders.access.filename = filename.replace('%p', CONFIG.FEDERATION_PORT.toString()) filename = options.appenders.apollo.filename diff --git a/federation/yarn.lock b/federation/yarn.lock index e35a5ac1b..33019912d 100644 --- a/federation/yarn.lock +++ b/federation/yarn.lock @@ -53,42 +53,6 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" -"@hyperswarm/dht@^6.3.3": - version "6.3.3" - resolved "https://registry.yarnpkg.com/@hyperswarm/dht/-/dht-6.3.3.tgz#a9266cb56549f74e2d5dea587aad00c483799ad6" - integrity sha512-2eGtS2i0Ij6zQL2IuDWzUbN6/c+NBpigBzRsH2/x2aA+8AJUO0IL3BaHECnO69T6WigCOMz+mp2exFkDjjGTRQ== - dependencies: - "@hyperswarm/secret-stream" "^6.0.0" - b4a "^1.3.1" - bogon "^1.0.0" - compact-encoding "^2.4.1" - compact-encoding-net "^1.0.1" - debugging-stream "^2.0.0" - dht-rpc "^6.3.0" - events "^3.3.0" - hypercore-crypto "^3.3.0" - noise-curve-ed "^2.0.0" - noise-handshake "^3.0.0" - record-cache "^1.1.1" - safety-catch "^1.0.1" - sodium-universal "^3.0.4" - udx-native "^1.5.1" - xache "^1.1.0" - -"@hyperswarm/secret-stream@^6.0.0": - version "6.1.0" - resolved "https://registry.yarnpkg.com/@hyperswarm/secret-stream/-/secret-stream-6.1.0.tgz#e99e6d449a0b1a571c42730841642da3356ea4da" - integrity sha512-6GjmdrYxZgJYGi8Ji7AZoqmmwQXSR9ByERkMPatcC5FMYgx9n5lDkwgKRK7faPQHpgtwjg2oLCrFveyGRLHV5g== - dependencies: - b4a "^1.1.0" - hypercore-crypto "^3.3.0" - noise-curve-ed "^2.0.0" - noise-handshake "^3.0.0" - sodium-secretstream "^1.0.0" - sodium-universal "^3.0.4" - streamx "^2.10.2" - timeout-refresh "^2.0.0" - "@josephg/resolvable@^1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/@josephg/resolvable/-/resolvable-1.0.1.tgz#69bc4db754d79e1a2f17a650d3466e038d94a5eb" @@ -657,11 +621,6 @@ async-retry@^1.2.1: dependencies: retry "0.13.1" -b4a@^1.0.1, b4a@^1.1.0, b4a@^1.1.1, b4a@^1.3.0, b4a@^1.3.1, b4a@^1.5.0: - version "1.6.1" - resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.1.tgz#9effac93a469a868d024e16fd77162c653544cbd" - integrity sha512-AsKjNhz72yxteo/0EtQEiwkMUgk/tGmycXlbG4g3Ard2/ULtNLUykGOkeK0egmN27h0xMAhb76jYccW+XTBExA== - backo2@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" @@ -677,22 +636,6 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -blake2b-wasm@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/blake2b-wasm/-/blake2b-wasm-2.4.0.tgz#9115649111edbbd87eb24ce7c04b427e4e2be5be" - integrity sha512-S1kwmW2ZhZFFFOghcx73+ZajEfKBqhP82JMssxtLVMxlaPea1p9uoLiUZ5WYyHn0KddwbLc+0vh4wR0KBNoT5w== - dependencies: - b4a "^1.0.1" - nanoassert "^2.0.0" - -blake2b@^2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/blake2b/-/blake2b-2.1.4.tgz#817d278526ddb4cd673bfb1af16d1ad61e393ba3" - integrity sha512-AyBuuJNI64gIvwx13qiICz6H6hpmjvYS5DGkG6jbXMOT8Z3WUJ3V1X0FlhIoT1b/5JtHE3ki+xjtMvu1nn+t9A== - dependencies: - blake2b-wasm "^2.4.0" - nanoassert "^2.0.0" - body-parser@1.19.0: version "1.19.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" @@ -727,14 +670,6 @@ body-parser@1.20.1, body-parser@^1.18.3: type-is "~1.6.18" unpipe "1.0.0" -bogon@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/bogon/-/bogon-1.1.0.tgz#14234260353d8f806c3a307202f66698f635d18b" - integrity sha512-a6SnToksXHuUlgeMvI/txWmTcKz7c7iBa8f0HbXL4toN1Uza/CTQ4F7n9jSDX49TCpxv3KUP100q4sZfwLyLiw== - dependencies: - compact-encoding "^2.11.0" - compact-encoding-net "^1.2.0" - boolean@^3.1.4: version "3.2.0" resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.2.0.tgz#9e5294af4e98314494cbb17979fa54ca159f116b" @@ -785,13 +720,6 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" -chacha20-universal@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/chacha20-universal/-/chacha20-universal-1.0.4.tgz#e8a33a386500b1ce5361b811ec5e81f1797883f5" - integrity sha512-/IOxdWWNa7nRabfe7+oF+jVkGjlr2xUL4J8l/OvzZhj+c9RpMqoo3Dq+5nU1j/BflRV4BKnaQ4+4oH1yBpQG1Q== - dependencies: - nanoassert "^2.0.0" - chokidar@^3.5.2: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" @@ -820,20 +748,6 @@ commander@^2.20.3: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -compact-encoding-net@^1.0.1, compact-encoding-net@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/compact-encoding-net/-/compact-encoding-net-1.2.0.tgz#19d2efd55df10f2ee793576fc4483bf6d2218743" - integrity sha512-LVXpNpF7PGQeHRVVLGgYWzuVoYAaDZvKUsUxRioGfkotzvOh4AzoQF1HBH3zMNaSnx7gJXuUr3hkjnijaH/Eng== - dependencies: - compact-encoding "^2.4.1" - -compact-encoding@^2.1.0, compact-encoding@^2.11.0, compact-encoding@^2.4.1, compact-encoding@^2.5.1: - version "2.11.0" - resolved "https://registry.yarnpkg.com/compact-encoding/-/compact-encoding-2.11.0.tgz#eff11cb0c328b3f82556cb391ed54519155fbdf8" - integrity sha512-CRfTuyy9Tg7EwxNKvIq3yFIr2JnJLyVr9Yj234VsDCL59hdXcZH3TdzY/2kwbAqVogIoRBJjnNKCEnXbxTIEeg== - dependencies: - b4a "^1.3.0" - concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -938,13 +852,6 @@ debug@^4.3.3, debug@^4.3.4: dependencies: ms "2.1.2" -debugging-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/debugging-stream/-/debugging-stream-2.0.0.tgz#515cad5a35299cf4b4bc0afcbd69d52c809c84ce" - integrity sha512-xwfl6wB/3xc553uwtGnSa94jFxnGOc02C0WU2Nmzwr80gzeqn1FX4VcbvoKIhe8L/lPq4BTQttAbrTN94uN8rA== - dependencies: - streamx "^2.12.4" - decimal.js-light@^2.5.1: version "2.5.1" resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz#134fd32508f19e208f4fb2f8dac0d2626a867934" @@ -983,23 +890,6 @@ destroy@~1.0.4: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg== -dht-rpc@^6.3.0: - version "6.3.1" - resolved "https://registry.yarnpkg.com/dht-rpc/-/dht-rpc-6.3.1.tgz#6571a3b48006c8256aadc6b993a7753582db551d" - integrity sha512-TCvDU5Pc7CL3QwFv1QKe/7IKj24Fp1JxWSRqZd1vVKFQCMRbYZxGsD3pIsPa/ILTzEUUOK5oBWPxeO2mDQr+gw== - dependencies: - b4a "^1.3.1" - compact-encoding "^2.1.0" - compact-encoding-net "^1.0.1" - events "^3.3.0" - fast-fifo "^1.0.0" - kademlia-routing-table "^1.0.0" - nat-sampler "^1.0.1" - sodium-universal "^3.0.4" - streamx "^2.10.3" - time-ordered-set "^1.0.2" - udx-native "^1.2.0" - dicer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.3.0.tgz#eacd98b3bfbf92e8ab5c2fdb71aaac44bb06b872" @@ -1099,11 +989,6 @@ eventemitter3@^3.1.0: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== -events@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - express@4.17.1: version "4.17.1" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" @@ -1177,11 +1062,6 @@ express@^4.17.1: utils-merge "1.0.1" vary "~1.1.2" -fast-fifo@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.1.0.tgz#17d1a3646880b9891dfa0c54e69c5fef33cad779" - integrity sha512-Kl29QoNbNvn4nhDsLYjyIAaIqaJB6rBx5p3sL9VjaefJ+eMFBWVZiaoguaoZfzEKr5RhAti0UgM8703akGPJ6g== - fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -1423,15 +1303,6 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -hmac-blake2b@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/hmac-blake2b/-/hmac-blake2b-2.0.0.tgz#09494e5d245d7afe45d157093080b159f7bacf15" - integrity sha512-JbGNtM1YRd8EQH/2vNTAP1oy5lJVPlBFYZfCJTu3k8sqOUm0rRIf/3+MCd5noVykETwTbun6jEOc+4Tu78ubHA== - dependencies: - nanoassert "^1.1.0" - sodium-native "^3.1.1" - sodium-universal "^3.0.0" - http-errors@1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" @@ -1476,16 +1347,7 @@ http-errors@~1.7.2: statuses ">= 1.5.0 < 2" toidentifier "1.0.0" -hypercore-crypto@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/hypercore-crypto/-/hypercore-crypto-3.3.0.tgz#03ab5b44608a563e131f629f671c6f90a83c52e6" - integrity sha512-zAWbDqG7kWwS6rCxxTUeB/OeFAz3PoOmouKaoMubtDJYJsLHqXtA3wE2mLsw+E2+iYyom5zrFyBTFVYxmgwW6g== - dependencies: - b4a "^1.1.0" - compact-encoding "^2.5.1" - sodium-universal "^3.0.0" - -i18n@^0.15.1: +i18n@0.15.1: version "0.15.1" resolved "https://registry.yarnpkg.com/i18n/-/i18n-0.15.1.tgz#68fb8993c461cc440bc2485d82f72019f2b92de8" integrity sha512-yue187t8MqUPMHdKjiZGrX+L+xcUsDClGO0Cz4loaKUOK9WrGw5pgan4bv130utOwX7fHE9w2iUeHFalVQWkXA== @@ -1568,13 +1430,6 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.9.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" - integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== - dependencies: - has "^1.0.3" - is-date-object@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" @@ -1702,11 +1557,6 @@ jws@^3.2.2: jwa "^1.4.1" safe-buffer "^5.0.1" -kademlia-routing-table@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/kademlia-routing-table/-/kademlia-routing-table-1.0.1.tgz#6f18416f612e885a8d4df128f04c490a90d772f6" - integrity sha512-dKk19sC3/+kWhBIvOKCthxVV+JH0NrswSBq4sA4eOkkPMqQM1rRuOWte1WSKXeP8r9Nx4NuiH2gny3lMddJTpw== - libphonenumber-js@^1.9.43: version "1.10.14" resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.14.tgz#e29da7f539751f724ac54017a098e3c7ca23de94" @@ -1879,26 +1729,6 @@ mustache@^4.2.0: resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.2.0.tgz#e5892324d60a12ec9c2a73359edca52972bf6f64" integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ== -nanoassert@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/nanoassert/-/nanoassert-1.1.0.tgz#4f3152e09540fde28c76f44b19bbcd1d5a42478d" - integrity sha512-C40jQ3NzfkP53NsO8kEOFd79p4b9kDXQMwgiY1z8ZwrDZgUyom0AHwGegF4Dm99L+YoYhuaB0ceerUcXmqr1rQ== - -nanoassert@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/nanoassert/-/nanoassert-2.0.0.tgz#a05f86de6c7a51618038a620f88878ed1e490c09" - integrity sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA== - -napi-macros@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.1.0.tgz#d0a8bd90b65be19dd37e425386a005c694f7039d" - integrity sha512-wJugWHfxRnVhV26BpJl2vyLHOXPrNBUyYJA5CTYcgbRcqHXAEJqStqpKOfBJyd0eb1VMbjdNvoeBWucpbdDrTw== - -nat-sampler@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/nat-sampler/-/nat-sampler-1.0.1.tgz#2b68338ea6d4c139450cd971fd00a4ac1b33d923" - integrity sha512-yQvyNN7xbqR8crTKk3U8gRgpcV1Az+vfCEijiHu9oHHsnIl8n3x+yXNHl42M6L3czGynAVoOT9TqBfS87gDdcw== - negotiator@0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" @@ -1911,11 +1741,6 @@ node-fetch@^2.6.1: dependencies: whatwg-url "^5.0.0" -node-gyp-build@^4.3.0, node-gyp-build@^4.4.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40" - integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg== - nodemon@^2.0.20: version "2.0.20" resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.20.tgz#e3537de768a492e8d74da5c5813cb0c7486fc701" @@ -1932,25 +1757,6 @@ nodemon@^2.0.20: touch "^3.1.0" undefsafe "^2.0.5" -noise-curve-ed@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/noise-curve-ed/-/noise-curve-ed-2.0.0.tgz#d5fb33b80ab87c78e0297010ea3e068035163415" - integrity sha512-DRMv6ciwQVDpDMMcNWyt20kLuAmXVYVJoPUhmvmIZkgSALA6a+OeNTrX35gt5vQ6LgE36DSOFMpGfdmWpBmjDg== - dependencies: - b4a "^1.1.0" - nanoassert "^2.0.0" - sodium-universal "^3.0.4" - -noise-handshake@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/noise-handshake/-/noise-handshake-3.0.0.tgz#cce40781a4da7c650d62e02d0164f5fb4fd71844" - integrity sha512-/EQq+TbCZpOFDg0bD3jtxKYqwgSBCFU1tfGxUzHHy94kBKMwVY8GHNxtWR+gekwkhXCu7TyBXqNPY3qdaxe+fQ== - dependencies: - b4a "^1.1.0" - hmac-blake2b "^2.0.0" - nanoassert "^2.0.0" - sodium-universal "^3.0.4" - nopt@~1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" @@ -2039,11 +1845,6 @@ path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" @@ -2079,11 +1880,6 @@ qs@6.7.0: resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== -queue-tick@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142" - integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag== - range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -2116,13 +1912,6 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -record-cache@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/record-cache/-/record-cache-1.2.0.tgz#e601bc4f164d58330cc00055e27aa4682291c882" - integrity sha512-kyy3HWCez2WrotaL3O4fTn0rsIdfRKOdQQcEJ9KpvmKmbffKVvwsloX063EgRUlpJIXHiDQFhJcTbZequ2uTZw== - dependencies: - b4a "^1.3.1" - reflect-metadata@^0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" @@ -2137,15 +1926,6 @@ regexp.prototype.flags@^1.4.3: define-properties "^1.1.3" functions-have-names "^1.2.2" -resolve@^1.17.0: - version "1.22.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" - integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== - dependencies: - is-core-module "^2.9.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - retry@0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" @@ -2185,11 +1965,6 @@ safe-regex-test@^1.0.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -safety-catch@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/safety-catch/-/safety-catch-1.0.2.tgz#d64cbd57fd601da91c356b6ab8902f3e449a7a4b" - integrity sha512-C1UYVZ4dtbBxEtvOcpjBaaD27nP8MlvyAQEp2fOTOEe6pfUpk1cDUxij6BR1jZup6rSyUTaBBplK7LanskrULA== - semver@^5.6.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" @@ -2283,38 +2058,6 @@ sha.js@^2.4.11: inherits "^2.0.1" safe-buffer "^5.0.1" -sha256-universal@^1.1.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/sha256-universal/-/sha256-universal-1.2.1.tgz#051d92decce280cd6137d42d496eac88da942c0e" - integrity sha512-ghn3muhdn1ailCQqqceNxRgkOeZSVfSE13RQWEg6njB+itsFzGVSJv+O//2hvNXZuxVIRyNzrgsZ37SPDdGJJw== - dependencies: - b4a "^1.0.1" - sha256-wasm "^2.2.1" - -sha256-wasm@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/sha256-wasm/-/sha256-wasm-2.2.2.tgz#4940b6c9ba28f3f08b700efce587ef36d4d516d4" - integrity sha512-qKSGARvao+JQlFiA+sjJZhJ/61gmW/3aNLblB2rsgIxDlDxsJPHo8a1seXj12oKtuHVgJSJJ7QEGBUYQN741lQ== - dependencies: - b4a "^1.0.1" - nanoassert "^2.0.0" - -sha512-universal@^1.1.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/sha512-universal/-/sha512-universal-1.2.1.tgz#829505a7586530515cc1a10b78815c99722c4df0" - integrity sha512-kehYuigMoRkIngCv7rhgruLJNNHDnitGTBdkcYbCbooL8Cidj/bS78MDxByIjcc69M915WxcQTgZetZ1JbeQTQ== - dependencies: - b4a "^1.0.1" - sha512-wasm "^2.3.1" - -sha512-wasm@^2.3.1: - version "2.3.4" - resolved "https://registry.yarnpkg.com/sha512-wasm/-/sha512-wasm-2.3.4.tgz#b86b37112ff6d1fc3740f2484a6855f17a6e1300" - integrity sha512-akWoxJPGCB3aZCrZ+fm6VIFhJ/p8idBv7AWGFng/CZIrQo51oQNsvDbTSRXWAzIiZJvpy16oIDiCCPqTe21sKg== - dependencies: - b4a "^1.0.1" - nanoassert "^2.0.0" - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -2343,57 +2086,6 @@ simple-update-notifier@^1.0.7: dependencies: semver "~7.0.0" -siphash24@^1.0.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/siphash24/-/siphash24-1.3.1.tgz#7f87fd2c5db88d8d46335a68f780f281641c8b22" - integrity sha512-moemC3ZKiTzH29nbFo3Iw8fbemWWod4vNs/WgKbQ54oEs6mE6XVlguxvinYjB+UmaE0PThgyED9fUkWvirT8hA== - dependencies: - nanoassert "^2.0.0" - -sodium-javascript@~0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/sodium-javascript/-/sodium-javascript-0.8.0.tgz#0a94d7bb58ab17be82255f3949259af59778fdbc" - integrity sha512-rEBzR5mPxPES+UjyMDvKPIXy9ImF17KOJ32nJNi9uIquWpS/nfj+h6m05J5yLJaGXjgM72LmQoUbWZVxh/rmGg== - dependencies: - blake2b "^2.1.1" - chacha20-universal "^1.0.4" - nanoassert "^2.0.0" - sha256-universal "^1.1.0" - sha512-universal "^1.1.0" - siphash24 "^1.0.1" - xsalsa20 "^1.0.0" - -sodium-native@^3.1.1, sodium-native@^3.2.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/sodium-native/-/sodium-native-3.4.1.tgz#44616c07ccecea15195f553af88b3e574b659741" - integrity sha512-PaNN/roiFWzVVTL6OqjzYct38NSXewdl2wz8SRB51Br/MLIJPrbM3XexhVWkq7D3UWMysfrhKVf1v1phZq6MeQ== - dependencies: - node-gyp-build "^4.3.0" - -sodium-secretstream@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/sodium-secretstream/-/sodium-secretstream-1.0.2.tgz#ae6fec16555f1a1d9fd2460b41256736d5044e13" - integrity sha512-AsWztbBHhHid+w5g28ftXA0mTrS52Dup7FYI0GR7ri1TQTlVsw0z//FNlhIqWsgtBctO/DxQosacbElCpmdcZw== - dependencies: - b4a "^1.1.1" - sodium-universal "^3.0.4" - -sodium-universal@^3.0.0, sodium-universal@^3.0.4: - version "3.1.0" - resolved "https://registry.yarnpkg.com/sodium-universal/-/sodium-universal-3.1.0.tgz#f2fa0384d16b7cb99b1c8551a39cc05391a3ed41" - integrity sha512-N2gxk68Kg2qZLSJ4h0NffEhp4BjgWHCHXVlDi1aG1hA3y+ZeWEmHqnpml8Hy47QzfL1xLy5nwr9LcsWAg2Ep0A== - dependencies: - blake2b "^2.1.1" - chacha20-universal "^1.0.4" - nanoassert "^2.0.0" - resolve "^1.17.0" - sha256-universal "^1.1.0" - sha512-universal "^1.1.0" - siphash24 "^1.0.1" - sodium-javascript "~0.8.0" - sodium-native "^3.2.0" - xsalsa20 "^1.0.0" - statuses@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" @@ -2418,14 +2110,6 @@ streamsearch@0.1.2: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" integrity sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA== -streamx@^2.10.2, streamx@^2.10.3, streamx@^2.12.0, streamx@^2.12.4: - version "2.12.5" - resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.12.5.tgz#485d6b6bf74df6f94bc1cc262e67392ed6862dc0" - integrity sha512-Y+nkFw57Z5JHT3zLlqFm3GccOy2FeYdUrrqita6Dd8kr/8enPn9GKa8IYf3/DmEKfZl/E2sWoSKUnd4qhonrgg== - dependencies: - fast-fifo "^1.0.0" - queue-tick "^1.0.0" - string.prototype.trimend@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" @@ -2467,26 +2151,11 @@ supports-color@^5.5.0: dependencies: has-flag "^3.0.0" -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - symbol-observable@^1.0.4: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== -time-ordered-set@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/time-ordered-set/-/time-ordered-set-1.0.2.tgz#3bd931fc048234147f8c2b8b1ebbebb0a3ecb96f" - integrity sha512-vGO99JkxvgX+u+LtOKQEpYf31Kj3i/GNwVstfnh4dyINakMgeZCpew1e3Aj+06hEslhtHEd52g7m5IV+o1K8Mw== - -timeout-refresh@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/timeout-refresh/-/timeout-refresh-2.0.1.tgz#f8ec7cf1f9d93b2635b7d4388cb820c5f6c16f98" - integrity sha512-SVqEcMZBsZF9mA78rjzCrYrUs37LMJk3ShZ851ygZYW1cMeIjs9mL57KO6Iv5mmjSQnOe/29/VAfGXo+oRCiVw== - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -2588,17 +2257,6 @@ typescript@^4.9.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db" integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA== -udx-native@^1.2.0, udx-native@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/udx-native/-/udx-native-1.5.1.tgz#aa71b7f2ee5cf3f738f2c59a64f3b2eeb4575337" - integrity sha512-sqIHaQVgB1zVZ2vcSLo/yuErLK7eon6Y4/rwPTz4s7B4yLhqxP33nh/Pj+C4TOj4KxK01HMzdLveZMUbutcGdQ== - dependencies: - b4a "^1.5.0" - events "^3.3.0" - napi-macros "^2.0.0" - node-gyp-build "^4.4.0" - streamx "^2.12.0" - unbox-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" @@ -2706,16 +2364,6 @@ wrappy@1: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== -xache@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/xache/-/xache-1.1.0.tgz#afc20dec9ff8b2260eea03f5ad9422dc0200c6e9" - integrity sha512-RQGZDHLy/uCvnIrAvaorZH/e6Dfrtxj16iVlGjkj4KD2/G/dNXNqhk5IdSucv5nSSnDK00y8Y/2csyRdHveJ+Q== - -xsalsa20@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/xsalsa20/-/xsalsa20-1.2.0.tgz#e5a05cb26f8cef723f94a559102ed50c1b44c25c" - integrity sha512-FIr/DEeoHfj7ftfylnoFt3rAIRoWXpx2AoDfrT2qD2wtp7Dp+COajvs/Icb7uHqRW9m60f5iXZwdsJJO3kvb7w== - xss@^1.0.8: version "1.0.14" resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.14.tgz#4f3efbde75ad0d82e9921cc3c95e6590dd336694"