diff options
author | pukkamustard <pukkamustard@posteo.net> | 2020-06-10 17:58:43 +0200 |
---|---|---|
committer | pukkamustard <pukkamustard@posteo.net> | 2020-06-10 17:58:43 +0200 |
commit | e5f9fc2d38e757fec1f80c537cbad3a3c3ab6089 (patch) | |
tree | 2e893b59d46656ed173185d5ebd73432867b0514 | |
parent | bde4ce46aa2031bb7b1b811048ea8b577d320f82 (diff) |
web-demo: ipfs (kinda)
-rw-r--r-- | examples/web-demo/index.html | 13 | ||||
-rw-r--r-- | examples/web-demo/package-lock.json | 98 | ||||
-rw-r--r-- | examples/web-demo/src/index.js | 141 | ||||
-rw-r--r-- | src/eris.js | 2 |
4 files changed, 181 insertions, 73 deletions
diff --git a/examples/web-demo/index.html b/examples/web-demo/index.html index 62d9dd3..6381519 100644 --- a/examples/web-demo/index.html +++ b/examples/web-demo/index.html @@ -21,9 +21,8 @@ <div id="input"> <h2>Input</h2> - <p>Enter some text and click Encode to get the URN that uniquely identifies the text.</p> - - <textarea id="input-textarea"></textarea> + <textarea id="input-textarea" + placeholder="Enter some text and click Encode..."></textarea> <br> <br> @@ -85,6 +84,14 @@ <div id="blocks"> <h3>Blocks</h3> + <p>Blocks are stored in memory and can be removed or randomized (corrupted).</p> + + <details> + <summary>IPFS</summary> + <p>Optionally IPFS can be used as block storage and transport. Note: This does not work reliably from the browser. For more reliable demos of how to use ERIS with IPFS see the <a href="https://gitlab.com/openengiadina/data-model/">Guile</a> and <a href="https://gitlab.com/openengiadina/js-eris/-/tree/master/examples/ipfs">node.js </a> implementations/demos.</p> + <input id="checkbox-enable-ipfs" type="checkbox">enable IPFS</input> + </details> + <div id="block-container"> </div> </div> diff --git a/examples/web-demo/package-lock.json b/examples/web-demo/package-lock.json index 64c3c06..b7d072a 100644 --- a/examples/web-demo/package-lock.json +++ b/examples/web-demo/package-lock.json @@ -4710,16 +4710,16 @@ } }, "ipld": { - "version": "0.26.2", - "resolved": "https://registry.npmjs.org/ipld/-/ipld-0.26.2.tgz", - "integrity": "sha512-HGBXh3kBXVGpvmuIaHYn18tBGqNmmaGv4PLgKkKuwqnn6YE/zl/EI5qrKDuPmZ1Vu07GJdacCw2+Tf/PzG3eug==", + "version": "0.26.3", + "resolved": "https://registry.npmjs.org/ipld/-/ipld-0.26.3.tgz", + "integrity": "sha512-x6Udh4LVMerZduKk0eRNOhBKJeZwQgZ1YIH9AR7E5RjRJ0cPqEpq43DGbiHhU5XOXjBQiwdJwX5p9pxxiKkG9Q==", "requires": { "buffer": "^5.6.0", "cids": "~0.8.0", "ipld-block": "~0.9.1", "ipld-dag-cbor": "~0.15.0", "ipld-dag-pb": "~0.18.1", - "ipld-raw": "^4.0.0", + "ipld-raw": "^5.0.0", "merge-options": "^2.0.0", "multicodec": "^1.0.0", "typical": "^6.0.0" @@ -4733,6 +4733,16 @@ "base64-js": "^1.0.2", "ieee754": "^1.1.4" } + }, + "ipld-raw": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ipld-raw/-/ipld-raw-5.0.0.tgz", + "integrity": "sha512-z1Fie224lTtQZbFg+wC5WDY692G3SIpO8vT86yCU83vqpIvasVuV3SzDSv7G36kRxP03PPZOkvKAOFrcjb7gpw==", + "requires": { + "cids": "~0.8.0", + "multicodec": "^1.0.1", + "multihashing-async": "~0.8.1" + } } } }, @@ -4802,9 +4812,9 @@ } }, "ipld-dag-cbor": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/ipld-dag-cbor/-/ipld-dag-cbor-0.15.2.tgz", - "integrity": "sha512-Ioni4s959P/CtkWQOt1TXrj4zqc3MoPxvHrEmybCn5JFdG3dpBNJR1oBVvP6uUrmF5bBtUGKNbX1pSI5SEOaHg==", + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/ipld-dag-cbor/-/ipld-dag-cbor-0.15.3.tgz", + "integrity": "sha512-m23nG7ZyoVFnkK55/bLAErc7EfiMgaEQlqHWDTGzPI+O5r6bPfp+qbL5zTVSIT8tpbHmu174dwerVtLoVgeVyA==", "requires": { "borc": "^2.1.2", "buffer": "^5.5.0", @@ -5692,6 +5702,9 @@ }, "js-eris": { "version": "file:../..", + "requires": { + "libsodium-wrappers-sumo": "^0.7.6" + }, "dependencies": { "libsodium-sumo": { "version": "0.7.6", @@ -6234,9 +6247,9 @@ } }, "libp2p-crypto": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/libp2p-crypto/-/libp2p-crypto-0.17.6.tgz", - "integrity": "sha512-ixTSlXXObarf2x+8voGBywr2SyiZh4nw21ZRe1FVz4sxg47crXLqBXhb7gGy2U6Kf0ANbTVaOgLs45WAtM/HpQ==", + "version": "0.17.7", + "resolved": "https://registry.npmjs.org/libp2p-crypto/-/libp2p-crypto-0.17.7.tgz", + "integrity": "sha512-z5Vkser8oGKsF8MAWovmXtFnEG7PqsgxrIgdSDejs2N6X+g3hUKFtxL/sKZpWD3tlLywcH9wqoE9L096ExB1lA==", "requires": { "buffer": "^5.5.0", "err-code": "^2.0.0", @@ -6245,7 +6258,7 @@ "keypair": "^1.0.1", "multibase": "^0.7.0", "multihashing-async": "^0.8.1", - "node-forge": "~0.9.1", + "node-forge": "^0.9.1", "pem-jwk": "^2.0.0", "protons": "^1.0.1", "secp256k1": "^4.0.0", @@ -6570,65 +6583,16 @@ } }, "libp2p-keychain": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/libp2p-keychain/-/libp2p-keychain-0.6.0.tgz", - "integrity": "sha512-r0EmaRvEwOImiYxrhTAjxzFf+JHxk66ooMezHF/LkXIdncc/eGt32k80UvnJ/xgoCzDHl4IlzXu1j8VKxy/80g==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/libp2p-keychain/-/libp2p-keychain-0.6.1.tgz", + "integrity": "sha512-7K7MZ4KHQVtudAatPnJ2eWI0NvnXxtdEnp3+AXdiDd4/DmwF4wLu+XJ0PR9EQpnsMNu8tIgsNUIA8bmDyUU5iw==", "requires": { "err-code": "^2.0.0", - "interface-datastore": "^0.8.0", + "interface-datastore": "^1.0.2", "libp2p-crypto": "^0.17.1", "merge-options": "^2.0.0", "node-forge": "^0.9.1", "sanitize-filename": "^1.6.1" - }, - "dependencies": { - "buffer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", - "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "interface-datastore": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/interface-datastore/-/interface-datastore-0.8.3.tgz", - "integrity": "sha512-0boeaQbqRUV+7edgdkDDNl8/m0bzFbBEfM3tC0Prro2ZE7N9dtcIDh/cW812P/22Gjhlj1J7KIn0mPzbO4HjPQ==", - "requires": { - "buffer": "^5.5.0", - "class-is": "^1.1.0", - "err-code": "^2.0.0", - "ipfs-utils": "^1.2.3", - "iso-random-stream": "^1.1.1", - "nanoid": "^3.0.2" - } - }, - "ipfs-utils": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/ipfs-utils/-/ipfs-utils-1.2.4.tgz", - "integrity": "sha512-xUP7SmOAb50OHL8D2KasRHRBOtRdyHHerfCEJBmS9+qpe6wzpbhftdsZJ2UD2v7HXgi7IH9eTps5uPXKUd2aVg==", - "requires": { - "abort-controller": "^3.0.0", - "buffer": "^5.4.2", - "err-code": "^2.0.0", - "fs-extra": "^9.0.0", - "is-electron": "^2.2.0", - "iso-url": "^0.4.7", - "it-glob": "0.0.7", - "merge-options": "^2.0.0", - "nanoid": "^2.1.11", - "node-fetch": "^2.6.0", - "stream-to-it": "^0.2.0" - }, - "dependencies": { - "nanoid": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz", - "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==" - } - } - } } }, "libp2p-mdns": { @@ -9457,9 +9421,9 @@ } }, "timeout-abort-controller": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/timeout-abort-controller/-/timeout-abort-controller-1.1.0.tgz", - "integrity": "sha512-xLV+Ms6mDc8UKpBAGGwRkZ137VqS63nGYRnzvI2f1bbv5TWqr4S7ST81870ekn+zlODruVsUexU6GCnErkM7Pw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/timeout-abort-controller/-/timeout-abort-controller-1.1.1.tgz", + "integrity": "sha512-BsF9i3NAJag6T0ZEjki9j654zoafI2X6ayuNd6Tp8+Ul6Tr5s4jo973qFeiWrRSweqvskC+AHDKUmIW4b7pdhQ==", "requires": { "abort-controller": "^3.0.0", "retimer": "^2.0.0" diff --git a/examples/web-demo/src/index.js b/examples/web-demo/src/index.js index ea4db5f..6faadd1 100644 --- a/examples/web-demo/src/index.js +++ b/examples/web-demo/src/index.js @@ -2,6 +2,11 @@ const ERIS = require('js-eris') const rdfParser = require('rdf-parse').default const Streamify = require('streamify-string') const FragmentGraph = require('./rdf/fragment-graph.js') +const IPFS = require('ipfs') +const CID = require('cids') +const multihash = require('multihashes') +const base32 = require('../../../src/base32.js') +const crypto = require('../../../src/crypto.js') const signify = ` @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . @@ -58,6 +63,92 @@ const alyssa = ` "liked": "https://social.example/alyssa/liked/"} ` +function MapAndIPFSContentAddressableStorage () { + this._map = new Map() + + this._ipfsPut = async function (block) { + // put block in IPFS + const ipfsBlock = await this._ipfs.block.put(Buffer.from(block), { + version: 1, // CIDv1 + format: 'raw', // don't do any tricks IPFS + mhtype: 'blake2b-256', // use BLAKE2b (256bit) + timeout: 2000 + }) + + console.log('Put block on IPFS: ' + ipfsBlock.cid.toString()) + + // decode the multihash + const mhash = await multihash.decode(ipfsBlock.cid.multihash) + + // return the digest + return Uint8Array.from(mhash.digest) + } + + this._ipfsGet = async function (ref) { + // encode ref as mhash + const mhash = multihash.encode(Buffer.from(ref), 'blake2b-256') + // and as cid + const cid = new CID(1, 'raw', mhash) + + // get block from IPFS (timeout after 5s) + const block = await this._ipfs.block.get(cid, { timeout: 2000 }) + + return Uint8Array.from(block.data) + } + + this.activateIPFS = async function () { + const ipfs = await IPFS.create({ + config: { + Addresses: { + Swarm: [ + // This is a public webrtc-star server + // '/dns4/star-signal.cloud.ipfs.team/wss/p2p-webrtc-star' + ] + } + }, + repo: 'ipfs-eris', + relay: { + enabled: true, + hop: { + enabled: true + } + } + }) + this._ipfs = ipfs + const version = await ipfs.version() + console.log('JS-IPFS Version:', version.version) + return version + } + + this.deactivateIPFS = async function () { + await this._ipfs.stop() + delete this._ipfs + } + + ERIS.ContentAddressableStorage.call( + this, + async function (block) { + const ref = await crypto.hash(block) + const key = base32.encode(ref) + this._map.set(key, block) + + if (this._ipfs) { + await this._ipfsPut(block) + } + + return ref + }, async function (ref) { + const key = base32.encode(ref) + + if (this._map.has(key)) { + return this._map.get(key) + } else if (this._ipfs) { + return this._ipfsGet(key) + } + } + ) +} + function rdfParse (input, contentType) { return new Promise((resolve, reject) => { const textStream = Streamify(input) @@ -99,9 +190,10 @@ async function main () { const encodedErisReadCap = document.getElementById('encoded-eris-read-cap') const encodedErisVerificationCap = document.getElementById('encoded-eris-verification-cap') const blockContainer = document.getElementById('block-container') + const checkBoxEnableIPFS = document.getElementById('checkbox-enable-ipfs') - // a ContentAddressableStorage based on a JavaScipt Map - const cas = new ERIS.MapContentAddressableStorage() + // a ContentAddressableStorage based on a JavaScript Map and optionally on IPFS + const cas = new MapAndIPFSContentAddressableStorage() // a TextEncoder for encoding strings as UTF-8 encoded Uint8Array const utf8Encoder = new TextEncoder() @@ -183,8 +275,21 @@ async function main () { controlsSuccess.innerText = msg } + function disableControls () { + controlsEncode.disabled = true + controlsDecode.disabled = true + controlsVerify.disabled = true + } + + function enableControls () { + controlsEncode.disabled = false + controlsDecode.disabled = false + controlsVerify.disabled = false + } + controlsEncode.onclick = async function (e) { setSuccess('') + disableControls() try { const urn = await encode() encodedErisReadCap.value = urn @@ -192,31 +297,63 @@ async function main () { encodedErisVerificationCap.value = verifyUrn renderBlocks(cas) setSuccess('Encoded!') + enableControls() } catch (err) { console.error(err) setError(err) + enableControls() } } controlsDecode.onclick = async function (e) { setSuccess('') + disableControls() try { const decoded = await decode() inputTextarea.value = utf8Decoder.decode(decoded) setSuccess('Decoded!') + enableControls() } catch (err) { setError(err) + enableControls() } } controlsVerify.onclick = async function (e) { setSuccess('') + disableControls() try { const verificationCap = encodedErisVerificationCap.value await ERIS.verify(verificationCap, cas) setSuccess('Verification passed!') + enableControls() } catch (err) { setError(err) + enableControls() + } + } + + checkBoxEnableIPFS.onchange = async function (e) { + setSuccess('') + disableControls() + if (checkBoxEnableIPFS.checked) { + try { + await cas.activateIPFS() + setSuccess('IPFS enabled!') + enableControls() + } catch (err) { + setError(err) + enableControls() + } + } else { + try { + await cas.deactivateIPFS() + setSuccess('IPFS disabled') + enableControls() + } catch (err) { + setError(err) + enableControls() + } } } diff --git a/src/eris.js b/src/eris.js index e4ddaea..1ea59fc 100644 --- a/src/eris.js +++ b/src/eris.js @@ -173,7 +173,7 @@ async function buildMerkleTree (input, verificationKey, cas) { return finalize(state, 0) } -function makeCapability(type, level, rootReference, readKey) { +function makeCapability (type, level, rootReference, readKey) { const cap = new Uint8Array(67) // Set version to 0 |