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

filtergraphy

v0.0.15

Published

Message exchange based on bloom filters and EC e2e cryptography

Downloads

20

Readme

FilterCryptography

Intro

This package implements the functionality of secure chat without transferring information about the sender and recipients.

Algorithm

Algorithm assumes asymmetric encryption with the ability to hide the sender and recipient of the message. The algorithm has the ability to exchange messages between users, as well as organize a media channel that allows you to broadcast messages to channel subscribers without revealing the recipients and the sender.

Media channels can be of two types - public and private. Public media assumes an open list of subscribers stored in the cloud, and private - a closed one, in which only the media stores the list of subscribers.

Аlgorithm has several options for interaction, described below.

p2p (person to person)

For all examples have: Alice (A) with private and public key Bob (B) with private and public key

X = secret key, created by diffi-hellman algorithm: Pseudocode:

X1 = (publicKeyAlice, privateKeyBob), X2 = (publicKeyBob, privateKeyAlice), X1 == X2 == X

EncryptedMessage = encrypt(X, message);

bloomFilterAliceWithSalt = bloomFilter(randomBytes + publicKeyAlice) bloomFilterBobWithSalt = bloomFilter(randomBytes + publicKeyBob)

keyfrom-keyto

Payload = publicKeyAlice|publicKeyBob|EncryptedMessage

filterfrom-keyto

Payload = bloomFilterAliceWithSalt|publicKeyBob|EncryptedMessage

keyfrom-filterto

Payload = publicKeyAlice|bloomFilterBobWithSalt|EncryptedMessage

filterfrom-filterto (f2f)

Payload = bloomFilterAliceWithSalt|bloomFilterBobWithSalt|EncryptedMessage

tempkey

Used for secretly change the public key of the opposite side. Alice sending message with oldkey and Bob after receive this message change dialog externalkey (PublicKeyAlice) to newkey.

Payload = publicKeyAlice|bloomFilterBobWithSalt|SwitchMessage|SwitchKeyAdditionalData SwitchMessage = encrypt(X,oldkey|newkey) SwitchKeyAdditionalData = EncryptedData

hellopublickey

Used for media channels. Bob create extendedPublicKey with xpub. Alice use this xpub for create new dialog. Alice makes temp key, and create externalkey by derive from xpub. Then send to xpub key message with new key (like in tempkey) and path of derived key. Bob received this message, create derived publicKey from path and xpub, and create dialog with tempkey, derivedkey

Payload = publicKeyAlice|bloomFilterBobWithSalt|SwitchHelloPublicKeyMessage SwitchHelloPublicKeyMessage = encrypt(X,oldkey|newkey|path) SwitchKeyAdditionalData = EncryptedData

Media (media to group of persons)

All info about media save in cloud db. Information contains media type, it can me public and private.

public media

Public media uses a cloud db to store a list of subscribers, which is stored openly and each network member can count the number of subscribers and their public keys. Messages are sent openly without encryption

private media

Private media store the list of subscribers locally, the subscription is done via encrypted messages. The number of subscribers and their list cannot be read. Messages are sent in encrypted form.

Events

All necessary methods are implemented as events that need to be overridden. Below is a list of events with parameters and the necessary functionality.


/*decrypt events*/
app.on('addDialog', (localkey, externalkey, callback, dialogName) => {
    //add dialog to local db
    callback();
})

app.on('removeDialog', (localkey, externalkey, callback) => {
    //remove existing dialog to local db
    callback();
})

app.on('getAllLocalPublicKeysList', (callback) => {
    //get all public keys from keystore
    callback(list);
})

app.on('getMediaKeys', (callback) => {
    //get all my media public keys 
    callback([])
})

app.on('getKeyInfo', (key, callback) => {
    //get dialog by localkey==key, and keystore of key
    callback(dialog, keystore);
})

app.on('getDialogByExternalKey', (externalkey, callback) => {
    //find dialog by externalkey
    callback();
})

/*encrypt events*/
app.on('getKeystoreByMeta', (context, version, callback) => {
    //fild keystore by context.localkey
});

/*keys events*/
app.on('seedAccess', (callback) => {
    //get access to seed phrase, use new app.seed("mnemonic")
    callback(new app.seed(mnemonic));
})

app.on('getLastIndex', (callback) => {
    //get last used key index
    callback(k++);
})

app.on('getLastPublicIndex', (callback) => {
    //get last used public key index
    callback(pk++)
})

app.on('saveNewKey', (type, keystore, callback) => {
    //save key to database, return keystore to callback
    callback(keystore);
})

//media:
app.on('getMediaInfo', (nameOrKey, callback) => {
    
    //find media by nameOrKey and return info
    callback(mediaLocalInfo);
})

app.on('saveMediaInfo', (data, callback) => {
    //save data to localdb
    callback(data)
})

app.on('getAllFollowedMediaKeys', (callback) => {
    //get add my media dialogs localkey
    callback([myMediaKey1, myMediaKey2])
})

app.on('addMediaDialog', (localkey, mediaName, callback) => {
    //add new dialog with media
    callback({ localkey, externalKey: mediaName });
})

app.on('removeMediaDialog', (localkey, mediaName, callback) => {
    //remove dialog with media
    callback();
})

app.on('getDialogWithMedia', (mediaName, callback) => {
    //find dialog by media name
    callback(dialogsWithMedia[mediaName])
})

app.on('getMediaFollowers', (mediaPubKey, callback) => {
    //get all followers from my private media
    callback(followers[mediaPubKey]);
})

app.on('addFollower', (localkey, followerkey, callback) => {
    //add follower to localtable of private media
    if (!followers[localkey])
        followers[localkey] = [];
    followers[localkey].push(followerkey);
    callback()
})

app.on('removeFollower', (localkey, followerkey, callback) => {
    //remove follower key from private media db
    followers[localkey].splice(followers[localkey].indexOf(followerkey), 1);
    callback()
})

//net
app.on('NET:getMediaInfo', (name, callback) => {
    //get media info from network
    callback(mediaNetInfo[name])
})

app.on('NET:saveMediaInfo', (name, data, callback) => {
    //save media info to network
    mediaNetInfo[name] = data;
    callback(mediaNetInfo[name]);
})

app.on('NET:setFollowState', (mediaName, followerState, callback) => {
    //set follower to follower table of public media
    callback();
})

app.on('NET:getFollowState', (mediaName, followerKey, callback) => {
    //get follower from follower table of public media
    callback(mediaNetFollowStateInfo[mediaName][followerKey]);
})

app.on('NET:getMempoolHistory', (callback) => {
    //get last N tx times from mempool
    callback([]);
});


app.on('NET:sendmempool', (data, callback) => {
    //send data to mempool
    callback()
});

/**
 * another events
 */

app.on('saveMessage', (dialog, content, options, callback) => {
    //save message to localdb
    callback({ hash: options.hash });
})

app.on('follower', (pubkey, followerKey) => {
    //info about new follower to private media (without callback)
})

app.on('notfollower', () => {
    //info about unfollow of follower to private media (without callback)
})

app.on('msg', (msg) => {
    //info about new message from network (without callback)
});

Initialization

    const APP = require('filtergraphy')
    let app = new APP();

Methods

app.createKeyPair(type)
    .then(keystore=>{
        
    })
app.createPublicKeyPair()
    .then(keystore=>{
        //creates keystore with keystore.xpub key (for hellopublickey and medias)
    })
app.addDialog(localkey, externalkey)
    .then(dialog=>{
        //creates new private dialog
    })
app.removeDialog(localkey, externalkey)
    .then(()=>{
        //remove private dialog
    })
app.addMediaDialog(localkey, mediaName)
    .then(()=>{
        //add dialog with media dialog 
    })
app.removeMediaDialog(localkey, mediaName)
    .then(()=>{
        //remove dialog with media dialog
    })
app.addMediaFollower(localKey, followerKey)
    .then(()=>{
        //add followers to PRIVATE_MEDIA media
    })
app.removeMediaFollower(localKey, followerKey)
    .then(()=>{
        //remove followers to PRIVATE_MEDIA media
    })
//creates new media and add it to media table.
//name is a `username` of media
//type can me 'MEDIA_PUBLIC' or 'MEDIA_PRIVATE'
app.createMedia(name, type)
    .then(()=>{
        //remove followers to PRIVATE_MEDIA media
    })
//get info about media
app.getMedia(media_name)
    .then(media=>{
        
    })
//only for media.type == MEDIA_PUBLIC
app.getFollowState(mediaName, followerKey)
    .then(followState=>{
        //returns info about follower of media  
    })
//create new keystore and follow to media
app.follow(mediaName)
//get follow keystore and unfollow from media
app.unfollow(mediaName)
//broadcast buffer to all followers of media
app.mediaBroadcast(mediaName, buffer)
/**
 * version types:
 * App.Crypto.FILTERTO
 * App.Crypto.FILTERFROMFILTERTO
 * App.Crypto.KEYTO
 * App.Crypto.KEYFROMKEYTO
 * App.Crypto.MEDIA
 * App.Crypto.HELLOPUBLICKEY
 * App.Crypto.TEMPKEY
 * 
 * 
 * context = {localkey, externalkey}
 * 
 * For version App.Crypto.HELLOPUBLICKEY
 * context = { externalkeyWithDerive: xpub }
 */
app.encrypt(context, buffer, version)
    .then(encryptedBuffer=>{
        
    })
app.decrypt(encryptedBuffer)
    .then(result=>{

        //filter from-to, key from-to etc..
        result = {
            key: '03e27cfa304366c849be09cac09c0e03baf3f371291eb4adc2a36a2a9a002ae83c',
            dialog: {
                localkey: '03e27cfa304366c849be09cac09c0e03baf3f371291eb4adc2a36a2a9a002ae83c',
                externalkey: '02178d4517d71b8ed15544e377000f832725b6ebd1dfda72e2a01af2467d30395e'
            },
            keystore: {
                publicKey: '03e27cfa304366c849be09cac09c0e03baf3f371291eb4adc2a36a2a9a002ae83c',
                privateKey: '30068c1e860fac3e3aa16083310d3e6b1d061e53da16b08b100621c4f11796ec',
                path: "0'/0'/2",
                index: 2,
                keyType: 'private_dialog'
            },
            content: Buffer,
            meta: {
                from: '02178d4517d71b8ed15544e377000f832725b6ebd1dfda72e2a01af2467d30395e',
                to: '03e27cfa304366c849be09cac09c0e03baf3f371291eb4adc2a36a2a9a002ae83c',
                version: 2
            }
        }
        
        //tempkey result:
        result = {
            key: '03e27cfa304366c849be09cac09c0e03baf3f371291eb4adc2a36a2a9a002ae83c',
            dialog: {
                localkey: '03e27cfa304366c849be09cac09c0e03baf3f371291eb4adc2a36a2a9a002ae83c',
                externalkey: '02ff3efab1d0916490814cf03bc6e4d4b6125e14a2a41b2f04766a202209ba4bdb'
            },
            keystore: {
                publicKey: '03e27cfa304366c849be09cac09c0e03baf3f371291eb4adc2a36a2a9a002ae83c',
                privateKey: 'xxxx',
                path: "0'/0'/2",
                index: 2,
                keyType: 'private_dialog'
            },
            content: Buffer,
            meta: {
                from: '02ff3efab1d0916490814cf03bc6e4d4b6125e14a2a41b2f04766a202209ba4bdb',
                to: '03e27cfa304366c849be09cac09c0e03baf3f371291eb4adc2a36a2a9a002ae83c',
                version: 11,
                switch: SwitchKey {
                typename: 'SwitchKey',
                oldkey: [PublicKey],
                newkey: [PublicKey]
                }
            },
            raw: Buffer
        }

        //hellopublickey result:
        result = {
            dialog: {
                externalkey: '02ff3efab1d0916490814cf03bc6e4d4b6125e14a2a41b2f04766a202209ba4bdb',
                localkey: '02da762b0cf81bb366bb6d83349cdc631626f1457bf61c7ab1080c8d4163ec885c'
            },
            keystore: {
                publicKey: '02da762b0cf81bb366bb6d83349cdc631626f1457bf61c7ab1080c8d4163ec885c',
                privateKey: 'xxxxx',
                path: '0/0/1',
                index: 1,
                keyType: 'public_keypair',
                xpub: 'xpub6H3ZCjPj4Dsam3gx8VA29NRMqfujTXM8Wefuoa7T2o4fmRsPTmURiiCF2RXvM2g3nMMyFZRgab3JheQnAay7g1NkAP8JasxATGy7hjYBA5z'
            },
            content: Buffer,
            meta: {
                from: '02ff3efab1d0916490814cf03bc6e4d4b6125e14a2a41b2f04766a202209ba4bdb',
                to: '02da762b0cf81bb366bb6d83349cdc631626f1457bf61c7ab1080c8d4163ec885c',
                version: 10,
                switchHelloPublicKey: SwitchHelloPublicKey {
                    typename: 'SwitchHelloPublicKey',
                    oldkey: [PublicKey],
                    newkey: [PublicKey],
                    path: [HelloPublicKeyPath]
                }
            }
        }



    })  
    .catch(message=>{
        //can not decrypt message
    })