npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@diva.exchange/i2p-sam

v5.4.1

Published

I2P SAM: peer-to-peer communication between applications over I2P

Downloads

39,391

Readme

I2P SAM

An I2P SAM library: enabling applications to communicate through the I2P network.

Long story short: I2P is an anonymous network layer allowing censorship-resistant and end-to-end-encrypted communication. I2P is a fully distributed, "privacy-by-design" peer-to-peer network.

To get I2P up and running, take a look at the project: https://github.com/diva-exchange/i2p

Use Cases

I2P is an instantly available peer-to-peer network which can be used for things like:

  • chat, social media and alike - all private and secure
  • distributed databases, aka blockchains (see https://testnet.diva.exchange as an example)
  • gaming, file sharing and ... whatever else you come up with

I2P is fully distributed, well researched and gets further developed by a competent community.

This I2P SAM library helps developers to create an I2P application quickly and hassle-free.

Get Started

npm i @diva.exchange/i2p-sam

or, lighter, without developer dependencies:

npm i --omit dev @diva.exchange/i2p-sam

Quick Start - Examples

How to Use Streams

Send an HTTP GET request to diva.i2p and output the response:

import { createStream } from '@diva.exchange/i2p-sam';

(async () => {

  const s = await createStream({
    stream: {
      destination: 'diva.i2p'
    },
    sam: {
      // your local I2P SAM host,
      // like 172.19.74.11 if you use the given test
      // docker container (see "Unit Tests" below)
      host: '127.0.0.1',
      // your local I2P SAM port, this is the default
      portTCP: 7656
    },
  });
  s.on('data', (data: Buffer) => {
    console.log('Incoming Data: ' + data.toString());
  });
  
  s.stream(Buffer.from('GET /hosts.txt HTTP/1.1\r\nHost: diva.i2p\r\n\r\n'));

})();

Forward incoming streaming data to a local socket server:

import { createStream, createForward, I2pSamStream } from '@diva.exchange/i2p-sam';
import net from 'net';

(async () => {
  const serverForward = net.createServer((c) => {
    console.debug('client connected');
    c.on('end', () => {
      console.debug('client disconnected');
    });
    c.on('data', (data: Buffer) => {
      console.debug(data.toString());
      c.write(`Hello Client!\n`);
    });
  });
  serverForward.listen(20222, '127.0.0.2');

  const samForward: I2pSamStream = await createForward({
    sam: { 
      host: '127.0.0.1',  // your local I2P SAM host
      portTCP: 7656       // your local I2P SAM port
    },
    forward: {
      host: '127.0.0.2',  // your local listener, see above
      port: 20222,        // your local listener, see above
    },
  });

  const samClient: I2pSamStream = await createStream({
    sam: { 
      host: '127.0.0.1',  // your local I2P SAM host
      portTCP: 7656       // your local I2P SAM port
    },
    stream: {
      destination: samForward.getPublicKey()
    },
  });
  // event handler
  samClient.on('data', (data: Buffer) => {
    console.debug(data.toString());
  });
  // send some data to destination
  samClient.stream(Buffer.from(`Hi Server!\n`));
})();

How to Use Reply-able Datagrams

NOTE: reply-able datagrams contain the origin of the data. An "origin" is defined as the public key of a node in the I2P network.

Send reply-able UDP messages from peer A to peer B through the I2P network:

import { createDatagram, toB32 } from '@diva.exchange/i2p-sam';

(async () => {
  // instantiate Peer A
  const peerA = await createDatagram({
    sam: {
      host: '127.0.0.1',  // your local I2P SAM host
      portTCP: 7656       // your local I2P SAM port
    }
  }); 
  
  // instantiate Peer B
  const peerB = await createDatagram({
    sam: {
      host: '127.0.0.1',  // your local I2P SAM host
      portTCP: 7656       // your local I2P SAM port
    },
    listen: { 
      address: '127.0.0.1',  // udp listener
      port: 20202            // udp listener
    }
  }).on('data', (data: Buffer, from) => {
    console.debug(`Incoming Data from ${toB32(from)}: ${data.toString()}`);
  });

    
  // send 100 messages via UDP, every 500ms a message
  // IMPORTANT: UDP is not reliable. Some messages might get lost.
  const msg: string = 'Hello World';
  await new Promise((resolve) => {
    let t = 0;
    const i = setInterval(() => {
      peerA.send(peerB.getPublicKey(), Buffer.from(`${t} ${msg}`));
      if (t++ >= 100) {
        clearInterval(i);
        resolve(true);
      }
    }, 500);
  });
})();

How to Use Raw Datagrams

NOTE: raw datagrams do not contain the "origin" of the data. A typical use case for raw datagrams: broadcasting of data. Raw datagrams are lean.

Send raw UDP messages from peer A to peer B through the I2P network:

import { createRaw } from '@diva.exchange/i2p-sam';

(async () => {
  // instantiate Peer A
  const peerA = await createRaw({
    sam: {
      host: '127.0.0.1',  // your local I2P SAM host
      portTCP: 7656       // your local I2P SAM port
    }
  }); 
  
  // instantiate Peer B
  const peerB = await createRaw({
    sam: {
      host: '127.0.0.1',  // your local I2P SAM host
      portTCP: 7656       // your local I2P SAM port
    },
    listen: { 
      address: '127.0.0.1',  // udp listener
      port: 20202            // udp listener
    }
  }).on('data', (data: Buffer) => {
    console.log('Incoming Data: ' + data.toString());
  });

  // send 100 messages via UDP, every 500ms a message
  // IMPORTANT: UDP is not reliable. Some messages might get lost.
  const msg: string = 'Hello Peer B - I am Peer A';
  await new Promise((resolve) => {
    let t = 0;
    const i = setInterval(() => {
      peerA.send(peerB.getPublicKey(), Buffer.from(`${t} ${msg}`));
      if (t++ >= 100) {
        clearInterval(i);
        resolve(true);
      }
    }, 500);
  });
})();

API

getPublicKey(): string

Get the public key of the local destination.

Example:

import { createDatagram } from '@diva.exchange/i2p-sam';

createDatagram({
  sam: {
    host: '127.0.0.1',  // your local I2P SAM host
    portTCP: 7656       // your local I2P SAM port
  }
}).then((sam) => console.log(sam.getPublicKey()));

getPrivateKey(): string

Get the private key of the local destination.

Example:

import { createDatagram } from '@diva.exchange/i2p-sam';

createDatagram({
  sam: {
    host: '127.0.0.1',  // your local I2P SAM host
    portTCP: 7656       // your local I2P SAM port
  }
}).then((sam) => console.log(sam.getPrivateKey()));

getKeyPair(): { public: string, private: string }

Get the public and private key of the local destination.

Example:

import { createStream } from '@diva.exchange/i2p-sam';

createStream({
  sam: {
    host: '127.0.0.1',  // your local I2P SAM host
    portTCP: 7656       // your local I2P SAM port
  },
  stream: {
    destination: 'diva.i2p'
  },
}).then((sam) => console.log(sam.getKeyPair()));

close()

Close a SAM connection.

Example:

import { createRaw } from '@diva.exchange/i2p-sam';

(async () => {
  const sam = await createRaw({
    sam: {
      host: '127.0.0.1',  // your local I2P SAM host
      portTCP: 7656       // your local I2P SAM port
    }
  });
  
  sam.close();
})();

toB32(destination: string): string

Convert a destination to a b32 address (without any extensions - just a Base32 string).

Example:

import { toB32 } from '@diva.exchange/i2p-sam';

console.log(toB32('[some base64-encoded destination]'));

createLocalDestination(c: Configuration): Promise<{ address: string, public: string, private: string }>

Create a new local destination and return its properties.

Example:

import { createLocalDestination } from '@diva.exchange/i2p-sam';

createLocalDestination({
  sam: {
    host: '127.0.0.1',  // your local I2P SAM host
    portTCP: 7656       // your local I2P SAM port
  }
}).then((obj) => console.log(obj));

lookup(c: Configuration, name: string): Promise<string>

Lookup (aka resolve) an I2P address (like diva.i2p or also a .b32.i2p address) to a destination. The destination, which is the public key, is a base64 encoded string.

Example:

import { lookup } from '@diva.exchange/i2p-sam';

lookup({
  sam: {
    host: '127.0.0.1',  // your local I2P SAM host
    portTCP: 7656       // your local I2P SAM port
  }
}, 'diva.i2p').then((dest) => console.log(dest));

stream(msg: Buffer)

Example: see the Get Started: How to Use Streams above.

send(destination: string, msg: Buffer)

Example: see Get Started: How to Use Datagrams above.

Configuration and its Defaults

type tSession = {
  id?: string;
  options?: string;
};

type tStream = {
  destination: string;
};

type tForward = {
  host: string;
  port: number;
  silent?: boolean;
};

type tListen = {
  address: string;
  port: number;
  hostForward?: string;
  portForward?: number;
};

type tSam = {
  host: string;
  portTCP: number;
  portUDP?: number;
  versionMin?: string;
  versionMax?: string;
  publicKey?: string;
  privateKey?: string;
  timeout?: number;
};

export type Configuration = {
  session?: tSession;
  stream?: tStream;
  forward?: tForward;
  listen?: tListen;
  sam?: tSam;
};

type ConfigurationDefault = {
  session: tSession;
  stream: tStream;
  forward: tForward;
  listen: tListen;
  sam: tSam;
};

const DEFAULT_CONFIGURATION: ConfigurationDefault = {
  session: {
    id: '',
    options: '',
  },
  stream: {
    destination: '',
  },
  forward: {
    host: '',
    port: 0,
    silent: false,
  },
  listen: {
    address: '127.0.0.1',
    port: 0,
    hostForward: '',
    portForward: 0,
  },
  sam: {
    host: '127.0.0.1',
    portTCP: 7656,
    portUDP: 7655,
    versionMin: '',
    versionMax: '',
    publicKey: '',
    privateKey: '',
    timeout: 300,
  },
};

Events

data

Incoming data.

error

Generic Error event - emitted if sockets report errors.

import { createRaw } from '@diva.exchange/i2p-sam';

(async () => {
  const sam = await createRaw({
    sam: {
      host: '127.0.0.1',  // your local I2P SAM host
      portTCP: 7656       // your local I2P SAM port
    }
  });
  sam.on('error', (error) => console.debug(error));
})();

close

Emitted if one of the involved sockets got closed.

How to Run Unit Tests

Assumptions:

  1. git, node and npm is available.
  2. docker and docker-compose is available.

Clone the source code from git git clone https://github.com/diva-exchange/i2p-sam.git and enter the folder i2p-sam.

Prepare the test environment by creating the docker container:

docker compose -f test/sam.diva.i2p.yml up -d

Check whether the I2P test node is properly running by accessing the local console on: http://172.19.74.11:7070.

To modify the IP address of the local console, adapt the file test/sam.diva.i2p.yml.

After the docker container is running for about five minutes (reason: the I2P network needs some minutes to integrate), execute the unit tests:

npm run test

Executing the unit tests will take around 5 minutes. Reason: the communication via I2P gets tested - which is the purpose of this library.

Stop the container (and purge all data within):

docker compose -f test/sam.diva.i2p.yml down --volumes

Linting

To lint the code, use

npm run lint

Contributions

Contributions are very welcome. This is the general workflow:

  1. Fork from https://github.com/diva-exchange/divachain/
  2. Pull the forked project to your local developer environment
  3. Make your changes, test, commit and push them
  4. Create a new pull request on github.com

It is strongly recommended to sign your commits: https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key

If you have questions, please just contact us (see below).

Donations

Your donation goes entirely to the project. Your donation makes the development of DIVA.EXCHANGE faster. Thanks a lot.

XMR

42QLvHvkc9bahHadQfEzuJJx4ZHnGhQzBXa8C9H3c472diEvVRzevwpN7VAUpCPePCiDhehH4BAWh8kYicoSxpusMmhfwgx

XMR

or via https://www.diva.exchange/en/join-in/

BTC

3Ebuzhsbs6DrUQuwvMu722LhD8cNfhG1gs

BTC

Contact the Developers

On DIVA.EXCHANGE you'll find various options to get in touch with the team.

Talk to us via Telegram (English or German).

References

SAM docs: https://geti2p.net/en/docs/api/samv3

I2Pd: https://i2pd.readthedocs.io/

License

APACHE 2.0