git ssb

3+

cel / ssb-publishguard



Tree: 3dda4939142e804350f42507b5bd03ce9eb6a3ec

Files: 3dda4939142e804350f42507b5bd03ce9eb6a3ec / confirm.js

5499 bytesRaw
1var proc = require('child_process')
2var fs = require('fs')
3var http = require('http')
4var URL = require('url')
5var crypto = require('crypto')
6var os = require('os')
7var qs = require('querystring')
8
9function escapeHTML (html) {
10 return String(html)
11 .replace(/</g, '&lt;')
12 .replace(/>/g, '&gt;')
13}
14
15function noPublish(content, cb) {
16 cb(new Error('missing publish function'))
17}
18
19function noPrivatePublish(content, recps, cb) {
20 cb(new Error('missing private publish function'))
21}
22
23function getForm(stream, cb) {
24 var bufs = []
25 stream.on('data', function (buf) {
26 bufs.push(buf)
27 })
28 stream.on('end', function () {
29 var data
30 try {
31 data = qs.parse(Buffer.concat(bufs).toString('utf8'))
32 } catch(e) {
33 return cb(e)
34 }
35 cb(null, data)
36 })
37}
38
39function confirm(opts, cb) {
40 var content = opts.content
41 var browser = opts.browser
42 var recps = opts.recps
43 var publish = opts.publish || noPublish
44 var getUrl = opts.getUrl
45 var privatePublish = opts.privatePublish || noPrivatePublish
46 var redirectBase = opts.redirectBase
47
48 if (typeof cb !== 'function') {
49 throw new TypeError('bad callback')
50 }
51
52 if (browser && getUrl) {
53 return cb(new TypeError('browser option and getUrl option conflict'))
54 }
55 if (!browser && !getUrl) {
56 return cb(new TypeError('missing browser option'))
57 }
58 if (recps && !Array.isArray(recps)) {
59 return cb(new TypeError('recps should be array'))
60 }
61
62 var token = crypto.randomBytes(32).toString('base64')
63
64 function publish1(content, recps, cb) {
65 if (recps) privatePublish(content, recps, cb)
66 else publish(content, cb)
67 }
68
69 var server = http.createServer(function (req, res) {
70 var url = URL.parse(req.url, true)
71 if (url.pathname !== '/') {
72 res.writeHead(404)
73 return res.end('Not Found')
74 }
75
76 if (req.method === 'POST') return getForm(req, function (err, data) {
77 if (err) {
78 res.writeHead(500)
79 return res.end(err.stack || err)
80 }
81
82 if (data.token !== token) {
83 res.writeHead(403)
84 return res.end('Invalid token')
85 }
86
87 if (data.publish) {
88 return publish1(content, recps, function (err, msg) {
89 if (err) {
90 res.writeHead(500, {'Content-Type': 'text/html'})
91 res.end('<!doctype html><html><head><meta charset=utf8><title>publish error</title></head><body>'
92 + '<h1>' + escapeHTML(err.name || err) + '</h1>'
93 + '<pre>' + escapeHTML(err.stack || '') + '</pre>'
94 + '</body></html>')
95 server.close()
96 return !getUrl && cb(err)
97 }
98 var json = JSON.stringify(msg, 0, 2)
99 if (redirectBase) {
100 var url = redirectBase + encodeURIComponent(msg.key)
101 res.writeHead(302, {'Location': url})
102 res.end()
103 } else {
104 res.writeHead(200, {'Content-Type': 'text/html'})
105 res.end('<!doctype html><html><head><meta charset=utf8><title>published</title></head><body>'
106 + '<pre>' + escapeHTML(json) + '</pre>'
107 + '</body></html>')
108 }
109 server.close()
110 return !getUrl && cb(null, msg)
111 })
112 }
113 if (data.cancel) {
114 res.writeHead(200, {'Content-Type': 'text/html'})
115 res.end('<!doctype html><html><head><meta charset=utf8><title>canceled</title></head><body>'
116 + '<p>Cancelled</p>'
117 + '</body></html>')
118 if (server) server.close()
119 return !getUrl && cb(new Error('User cancelled'))
120 }
121 })
122
123 var contentJson = JSON.stringify(content, null, 2)
124 var recpsJson = JSON.stringify(recps, null, 2)
125 res.writeHead(200, {'Content-Type': 'text/html'})
126 res.end('<!doctype html><html><head><meta charset=utf8><title>publish</title></head><body>'
127 + '<form action="/" method="post">'
128 + (recps ? '<pre>' + recpsJson + '</pre>' : '')
129 + '<pre>' + escapeHTML(contentJson) + '</pre>'
130 + '<input type="hidden" name="token" value="' + token + '">'
131 + '<input type="submit" name="publish" value="Publish"> '
132 + '<input type="submit" name="cancel" value="Cancel">'
133 + '</form>'
134 + '</body></html>')
135 }).listen(0, '127.0.0.1', function () {
136 var port = this.address().port
137 var url = 'http://127.0.0.1:' + port + '/'
138 if (browser) proc.spawn(browser, [url], {stdio: 'inherit'})
139 else cb(null, url)
140 }).on('error', cb)
141}
142
143module.exports = function (opts) {
144 var publish = opts.publish
145 var privatePublish = opts.privatePublish
146 var config = opts.config || {}
147 var browser = config.browser ||
148 (os.platform() === 'darwin' ? 'open' : 'xdg-open')
149 var name = opts.name || 'confirm'
150
151 return {
152 publish: function (content, cb) {
153 confirm({
154 publish: publish,
155 content: content,
156 browser: browser,
157 }, cb)
158 },
159 privatePublish: function (content, recps, cb) {
160 confirm({
161 privatePublish: privatePublish,
162 recps: recps,
163 content: content,
164 browser: browser,
165 }, cb)
166 },
167 publishGetUrl: function (opts, cb) {
168 confirm({
169 publish: publish,
170 content: opts.content,
171 redirectBase: opts.redirectBase,
172 getUrl: true,
173 }, cb)
174 },
175 privatePublishGetUrl: function (opts, cb) {
176 confirm({
177 privatePublish: privatePublish,
178 recps: opts.recps,
179 content: opts.content,
180 redirectBase: opts.redirectBase,
181 getUrl: true,
182 }, cb)
183 }
184 }
185}
186

Built with git-ssb-web