@diva.exchange/i2p-sam
Version:
I2P SAM: peer-to-peer communication between applications over I2P
224 lines (202 loc) • 6.54 kB
text/typescript
/**
* Copyright 2021-2023 diva.exchange
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author/Maintainer: DIVA.EXCHANGE Association, https://diva.exchange
*/
import { suite, test, timeout } from '@testdeck/mocha';
import { expect } from 'chai';
import net from 'net';
import { createForward, createStream, toB32, I2pSamStream } from '../../lib/index.js';
const SAM_HOST: string = process.env.SAM_HOST || '172.19.74.11';
const SAM_PORT_TCP: number = Number(process.env.SAM_PORT_TCP || 7656);
const SAM_FORWARD_HOST: string = process.env.SAM_FORWARD_HOST || '172.19.74.1';
const SAM_FORWARD_PORT: number = Number(process.env.SAM_PORT_TCP || 20226);
class TestI2pSamStream {
(300000)
async stream(): Promise<void> {
let messageCounter: number = 0;
console.log('Creating Stream...');
let stream: I2pSamStream = {} as I2pSamStream;
try {
stream = await createStream({
sam: { host: SAM_HOST, portTCP: SAM_PORT_TCP },
stream: {
destination: 'diva.i2p',
},
});
stream.on('data', (): void => {
messageCounter++;
});
console.log('Start streaming data...');
console.log(Date.now());
// send some data to diva.i2p
stream.stream(Buffer.from('GET /hosts.txt HTTP/1.1\r\nHost: diva.i2p\r\n\r\n'));
while (!messageCounter) {
await TestI2pSamStream.wait(500);
}
console.log(Date.now());
} catch (error: any) {
console.debug(error.toString());
}
Object.keys(stream).length && stream.close();
expect(messageCounter).not.to.be.equal(0);
}
(300000)
async forward(): Promise<void> {
let messageCounter: number = 0;
console.log('Creating listener');
const serverForward: net.Server = net.createServer((c: net.Socket): void => {
console.debug('client connected');
c.on('end', (): void => {
console.debug('client disconnected');
});
c.on('data', (): void => {
c.write(`hello ${messageCounter}\n`);
});
});
serverForward.listen(SAM_FORWARD_PORT);
console.log('Creating Forward...');
let i2pForward: I2pSamStream = {} as I2pSamStream;
let i2pSender: I2pSamStream = {} as I2pSamStream;
try {
i2pForward = await createForward({
sam: { host: SAM_HOST, portTCP: SAM_PORT_TCP },
forward: {
host: SAM_FORWARD_HOST,
port: SAM_FORWARD_PORT,
silent: true,
},
});
} catch (error: any) {
console.debug(error.toString());
}
if (Object.keys(i2pForward).length) {
const destination: string = i2pForward.getPublicKey();
console.log('Creating Stream to ' + destination);
try {
i2pSender = await createStream({
sam: { host: SAM_HOST, portTCP: SAM_PORT_TCP },
stream: {
destination: destination,
},
});
i2pSender.on('data', (): void => {
messageCounter++;
});
console.log('Start streaming data...');
const start: number = Date.now();
// send some data to destination
const amount: number = 5;
while (messageCounter < amount) {
i2pSender.stream(Buffer.from(`GET / HTTP/1.1\r\nHost: ${toB32(destination)}.b32.i2p\r\n\r\n`));
await TestI2pSamStream.wait(500);
}
console.log(`${(Date.now() - start) / amount} milliseconds per roundtrip`);
} catch (error: any) {
console.debug(error.toString());
}
}
Object.keys(i2pForward).length && i2pForward.close();
Object.keys(i2pSender).length && i2pSender.close();
serverForward.close();
expect(messageCounter).not.to.be.equal(0);
}
(5000)
async failTimeout(): Promise<void> {
let stream: I2pSamStream = {} as I2pSamStream;
// timeout error
try {
stream = await createStream({
sam: { host: SAM_HOST, portTCP: SAM_PORT_TCP, timeout: 2 },
stream: {
destination: 'diva.i2p',
},
});
expect(false).to.be.true;
} catch (error: any) {
expect(error.toString()).contains('timeout');
} finally {
Object.keys(stream).length && stream.close();
}
}
(5000)
async failNotFound(): Promise<void> {
let stream: I2pSamStream = {} as I2pSamStream;
// connection error
try {
stream = await createStream({
sam: {
host: '127.0.0.256',
portTCP: SAM_PORT_TCP,
},
stream: { destination: 'diva.i2p' },
});
expect(false).to.be.true;
} catch (error: any) {
expect(error.toString()).contains('ENOTFOUND');
} finally {
Object.keys(stream).length && stream.close();
}
}
(5000)
async failEmptyDestination(): Promise<void> {
let stream: I2pSamStream = {} as I2pSamStream;
// empty destination
try {
stream = await createStream({
sam: {
host: SAM_HOST,
portTCP: SAM_PORT_TCP,
},
stream: { destination: '' },
});
expect(false).to.be.true;
} catch (error: any) {
expect(error.toString()).contains('Stream configuration invalid');
} finally {
Object.keys(stream).length && stream.close();
}
}
async failKeys(): Promise<void> {
// public key / private key issues
let stream: I2pSamStream = {} as I2pSamStream;
try {
stream = await createStream({
sam: {
host: SAM_HOST,
portTCP: SAM_PORT_TCP,
publicKey: '-',
privateKey: '--',
},
stream: { destination: 'diva.i2p' },
});
expect(false).to.be.true;
} catch (error: any) {
expect(error.toString()).contains('SESSION failed').contains('RESULT=INVALID_KEY');
} finally {
Object.keys(stream).length && stream.close();
}
}
static async wait(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
}