git ssb

3+

cel / ssb-publishguard



Commit 646e9a686ffbb78a9b41f4c9fbadcba6f3681648

Initial commit

cel committed on 1/12/2018, 5:23:45 AM

Files changed

README.mdadded
confirm.jsadded
index.jsadded
package.jsonadded
README.mdView
@@ -1,0 +1,17 @@
1 +# ssb-publishguard
2 +
3 +Intercept publishing messages with a prompt in a local web browser.
4 +
5 +With this scuttlebot plugin installed, any call to `sbot.publish` or
6 +`sbot.private.publish` will trigger opening a web browser with a form to
7 +confirm or cancel publishing the proposed message.
8 +
9 +The purpose of this to give the user a final review of any message that their scuttlebot client is going to publish. This may help reduce the likelihood of publishing accidental, malformed, duplicate, or poorly-thought-out messages.
10 +
11 +## Install
12 +
13 +```
14 +ln -rs . ~/.ssb/node_modules/ssb-publishguard
15 +sbot plugins.enable ssb-publishguard
16 +# restart sbot server
17 +```
confirm.jsView
@@ -1,0 +1,125 @@
1 +var proc = require('child_process')
2 +var fs = require('fs')
3 +var http = require('http')
4 +var URL = require('url')
5 +var crypto = require('crypto')
6 +var os = require('os')
7 +
8 +function escapeHTML (html) {
9 + return String(html)
10 + .replace(/</g, '&lt;')
11 + .replace(/>/g, '&gt;')
12 +}
13 +
14 +function noPublish(content, cb) {
15 + cb(new Error('missing publish function'))
16 +}
17 +
18 +function noPrivatePublish(content, recps, cb) {
19 + cb(new Error('missing private publish function'))
20 +}
21 +
22 +function confirm(opts, cb) {
23 + var content = opts.content
24 + var browser = opts.browser
25 + var recps = opts.recps
26 + var publish = opts.publish || noPublish
27 + var privatePublish = opts.privatePublish || noPrivatePublish
28 +
29 + if (!browser) {
30 + return cb(new TypeError('missing browser option'))
31 + }
32 + if (recps && !Array.isArray(recps)) {
33 + return cb(new TypeError('recps should be array'))
34 + }
35 +
36 + var token = crypto.randomBytes(32).toString('base64')
37 +
38 + function publish1(content, recps, cb) {
39 + if (recps) privatePublish(content, recps, cb)
40 + else publish(content, cb)
41 + }
42 +
43 + var server = http.createServer(function (req, res) {
44 + var url = URL.parse(req.url, true)
45 + if (url.pathname !== '/') {
46 + res.writeHead(404)
47 + return res.end('Not Found')
48 + }
49 +
50 + if (url.query.token === token) {
51 + if (url.query.publish) {
52 + return publish1(content, recps, function (err, msg) {
53 + if (err) {
54 + res.writeHead(500, {'Content-Type': 'text/html'})
55 + res.end('<!doctype html><html><head><meta charset=utf8><title>publish error</title></head><body>'
56 + + '<h1>' + escapeHTML(err.name || err) + '</h1>'
57 + + '<pre>' + escapeHTML(err.stack || '') + '</pre>'
58 + + '</body></html>')
59 + server.close()
60 + return cb(err)
61 + }
62 + var json = JSON.stringify(msg, 0, 2)
63 + res.writeHead(200, {'Content-Type': 'text/html'})
64 + res.end('<!doctype html><html><head><meta charset=utf8><title>published</title></head><body>'
65 + + '<pre>' + escapeHTML(json) + '</pre>'
66 + + '</body></html>')
67 + server.close()
68 + return cb(null, msg)
69 + })
70 + }
71 + if (url.query.cancel) {
72 + res.writeHead(200, {'Content-Type': 'text/html'})
73 + res.end('<!doctype html><html><head><meta charset=utf8><title>canceled</title></head><body>'
74 + + '<p>Cancelled</p>'
75 + + '</body></html>')
76 + server.close()
77 + return cb(new Error('User cancelled'))
78 + }
79 + }
80 +
81 + var contentJson = JSON.stringify(content, null, 2)
82 + var recpsJson = JSON.stringify(recps, null, 2)
83 + res.writeHead(200, {'Content-Type': 'text/html'})
84 + res.end('<!doctype html><html><head><meta charset=utf8><title>publish</title></head><body>'
85 + + '<form action="/" method="get">'
86 + + (recps ? '<pre>' + recpsJson + '</pre>' : '')
87 + + '<pre>' + escapeHTML(contentJson) + '</pre>'
88 + + '<input type="hidden" name="token" value="' + token + '">'
89 + + '<input type="submit" name="publish" value="Publish"> '
90 + + '<input type="submit" name="cancel" value="Cancel">'
91 + + '</form>'
92 + + '</body></html>')
93 + }).listen(0, '127.0.0.1', function () {
94 + var port = this.address().port
95 + var url = 'http://127.0.0.1:' + port + '/'
96 + proc.spawn(browser, [url], {stdio: 'inherit'})
97 + }).on('error', cb)
98 +}
99 +
100 +module.exports = function (opts) {
101 + var publish = opts.publish
102 + var privatePublish = opts.privatePublish
103 + var config = opts.config || {}
104 + var browser = opts.browser ||
105 + (os.platform() === 'darwin' ? 'open' : 'xdg-open')
106 + var name = opts.name || 'confirm'
107 +
108 + return {
109 + publish: function (content, cb) {
110 + confirm({
111 + publish: publish,
112 + content: content,
113 + browser: browser,
114 + }, cb)
115 + },
116 + privatePublish: function (content, recps, cb) {
117 + confirm({
118 + privatePublish: privatePublish,
119 + recps: recps,
120 + content: content,
121 + browser: browser,
122 + }, cb)
123 + }
124 + }
125 +}
index.jsView
@@ -1,0 +1,16 @@
1 +var confirmer = require('./confirm')
2 +
3 +exports.name = 'publishguard'
4 +exports.version = '1.0.0'
5 +exports.manifest = {
6 +}
7 +exports.init = function (sbot, config) {
8 + var confirm = confirmer({
9 + publish: sbot.publish,
10 + privatePublish: sbot.private.publish,
11 + config: config.publishguard
12 + })
13 + sbot.publish = confirm.publish
14 + sbot.private.publish = confirm.privatePublish
15 + console.log('[' + exports.name + '] enabled')
16 +}
package.jsonView
@@ -1,0 +1,2 @@
1 +{
2 +}

Built with git-ssb-web