mirror of
https://github.com/irislib/iris-messenger.git
synced 2024-09-19 17:46:33 +00:00
./iris-lib, restore lib build stuff
This commit is contained in:
parent
117e2b1417
commit
fb22e63931
28
iris-lib/.babelrc
Normal file
28
iris-lib/.babelrc
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"plugins": [
|
||||
["transform-flow-strip-types"], ["transform-runtime"]
|
||||
],
|
||||
"env": {
|
||||
"test": {
|
||||
"presets": [
|
||||
["es2015", {"loose": true}]
|
||||
],
|
||||
"plugins": [
|
||||
["add-module-exports"]
|
||||
]
|
||||
},
|
||||
"cjs": {
|
||||
"presets": [
|
||||
["es2015", {"loose": true}]
|
||||
],
|
||||
"plugins": [
|
||||
["add-module-exports"], ["transform-runtime"]
|
||||
]
|
||||
},
|
||||
"es": {
|
||||
"presets": [
|
||||
["es2015", {"loose": true, "modules": false}]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
5
iris-lib/.eslintignore
Normal file
5
iris-lib/.eslintignore
Normal file
@ -0,0 +1,5 @@
|
||||
cjs
|
||||
es
|
||||
dist
|
||||
coverage
|
||||
node_modules
|
12
iris-lib/.gitignore
vendored
Normal file
12
iris-lib/.gitignore
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
es
|
||||
cjs
|
||||
node_modules
|
||||
coverage
|
||||
*.log
|
||||
test-report.html
|
||||
jest-stare
|
||||
.iris
|
||||
.idea
|
||||
.env
|
||||
radata
|
||||
*.key
|
35
iris-lib/.npmignore
Normal file
35
iris-lib/.npmignore
Normal file
@ -0,0 +1,35 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directory
|
||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
|
||||
node_modules
|
||||
|
||||
.DS_Store
|
||||
|
||||
__tests__
|
||||
test-report.html
|
||||
jest-stare
|
||||
|
||||
.github
|
122
iris-lib/README.md
Normal file
122
iris-lib/README.md
Normal file
@ -0,0 +1,122 @@
|
||||
# iris-lib
|
||||
|
||||
![Node](https://img.shields.io/node/v/iris-lib.svg?style=flat-square)
|
||||
[![NPM](https://img.shields.io/npm/v/iris-lib.svg?style=flat-square)](https://www.npmjs.com/package/iris-lib)
|
||||
[![Travis](https://img.shields.io/travis/irislib/iris-lib/master.svg?style=flat-square)](https://travis-ci.org/irislib/iris-lib)
|
||||
[![David](https://img.shields.io/david/irislib/iris-lib.svg?style=flat-square)](https://david-dm.org/irislib/iris-lib)
|
||||
[![Coverage Status](https://img.shields.io/coveralls/irislib/iris-lib.svg?style=flat-square)](https://coveralls.io/github/irislib/iris-lib)
|
||||
[![Gitmoji](https://img.shields.io/badge/gitmoji-%20😜%20😍-FFDD67.svg?style=flat-square)](https://gitmoji.carloscuesta.me/)
|
||||
|
||||
<a href="https://opencollective.com/iris-social/donate" target="_blank"><img src="https://opencollective.com/iris-social/donate/button@2x.png?color=blue" width=200 /></a>
|
||||
|
||||
<p><sub>BTC donations: 3GopC1ijpZktaGLXHb7atugPj9zPGyQeST</sub></p>
|
||||
|
||||
### Description
|
||||
Iris-lib allows you to integrate __decentralized social networking__ features into your application.
|
||||
|
||||
Public messaging: Add a troll-free comment box to your website or app.
|
||||
|
||||
Private chats: Don't reinvent the wheel - just deploy iris-lib for real-time private and group discussions. No phone number or other "account" needed - just generate a public key that your friends can optionally verify.
|
||||
|
||||
Web of trust: Filter out spam and other unwanted content, without giving power to central moderators. Iris public and private messages are automatically filtered. You can also filter your own datasets by user's web of trust distance.
|
||||
|
||||
Contacts management: Ask friends to verify your public key or cryptocurrency address and changes to them. Use verified payment addresses in crypto wallets. Use verified public keys for authentication instead of relying on centralized email addresses, domain names and passwords. Any other types of attributes can also be added and verified.
|
||||
|
||||
Iris-lib runs in the browser and on Node.js.
|
||||
|
||||
### Documentation
|
||||
* [Iris API](http://docs.iris.to/)
|
||||
* [Web components](https://examples.iris.to/components/)
|
||||
|
||||
### Example
|
||||
|
||||
Private channel:
|
||||
```js
|
||||
// Copy & paste this to console at https://iris.to or other page that has gun, sea and iris-lib
|
||||
// Due to an unsolved bug, someoneElse's messages only start showing up after a reload
|
||||
|
||||
var gun1 = new Gun('https://gun-us.herokuapp.com/gun');
|
||||
var gun2 = new Gun('https://gun-us.herokuapp.com/gun');
|
||||
var myKey = await iris.Key.getDefault();
|
||||
var someoneElse = localStorage.getItem('someoneElsesKey');
|
||||
if (someoneElse) {
|
||||
someoneElse = JSON.parse(someoneElse);
|
||||
} else {
|
||||
someoneElse = await iris.Key.generate();
|
||||
localStorage.setItem('someoneElsesKey', JSON.stringify(someoneElse));
|
||||
}
|
||||
|
||||
iris.Channel.initUser(gun1, myKey); // saves myKey.epub to gun.user().get('epub')
|
||||
iris.Channel.initUser(gun2, someoneElse);
|
||||
|
||||
var ourChannel = new iris.Channel({key: myKey, gun: gun1, participants: someoneElse.pub});
|
||||
var theirChannel = new iris.Channel({key: someoneElse, gun: gun2, participants: myKey.pub});
|
||||
|
||||
var myChannels = {}; // you can list them in a user interface
|
||||
function printMessage(msg, info) {
|
||||
console.log(`[${new Date(msg.time).toLocaleString()}] ${info.from.slice(0,8)}: ${msg.text}`)
|
||||
}
|
||||
iris.Channel.getChannels(gun1, myKey, channel => {
|
||||
var pub = channel.getParticipants()[0];
|
||||
gun1.user(pub).get('profile').get('name').on(name => channel.name = name);
|
||||
myChannels[pub] = channel;
|
||||
channel.getMessages(printMessage);
|
||||
channel.on('mood', (mood, from) => console.log(from.slice(0,8) + ' is feeling ' + mood));
|
||||
});
|
||||
|
||||
// you can play with these in the console:
|
||||
ourChannel.send('message from myKey');
|
||||
theirChannel.send('message from someoneElse');
|
||||
|
||||
ourChannel.put('mood', 'blessed');
|
||||
theirChannel.put('mood', 'happy');
|
||||
```
|
||||
|
||||
More examples: [tests](https://github.com/irislib/iris-lib/tree/master/__tests__)
|
||||
|
||||
### Tech
|
||||
Data storage and networking are outsourced to [GUN](https://github.com/amark/gun), which manages the synchronization of data between different storages: RAM, localstorage, GUN websocket server, WebRTC peers, LAN multicast peers, IPFS (no adapter yet), S3 or others.
|
||||
|
||||
GUN enables subscription to data changes, so message feeds and contact details just update real-time without having to hit f5 or writing complex update logic.
|
||||
|
||||
IPFS is used to store file attachments and optional message backups.
|
||||
|
||||
### Installation
|
||||
|
||||
Install via [yarn](https://github.com/yarnpkg/yarn)
|
||||
|
||||
yarn add iris-lib (--dev)
|
||||
|
||||
or npm
|
||||
|
||||
npm install iris-lib (--save-dev)
|
||||
|
||||
### Builds
|
||||
|
||||
If you don't use a package manager, you can [access `iris-lib` via unpkg (CDN)](https://unpkg.com/iris-lib/), download the source, or point your package manager to the url.
|
||||
|
||||
`iris-lib` is compiled as a collection of [CommonJS](http://webpack.github.io/docs/commonjs.html) modules & [ES2015 modules](http://www.2ality.com/2014/09/es6-modules-final.html) for bundlers that support the `jsnext:main` or `module` field in package.json (Rollup, Webpack 2)
|
||||
|
||||
The `iris-lib` package includes precompiled production and development [UMD](https://github.com/umdjs/umd) builds in the [`dist` folder](https://unpkg.com/iris-lib/dist/). They can be used directly without a bundler and are thus compatible with many popular JavaScript module loaders and environments. You can drop a UMD build as a [`<script>` tag](https://unpkg.com/iris-lib) on your page. The UMD builds make `iris-lib` available as a `window.iris` global variable. Be sure to include [gun.js and sea.js](https://github.com/amark/gun) first.
|
||||
|
||||
```
|
||||
<script src="https://cdn.jsdelivr.net/npm/gun/gun.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/gun/sea.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/iris-lib@latest/dist/iris.min.js"></script>
|
||||
```
|
||||
|
||||
### License
|
||||
|
||||
The code is available under the [MIT](LICENSE) license.
|
||||
|
||||
### Contributing
|
||||
|
||||
Please do **integrate** iris-lib with your existing application or with a test application and **create Github issues** for the bugs and other problems you may encounter. Your help is much appreciated!
|
||||
|
||||
TODO list is also available on [Trello](https://trello.com/b/8qUutkmP/iris).
|
||||
|
||||
[Majestic](https://github.com/Raathigesh/majestic) is a handy tool for viewing jest test results and coverage.
|
||||
|
||||
### Misc
|
||||
|
||||
This module was created using [generator-module-boilerplate](https://github.com/duivvv/generator-module-boilerplate).
|
358
iris-lib/__tests__/Channel.js
Normal file
358
iris-lib/__tests__/Channel.js
Normal file
@ -0,0 +1,358 @@
|
||||
const iris = require(`index.js`);
|
||||
const GUN = require(`gun`);
|
||||
const SEA = require(`gun/sea`);
|
||||
const load = require(`gun/lib/load`);
|
||||
const then = require(`gun/lib/then`);
|
||||
const radix = require(`gun/lib/radix`); // Require before instantiating Gun, if running in jsdom mode
|
||||
|
||||
const server = require('http').createServer(GUN.serve);
|
||||
const superNode = GUN({radisk: false, web: server.listen(8768), multicast: false });
|
||||
const gun1 = new GUN({radisk: false, multicast: false, peers: ['http://localhost:8768/gun']});
|
||||
const gun2 = new GUN({radisk: false, multicast: false, peers: ['http://localhost:8768/gun']});
|
||||
|
||||
const logger = function()
|
||||
{
|
||||
let oldConsoleLog = null;
|
||||
const pub = {};
|
||||
|
||||
pub.enable = function enable()
|
||||
{
|
||||
if (oldConsoleLog == null)
|
||||
return;
|
||||
|
||||
window[`console`][`log`] = oldConsoleLog;
|
||||
};
|
||||
|
||||
pub.disable = function disable()
|
||||
{
|
||||
oldConsoleLog = console.log;
|
||||
window[`console`][`log`] = function() {};
|
||||
};
|
||||
|
||||
return pub;
|
||||
}();
|
||||
logger.disable();
|
||||
|
||||
test(`User1 says hi`, async (done) => {
|
||||
const user1 = await iris.Key.generate();
|
||||
const user2 = await iris.Key.generate();
|
||||
const user2Channel = new iris.Channel({ gun: gun2, key: user2, participants: user1.pub });
|
||||
const user1Channel = new iris.Channel({
|
||||
gun: gun1,
|
||||
key: user1,
|
||||
participants: user2.pub
|
||||
});
|
||||
user1Channel.getMessages((msg, info) => {
|
||||
expect(msg.text).toEqual(`hi`);
|
||||
expect(info.selfAuthored).toBe(true);
|
||||
done();
|
||||
});
|
||||
user1Channel.send(`hi`);
|
||||
});
|
||||
test(`Set and get msgsLastSeenTime`, async (done) => {
|
||||
const user1 = await iris.Key.generate();
|
||||
const user1Channel = new iris.Channel({
|
||||
gun: gun1,
|
||||
key: user1,
|
||||
participants: user1.pub
|
||||
});
|
||||
const t = new Date();
|
||||
user1Channel.setMyMsgsLastSeenTime();
|
||||
user1Channel.getMyMsgsLastSeenTime(time => {
|
||||
expect(time).toBeDefined();
|
||||
expect(new Date(time).getTime()).toBeGreaterThanOrEqual(t.getTime());
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test(`User2 says hi`, async (done) => {
|
||||
const user1 = await iris.Key.generate();
|
||||
const user2 = await iris.Key.generate();
|
||||
const user1Channel = new iris.Channel({
|
||||
gun: gun1,
|
||||
key: user1,
|
||||
participants: user2.pub,
|
||||
});
|
||||
|
||||
const user2Channel = new iris.Channel({ gun: gun2, key: user2, participants: user1.pub });
|
||||
user2Channel.send(`hi`);
|
||||
user1Channel.getMessages((msg) => {
|
||||
if (msg.text === `hi`) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test(`3 users send and receive messages and key-value pairs on a group channel`, async (done) => {
|
||||
const user1 = await iris.Key.generate();
|
||||
const user2 = await iris.Key.generate();
|
||||
const user3 = await iris.Key.generate();
|
||||
iris.Channel.initUser(gun1, user1);
|
||||
iris.Channel.initUser(gun2, user2);
|
||||
iris.Channel.initUser(superNode, user3);
|
||||
|
||||
const user1Channel = new iris.Channel({
|
||||
gun: gun1,
|
||||
key: user1,
|
||||
participants: [user2.pub, user3.pub]
|
||||
});
|
||||
expect(typeof user1Channel.uuid).toBe('string');
|
||||
expect(typeof user1Channel.myGroupSecret).toBe('string');
|
||||
expect(user1Channel.uuid.length).toBe(36);
|
||||
user1Channel.send('1')
|
||||
user1Channel.put('name', 'Champions');
|
||||
|
||||
const r1 = [];
|
||||
const r2 = [];
|
||||
const r3 = [];
|
||||
let user1MsgsReceived, user2MsgsReceived, user3MsgsReceived, putReceived1, putReceived2, putReceived3;
|
||||
function checkDone() {
|
||||
if (user1MsgsReceived && user2MsgsReceived && user3MsgsReceived && putReceived1 && putReceived2 && putReceived3) {
|
||||
done();
|
||||
}
|
||||
}
|
||||
user1Channel.getMessages((msg) => {
|
||||
r1.push(msg.text);
|
||||
if (r1.indexOf('1') >= 0 && r1.indexOf('2') >= 0 && r1.indexOf('3') >= 0) {
|
||||
user1MsgsReceived = true;
|
||||
checkDone();
|
||||
}
|
||||
});
|
||||
user1Channel.on('name', name => {
|
||||
putReceived1 = name === 'Champions';
|
||||
checkDone();
|
||||
});
|
||||
|
||||
const user2Channel = new iris.Channel({ gun: gun2, key: user2, participants: [user1.pub, user3.pub], uuid: user1Channel.uuid });
|
||||
user2Channel.send('2');
|
||||
expect(user2Channel.uuid).toEqual(user1Channel.uuid);
|
||||
expect(typeof user2Channel.myGroupSecret).toBe('string');
|
||||
user2Channel.getMessages((msg) => {
|
||||
r2.push(msg.text);
|
||||
if (r2.indexOf('1') >= 0 && r2.indexOf('2') >= 0 && r2.indexOf('3') >= 0) {
|
||||
user2MsgsReceived = true;
|
||||
checkDone();
|
||||
}
|
||||
});
|
||||
user2Channel.on('name', name => {
|
||||
putReceived2 = name === 'Champions';
|
||||
checkDone();
|
||||
});
|
||||
|
||||
const user3Channel = new iris.Channel({ gun: superNode, key: user3, participants: [user1.pub, user2.pub], uuid: user1Channel.uuid });
|
||||
user3Channel.send('3');
|
||||
expect(user3Channel.uuid).toEqual(user1Channel.uuid);
|
||||
expect(typeof user3Channel.myGroupSecret).toBe('string');
|
||||
user3Channel.getMessages((msg) => {
|
||||
r3.push(msg.text);
|
||||
if (r3.indexOf('1') >= 0 && r3.indexOf('2') >= 0 && r3.indexOf('3') >= 0) {
|
||||
user3MsgsReceived = true;
|
||||
checkDone();
|
||||
}
|
||||
});
|
||||
user3Channel.on('name', name => {
|
||||
putReceived3 = name === 'Champions';
|
||||
checkDone();
|
||||
});
|
||||
});
|
||||
|
||||
test(`create new channel, send messages, add participants afterwards`, async (done) => {
|
||||
return done(); // temp disabled
|
||||
logger.enable();
|
||||
const user1 = await iris.Key.generate();
|
||||
const user2 = await iris.Key.generate();
|
||||
const user3 = await iris.Key.generate();
|
||||
console.log(1, user1.pub.slice(0,4));
|
||||
console.log(2, user2.pub.slice(0,4));
|
||||
console.log(3, user3.pub.slice(0,4));
|
||||
iris.Channel.initUser(gun1, user1);
|
||||
iris.Channel.initUser(gun2, user2);
|
||||
iris.Channel.initUser(superNode, user3);
|
||||
|
||||
const user1Channel = new iris.Channel({
|
||||
gun: gun1,
|
||||
key: user1,
|
||||
participants: []
|
||||
});
|
||||
const chatLink = user1Channel.getSimpleLink();
|
||||
expect(typeof user1Channel.uuid).toBe('string');
|
||||
expect(typeof user1Channel.myGroupSecret).toBe('string');
|
||||
expect(user1Channel.uuid.length).toBe(36);
|
||||
user1Channel.send('1')
|
||||
user1Channel.put('name', 'Champions');
|
||||
|
||||
user1Channel.addParticipant(user2.pub);
|
||||
user1Channel.addParticipant(user3.pub);
|
||||
|
||||
const r1 = [];
|
||||
const r2 = [];
|
||||
const r3 = [];
|
||||
let user1MsgsReceived, user2MsgsReceived, user3MsgsReceived, putReceived1, putReceived2, putReceived3;
|
||||
function checkDone() {
|
||||
if (user1MsgsReceived && user2MsgsReceived && user3MsgsReceived && putReceived1 && putReceived2 && putReceived3) {
|
||||
logger.disable();
|
||||
done();
|
||||
}
|
||||
}
|
||||
user1Channel.getMessages((msg) => {
|
||||
r1.push(msg.text);
|
||||
console.log('user1', r1);
|
||||
if (r1.indexOf('1') >= 0 && r1.indexOf('2') >= 0 && r1.indexOf('3') >= 0) {
|
||||
user1MsgsReceived = true;
|
||||
checkDone();
|
||||
}
|
||||
});
|
||||
user1Channel.on('name', name => {
|
||||
putReceived1 = name === 'Champions';
|
||||
checkDone();
|
||||
});
|
||||
|
||||
setTimeout(() => { // with separate gun instances would work without timeout?
|
||||
const user2Channel = new iris.Channel({ gun: gun2, key: user2, chatLink });
|
||||
user2Channel.send('2');
|
||||
expect(user2Channel.uuid).toEqual(user1Channel.uuid);
|
||||
expect(typeof user2Channel.myGroupSecret).toBe('string');
|
||||
user2Channel.getMessages((msg) => {
|
||||
r2.push(msg.text);
|
||||
console.log('user2', r2);
|
||||
if (r2.indexOf('1') >= 0 && r2.indexOf('2') >= 0 && r2.indexOf('3') >= 0) {
|
||||
user2MsgsReceived = true;
|
||||
checkDone();
|
||||
}
|
||||
});
|
||||
user2Channel.on('name', name => {
|
||||
putReceived2 = name === 'Champions';
|
||||
checkDone();
|
||||
});
|
||||
}, 500);
|
||||
|
||||
setTimeout(() => {
|
||||
const user3Channel = new iris.Channel({ gun: superNode, key: user3, chatLink });
|
||||
user3Channel.send('3');
|
||||
expect(user3Channel.uuid).toEqual(user1Channel.uuid);
|
||||
expect(typeof user3Channel.myGroupSecret).toBe('string');
|
||||
user3Channel.getMessages((msg) => {
|
||||
r3.push(msg.text);
|
||||
console.log('user3', r3);
|
||||
if (r3.indexOf('1') >= 0 && r3.indexOf('2') >= 0 && r3.indexOf('3') >= 0) {
|
||||
user3MsgsReceived = true;
|
||||
checkDone();
|
||||
}
|
||||
});
|
||||
user3Channel.on('name', name => {
|
||||
putReceived3 = name === 'Champions';
|
||||
checkDone();
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
test(`Join a channel using a simple chat link`, async (done) => {
|
||||
const user1 = await iris.Key.generate();
|
||||
const user2 = await iris.Key.generate();
|
||||
const user3 = await iris.Key.generate();
|
||||
iris.Channel.initUser(gun1, user1);
|
||||
iris.Channel.initUser(gun2, user2);
|
||||
iris.Channel.initUser(superNode, user3);
|
||||
|
||||
const user1Channel = new iris.Channel({
|
||||
gun: gun1,
|
||||
key: user1,
|
||||
participants: [user2.pub, user3.pub]
|
||||
});
|
||||
|
||||
const chatLink = user1Channel.getSimpleLink();
|
||||
|
||||
setTimeout(() => {
|
||||
const user2Channel = new iris.Channel({gun: gun2, key: user2, chatLink});
|
||||
expect(user2Channel.uuid).toBe(user1Channel.uuid);
|
||||
expect(Object.keys(user2Channel.participants).length).toBe(2);
|
||||
user2Channel.onTheir('participants', pants => {
|
||||
expect(typeof pants).toBe('object');
|
||||
expect(Object.keys(pants).length).toBe(3);
|
||||
expect(Object.keys(user2Channel.participants).length).toBe(3);
|
||||
done();
|
||||
});
|
||||
}, 500);
|
||||
});
|
||||
|
||||
test(`Retrieve chat links`, async (done) => {
|
||||
const user1 = await iris.Key.generate();
|
||||
iris.Channel.initUser(gun1, user1);
|
||||
const user1Channel = new iris.Channel({
|
||||
gun: gun1,
|
||||
key: user1,
|
||||
participants: []
|
||||
});
|
||||
const chatLink = await user1Channel.createChatLink();
|
||||
user1Channel.getChatLinks(link => {
|
||||
expect(link).toBeDefined();
|
||||
expect(link.url).toEqual(chatLink);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test(`Join a channel using an advanced chat link`, async (done) => {
|
||||
logger.enable();
|
||||
|
||||
const user1 = await iris.Key.generate();
|
||||
const user2 = await iris.Key.generate();
|
||||
const user3 = await iris.Key.generate();
|
||||
iris.Channel.initUser(gun1, user1);
|
||||
iris.Channel.initUser(gun2, user2);
|
||||
iris.Channel.initUser(superNode, user3);
|
||||
|
||||
const user1Channel = new iris.Channel({
|
||||
gun: gun1,
|
||||
key: user1,
|
||||
participants: [user3.pub]
|
||||
});
|
||||
|
||||
const chatLink = await user1Channel.createChatLink();
|
||||
|
||||
setTimeout(() => {
|
||||
const user2Channel = new iris.Channel({gun: gun2, key: user2, chatLink});
|
||||
console.log(1, chatLink);
|
||||
console.log(2, user2Channel);
|
||||
expect(user2Channel.uuid).toBe(user1Channel.uuid);
|
||||
expect(Object.keys(user2Channel.participants).length).toBe(2);
|
||||
user2Channel.onTheir('participants', pants => {
|
||||
expect(typeof pants).toBe('object');
|
||||
expect(Object.keys(pants).length).toBe(3);
|
||||
expect(Object.keys(user2Channel.participants).length).toBe(3);
|
||||
logger.disable();
|
||||
done();
|
||||
});
|
||||
}, 500);
|
||||
});
|
||||
|
||||
test(`Save and retrieve direct and group channels`, async (done) => {
|
||||
const user1 = await iris.Key.generate();
|
||||
const user2 = await iris.Key.generate();
|
||||
iris.Channel.initUser(gun2, user2); // TODO direct chat is not saved unless the other guy's epub is found
|
||||
const user3 = await iris.Key.generate();
|
||||
const directChannel = new iris.Channel({
|
||||
gun: gun1,
|
||||
key: user1,
|
||||
participants: user2.pub
|
||||
});
|
||||
const groupChannel = new iris.Channel({
|
||||
gun: gun1,
|
||||
key: user1,
|
||||
participants: [user2.pub, user3.pub]
|
||||
});
|
||||
let direct, group;
|
||||
iris.Channel.getChannels(gun1, user1, channel => {
|
||||
if (channel.uuid) {
|
||||
group = channel;
|
||||
} else {
|
||||
direct = channel;
|
||||
}
|
||||
if (group && direct) {
|
||||
expect(direct.getId()).toBe(user2.pub);
|
||||
expect(group.getId()).toBe(groupChannel.uuid);
|
||||
expect(groupChannel.getCurrentParticipants().length).toBe(2);
|
||||
expect(group.getCurrentParticipants().length).toBe(2);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
105
iris-lib/__tests__/SignedMessage.js
Normal file
105
iris-lib/__tests__/SignedMessage.js
Normal file
@ -0,0 +1,105 @@
|
||||
/*global describe, it, after, before */
|
||||
const crypto = require(`crypto`);
|
||||
const Attribute = require(`Attribute.js`);
|
||||
const SignedMessage = require(`SignedMessage.js`);
|
||||
const Contact = require(`Contact.js`);
|
||||
const Key = require(`Key.js`);
|
||||
|
||||
jest.setTimeout(30000);
|
||||
|
||||
describe(`SignedMessage`, async () => {
|
||||
let msg;
|
||||
msg = void 0;
|
||||
describe(`createRating method`, async () => {
|
||||
test(`should create a rating message`, async () => {
|
||||
msg = await SignedMessage.createRating({
|
||||
author: {email: `alice@example.com`},
|
||||
recipient: {email: `bob@example.com`},
|
||||
rating: 5,
|
||||
text: `Good guy`
|
||||
});
|
||||
expect(msg).toHaveProperty(`signedData.time`);
|
||||
expect(msg.signedData.type).toEqual(`rating`);
|
||||
});
|
||||
/*
|
||||
test('should get message author and recipient', async () => {
|
||||
expect(msg.getAuthor()).toBeInstanceOf(Contact);
|
||||
expect(msg.getRecipient()).toBeInstanceOf(Contact);
|
||||
});
|
||||
*/
|
||||
test(`should use signing key as author if not defined`, async () => {
|
||||
const defaultKey = await Key.getDefault(`.`, undefined, require('fs'));
|
||||
msg = await SignedMessage.createRating({
|
||||
recipient: {email: `bob@example.com`},
|
||||
rating: 5,
|
||||
text: `Good guy`
|
||||
}, defaultKey);
|
||||
expect(msg).toHaveProperty(`signedData.author`);
|
||||
expect(JSON.stringify(msg.signedData.author)).toEqual(`{"keyID":"${ Key.getId(defaultKey) }"}`);
|
||||
});
|
||||
});
|
||||
describe(`createVerification method`, async () => {
|
||||
test(`should create a verification message`, async () => {
|
||||
msg = await SignedMessage.createVerification({
|
||||
author: {email: `alice@example.com`},
|
||||
recipient: {email: `bob@example.com`, name: `Bob`},
|
||||
text: `Good guy`
|
||||
});
|
||||
expect(msg).toHaveProperty(`signedData.time`);
|
||||
expect(msg.signedData.type).toEqual(`verification`);
|
||||
});
|
||||
});
|
||||
describe(`Recipient iterator`, async () => {
|
||||
test(`should go over recipient attributes`, async () => {
|
||||
msg = await SignedMessage.createVerification({
|
||||
author: {email: `alice@example.com`},
|
||||
recipient: {email: `bob@example.com`, name: `Bob`, nickname: [`Bobby`, `Bobbie`]},
|
||||
text: `Good guy`
|
||||
});
|
||||
const seen = {};
|
||||
for (const a of msg.getRecipientIterable()) {
|
||||
seen[`${a.type }:${ a.value}`] = true;
|
||||
}
|
||||
expect(seen.hasOwnProperty(`email:bob@example.com`)).toBe(true);
|
||||
expect(seen.hasOwnProperty(`name:Bob`)).toBe(true);
|
||||
expect(seen.hasOwnProperty(`nickname:Bobby`)).toBe(true);
|
||||
expect(seen.hasOwnProperty(`nickname:Bobbie`)).toBe(true);
|
||||
});
|
||||
});
|
||||
describe(`Validation`, async () => {
|
||||
test(`should not accept a message without signedData`, async () => {
|
||||
const f = () => {
|
||||
new SignedMessage({});
|
||||
};
|
||||
expect(f).toThrow(Error);
|
||||
});
|
||||
});
|
||||
describe(`methods`, async () => {
|
||||
let key;
|
||||
msg = void 0;
|
||||
beforeAll(async () => {
|
||||
msg = await SignedMessage.createRating({
|
||||
author: {email: `alice@example.com`},
|
||||
recipient: {email: `bob@example.com`},
|
||||
rating: 5,
|
||||
text: `Good guy`
|
||||
});
|
||||
key = await Key.generate();
|
||||
});
|
||||
test(`should be signed with sign()`, async () => {
|
||||
await msg.sign(key);
|
||||
expect(msg).toHaveProperty(`sig`);
|
||||
expect(msg).toHaveProperty(`pubKey`);
|
||||
expect(msg).toHaveProperty(`hash`);
|
||||
});
|
||||
test(`should be verified with verify()`, async () => {
|
||||
expect(await msg.verify()).toBe(true);
|
||||
});
|
||||
test(`serialize & deserialize`, async () => {
|
||||
const h = msg.getHash();
|
||||
const s = msg.toString();
|
||||
const m = await SignedMessage.fromString(s);
|
||||
expect(m.getHash()).toEqual(h);
|
||||
});
|
||||
});
|
||||
});
|
75
iris-lib/__tests__/attribute.js
Normal file
75
iris-lib/__tests__/attribute.js
Normal file
@ -0,0 +1,75 @@
|
||||
const iris = require(`index.js`);
|
||||
const Attribute = iris.Attribute;
|
||||
|
||||
describe(`Constructor`, () => {
|
||||
test(`new Attribute(type, value)`, () => {
|
||||
const a = new Attribute('email', 'alice@example.com');
|
||||
expect(a.type).toBe('email');
|
||||
expect(a.value).toBe('alice@example.com');
|
||||
});
|
||||
test(`new Attribute({type, value})`, () => {
|
||||
const a = new Attribute({type: 'email', value: 'alice@example.com'});
|
||||
expect(a.type).toBe('email');
|
||||
expect(a.value).toBe('alice@example.com');
|
||||
});
|
||||
test(`new Attribute(value), recognized type`, () => {
|
||||
const a = new Attribute('alice@example.com');
|
||||
expect(a.type).toBe('email');
|
||||
expect(a.value).toBe('alice@example.com');
|
||||
});
|
||||
test(`new Attribute(value) unrecognized type`, () => {
|
||||
expect(() => new Attribute('#BADBAD;')).toThrow(Error);
|
||||
});
|
||||
test(`new Attribute(1, 'asdf') non-string 1st param`, () => {
|
||||
expect(() => new Attribute(1, 'asdf')).toThrow(Error);
|
||||
});
|
||||
test(`new Attribute('asdf', 1) non-string 2nd param`, () => {
|
||||
expect(() => new Attribute('asdf', 1)).toThrow(Error);
|
||||
});
|
||||
test(`new Attribute('', 'asdf') empty string 1st param`, () => {
|
||||
expect(() => new Attribute('', 'asdf')).toThrow(Error);
|
||||
});
|
||||
test(`new Attribute('asdf', '') empty string 2nd param`, () => {
|
||||
expect(() => new Attribute('asdf', '')).toThrow(Error);
|
||||
});
|
||||
});
|
||||
describe(`equals`, () => {
|
||||
test(`true`, () => {
|
||||
const a = new Attribute('email', 'alice@example.com');
|
||||
const b = new Attribute('email', 'alice@example.com');
|
||||
expect(a.equals(b)).toBe(true);
|
||||
expect(Attribute.equals(a, b)).toBe(true);
|
||||
});
|
||||
test(`false`, () => {
|
||||
const a = new Attribute('email', 'alice@example.com');
|
||||
const b = new Attribute('email', 'bob@example.com');
|
||||
expect(a.equals(b)).toBe(false);
|
||||
expect(Attribute.equals(a, b)).toBe(false);
|
||||
expect(a.equals({})).toBe(false);
|
||||
});
|
||||
});
|
||||
describe(`static methods`, () => {
|
||||
test(`guessTypeOf`, () => {
|
||||
expect(Attribute.guessTypeOf('bob@example.com')).toBe('email');
|
||||
expect(Attribute.guessTypeOf('#BADBAD;')).toBe(undefined);
|
||||
});
|
||||
test(`getUniqueIdValidators`, () => {
|
||||
expect(typeof Attribute.getUniqueIdValidators()).toBe(`object`);
|
||||
expect(Object.keys(Attribute.getUniqueIdValidators()).length).toBeGreaterThan(10);
|
||||
})
|
||||
});
|
||||
describe(`methods`, () => {
|
||||
/*
|
||||
test(`identicon()`, () => {
|
||||
const a = new Attribute('a', 'b');
|
||||
const identicon = a.identicon(50);
|
||||
expect(a.identicon(50).constructor.name).toBe(`HTMLDivElement`);
|
||||
});
|
||||
*/
|
||||
test(`getUuid()`, () => {
|
||||
const uuid = Attribute.getUuid();
|
||||
expect(uuid.type).toBe(`uuid`);
|
||||
expect(typeof uuid.value).toBe(`string`);
|
||||
expect(uuid.value.length).toBeGreaterThan(10);
|
||||
})
|
||||
});
|
95
iris-lib/__tests__/collection.js
Normal file
95
iris-lib/__tests__/collection.js
Normal file
@ -0,0 +1,95 @@
|
||||
const Collection = require(`Collection.js`);
|
||||
const Gun = require(`gun`);
|
||||
const open = require(`gun/lib/open`);
|
||||
const radix = require(`gun/lib/radix`); // Require before instantiating Gun, if running in jsdom mode
|
||||
|
||||
class Animal {
|
||||
constructor(name, species) {
|
||||
if (!name || name.length === 0) { throw new Error(`Invalid name`); }
|
||||
if (!species || species.length === 0) { throw new Error(`Invalid species`); }
|
||||
this.name = name;
|
||||
this.species = species;
|
||||
}
|
||||
|
||||
serialize() {
|
||||
return {name: this.name, species: this.species};
|
||||
}
|
||||
|
||||
static deserialize(data) {
|
||||
return new Animal(data.name, data.species);
|
||||
}
|
||||
}
|
||||
|
||||
describe(`Collection`, () => {
|
||||
let gun, animals, n = 0;
|
||||
beforeAll(() => {
|
||||
gun = new Gun({radisk: false});
|
||||
const indexer = animal => {
|
||||
const reversedName = animal.name.split(``).reverse().join(``).toLowerCase();
|
||||
return {reversedName};
|
||||
};
|
||||
animals = new Collection({gun, class: Animal, indexes: ['name', 'species'], indexer});
|
||||
});
|
||||
test(`put`, () => {
|
||||
animals.put(new Animal('Moisture', 'cat'));n++;
|
||||
animals.put(new Animal('Petard', 'cat'));n++;
|
||||
animals.put(new Animal('Petunia', 'cat'));n++;
|
||||
animals.put(new Animal('Petrol', 'cat'));n++;
|
||||
animals.put(new Animal('Parsley', 'cat'));n++;
|
||||
animals.put(new Animal('proton', 'cat'));n++;
|
||||
animals.put(new Animal('Oilbag', 'cat'));n++;
|
||||
animals.put(new Animal('Scumbag', 'dog'));n++;
|
||||
animals.put(new Animal('Deadbolt', 'parrot'));n++;
|
||||
animals.put(new Animal('Moisture', 'dog'));n++;
|
||||
});
|
||||
test(`get all`, done => {
|
||||
let timesCalled = 0;
|
||||
function callback(animal) {
|
||||
expect(animal).toBeInstanceOf(Animal);
|
||||
timesCalled++;
|
||||
if (timesCalled === n) {
|
||||
done();
|
||||
}
|
||||
}
|
||||
animals.get({callback});
|
||||
});
|
||||
test(`search (case sensitive)`, done => {
|
||||
let timesCalled = 0;
|
||||
function callback(animal) {
|
||||
expect(animal).toBeInstanceOf(Animal);
|
||||
expect(animal.name.indexOf('P')).toBe(0);
|
||||
timesCalled++;
|
||||
if (timesCalled === 4) {
|
||||
done();
|
||||
}
|
||||
}
|
||||
animals.get({callback, query: {name: 'P'}});
|
||||
});
|
||||
test(`search (case insensitive)`, done => {
|
||||
let timesCalled = 0;
|
||||
function callback(animal) {
|
||||
expect(animal).toBeInstanceOf(Animal);
|
||||
expect(animal.name.toLowerCase().indexOf('p')).toBe(0);
|
||||
timesCalled++;
|
||||
if (timesCalled === 5) {
|
||||
done();
|
||||
}
|
||||
}
|
||||
animals.get({callback, query: {name: 'P'}, caseSensitive: false});
|
||||
});
|
||||
test(`selector`, done => {
|
||||
let timesCalled = 0;
|
||||
function callback(animal) {
|
||||
expect(animal).toBeInstanceOf(Animal);
|
||||
expect(animal.name).toBe(`Moisture`);
|
||||
timesCalled++;
|
||||
if (timesCalled === 2) {
|
||||
done();
|
||||
}
|
||||
}
|
||||
animals.get({callback, selector: {name: 'Moisture'}});
|
||||
});
|
||||
// TODO: test multiple index search
|
||||
// TODO: unique vs non-unique indexes
|
||||
// TODO: delete from collection and indexes
|
||||
});
|
67
iris-lib/__tests__/contact.js
Normal file
67
iris-lib/__tests__/contact.js
Normal file
@ -0,0 +1,67 @@
|
||||
const iris = require('index.js');
|
||||
const Contact = iris.Contact;
|
||||
|
||||
const GUN = require(`gun`);
|
||||
const load = require(`gun/lib/load`);
|
||||
const then = require(`gun/lib/then`);
|
||||
const SEA = require(`gun/sea`);
|
||||
const radix = require(`gun/lib/radix`); // Require before instantiating Gun, if running in jsdom mode
|
||||
const gun = new GUN({radisk: false});
|
||||
const $ = require(`jquery`);
|
||||
|
||||
const logger = function()
|
||||
{
|
||||
let oldConsoleLog = null;
|
||||
const pub = {};
|
||||
|
||||
pub.enable = function enable()
|
||||
{
|
||||
if (oldConsoleLog == null)
|
||||
return;
|
||||
|
||||
window[`console`][`log`] = oldConsoleLog;
|
||||
};
|
||||
|
||||
pub.disable = function disable()
|
||||
{
|
||||
oldConsoleLog = console.log;
|
||||
window[`console`][`log`] = function() {};
|
||||
};
|
||||
|
||||
return pub;
|
||||
}();
|
||||
|
||||
// get them from index, actually?
|
||||
let index, vp;
|
||||
beforeAll(async () => {
|
||||
logger.disable();
|
||||
index = new iris.SocialNetwork({gun});
|
||||
await index.ready;
|
||||
vp = index.getRootContact();
|
||||
});
|
||||
|
||||
describe(`Contact`, () => {
|
||||
test(`verified()`, async () => {
|
||||
expect(await vp.verified(`email`)).toBe(undefined);
|
||||
expect(typeof await vp.verified(`keyID`)).toBe(`string`);
|
||||
});
|
||||
test(`identicon()`, () => {
|
||||
const identicon = vp.identicon(50);
|
||||
expect(identicon.constructor.name).toBe(`HTMLDivElement`);
|
||||
});
|
||||
test(`profileCard()`, () => {
|
||||
const profileCard = vp.profileCard();
|
||||
expect(profileCard.constructor.name).toBe(`HTMLDivElement`);
|
||||
});
|
||||
test(`appendSearchWidget()`, () => {
|
||||
const parent = document.createElement(`div`); // index param
|
||||
const widget = Contact.appendSearchWidget(parent);
|
||||
expect(parent.hasChildNodes()).toBe(true);
|
||||
const input = $(widget).find(`input`).first();
|
||||
const results = $(widget).find(`div`).first();
|
||||
expect(input.constructor.name).toBe(`jQuery`);
|
||||
expect(results.constructor.name).toBe(`jQuery`);
|
||||
input.val(`Al`);
|
||||
input.keyup();
|
||||
});
|
||||
});
|
41
iris-lib/__tests__/key.js
Normal file
41
iris-lib/__tests__/key.js
Normal file
@ -0,0 +1,41 @@
|
||||
const iris = require(`index.js`);
|
||||
const fs = require(`fs`);
|
||||
|
||||
jest.setTimeout(30000);
|
||||
|
||||
beforeAll(() => {
|
||||
if (fs.existsSync(`./private.key`)) {
|
||||
const f = fs.unlinkSync(`./private.key`);
|
||||
}
|
||||
});
|
||||
test(`Generate key`, async () => {
|
||||
const i = await iris.Key.generate();
|
||||
expect(i).toBeDefined();
|
||||
});
|
||||
test(`Serialize and deserialize a key`, async () => {
|
||||
const i = await iris.Key.generate();
|
||||
const serialized = iris.Key.toString(i);
|
||||
expect(typeof serialized).toBe(`string`);
|
||||
const deserialized = iris.Key.fromString(serialized);
|
||||
expect(typeof deserialized).toBe(`object`);
|
||||
expect(i).toBeDefined();
|
||||
});
|
||||
test(`Get default key and sign a message with it`, async () => {
|
||||
const i = await iris.Key.getDefault(`.`, undefined, fs);
|
||||
expect(i).toBeDefined();
|
||||
const j = await iris.Key.getDefault(`.`, undefined, fs);
|
||||
expect(i).toEqual(j);
|
||||
const msg = await iris.SignedMessage.createRating({
|
||||
author: {email: `alice@example.com`},
|
||||
recipient: {email: `bob@example.com`},
|
||||
rating: 5,
|
||||
comment: `Good guy`
|
||||
});
|
||||
await msg.sign(i);
|
||||
expect(await msg.verify()).toBe(true);
|
||||
});
|
||||
afterAll(() => {
|
||||
if (fs.existsSync(`./private.key`)) {
|
||||
const f = fs.unlinkSync(`./private.key`);
|
||||
}
|
||||
});
|
8159
iris-lib/dist/iris.js
vendored
Normal file
8159
iris-lib/dist/iris.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
iris-lib/dist/iris.min.js
vendored
Normal file
1
iris-lib/dist/iris.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
65
iris-lib/example/addmessages.js
Normal file
65
iris-lib/example/addmessages.js
Normal file
@ -0,0 +1,65 @@
|
||||
const identifi = require('../cjs/index.js');
|
||||
const IPFS = require('ipfs');
|
||||
const fs = require('fs');
|
||||
|
||||
let key, ipfsNode;
|
||||
async function init() {
|
||||
key = identifi.Key.getDefault();
|
||||
ipfsNode = new IPFS({repo: './ipfs_repo'});
|
||||
await new Promise((resolve, reject) => {
|
||||
ipfsNode.on('ready', () => {
|
||||
console.log('ipfs ready');
|
||||
resolve();
|
||||
});
|
||||
ipfsNode.on('error', error => {
|
||||
console.error(error.message);
|
||||
reject();
|
||||
});
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
function shuffle(array) {
|
||||
let currentIndex = array.length, temporaryValue, randomIndex;
|
||||
|
||||
// While there remain elements to shuffle...
|
||||
while (0 !== currentIndex) {
|
||||
|
||||
// Pick a remaining element...
|
||||
randomIndex = Math.floor(Math.random() * currentIndex);
|
||||
currentIndex -= 1;
|
||||
|
||||
// And swap it with the current element.
|
||||
temporaryValue = array[currentIndex];
|
||||
array[currentIndex] = array[randomIndex];
|
||||
array[randomIndex] = temporaryValue;
|
||||
}
|
||||
|
||||
return array;
|
||||
};
|
||||
|
||||
init().then(async () => {
|
||||
console.log(1);
|
||||
const i = await identifi.Index.create(ipfsNode);
|
||||
console.log(11);
|
||||
const msgs = [];
|
||||
let msg = identifi.Message.createRating({recipient: [['email', 'bob@example.com']], rating:10}, key);
|
||||
msgs.push(msg);
|
||||
msg = identifi.Message.createRating({author: [['email', 'bob@example.com']], recipient: [['email', 'bob1@example.com']], rating:10}, key);
|
||||
msgs.push(msg);
|
||||
for (let i = 0;i < 10;i++) {
|
||||
msg = identifi.Message.createRating({author: [['email', `bob${i}@example.com`]], recipient: [['email', `bob${i+1}@example.com`]], rating:10}, key);
|
||||
msgs.push(msg);
|
||||
}
|
||||
msg = identifi.Message.createRating({author: [['email', 'bert@example.com']], recipient: [['email', 'chris@example.com']], rating:10}, key);
|
||||
msgs.push(msg);
|
||||
await i.addMessages(shuffle(msgs));
|
||||
p = await i.get('bob10@example.com');
|
||||
console.log(111,p);
|
||||
p = await i.get('bert@example.com');
|
||||
console.log(1111,p);
|
||||
p = await i.get('chris@example.com');
|
||||
console.log(11111,p);
|
||||
await ipfsNode.stop();
|
||||
console.log('ipfsNode stopped');
|
||||
});
|
6
iris-lib/example/assets/bootstrap.min.css
vendored
Normal file
6
iris-lib/example/assets/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
2291
iris-lib/example/assets/gun.js
Normal file
2291
iris-lib/example/assets/gun.js
Normal file
File diff suppressed because it is too large
Load Diff
53
iris-lib/example/assets/gun.open.js
Normal file
53
iris-lib/example/assets/gun.open.js
Normal file
@ -0,0 +1,53 @@
|
||||
var Gun = (typeof window !== "undefined")? window.Gun : require('../gun');
|
||||
|
||||
Gun.chain.open = function(cb, opt, at){
|
||||
opt = opt || {};
|
||||
opt.doc = opt.doc || {};
|
||||
opt.ids = opt.ids || {};
|
||||
opt.any = opt.any || cb;
|
||||
opt.ev = opt.ev || {off: function(){
|
||||
Gun.obj.map(opt.ev.s, function(e){
|
||||
if(e){ e.off() }
|
||||
});
|
||||
opt.ev.s = {};
|
||||
}, s:{}}
|
||||
return this.on(function(data, key, ctx, ev){
|
||||
delete ((data = Gun.obj.copy(data))||{})._;
|
||||
clearTimeout(opt.to);
|
||||
opt.to = setTimeout(function(){
|
||||
if(!opt.any){ return }
|
||||
opt.any.call(opt.at.$, opt.doc, opt.key, opt, opt.ev);
|
||||
if(opt.off){
|
||||
opt.ev.off();
|
||||
opt.any = null;
|
||||
}
|
||||
}, opt.wait || 1);
|
||||
opt.at = opt.at || ctx;
|
||||
opt.key = opt.key || key;
|
||||
opt.ev.s[this._.id] = ev;
|
||||
if(Gun.val.is(data)){
|
||||
if(!at){
|
||||
opt.doc = data;
|
||||
} else {
|
||||
at[key] = data;
|
||||
}
|
||||
return;
|
||||
}
|
||||
var tmp = this, id;
|
||||
Gun.obj.map(data, function(val, key){
|
||||
var doc = at || opt.doc;
|
||||
if (!doc) {
|
||||
return;
|
||||
}
|
||||
if(!(id = Gun.val.link.is(val))){
|
||||
doc[key] = val;
|
||||
return;
|
||||
}
|
||||
if(opt.ids[id]){
|
||||
doc[key] = opt.ids[id];
|
||||
return;
|
||||
}
|
||||
tmp.get(key).open(opt.any, opt, opt.ids[id] = doc[key] = {});
|
||||
});
|
||||
})
|
||||
}
|
21
iris-lib/example/assets/gun.then.js
Normal file
21
iris-lib/example/assets/gun.then.js
Normal file
@ -0,0 +1,21 @@
|
||||
var Gun = (typeof window !== "undefined")? window.Gun : require('../gun');
|
||||
|
||||
// Returns a gun reference in a promise and then calls a callback if specified
|
||||
Gun.chain.promise = function(cb) {
|
||||
var gun = this, cb = cb || function(ctx) { return ctx };
|
||||
return (new Promise(function(res, rej) {
|
||||
gun.once(function(data, key){
|
||||
res({put: data, get: key, gun: this}); // gun reference is returned by promise
|
||||
});
|
||||
})).then(cb); //calling callback with resolved data
|
||||
};
|
||||
|
||||
// Returns a promise for the data, key of the gun call
|
||||
Gun.chain.then = function() {
|
||||
var gun = this;
|
||||
return (new Promise((res, rej)=>{
|
||||
gun.once(function (data, key) {
|
||||
res(data, key); //call resolve when data is returned
|
||||
})
|
||||
}))
|
||||
};
|
112
iris-lib/example/browser.html
Normal file
112
iris-lib/example/browser.html
Normal file
@ -0,0 +1,112 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>identifi-lib</title>
|
||||
<!--<script type="text/javascript" src="../dist/iris.js"></script>-->
|
||||
<script type="text/javascript" src="./assets/gun.js"></script>
|
||||
<script type="text/javascript" src="./assets/gun.then.js"></script>
|
||||
<script type="text/javascript" src="./assets/gun.open.js"></script>
|
||||
<script type="text/javascript" src="../dist/iris.js"></script>
|
||||
<script src="script.js"></script>
|
||||
<link rel="stylesheet" href="./assets/bootstrap.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Saving the world with identifi-lib</h1>
|
||||
|
||||
<p>The building blocks of Identifi data are digitally signed <b>Messages</b>
|
||||
which are typically <i>verifications</i> or <i>ratings</i>.</p>
|
||||
|
||||
<p>Ratings are used to build a <i>web of trust</i>. Your web of trust consists
|
||||
of the identities that you have rated positively, the identities that they have rated
|
||||
positively and so on, up to an arbitrary <i>trust distance</i>.</p>
|
||||
|
||||
<p>Verifications are claims that certain <b>Attributes</b>
|
||||
(name, email, bitcoin address etc.) belong to the same <b>Identity</b>.
|
||||
Verifications from your web of trust are used to bundle together
|
||||
attributes into Identity objects.</p>
|
||||
|
||||
<p>Identifi-lib can be used to read and write <b>Indices</b> of Messages and
|
||||
Identities. An Identifi Index typically contains four indices:
|
||||
<i>messagesByTimestamp</i>, <i>messagesByTrustDistance</i>,
|
||||
<i>identitiesByTrustDistance</i> and <i>identitiesBySearchKey</i>.</p>
|
||||
|
||||
<p>Identifi messages and indexes are stored on GUN. Additionally, messages are saved to IPFS.</p>
|
||||
|
||||
<h2>Including the library</h2>
|
||||
<h3>Browser</h3>
|
||||
<pre><script type="text/javascript" src="https://unpkg.com/identifi-lib/dist/iris.min.js"></script></pre>
|
||||
<p>The lib will be available as <i>window.irisLib</i>.</p>
|
||||
|
||||
<h3>Node.js</h3>
|
||||
<pre>npm install identifi-lib</pre>
|
||||
|
||||
<!--
|
||||
<h2>index = await Index.load(indexRootIpfsUri)</h2>
|
||||
<p>Load an Index from a given index root IPFS/IPNS URI. If ipfsUri is undefined,
|
||||
identi.fi index is loaded by default. As of April 2018, identi.fi index consists
|
||||
mostly of data crawled from bitcoin-otc.com.</p>
|
||||
-->
|
||||
|
||||
<h2>index.search(value, type, callback, limit)</h2>
|
||||
<p>Search an identifi index for identitiesBySearchKey. Callback is called for each result.</p>
|
||||
<input type="text" value="ma" id="query" onkeyup="search()" class="form-control">
|
||||
<p id="searchResults"></p>
|
||||
|
||||
<p>You can create a similar search widget with:</p>
|
||||
<pre>window.irisLib.Identity.appendSearchWidget(parentElement, index);</pre>
|
||||
<p id="searchWidget"></p>
|
||||
|
||||
<h2>index.get([type,] value)</h2>
|
||||
<p>Search the identitiesBySearchKey index using type and value. If an exact
|
||||
match is found, the resulting Identity object is returned. If type is not defined,
|
||||
it will be guessed using a regex list.</p>
|
||||
<p><input type="text" value="martti@moni.com" id="profileQuery" onkeyup="getProfile()" class="form-control"></p>
|
||||
<textarea style="width:100%" rows=10 id="profileResults" class="form-control"></textarea>
|
||||
|
||||
<h3>identity.identicon(100)</h3>
|
||||
<p>Generate identicon of width 100px:</p>
|
||||
<p id="identicon"></p>
|
||||
|
||||
<h3>identity.verified('name')</h3>
|
||||
<p>Get the most verified attribute of type 'name':</p>
|
||||
<p>Result: <b id="verifiedAttribute"></b></p>
|
||||
|
||||
<h2>Create, sign and publish a message</h2>
|
||||
<pre>msg = await Message.createRating(</pre>
|
||||
<textarea id="ratingMsg" style="width: 100%" rows=12 class="form-control">
|
||||
{
|
||||
"author": {
|
||||
name: "Alice",
|
||||
email: "alice@example.com"
|
||||
},
|
||||
"recipient": {
|
||||
name: "Bob",
|
||||
keyID: "4321DCBA"
|
||||
},
|
||||
"rating": 10,
|
||||
"comment": "Good"
|
||||
}</textarea>
|
||||
<pre>
|
||||
);
|
||||
key = await util.getDefaultKey();</pre>
|
||||
<p><input type="button" value="msg.sign(key);" id="signMsg" class="btn btn-primary"></p>
|
||||
<pre id="signMsgResult"></pre>
|
||||
<p><input type="button" value="index.addMessage(msg);" id="publishMsg" class="btn btn-primary"></p>
|
||||
<pre id="publishMsgResult"></pre>
|
||||
<p id="publishMsgResultLink"></p>
|
||||
|
||||
<p>Possible applications:</p>
|
||||
<ul>
|
||||
<li>Contact details search in any application</li>
|
||||
<li>Finding payment addresses in crypto wallets</li>
|
||||
<li>Finding public keys of other users in encrypted instant messaging apps</li>
|
||||
<li>Finding network addresses of servers (instead of using DNS)</li>
|
||||
<li>Filter out untrusted content in decentralized social media</li>
|
||||
<li>Browser plugin to filter the content in existing social media</li>
|
||||
<li>Email spam filtering</li>
|
||||
<li>Filter reviews on marketplace platforms (Airbnb, eBay, Uber, LocalBitcoins)</li>
|
||||
<li>Uncensorable platforms for dispute announcement and resolution</li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
19
iris-lib/example/chatbox/index.html
Normal file
19
iris-lib/example/chatbox/index.html
Normal file
@ -0,0 +1,19 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Live Chat Example</title>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no">
|
||||
<script src="https://cdn.jsdelivr.net/npm/gun/gun.js"></script>
|
||||
<script src="./sea.js"></script>
|
||||
<script src="../iris.js"></script>
|
||||
</head>
|
||||
<body style="background: #c5c7f7">
|
||||
<script type="text/javascript">
|
||||
iris.Key.getDefault().then(key => {
|
||||
var gun = new Gun({peers: ['https://gun-eu.herokuapp.com/gun']});
|
||||
// replace chatLink with your own chat link from iris.to
|
||||
var chatLink = 'https://iris.to/?chatWith=4JhaYuPVcq4y2Sp6sRAGkbwM5FdhsMih3b4E6tvd5W4.ULpD5dhra5ojHtKFEdcTZ80UZEmZnRl4dfM2JCEzj2M&s=ZaUbkxPsQeSSdSP1ety7y19eTjPq1gHu15s1v8cbGX4&k=26vMMto5xufO';
|
||||
iris.Chat.addChatButton({label: 'Live Chat', chatOptions: {gun, key, chatLink}});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
1339
iris-lib/example/chatbox/sea.js
Normal file
1339
iris-lib/example/chatbox/sea.js
Normal file
File diff suppressed because it is too large
Load Diff
127
iris-lib/example/components/index.html
Normal file
127
iris-lib/example/components/index.html
Normal file
@ -0,0 +1,127 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Iris web components</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<script src="https://cdn.jsdelivr.net/npm/gun/gun.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/gun/sea.js"></script>
|
||||
<script src="../iris.js"></script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
|
||||
</head>
|
||||
<body>
|
||||
<div class="jumbotron">
|
||||
<div class="container">
|
||||
<h1 class="display-1">Iris web components</h1>
|
||||
<p class="lead">
|
||||
Just include iris, gun and sea, and these web components are available on your page.
|
||||
</p>
|
||||
<pre>
|
||||
<script src="https://cdn.jsdelivr.net/npm/gun/gun.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/gun/sea.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/iris-lib/dist/iris.js"></script>
|
||||
</pre>
|
||||
<p><a href="https://github.com/irislib/iris-lib">GitHub</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<h2>Text node</h2>
|
||||
<p>
|
||||
Get a text node, optionally editable, from <code>gun.user(pub)</code> space. Useful for fetching profile attributes and other text fields.
|
||||
</p>
|
||||
<p>
|
||||
<code><iris-text path="profile/name" user="hyECQHwSo7fgr2MVfPyakvayPeixxsaAWVtZ-vbaiSc.TXIp8MnCtrnW6n2MrYquWPcc-DTmZzMBmc2yaGv9gIU"/></code>
|
||||
</p>
|
||||
<p>
|
||||
<iris-text path="profile/name" user="hyECQHwSo7fgr2MVfPyakvayPeixxsaAWVtZ-vbaiSc.TXIp8MnCtrnW6n2MrYquWPcc-DTmZzMBmc2yaGv9gIU"/>
|
||||
</p>
|
||||
<p>
|
||||
<code><iris-text path="profile/about" user="hyECQHwSo7fgr2MVfPyakvayPeixxsaAWVtZ-vbaiSc.TXIp8MnCtrnW6n2MrYquWPcc-DTmZzMBmc2yaGv9gIU"/></code>
|
||||
</p>
|
||||
<p>
|
||||
<iris-text path="profile/about" user="hyECQHwSo7fgr2MVfPyakvayPeixxsaAWVtZ-vbaiSc.TXIp8MnCtrnW6n2MrYquWPcc-DTmZzMBmc2yaGv9gIU"/>
|
||||
</p>
|
||||
|
||||
<p>For currently logged in user attribute, leave user blank: <code>user=""</code>. It will be contenteditable, unless you add <code>editable="false"</code>.</p>
|
||||
<p>
|
||||
<code><iris-text placeholder="What's your name?" user="" path="profile/name"/></code><br/>
|
||||
<code>Hello <b><iris-text placeholder="name" user="" editable="false" path="profile/name"/></b>!</code>
|
||||
</p>
|
||||
<p>
|
||||
<iris-text placeholder="What's your name?" user="" path="profile/name"/>
|
||||
<br/>
|
||||
Hello <b><iris-text placeholder="name" user="" editable="false" path="profile/name"></iris-text></b>!
|
||||
</p>
|
||||
|
||||
<p>To parse user input as JSON, add <code>json="true"</code>.</p>
|
||||
|
||||
<h2>Image node</h2>
|
||||
<p>Same as text node, but stores a base64 image. If user === loggedInUser, you can click the photo to change it.</p>
|
||||
<p>
|
||||
<code><iris-img btn-class="btn btn-primary" path="profile/photo"/></code>
|
||||
</p>
|
||||
<p>
|
||||
<iris-img btn-class="btn btn-primary" path="profile/photo"/>
|
||||
</p>
|
||||
|
||||
<h2>Identicon</h2>
|
||||
<p>
|
||||
<code><iris-identicon user="hyECQHwSo7fgr2MVfPyakvayPeixxsaAWVtZ-vbaiSc.TXIp8MnCtrnW6n2MrYquWPcc-DTmZzMBmc2yaGv9gIU" width="100"/></code>
|
||||
</p>
|
||||
<p>
|
||||
<iris-identicon user="hyECQHwSo7fgr2MVfPyakvayPeixxsaAWVtZ-vbaiSc.TXIp8MnCtrnW6n2MrYquWPcc-DTmZzMBmc2yaGv9gIU" width="100"/>
|
||||
</p>
|
||||
|
||||
<h2>Copy button</h2>
|
||||
<p>
|
||||
<code><iris-copy-button inner-class="btn btn-primary" str="https://iris.to/#/profile/hyECQHwSo7fgr2MVfPyakvayPeixxsaAWVtZ-vbaiSc.TXIp8MnCtrnW6n2MrYquWPcc-DTmZzMBmc2yaGv9gIU"/></code>
|
||||
</p>
|
||||
<p>
|
||||
<iris-copy-button inner-class="btn btn-primary" str="https://iris.to/#/profile/hyECQHwSo7fgr2MVfPyakvayPeixxsaAWVtZ-vbaiSc.TXIp8MnCtrnW6n2MrYquWPcc-DTmZzMBmc2yaGv9gIU"/>
|
||||
</p>
|
||||
|
||||
<h2>Follow button</h2>
|
||||
<p>
|
||||
<code><iris-follow-button inner-class="btn btn-primary" user="hyECQHwSo7fgr2MVfPyakvayPeixxsaAWVtZ-vbaiSc.TXIp8MnCtrnW6n2MrYquWPcc-DTmZzMBmc2yaGv9gIU"/></code>
|
||||
</p>
|
||||
<p>
|
||||
<iris-follow-button inner-class="btn btn-primary" user="hyECQHwSo7fgr2MVfPyakvayPeixxsaAWVtZ-vbaiSc.TXIp8MnCtrnW6n2MrYquWPcc-DTmZzMBmc2yaGv9gIU"/>
|
||||
</p>
|
||||
|
||||
<h2>Search</h2>
|
||||
<p>
|
||||
<code><iris-search inner-class="form-control"/></code>
|
||||
<pre>
|
||||
<script type="text/javascript">
|
||||
window.onIrisSearchSelect = item => doSomething(item);
|
||||
</script>
|
||||
</pre>
|
||||
</p>
|
||||
<p>
|
||||
<iris-search id="search" inner-class="form-control"/>
|
||||
<script type="text/javascript">
|
||||
window.onIrisSearchSelect = i => {
|
||||
console.log(i);
|
||||
const identicon = document.querySelector('#selected-result-identicon');
|
||||
identicon.style.display = '';
|
||||
identicon.setAttribute('user', i.key);
|
||||
const nameEl = document.querySelector('#selected-result-name');
|
||||
nameEl.style.display = '';
|
||||
nameEl.setAttribute('user', i.key);
|
||||
document.querySelector('#search-result-raw').innerHTML = JSON.stringify(i);
|
||||
}
|
||||
</script>
|
||||
</p>
|
||||
|
||||
<h3>
|
||||
<iris-text style="display:none" id="selected-result-name" path="profile/name"/>
|
||||
</h3>
|
||||
<p>
|
||||
<iris-identicon style="display: none;" id="selected-result-identicon" width="100"/>
|
||||
</p>
|
||||
<pre id="search-result-raw"></pre>
|
||||
|
||||
<hr style="margin-bottom:500px" />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
BIN
iris-lib/example/favicon.ico
Normal file
BIN
iris-lib/example/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
11881
iris-lib/example/iris.js
Normal file
11881
iris-lib/example/iris.js
Normal file
File diff suppressed because one or more lines are too long
15
iris-lib/example/nodejs-example.js
Normal file
15
iris-lib/example/nodejs-example.js
Normal file
@ -0,0 +1,15 @@
|
||||
const identifi = require('../cjs/');
|
||||
|
||||
identifi.Index.load().then(async (index) => {
|
||||
let r = await index.search('ma');
|
||||
console.log('Search results for "ma":');
|
||||
console.log(JSON.stringify(r, null, 2));
|
||||
console.log();
|
||||
console.log('Identity profile for martti@moni.com:');
|
||||
r = await index.get('martti@moni.com');
|
||||
console.log(JSON.stringify(r, null, 2));
|
||||
console.log();
|
||||
console.log('The most verified name for martti@moni.com:');
|
||||
console.log(JSON.stringify(r.verified('name'), null, 2));
|
||||
})
|
||||
;
|
113
iris-lib/example/script.js
Normal file
113
iris-lib/example/script.js
Normal file
@ -0,0 +1,113 @@
|
||||
let index, msg, key;
|
||||
|
||||
gun = new Gun(['http://localhost:8765/gun']);
|
||||
|
||||
index = new window.irisLib.Index({gun}); // <--- Create identifi index
|
||||
|
||||
index.ready.then(async () => {
|
||||
document.getElementById('searchResults').textContent = 'Searching...';
|
||||
document.getElementById('profileResults').textContent = 'Searching...';
|
||||
await search(index);
|
||||
await getProfile(index);
|
||||
document.getElementById('query').addEventListener('change', search);
|
||||
document.getElementById('profileQuery').addEventListener('change', getProfile);
|
||||
document.getElementById('signMsg').addEventListener('click', signMsg);
|
||||
document.getElementById('publishMsg').addEventListener('click', publishMsg);
|
||||
document.getElementById('runIndexExample').addEventListener('click', runIndexExample);
|
||||
const searchWidget = document.getElementById('searchWidget');
|
||||
window.irisLib.Identity.appendSearchWidget(searchWidget, index);
|
||||
});
|
||||
|
||||
async function search() {
|
||||
const query = document.getElementById('query').value;
|
||||
|
||||
let r = await index.search(query); // <--- Search identities from identifi
|
||||
|
||||
let text = `Search results for "${query}":\n`;
|
||||
document.getElementById('searchResults').textContent = text;
|
||||
r.sort((a, b) => {return a.trustDistance - b.trustDistance;});
|
||||
r.forEach(i => {
|
||||
console.log('ii', i);
|
||||
document.getElementById('searchResults').appendChild(i.profileCard());
|
||||
});
|
||||
}
|
||||
|
||||
async function getProfile() {
|
||||
const profileQuery = document.getElementById('profileQuery').value;
|
||||
const identiconParent = document.getElementById('identicon');
|
||||
const verifiedAttributeEl = document.getElementById('verifiedAttribute');
|
||||
|
||||
i = await index.get(profileQuery); // <--- Get an identity from identifi
|
||||
|
||||
let text = `Identity profile for ${profileQuery}:\n`;
|
||||
if (i) {
|
||||
const data = await new Promise(resolve => i.gun.load(r => resolve(r)));
|
||||
text += JSON.stringify(data, null, 2);
|
||||
const verifiedName = await i.verified('name'); // <--- Get a verified name of an identity
|
||||
verifiedAttributeEl.textContent = verifiedName;
|
||||
|
||||
console.log('i', i);
|
||||
const identicon = i.identicon(100); // <--- Generate an identity icon as a DOM element, width 100px
|
||||
identiconParent.innerHTML = '';
|
||||
identiconParent.appendChild(identicon);
|
||||
} else {
|
||||
identiconParent.innerHTML = '';
|
||||
verifiedAttributeEl.innerHTML = '-';
|
||||
text += 'Profile not found'
|
||||
}
|
||||
document.getElementById('profileResults').textContent = text;
|
||||
}
|
||||
|
||||
function signMsg() {
|
||||
const d = document.getElementById('ratingMsg').value;
|
||||
const msgData = JSON.parse(d);
|
||||
window.message = window.irisLib.Message.createRating(msgData); // <--- Create an Identifi message
|
||||
key = window.irisLib.Key.getDefault(); // <--- Get or generate local key
|
||||
window.message.sign(key); // <--- Sign message with the key
|
||||
document.getElementById('signMsgResult').textContent = JSON.stringify(window.message, null, 2);
|
||||
}
|
||||
|
||||
async function publishMsg() {
|
||||
const r = await index.addMessage(window.message);
|
||||
document.getElementById('publishMsgResult').textContent = JSON.stringify(r);
|
||||
if (r && r.hash) {
|
||||
const link = `https://ipfs.io/ipfs/${r.hash}`;
|
||||
const el = document.getElementById('publishMsgResultLink');
|
||||
el.className = `alert alert-info`;
|
||||
el.innerHTML = `<a href="${link}">${link}</a>`;
|
||||
}
|
||||
}
|
||||
|
||||
async function runIndexExample() {
|
||||
el = document.getElementById('runIndexExampleResult');
|
||||
el.innerHTML = '';
|
||||
|
||||
ipfs = new window.Ipfs();
|
||||
await new Promise((resolve, reject) => {
|
||||
ipfs.on('ready', () => {
|
||||
console.log('ipfs ready');
|
||||
resolve();
|
||||
});
|
||||
ipfs.on('error', error => {
|
||||
console.error(error.message);
|
||||
reject();
|
||||
});
|
||||
});
|
||||
index = new window.irisLib.Index({gun, ipfs});
|
||||
myKey = window.irisLib.Key.getDefault('.');
|
||||
msg = window.irisLib.Message.createVerification({
|
||||
recipient: {'keyID': myKey.keyID, 'name': 'Alice Example'},
|
||||
comment: 'add name'
|
||||
}, myKey);
|
||||
await index.addMessage(msg);
|
||||
msg2 = window.irisLib.Message.createRating({
|
||||
recipient: {'email': 'bob@example.com'},
|
||||
rating: 5
|
||||
}, myKey);
|
||||
await index.addMessage(msg2);
|
||||
identities = await index.search('');
|
||||
el.innerHTML += 'Identities in index:\n'
|
||||
el.innerHTML += JSON.stringify(identities, null, 2);
|
||||
uri = await index.save();
|
||||
el.innerHTML += '\nSaved index URI: ' + uri
|
||||
}
|
135
iris-lib/package.json
Normal file
135
iris-lib/package.json
Normal file
@ -0,0 +1,135 @@
|
||||
{
|
||||
"name": "iris-lib",
|
||||
"version": "0.0.159",
|
||||
"description": "Basic tools for reading and writing Iris messages and identities.",
|
||||
"main": "src/index.js",
|
||||
"react-native": {
|
||||
"fs": false
|
||||
},
|
||||
"browser": "dist/iris.js",
|
||||
"module": "es/index.js",
|
||||
"jsxnext:main": "es/index.js",
|
||||
"jest": {
|
||||
"testURL": "http://localhost/",
|
||||
"bail": true,
|
||||
"forceExit": true,
|
||||
"testEnvironment": "jsdom",
|
||||
"verbose": true,
|
||||
"collectCoverage": true,
|
||||
"watchPathIgnorePatterns": [
|
||||
"jest-results.json",
|
||||
"jest-stare.*",
|
||||
""
|
||||
],
|
||||
"reporters": [
|
||||
"default",
|
||||
[
|
||||
"./node_modules/jest-html-reporter",
|
||||
{
|
||||
"pageTitle": "Test Report",
|
||||
"includeFailureMsg": true,
|
||||
"includeConsoleLog": true
|
||||
}
|
||||
],
|
||||
"jest-stare"
|
||||
],
|
||||
"testPathIgnorePatterns": [
|
||||
"/node_modules/",
|
||||
"/yarn_dev/",
|
||||
"/yarn_prod/"
|
||||
],
|
||||
"modulePaths": [
|
||||
"<rootDir>/node_modules/",
|
||||
"<rootDir>/cjs/"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"cjs",
|
||||
"es",
|
||||
"src"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"release": "release-it",
|
||||
"coveralls": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls",
|
||||
"lint": "yarn run lint:eslint",
|
||||
"lint:eslint": "eslint src/*.js",
|
||||
"lint:flow": "flow --color always",
|
||||
"test": "clear && jest",
|
||||
"test:coverage": "jest --coverage ",
|
||||
"test:watch": "clear && yarn build:cjs && jest --watchAll",
|
||||
"test:debug": "node --inspect node_modules/.bin/jest --runInBand",
|
||||
"test:all": "yarn lint:test && yarn lint && yarn test:coverage --runInBand",
|
||||
"lint:test": "yarn run lint && npm run test:coverage",
|
||||
"build": "clear && npm run build:cjs && npm run lint:test && npm run build:es && npm run build:umd && npm run build:docs",
|
||||
"build:watch": "clear && rimraf cjs && cross-env BABEL_ENV=cjs babel -w src --out-dir cjs",
|
||||
"build:es": "rimraf es && cross-env BABEL_ENV=es babel src --out-dir es",
|
||||
"build:cjs": "rimraf cjs && cross-env BABEL_ENV=cjs babel src --out-dir cjs",
|
||||
"build:umd": "rimraf dist && cross-env BABEL_ENV=es rollup -c & cross-env BABEL_ENV=es NODE_ENV=production rollup -c",
|
||||
"build:umdev": "rimraf dist && cross-env BABEL_ENV=es rollup -c",
|
||||
"build:docs": "documentation build src/** -f html -o docs --config documentation.yml",
|
||||
"build:run": "clear && rimraf cjs && cross-env BABEL_ENV=cjs yarn nodemon src/server.js --watch src --exec babel-node",
|
||||
"dev": "concurrently -n build,tests \"yarn build:watch\" \"yarn test:watch\"",
|
||||
"dev:server": "concurrently -n build,tests,server \"yarn build:watch\" \"yarn test:watch\" \"yarn build:run\"",
|
||||
"serve": "node cjs/server.js",
|
||||
"start": "node cjs/server.js",
|
||||
"heroku-postbuild": "echo \"not running build script\""
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Martti Malmi (martti.malmi@iki.fi)",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/irislib/iris-lib",
|
||||
"homepage": "https://github.com/irislib/iris-lib",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.19.1",
|
||||
"@babel/node": "^7.19.1",
|
||||
"@babel/preset-env": "^7.19.1",
|
||||
"babel-cli": "^6.26.0",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-plugin-add-module-exports": "^1.0.4",
|
||||
"babel-plugin-external-helpers": "^6.22.0",
|
||||
"babel-plugin-transform-flow-strip-types": "^6.22.0",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"concurrently": "^4.1.1",
|
||||
"coveralls": "^3.0.2",
|
||||
"cross-env": "^5.2.0",
|
||||
"documentation": "^9.1.1",
|
||||
"eslint": "^8.23.1",
|
||||
"flow-bin": "^0.79.1",
|
||||
"http-server": "^0.12.1",
|
||||
"jest": "^23.5.0",
|
||||
"jest-html-reporter": "^2.5.0",
|
||||
"jest-stare": "^1.16.0",
|
||||
"jquery": "^3.4.1",
|
||||
"nodemon": "^1.19.1",
|
||||
"release-it": "^12.3.0",
|
||||
"rimraf": "^2.6.2",
|
||||
"rollup": "^0.65.0",
|
||||
"rollup-plugin-babel": "^3.0.7",
|
||||
"rollup-plugin-commonjs": "^9.1.6",
|
||||
"rollup-plugin-filesize": "^4.0.1",
|
||||
"rollup-plugin-hypothetical": "^2.1.0",
|
||||
"rollup-plugin-ignore": "^1.0.4",
|
||||
"rollup-plugin-json": "^3.0.0",
|
||||
"rollup-plugin-node-builtins": "^2.1.2",
|
||||
"rollup-plugin-node-globals": "^1.2.1",
|
||||
"rollup-plugin-node-resolve": "^3.3.0",
|
||||
"rollup-plugin-terser": "^1.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"gun": "^0.2020.1238"
|
||||
},
|
||||
"dependencies": {
|
||||
"fuse.js": "^6.6.2",
|
||||
"htm": "^3.1.1",
|
||||
"identicon.js": "^2.3.3",
|
||||
"jsxstyle": "^2.5.1",
|
||||
"preact": "^10.11.0",
|
||||
"preact-custom-element": "^4.2.1"
|
||||
}
|
||||
}
|
64
iris-lib/rollup.config.js
Normal file
64
iris-lib/rollup.config.js
Normal file
@ -0,0 +1,64 @@
|
||||
import json from 'rollup-plugin-json';
|
||||
import babel from 'rollup-plugin-babel';
|
||||
import nodeResolve from 'rollup-plugin-node-resolve';
|
||||
import {terser} from 'rollup-plugin-terser';
|
||||
import filesize from 'rollup-plugin-filesize';
|
||||
import commonjs from 'rollup-plugin-commonjs';
|
||||
import builtins from 'rollup-plugin-node-builtins';
|
||||
import globals from 'rollup-plugin-node-globals';
|
||||
import hypothetical from 'rollup-plugin-hypothetical';
|
||||
import ignore from 'rollup-plugin-ignore';
|
||||
|
||||
const name = `iris`;
|
||||
|
||||
const plugins = [
|
||||
ignore(['gun/lib/then', 'gun/lib/load']),
|
||||
hypothetical({
|
||||
allowFallthrough: true,
|
||||
files: {
|
||||
'node-webcrypto-ossl/': `
|
||||
export default {};
|
||||
`,
|
||||
'text-encoding/': `
|
||||
export default {};
|
||||
`,
|
||||
'@trust/webcrypto/': `
|
||||
export default {};
|
||||
`
|
||||
}
|
||||
}),
|
||||
json(),
|
||||
babel({
|
||||
exclude: 'node_modules/**',
|
||||
plugins: ['external-helpers', 'transform-runtime'],
|
||||
runtimeHelpers: true
|
||||
}),
|
||||
builtins(),
|
||||
nodeResolve({
|
||||
module: true,
|
||||
jsnext: true,
|
||||
browser: true,
|
||||
}),
|
||||
commonjs({
|
||||
include: `node_modules/**`
|
||||
}),
|
||||
filesize(),
|
||||
globals()
|
||||
];
|
||||
|
||||
const isProd = process.env.NODE_ENV === `production`;
|
||||
if (isProd) plugins.push(terser());
|
||||
|
||||
export default {
|
||||
input: `src/index.js`,
|
||||
external: ['gun', 'gun/sea'],
|
||||
plugins,
|
||||
output: {
|
||||
file: `dist/${name}${isProd ? `.min` : ``}.js`,
|
||||
name,
|
||||
format: `umd`,
|
||||
globals: {
|
||||
gun: 'Gun'
|
||||
}
|
||||
}
|
||||
};
|
@ -123,7 +123,7 @@ export default {
|
||||
} else if (document.selection) {
|
||||
el.focus();
|
||||
const r = document.selection.createRange();
|
||||
if (r == null) {
|
||||
if (r === null) {
|
||||
return 0;
|
||||
}
|
||||
const re = el.createTextRange(), rc = re.duplicate();
|
||||
@ -566,10 +566,10 @@ export default {
|
||||
return 'today';
|
||||
}
|
||||
const dayDifference = Math.round((now - date) / (1000 * 60 * 60 * 24));
|
||||
if(dayDifference == 0){
|
||||
if (dayDifference === 0) {
|
||||
return 'today';
|
||||
}
|
||||
if (dayDifference == 1) {
|
||||
if (dayDifference === 1) {
|
||||
return 'yesterday';
|
||||
}
|
||||
if (dayDifference <= 5) {
|
11261
iris-lib/yarn.lock
Normal file
11261
iris-lib/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,10 +6,9 @@
|
||||
"build": "preact build --no-prerender",
|
||||
"serve": "sirv build --port 8080 --cors --single",
|
||||
"dev": "preact watch --host localhost --sw",
|
||||
"lint": "eslint src",
|
||||
"lint": "eslint src;eslint iris-lib/src",
|
||||
"test": "jest",
|
||||
"build:lib": "echo 'placeholder for building lib'",
|
||||
"build:docs": "documentation build src/js/iris-lib/** -f html -o docs"
|
||||
"build:docs": "documentation build iris-lib/src/** -f html -o docs"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "preact",
|
||||
@ -50,6 +49,7 @@
|
||||
"webpack-build-notifier": "^2.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"iris-lib": "file:./iris-lib",
|
||||
"@walletconnect/web3-provider": "^1.7.8",
|
||||
"@zxing/library": "^0.18.6",
|
||||
"aether-torrent": "^0.3.0",
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {translate as t} from './translations/Translation';
|
||||
import $ from 'jquery';
|
||||
import _ from 'lodash';
|
||||
import iris from './iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
import Autolinker from 'autolinker';
|
||||
|
||||
const emojiRegex = /[\u{1f300}-\u{1f5ff}\u{1f900}-\u{1f9ff}\u{1f600}-\u{1f64f}\u{1f680}-\u{1f6ff}\u{2600}-\u{26ff}\u{2700}-\u{27bf}\u{1f1e6}-\u{1f1ff}\u{1f191}-\u{1f251}\u{1f004}\u{1f0cf}\u{1f170}-\u{1f171}\u{1f17e}-\u{1f17f}\u{1f18e}\u{3030}\u{2b50}\u{2b55}\u{2934}-\u{2935}\u{2b05}-\u{2b07}\u{2b1b}-\u{2b1c}\u{3297}\u{3299}\u{303d}\u{00a9}\u{00ae}\u{2122}\u{23f3}\u{24c2}\u{23e9}-\u{23ef}\u{25b6}\u{23f8}-\u{23fa}]+/ug;
|
||||
|
@ -3,7 +3,7 @@ import Session from './Session';
|
||||
import { route } from 'preact-router';
|
||||
import State from './State';
|
||||
import _ from 'lodash';
|
||||
import iris from './iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
import Gun from 'gun';
|
||||
import $ from 'jquery';
|
||||
|
||||
|
@ -4,7 +4,7 @@ import Notifications from './Notifications';
|
||||
import Helpers from './Helpers';
|
||||
import PeerManager from './PeerManager';
|
||||
import { route } from 'preact-router';
|
||||
import iris from './iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
import _ from 'lodash';
|
||||
import Fuse from "./lib/fuse.basic.esm.min";
|
||||
import localforage from './lib/localforage.min';
|
||||
|
@ -9,7 +9,7 @@ import _ from 'lodash';
|
||||
import Fun from './Fun';
|
||||
|
||||
import PeerManager from './PeerManager';
|
||||
import iris from './iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
import Helpers from './Helpers';
|
||||
|
||||
const State = {
|
||||
|
@ -2,7 +2,7 @@ import { Component } from 'preact';
|
||||
import Helpers from '../Helpers';
|
||||
import {translate as t} from '../translations/Translation';
|
||||
import $ from 'jquery';
|
||||
import iris from '../iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
import { OptionalGetter } from '../types';
|
||||
import Button from './basic/Button';
|
||||
|
||||
|
@ -9,7 +9,7 @@ import SafeImg from './SafeImg';
|
||||
import Torrent from './Torrent';
|
||||
import $ from 'jquery';
|
||||
import EmojiButton from '../lib/emoji-button';
|
||||
import iris from '../iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
import SearchBox from './SearchBox';
|
||||
import MessageForm from './MessageForm';
|
||||
|
||||
|
@ -8,7 +8,7 @@ import { route } from 'preact-router';
|
||||
import Identicon from './Identicon';
|
||||
import SearchBox from './SearchBox';
|
||||
import Icons from '../Icons';
|
||||
import iris from '../iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
import {Link} from "preact-router/match";
|
||||
|
||||
import $ from 'jquery';
|
||||
|
@ -1,6 +1,6 @@
|
||||
import Component from '../BaseComponent';
|
||||
import State from '../State';
|
||||
import iris from '../iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
import Identicon from 'identicon.js';
|
||||
import SafeImg from './SafeImg';
|
||||
import styled from 'styled-components';
|
||||
|
@ -4,7 +4,7 @@ import { html } from 'htm/preact';
|
||||
import Session from '../Session';
|
||||
import Torrent from './Torrent';
|
||||
import Autolinker from 'autolinker';
|
||||
import iris from '../iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
import $ from 'jquery';
|
||||
import State from '../State';
|
||||
import {route} from 'preact-router';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Component } from 'preact';
|
||||
import State from '../State';
|
||||
import Session from '../Session';
|
||||
import iris from '../iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
|
||||
function twice(f) {
|
||||
f();
|
||||
|
@ -10,7 +10,7 @@ import Session from '../Session';
|
||||
import Torrent from './Torrent';
|
||||
import Icons from '../Icons';
|
||||
import Autolinker from 'autolinker';
|
||||
import iris from '../iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
import $ from 'jquery';
|
||||
import {Helmet} from "react-helmet";
|
||||
import Notifications from '../Notifications';
|
||||
|
@ -13,7 +13,7 @@ import View from './View';
|
||||
import SearchBox from '../components/SearchBox';
|
||||
import {SMS_VERIFIER_PUB} from '../SMS';
|
||||
import $ from 'jquery';
|
||||
import iris from '../iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
import Button from '../components/basic/Button';
|
||||
|
||||
function deleteChat(uuid) {
|
||||
|
@ -5,7 +5,7 @@ import Button from '../components/basic/Button';
|
||||
import {translate as t} from '../translations/Translation';
|
||||
import Name from '../components/Name';
|
||||
import View from './View';
|
||||
import iris from '../iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
import PublicMessage from "../components/PublicMessage";
|
||||
import NotificationTools from "../Notifications";
|
||||
|
||||
|
@ -16,7 +16,7 @@ import View from './View';
|
||||
import { Link } from 'preact-router/match';
|
||||
import $ from 'jquery';
|
||||
import QRCode from '../lib/qrcode.min';
|
||||
import iris from '../iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
import {Helmet} from "react-helmet";
|
||||
import {SMS_VERIFIER_PUB} from '../SMS';
|
||||
import ProfilePhoto from '../components/ProfilePhoto';
|
||||
|
@ -4,7 +4,7 @@ import { translate as t } from '../../translations/Translation';
|
||||
import Torrent from '../../components/Torrent';
|
||||
import State from '../../State';
|
||||
import Session from '../../Session';
|
||||
import iris from '../../iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import EmojiButton from '../../lib/emoji-button';
|
||||
|
@ -7,7 +7,7 @@ import CopyButton from '../../components/CopyButton';
|
||||
import { route } from 'preact-router';
|
||||
import $ from 'jquery';
|
||||
import QRCode from '../../lib/qrcode.min';
|
||||
import iris from '../../iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
import Component from '../../BaseComponent';
|
||||
import {Helmet} from 'react-helmet';
|
||||
import Button from '../../components/basic/Button';
|
||||
|
@ -12,7 +12,7 @@ import Notifications from '../../Notifications';
|
||||
import NewChat from './newchat/NewChat';
|
||||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import iris from '../../iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
import {Helmet} from 'react-helmet';
|
||||
import Component from '../../BaseComponent';
|
||||
|
||||
|
@ -3,7 +3,7 @@ import Session from '../../../Session';
|
||||
import $ from 'jquery';
|
||||
import Component from '../../../BaseComponent';
|
||||
import Button from '../../../components/basic/Button';
|
||||
import iris from '../../../iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
import { route } from 'preact-router';
|
||||
import State from '../../../State';
|
||||
|
||||
|
@ -7,7 +7,7 @@ import Button from '../../../components/basic/Button';
|
||||
import $ from 'jquery';
|
||||
import Component from '../../../BaseComponent';
|
||||
import { route } from 'preact-router';
|
||||
import iris from '../../../iris-lib';
|
||||
import iris from 'iris-lib';
|
||||
|
||||
class MainView extends Component {
|
||||
constructor() {
|
||||
|
14
yarn.lock
14
yarn.lock
@ -7652,7 +7652,7 @@ hsla-regex@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38"
|
||||
integrity sha512-7Wn5GMLuHBjZCb2bTmnDOycho0p/7UVaAeqXZGbHrBCl6Yd/xDhQJAXe6Ga9AXJH2I5zY1dEdYw2u1UptnSBJA==
|
||||
|
||||
htm@^3.1.0:
|
||||
htm@^3.1.0, htm@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/htm/-/htm-3.1.1.tgz#49266582be0dc66ed2235d5ea892307cc0c24b78"
|
||||
integrity sha512-983Vyg8NwUE7JkZ6NmOqpCZ+sh1bKv2iYTlUkzlWmA5JD2acKoxd4KVxbMmxX/85mtfdnDmTFoNKcg5DGAvxNQ==
|
||||
@ -8062,6 +8062,16 @@ ipaddr.js@1.9.1:
|
||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0"
|
||||
integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==
|
||||
|
||||
"iris-lib@file:./iris-lib":
|
||||
version "0.0.159"
|
||||
dependencies:
|
||||
fuse.js "^6.6.2"
|
||||
htm "^3.1.1"
|
||||
identicon.js "^2.3.3"
|
||||
jsxstyle "^2.5.1"
|
||||
preact "^10.11.0"
|
||||
preact-custom-element "^4.2.1"
|
||||
|
||||
is-absolute-url@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6"
|
||||
@ -12173,7 +12183,7 @@ preact@10.4.1:
|
||||
resolved "https://registry.yarnpkg.com/preact/-/preact-10.4.1.tgz#9b3ba020547673a231c6cf16f0fbaef0e8863431"
|
||||
integrity sha512-WKrRpCSwL2t3tpOOGhf2WfTpcmbpxaWtDbdJdKdjd0aEiTkvOmS4NBkG6kzlaAHI9AkQ3iVqbFWM3Ei7mZ4o1Q==
|
||||
|
||||
preact@^10.5.14:
|
||||
preact@^10.11.0, preact@^10.5.14:
|
||||
version "10.11.0"
|
||||
resolved "https://registry.yarnpkg.com/preact/-/preact-10.11.0.tgz#26af45a0613f4e17a197cc39d7a1ea23e09b2532"
|
||||
integrity sha512-Fk6+vB2kb6mSJfDgODq0YDhMfl0HNtK5+Uc9QqECO4nlyPAQwCI+BKyWO//idA7ikV7o+0Fm6LQmNuQi1wXI1w==
|
||||
|
Loading…
Reference in New Issue
Block a user