aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app.js224
-rw-r--r--bog.js128
-rw-r--r--css/style.css109
-rw-r--r--index.html19
-rw-r--r--lib.js230
-rw-r--r--package-lock.json64
-rw-r--r--package.json4
-rw-r--r--render.js143
-rw-r--r--server.js56
-rw-r--r--views.js59
-rw-r--r--welcome.js67
11 files changed, 406 insertions, 697 deletions
diff --git a/app.js b/app.js
index 0e5d054..26b06eb 100644
--- a/app.js
+++ b/app.js
@@ -1,176 +1,94 @@
var screen = h('div', {id: 'screen'})
document.body.appendChild(screen)
-function keyPage (keys) {
- var scroller = document.getElementById('scroller')
-
- var message = h('div', {classList: 'message'})
-
- message.appendChild(h('p', {innerHTML: marked('This is your ed25519 public/private keypair. It was generated using [Tweetnacl.js](https://tweetnacl.js.org/#/). Your public key is your identity when using [Bogbook](http://bogbook.com/), save your key in a safe place so that you can continue to use the same identity.')}))
-
- // print stringified keypair
- message.appendChild(h('pre', {style: 'width: 80%'}, [h('code', [JSON.stringify(keys)])]))
-
- // delete key button
- message.appendChild(h('button', {
- onclick: function () {
- localforage.removeItem('id', function () {
- location.hash = ''
- location.reload()
- })
- }
- }, ['Delete Key']))
-
- var textarea = h('textarea', {placeholder: 'Import your existing ed25519 keypair'})
- message.appendChild(textarea)
- message.appendChild(h('button', {
- onclick: function () {
- if (textarea.value) {
- localforage.setItem('id', JSON.parse(textarea.value))
- location.reload()
- }
- }
- }, ['Import Key']))
-
- scroller.appendChild(message)
-}
-
-function profilePage (src, keys) {
- var scroller = document.getElementById('scroller')
-
+function composer (keys, reply) {
+ var messageDiv = h('div')
var message = h('div', {classList: 'message'})
- var identify = h('input', {placeholder: 'Identify ' + src.substring(0, 10) + '...'})
+ var textarea = h('textarea', {placeholder: 'Write a new bog post...'})
- message.appendChild(h('div', [
- identify,
- h('button', {onclick: function () {
- if (identify.value) {
- var content = {
- author: keys.publicKey,
- type: 'name',
- naming: src,
- name: identify.value,
- timestamp: Date.now()
- }
-
- identify.value = ''
- publish(content, keys)
- localforage.setItem('id', keys, function (err, published) {
- if (published) {
- location.reload()
+ var publisher = h('div', [
+ textarea,
+ h('button', {
+ onclick: function () {
+ if (textarea.value) {
+ var content = {
+ type: 'post',
+ text: textarea.value,
+ timestamp: Date.now()
+ }
+ if (reply) {
+ content.reply = reply.key
}
- })
+ publish(content, keys).then(post => {
+ open(post).then(msg => {
+ textarea.value = ''
+ if (reply) {
+ messageDiv.removeChild(messageDiv.firstChild)
+ if (messageDiv.firstChild) {
+ messageDiv.insertBefore(h('div', {classList: 'submessage'}, [render(msg, keys)]), messageDiv.childNodes[1])
+ } else {
+ messageDiv.appendChild(h('div', {classList: 'submessage'}, [render(msg, keys)]))
+ }
+ } else {
+ if (messageDiv.firstChild) {
+ messageDiv.insertBefore(render(msg, keys), messageDiv.childNodes[1])
+ } else {
+ messageDiv.appendChild(render(msg, keys))
+ }
+ }
+ })
+ })
+ }
}
- }}, ['Identify'])
- ]))
-
- scroller.appendChild(message)
+ }, ['Publish'])
+ ])
- requestFeed(src, 'ws://localhost:8080/', keys.publicKey)
-
- localforage.getItem(src, function (err, log) {
- if (log) {
- for (var i=0; i < log.length; i++) {
- var post = log[i]
- scroller.appendChild(renderMessage(post))
- }
- }
- })
+ message.appendChild(publisher)
+ messageDiv.appendChild(message)
+ return messageDiv
}
-function threadPage (src, keys) {
- var scroller = document.getElementById('scroller')
-
- localforage.getItem('log', function (err, log) {
- for (var i = log.length - 1; i >= 0; --i) {
- if (log[i].key === src) {
- var post = log[i]
- scroller.appendChild(renderMessage(post))
- }
- }
- })
-}
-
-function publicPage (keys) {
- compose(keys)
-
- localforage.getItem('log', function (err, log) {
- if (log) {
- for (var i=0; i < log.length; i++) {
- var post = log[i]
- scroller.appendChild(renderMessage(post))
- }
- var newLog = log.sort(function (a, b) {
- return b.content.timestamp - a.content.timestamp
- })
- if (newLog) {
- localforage.setItem('log', log)
- }
- }
- })
-}
-
-function route () {
- localforage.getItem('id', function (err, keys) {
+function route (keys) {
+ src = window.location.hash.substring(1)
- src = window.location.hash.substring(1)
- var scroller = h('div', {id: 'scroller'})
- var screen = document.getElementById('screen')
- screen.appendChild(scroller)
+ var scroller = h('div', {id: 'scroller'})
+ var screen = document.getElementById('screen')
+ screen.appendChild(scroller)
- if (src === 'key') {
- keyPage(keys)
- } else if (src[0] === '@') {
- profilePage(src, keys)
- } else if (src[0] === '%') {
- threadPage(src, keys)
- } else {
- publicPage(keys)
- }
- })
+ if (src === 'key') {
+ keyPage(keys)
+ } else if (src[0] === '@') {
+ profilePage(src, keys)
+ } else if (src[0] === '%') {
+ threadPage(src, keys)
+ } else {
+ publicPage(keys)
+ }
}
-localforage.getItem('id', function (err, keys) {
- if (keys) {
+keys().then(key => {
- var navbar = h('div', {classList: 'navbar'}, [
- h('div', {classList: 'internal'}, [
- h('li', [h('a', {href: '/#'}, ['Home'])]),
- h('li', [h('a', {href: '#' + keys.publicKey}, [getName(keys.publicKey)])]),
- h('li', [h('a', {href: '/#key'}, ['Key'])])
- ])
+ var navbar = h('div', {classList: 'navbar'}, [
+ h('div', {classList: 'internal'}, [
+ h('li', [h('a', {href: '#'}, ['Home'])]),
+ h('li', [h('a', {href: '#' + key.publicKey}, [getName(key.publicKey)])]),
+ h('li', [h('a', {href: '#key'}, ['Key'])])
])
+ ])
+ document.body.appendChild(navbar)
- document.body.appendChild(navbar)
-
- route()
- } else {
- var genkey = nacl.sign.keyPair()
- if (genkey) {
- var keys = {
- publicKey: '@' + nacl.util.encodeBase64(genkey.publicKey),
- privateKey: nacl.util.encodeBase64(genkey.secretKey)
- }
-
- if (keys.publicKey.includes('/')) {
- console.log('TRYING AGAIN')
- setTimeout(function () {
- location.reload()
- }, 10)
- } else {
- welcomeScreen(keys)
- }
- }
- }
+ route(key)
})
-
-
window.onhashchange = function () {
- var oldscreen = document.getElementById('screen')
- var newscreen = h('div', {id: 'screen'})
- oldscreen.parentNode.replaceChild(newscreen, oldscreen)
- route()
+ keys().then(key => {
+ var oldscreen = document.getElementById('screen')
+ var newscreen = h('div', {id: 'screen'})
+ oldscreen.parentNode.replaceChild(newscreen, oldscreen)
+
+ route(key)
+ })
}
+
diff --git a/bog.js b/bog.js
new file mode 100644
index 0000000..aa347ce
--- /dev/null
+++ b/bog.js
@@ -0,0 +1,128 @@
+// bog.open -- opens a signature and returns content if you pass a signature and a public key
+// EX: open(msg).then(content => { console.log(content) })
+
+async function open (msg) {
+
+ var pubkey = nacl.util.decodeBase64(msg.author.substring(1))
+ var sig = nacl.util.decodeBase64(msg.signature)
+ var opened = await JSON.parse(nacl.util.encodeUTF8(nacl.sign.open(sig, pubkey)))
+
+ opened.key = msg.key
+
+ return opened
+}
+
+// bog.keys -- gets your public/private keypair, generates one if there is none
+// EX: keys().then(key => { console.log(key)})
+
+async function keys (key) {
+ var keypair = await localforage.getItem('id')
+ if (keypair != null) {
+ return keypair
+ } else {
+ var genkey = nacl.sign.keyPair()
+ var keypair = {
+ publicKey: '@' + nacl.util.encodeBase64(genkey.publicKey),
+ privateKey: nacl.util.encodeBase64(genkey.secretKey)
+ }
+ localforage.setItem('id', keypair)
+ return keypair
+ }
+}
+
+// bog.get -- iterates over log and returns a post.
+// EX: get('%x5T7KZ5haR2F59ynUuCggwEdFXlLHEtFoBQIyKYppZYerq9oMoIqH76YzXQpw2DnYiM0ugEjePXv61g3E4l/Gw==').then(msg => { console.log(msg)})
+
+async function get (key) {
+ var log = await localforage.getItem('log')
+ if (log != null) {
+ for (var i = log.length - 1; i >= 0; --i) {
+ if (log[i].key === key) {
+ return log[i]
+ }
+ }
+ }
+}
+
+// bog.getName -- iterates over a feed and returns a person's name
+
+function getName (id) {
+ var name = h('span')
+
+ name.textContent = id.substring(0, 10) + '...'
+
+ return name
+}
+
+// bog.log (feed) -- returns a specific feed if a parameter is passed, if not returns the entire log
+// EX: bog().then(log => { console.log(log)})
+// EX: bog('@ExE3QXmBhYQlGVA3WM2BD851turNzwhruWbIpMd7rbQ=').then(log => { console.log(log)})
+
+
+async function bog (feed) {
+ if (feed) {
+ var log = await localforage.getItem(feed)
+ return log
+ } else {
+ var log = await localforage.getItem('log')
+ return log
+ }
+}
+
+// bog.publish -- publishes a new bog post and updates the feeds
+// EX: publish({type: 'post', timestamp: Date.now(), text: 'Hello World'}).then(msg => { console.log(msg)})
+
+async function publish (post, keys) {
+ post.author = keys.publicKey
+
+ var message = { author: keys.publicKey }
+
+ var feed = await localforage.getItem(keys.publicKey)
+ if (feed) {
+ var firstMsg = await open(feed[0])
+
+ post.seq = ++firstMsg.seq
+
+ message.key = '%' + nacl.util.encodeBase64(nacl.hash(nacl.util.decodeUTF8(JSON.stringify(post)))),
+ message.signature = nacl.util.encodeBase64(nacl.sign(nacl.util.decodeUTF8(JSON.stringify(post)), nacl.util.decodeBase64(keys.privateKey)))
+
+ localforage.getItem('log').then(log => {
+ if (log) {
+ log.unshift(message)
+ localforage.setItem('log', log)
+ } else {
+ var feed = [message]
+ localforage.setItem('log', feed)
+ }
+ })
+
+ feed.unshift(message)
+ localforage.setItem(keys.publicKey, feed)
+
+ return message
+
+ } else {
+
+ post.seq = 0
+
+ message.key = '%' + nacl.util.encodeBase64(nacl.hash(nacl.util.decodeUTF8(JSON.stringify(post)))),
+ message.signature = nacl.util.encodeBase64(nacl.sign(nacl.util.decodeUTF8(JSON.stringify(post)), nacl.util.decodeBase64(keys.privateKey)))
+
+ localforage.getItem('log').then(log => {
+ if (log) {
+ log.unshift(message)
+ localforage.setItem('log', log)
+ } else {
+ var feed = [message]
+ localforage.setItem('log', feed)
+ }
+ })
+
+ var feed = [message]
+ localforage.setItem(keys.publicKey, feed)
+
+ return message
+ }
+}
+
+
diff --git a/css/style.css b/css/style.css
index a59af50..7a517d1 100644
--- a/css/style.css
+++ b/css/style.css
@@ -1,7 +1,7 @@
body {
font-family: 'Source Sans Pro';
- background: #222;
- color: #f5f5f5;
+ background: #f5f5f5;
+ color: #5a5a5a;
overflow-wrap: break-word;
word-wrap: break-word;
word-break: break-word;
@@ -49,12 +49,23 @@ hr {
.right { float: right;}
.message {
- background: #333;
+ border: 1px solid #ddd;
+ background: white;
margin-top: .5em;
padding: .3em .5em;
border-radius: 5px;
}
+.message, .message > *, .navbar, .navbar > * {
+ animation: fadein .5s;
+}
+
+@keyframes fadein {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+
+
.submessage {
margin-left: 2em;
}
@@ -73,7 +84,7 @@ img.small {
}
a {
- color: cyan;
+ color: #0088cc;
text-decoration: none;
}
@@ -82,7 +93,7 @@ a:hover {
}
pre {
- color: violet;
+ color: #dd1144;
width: 100%;
display: block;
}
@@ -105,13 +116,17 @@ code, pre {
textarea, input {
font-family: 'Source Sans Pro';
font-size: 1em;
- background: #222;
+ background: #f5f5f5;
padding: .5em;
- color: #f5f5f5;
+ color: #5a5a5a;
border: none;
border-radius: 5px;
}
+textarea:active, textarea:focus {
+ background: white;
+}
+
textarea {
width: 100%;
}
@@ -170,28 +185,82 @@ textarea {
button {
display: inline-block;
- padding: .25em .5em;
- margin: .15em;
- font-size: 1em;
- line-height: 1.2em;
- color: #d5d5d5;
+ *display: inline;
+ padding: 4px 12px;
+ margin-top: .5em;
+ margin-bottom: 0;
+ *margin-left: .3em;
+ font-size: 14px;
+ line-height: 20px;
+ color: #333333;
text-align: center;
- text-shadow: 0 1px 1px rgba(0, 0, 0, 0.75);
+ text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
vertical-align: middle;
cursor: pointer;
- background-color: #222;
- border: 1px solid #222;
- border-radius: 4px;
+ background-color: #f5f5f5;
+ *background-color: #e6e6e6;
+ background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
+ background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
+ background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
+ background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
+ background-repeat: repeat-x;
+ border: 1px solid #cccccc;
+ *border: 0;
+ border-color: #e6e6e6 #e6e6e6 #bfbfbf;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ border-bottom-color: #b3b3b3;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+ *zoom: 1;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
}
button:hover,
button:focus,
+button:active,
+button[disabled] {
+ color: #333333;
+ background-color: #e6e6e6;
+ *background-color: #d9d9d9;
+}
+
button:active {
- color: white;
- background-color: black;
+ background-color: #cccccc \9;
+}
+
+button:first-child {
+ *margin-left: 0;
}
-button.active {
- background-color: #111;
+button:hover,
+button:focus {
+ color: #333333;
+ text-decoration: none;
+ background-position: 0 -15px;
+ -webkit-transition: background-position 0.1s linear;
+ -moz-transition: background-position 0.1s linear;
+ -o-transition: background-position 0.1s linear;
+ transition: background-position 0.1s linear;
}
+button:focus {
+ outline: thin dotted #333;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+
+button:active {
+ background-image: none;
+ outline: 0;
+ -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+
+
diff --git a/index.html b/index.html
index 3eb5b1b..3d0d2e9 100644
--- a/index.html
+++ b/index.html
@@ -2,18 +2,19 @@
<head>
<title>Bogbook</title>
<meta name='viewport' content='width=device-width initial-scale=1' />
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<link rel='stylesheet' href='./css/source-sans-pro.min.css' />
<link rel='stylesheet' href='./css/style.css' />
+ <script src="./lib/nacl.min.js"></script>
+ <script src="./lib/nacl-util.min.js"></script>
+ <script src="./lib/localforage.min.js"></script>
+ <script src="./lib/marked.min.js"></script>
+ <script src="./lib/misc.js"></script>
+ <script async src="bog.js"></script>
+ <script async src="render.js"></script>
+ <script async src="views.js"></script>
+ <script async src="app.js"></script>
</head>
<body>
- <script src="./lib/nacl.min.js"></script>
- <script src="./lib/nacl-util.min.js"></script>
- <script src="./lib/localforage.min.js"></script>
- <script src="./lib/marked.min.js"></script>
- <script src="./lib/misc.js"></script>
- <script src="lib.js"></script>
- <script src="welcome.js"></script>
- <script src="render.js"></script>
- <script src="app.js"></script>
</body>
</html>
diff --git a/lib.js b/lib.js
deleted file mode 100644
index 5351f95..0000000
--- a/lib.js
+++ /dev/null
@@ -1,230 +0,0 @@
-/*function requestFeed (src, server, requester) {
-
- console.log(src)
- console.log(server)
-
- var ws = new WebSocket(server + src)
-
- localforage.getItem(src, function (err, log) {
- if (log) {
- console.log(log)
-
- var post = log[0]
-
- var pubkey = nacl.util.decodeBase64(src.substring(1))
- var sig = nacl.util.decodeBase64(post.signature)
- post.content = JSON.parse(nacl.util.encodeUTF8(nacl.sign.open(sig, pubkey)))
-
- var seq = post.content.sequence
-
- ws.onopen = function () {
- var req = {
- feed: src,
- seq,
- requester
- }
-
- console.log(req)
-
- ws.send(JSON.stringify(req))
-
- }
- ws.onmessage = function (message) {
- var res = JSON.parse(message.data)
- if (res.seq == null) {
- console.log('SENDING ENTIRE LOG')
- var send = {
- feed: src,
- log,
- requester
- }
- ws.send(JSON.stringify(send))
- }
- if (seq > res.req) {
- console.log('SENDING')
- console.log(log)
- }
- }
- } else {
- ws.onopen = function () {
- var seq = null
-
- }
- ws.onmessage = function (message) {
- console.log(message.data)
- }
- }
- })
-}*/
-
-// publish new messages to your log
-function publish (toPublish, keys) {
-
- localforage.getItem(keys.publicKey, function (err, log) {
- if (log) {
- var lastPost = log[0]
-
- var pubkey = nacl.util.decodeBase64(keys.publicKey.substring(1))
- var sig = nacl.util.decodeBase64(lastPost.signature)
-
- var opened = JSON.parse(nacl.util.encodeUTF8(nacl.sign.open(sig, pubkey)))
-
- var seq = opened.sequence
-
- toPublish.sequence = ++seq
- toPublish.previous = nacl.util.encodeBase64(nacl.hash(nacl.util.decodeUTF8(JSON.stringify(log[0]))))
-
- var author = keys.publicKey
- var key = '%' + nacl.util.encodeBase64(nacl.hash(nacl.util.decodeUTF8(JSON.stringify(toPublish))))
- var signature = nacl.util.encodeBase64(nacl.sign(nacl.util.decodeUTF8(JSON.stringify(toPublish)), nacl.util.decodeBase64(keys.privateKey)))
-
- var toPost = {
- author,
- key,
- signature
- }
-
- console.log(toPost)
-
- // update the log
- updateLog(keys.publicKey, toPost)
-
- /*var scroller = document.getElementById('scroller')
- if (scroller.firstChild) {
- scroller.insertBefore(renderMessage(toPost), scroller.childNodes[1])
- } else {
- scroller.appendChild(renderMessage(toPost))
- }*/
-
- } else {
- toPublish.sequence = 0
-
- var toPost = {
- author: keys.publicKey,
- key: '%' + nacl.util.encodeBase64(nacl.hash(nacl.util.decodeUTF8(JSON.stringify(toPublish)))),
- signature: nacl.util.encodeBase64(nacl.sign(nacl.util.decodeUTF8(JSON.stringify(toPublish)), nacl.util.decodeBase64(keys.privateKey)))
- }
-
- updateLog(keys.publicKey, toPost)
-
- /*var scroller = document.getElementById('scroller')
- if (scroller.firstChild) {
- scroller.insertBefore(renderMessage(toPost), scroller.childNodes[1])
- } else {
- scroller.appendChild(renderMessage(toPost))
- }*/
- }
- })
-}
-
-function compose (keys) {
- var message = h('div', {classList: 'message'})
-
- var scroller = document.getElementById('scroller')
-
- scroller.insertBefore(message, scroller.firstChild)
-
- var textarea = h('textarea', {placeholder: 'Write a new bog post'})
-
- message.appendChild(textarea)
-
- var composer = h('div', [
- h('button', {
- onclick: function () {
- if (textarea.value) {
- var toPublish = {
- author: keys.publicKey,
- type: 'post',
- text: textarea.value,
- timestamp: Date.now()
- }
- textarea.value = ''
- publish(toPublish, keys)
- }
- }
- }, ['Publish'])
- ])
- message.appendChild(composer)
-}
-
-
-// update your log in the browser
-
-function updateLog (feed, post) {
- localforage.getItem(feed, function (err, log) {
- if (log) {
- log.unshift(post)
- localforage.setItem(feed, log, function () {
- console.log('FEED UPDATED')
- })
- } else {
- log = []
- log.unshift(post)
- localforage.setItem(feed, log, function () {
- console.log('FEED UPDATED')
- })
- }
- })
-
- localforage.getItem('log', function (err, log) {
- if (log) {
- log.unshift(post)
- localforage.setItem('log', log, function () {
- console.log('LOG UPDATED')
- location.reload()
- })
- } else {
- log = []
- log.unshift(post)
- localforage.setItem('log', log, function () {
- console.log('LOG UPDATED')
- location.reload()
- })
- }
- })
-}
-
-function getName (id) {
- var name = h('span')
- name.textContent = id.substring(0, 10) + '...'
-
- localforage.getItem(id, function (err, log) {
- if (log) {
- for (var i=0; i < log.length; i++) {
- var post = log[i]
-
- var pubkey = nacl.util.decodeBase64(post.author.substring(1))
- var sig = nacl.util.decodeBase64(post.signature)
- post.content = JSON.parse(nacl.util.encodeUTF8(nacl.sign.open(sig, pubkey)))
-
- //if (post.content) {
- if (post.content.type == 'name') {
- name.textContent = '@' + post.content.name
- }
- //}
- }
- }
- })
- return name
-}
-
-function getHeader (post, mini) {
- var inner
- if (mini) {
- var inner = mini
- }
-
- var head = h('span', [
- h('a', {href: '#' + post.key}, [
- h('p', {classList: 'right'}, [human(new Date(post.content.timestamp))]),
- ]),
- h('p', [
- h('a', {href: '#' + post.content.author}, [
- getName(post.content.author)
- ]),
- inner
- ])
- ])
- return head
-}
-
diff --git a/package-lock.json b/package-lock.json
index 05b71a4..89c4e57 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,75 +1,21 @@
{
"name": "bogbook",
- "version": "1.1.0",
+ "version": "1.2.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
- "async-limiter": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
- "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
- },
- "ecstatic": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.1.tgz",
- "integrity": "sha512-/rrctvxZ78HMI/tPIsqdvFKHHscxR3IJuKrZI2ZoUgkt2SiufyLFBmcco+aqQBIu6P1qBsUNG3drAAGLx80vTQ==",
- "requires": {
- "he": "^1.1.1",
- "mime": "^1.6.0",
- "minimist": "^1.1.0",
- "url-join": "^2.0.5"
- }
- },
- "he": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
- "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
- },
"is-wsl": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
"integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0="
},
- "mime": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
- "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
- },
- "minimist": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
- "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
- },
- "opn": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/opn/-/opn-6.0.0.tgz",
- "integrity": "sha512-I9PKfIZC+e4RXZ/qr1RhgyCnGgYX0UEIlXgWnCOVACIvFgaC9rz6Won7xbdhoHrd8IIhV7YEpHjreNUNkqCGkQ==",
+ "open": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/open/-/open-6.2.0.tgz",
+ "integrity": "sha512-Vxf6HJkwrqmvh9UAID3MnMYXntbTxKLOSfOnO7LJdzPf3NE3KQYFNV0/Lcz2VAndbRFil58XVCyh8tiX11fiYw==",
"requires": {
"is-wsl": "^1.1.0"
}
- },
- "tweetnacl": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.1.tgz",
- "integrity": "sha512-kcoMoKTPYnoeS50tzoqjPY3Uv9axeuuFAZY9M/9zFnhoVvRfxz9K29IMPD7jGmt2c8SW7i3gT9WqDl2+nV7p4A=="
- },
- "tweetnacl-util": {
- "version": "0.15.0",
- "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.0.tgz",
- "integrity": "sha1-RXbBzuXi1j0gf+5S8boCgZSAvHU="
- },
- "url-join": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz",
- "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg="
- },
- "ws": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
- "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
- "requires": {
- "async-limiter": "~1.0.0"
- }
}
}
}
diff --git a/package.json b/package.json
index f73137a..cca809b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bogbook",
- "version": "1.2.0",
+ "version": "1.3.0",
"description": "secure blockchain logging (blogging, without the l) -- bogging",
"main": "server.js",
"scripts": {
@@ -11,7 +11,7 @@
"license": "MIT",
"dependencies": {
"ecstatic": "^3.3.1",
- "opn": "^6.0.0",
+ "open": "^6.2.0",
"tweetnacl": "^1.0.1",
"tweetnacl-util": "^0.15.0",
"ws": "^6.2.1"
diff --git a/render.js b/render.js
index c7b3f04..fa9fe5b 100644
--- a/render.js
+++ b/render.js
@@ -1,118 +1,53 @@
-function renderMessage (post) {
- var messageDiv = h('messageDiv', {id: post.key})
- var message = h('div', {classList: 'message'})
-
- var pubkey = nacl.util.decodeBase64(post.author.substring(1))
- var sig = nacl.util.decodeBase64(post.signature)
- post.content = JSON.parse(nacl.util.encodeUTF8(nacl.sign.open(sig, pubkey)))
-
-
- if (post.content.type == 'name') {
- var mini = h('span', [
- ' identified as ',
- post.content.name
+function getHeader (post, mini) {
+ var head = h('span', [
+ h('a', {href: '#' + post.key}, [
+ h('p', {classList: 'right'}, [human(new Date(post.timestamp))]),
+ ]),
+ h('p', [
+ h('a', {href: '#' + post.author}, [
+ getName(post.author)
+ ]),
+ mini
])
+ ])
+ return head
+}
- message.appendChild(getHeader(post, mini))
-
- messageDiv.appendChild(message)
- }
-
-
- if (post.content.type == 'post') {
+function render (msg, keys) {
+ var messageDiv = h('messageDiv', {id: msg.key})
+ var message = h('div', {classList: 'message'})
- /*
- NEED TO UNBOX THREADS
- localforage.getItem('log', function (err, log) {
- if (log) {
- for (var i = log.length - 1; i >= 0; --i) {
-
- if (log[i].content.reply == post.key) {
- var nextPost = log[i]
- var messageExists = (document.getElementById(nextPost.key) !== null);
- if (!messageExists) {
- messageDiv.appendChild(h('div', {classList: 'submessage'}, [
- renderMessage(nextPost)
- ]))
- }
+ bog().then(log => {
+ log.forEach(function (nextPost) {
+ open(nextPost).then(nextMessage => {
+ var messageExists = (document.getElementById(nextMessage.key) !== null);
+ if (nextMessage.reply == msg.key) {
+ if (!messageExists) {
+ messageDiv.appendChild(h('div', {classList: 'submessage'}, [render(nextMessage, keys)]))
}
}
- }
- })*/
-
- var renderer = new marked.Renderer();
- renderer.link = function(href, title, text) {
- if ((href[0] == '@') || (href[0] == '%')) {
- href = '#' + href
- }
- var link = marked.Renderer.prototype.link.call(this, href, title, text);
- return link
- }
-
- marked.setOptions({
- renderer: renderer
- });
+ })
+ })
+ })
+
+ if (msg.type == 'post') {
+ message.appendChild(getHeader(msg))
- message.appendChild(getHeader(post))
-
- if (post.content.reply) {
+ if (msg.reply) {
message.appendChild(h('span', [
're: ',
- h('a', {href: '#' + post.content.reply}, [post.content.reply.substring(0, 10) + '...'])
+ h('a', {href: '#' + msg.reply}, [msg.reply.substring(0, 10) + '...'])
]))
}
- message.appendChild(h('div', {innerHTML: marked(post.content.text)}))
-
- message.appendChild(h('span', {id: post.key + 'src', classList: 'right'}, [
- h('a', {
- onclick: function () {
- message.appendChild(h('pre', [JSON.stringify(post)]))
- var span = document.getElementById(post.key + 'src')
- span.parentNode.removeChild(span)
- }
- }, ['[src]'])
- ]))
-
- var gotName = getName(post.content.author)
-
- localforage.getItem('id', function (err, keys) {
-
- var publishButton = h('button', {
- onclick: function () {
- if (textarea.value) {
- var content = {
- author: keys.publicKey,
- type: 'post',
- text: textarea.value,
- reply: post.key,
- timestamp: Date.now()
- }
- publish(content, keys)
- message.removeChild(textarea)
- message.removeChild(publishButton)
- }
- }
- }, ['Publish'])
-
- var textarea = h('textarea', {placeholder: 'Reply to this bog post'}, ['['+ gotName.textContent + '](' + post.content.author + ')'])
-
- var replyButton = h('button', {
- classList: 'replyButton:' + post.key,
- onclick: function () {
- message.removeChild(replyButton)
- message.appendChild(textarea)
- message.appendChild(publishButton)
-
- }
- }, ['Reply'])
-
- message.appendChild(replyButton)
- })
-
- messageDiv.appendChild(message)
- }
+ message.appendChild(h('div', [msg.text]))
+ message.appendChild(h('button', {
+ onclick: function () {
+ messageDiv.appendChild(composer(keys, msg))
+ }
+ }, ['Reply']))
+ }
+ messageDiv.appendChild(message)
return messageDiv
}
-
diff --git a/server.js b/server.js
index a6583b7..0063ebf 100644
--- a/server.js
+++ b/server.js
@@ -2,62 +2,12 @@
var http = require('http')
var serve = require('ecstatic')
-var opn = require('opn')
+var open = require('open')
http.createServer(
serve({ root: __dirname})
).listen(8089)
-opn('http://localhost:8089')
-
-// websocket server (8080)
-
-var WebSocket = require('ws')
-var fs = require('fs')
-var nacl = require('tweetnacl')
- nacl.util = require('tweetnacl-util')
-
-var wserver = new WebSocket.Server({ port: 8080 })
-
-wserver.on('connection', function (ws) {
- ws.on('message', function (message) {
- var data = JSON.parse(message)
- console.log(data)
-
- // initial req/res contains a sequence number
- if (data.seq) {
- if (fs.existsSync(__dirname + '/bogs/' + data.feed)) {
- fs.readFile(__dirname + '/bogs/' + data.feed, 'UTF-8', function (err, data) {
- if (data) {
- var log = JSON.parse(data)
- console.log(log)
- }
- })
- } else {
- var res = {
- feed: data.feed,
- seq: null
- }
- console.log(res)
- ws.send(JSON.stringify(res))
- }
-
- }
-
- // if the client has a longer log, it'll send one for the server to save
- if (data.log) {
- console.log(data)
- if (fs.existsSync(__dirname + '/bogs/' + data.feed)) {
- var log = JSON.parse(fs.readFileSync(__dirname + '/bogs/' + data.feed))
- console.log(log)
-
- } else {
- fs.writeFile(__dirname + '/bogs/' + data.feed, JSON.stringify(data.log), function (err, success) {
- console.log('saved ' + data.feed + ' sent by ' + data.requester)
- })
- }
- }
-
- })
-})
+open('http://localhost:8089')
+// ws server (8080)
diff --git a/views.js b/views.js
new file mode 100644
index 0000000..94fcb5d
--- /dev/null
+++ b/views.js
@@ -0,0 +1,59 @@
+function threadPage (src, keys) {
+ get(src).then(msg => {
+ open(msg).then(post => {
+ scroller.appendChild(render(post, keys))
+ })
+ })
+}
+
+function profilePage (src, keys) {
+ bog(src).then(log => {
+ log.forEach(function (msg) {
+ open(msg).then(post => {
+ scroller.appendChild(render(post, keys))
+ })
+ })
+ })
+}
+
+function publicPage (keys) {
+ scroller.appendChild(composer(keys))
+ bog().then(log => {
+ log.forEach(function (msg) {
+ open(msg).then(post => {
+ scroller.appendChild(render(post, keys))
+ })
+ })
+ })
+}
+
+function keyPage (keys) {
+ var message = h('div', {classList: 'message'})
+
+ message.appendChild(h('p', {innerHTML: marked('This is your ed25519 public/private keypair. It was generated using [TweetNaCl.js](https://tweetnacl.js.org/#/). Your public key is your identity when using [Bogbook](http://bogbook.com/), save your key in a safe place so that you can continue to use the same identity.')}))
+
+ message.appendChild(h('pre', {style: 'width: 80%'}, [h('code', [JSON.stringify(keys)])]))
+
+ message.appendChild(h('button', {
+ onclick: function () {
+ localforage.removeItem('id', function () {
+ location.hash = ''
+ location.reload()
+ })
+ }
+ }, ['Delete Key']))
+
+ var textarea = h('textarea', {placeholder: 'Import your existing ed25519 keypair'})
+ message.appendChild(textarea)
+ message.appendChild(h('button', {
+ onclick: function () {
+ if (textarea.value) {
+ localforage.setItem('id', JSON.parse(textarea.value))
+ location.reload()
+ }
+ }
+ }, ['Import Key']))
+
+ scroller.appendChild(message)
+}
+
diff --git a/welcome.js b/welcome.js
deleted file mode 100644
index 342756a..0000000
--- a/welcome.js
+++ /dev/null
@@ -1,67 +0,0 @@
-function welcomeScreen (keys) {
- var screen = document.getElementById('screen')
-
- var scroller = h('div', {id: 'scroller'})
- screen.appendChild(scroller)
-
- var message = h('div', {classList: 'message'})
-
- scroller.appendChild(message)
-
- message.appendChild(h('h1', ['Welcome to Bogbook']))
- message.appendChild(h('p', ['Bogbook is a distributed blogging network of signed append-only feeds. We call them "bogs".']))
- message.appendChild(h('p', ['Please note: Bogbook is experimental software, not for use in producton environments. Expect bugs and breaking changes. Pull-requests are needed.']))
- message.appendChild(h('p', {innerHTML: marked('View the code: [http://github.com/bogbook/bog](http://github.com/bogbook/bog). Questions? [ev@evbogue.com](mailto:ev@evbogue.com).')}))
- message.appendChild(h('hr'))
- message.appendChild(h('h3', ['Get started']))
- message.appendChild(h('p', {innerHTML: marked('This is an ed25519 public/private signing keypair. It was generated using [TweetNaCl.js](https://tweetnacl.js.org/#/)')}))
- message.appendChild(h('pre', [JSON.stringify(keys)]))
- message.appendChild(h('p', ['Right now, this keypair exists only in memory. When you leave this page, the keypair will vanish forever. If you refresh this page you\'ll receive a new keypair.']))
- message.appendChild(h('p', {innerHTML: marked('To save this keypair, identify with a handle below. Once you identify, your public/private keypair will be stored in your browser using [localForage.js](https://localforage.github.io/localForage). Save your keypair somewhere safe to preserve your identity.')}))
- message.appendChild(h('hr'))
- message.appendChild(h('h3', ['Identify']))
-
- var identify = h('input', {placeholder: 'Your Name'})
-
- message.appendChild(h('div', [
- identify,
- h('button', {onclick: function () {
- if (identify.value) {
- var toPublish = {
- author: keys.publicKey,
- type: 'name',
- naming: keys.publicKey,
- name: identify.value,
- timestamp: Date.now()
- }
-
- identify.value = ''
- publish(toPublish, keys)
- localforage.setItem('id', keys, function (err, published) {
- if (published) {
- location.hash = ''
- location.reload()
- }
- })
- }
- }}, ['Identify'])
- ]))
- message.appendChild(h('p', ['When you click [Identify], you will post your first message to your append-only bog, your ed25519 keypair will be saved in your browser, and the page will reload. Don\'t forget to back up your key! and happy bogging.']))
- message.appendChild(h('hr'))
- message.appendChild(h('h3', ['Already have a key?']))
- message.appendChild(h('p', ['Import it here. Make sure to sync your existing feed from a Bogbook \'pub\' before posting a message.']))
-
- var textarea = h('textarea', {placeholder: 'Import your existing ed25519 keypair'})
- message.appendChild(textarea)
- message.appendChild(h('button', {
- onclick: function () {
- if (textarea.value) {
- localforage.setItem('id', JSON.parse(textarea.value))
- location.hash = ''
- location.reload()
- }
- }
- }, ['Import Key']))
-
-
-}