Files: 2d613e9d6e6888fc6cf9cdd2eaab0729966e438f / confirm.js
4941 bytesRaw
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, '<') |
11 | .replace(/>/g, '>') |
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 getUrl = opts.getUrl |
28 | var privatePublish = opts.privatePublish || noPrivatePublish |
29 | var redirectBase = opts.redirectBase |
30 | |
31 | if (typeof cb !== 'function') { |
32 | throw new TypeError('bad callback') |
33 | } |
34 | |
35 | if (browser && getUrl) { |
36 | return cb(new TypeError('browser option and getUrl option conflict')) |
37 | } |
38 | if (!browser && !getUrl) { |
39 | return cb(new TypeError('missing browser option')) |
40 | } |
41 | if (recps && !Array.isArray(recps)) { |
42 | return cb(new TypeError('recps should be array')) |
43 | } |
44 | |
45 | var token = crypto.randomBytes(32).toString('base64') |
46 | |
47 | function publish1(content, recps, cb) { |
48 | if (recps) privatePublish(content, recps, cb) |
49 | else publish(content, cb) |
50 | } |
51 | |
52 | var server = http.createServer(function (req, res) { |
53 | var url = URL.parse(req.url, true) |
54 | if (url.pathname !== '/') { |
55 | res.writeHead(404) |
56 | return res.end('Not Found') |
57 | } |
58 | |
59 | if (url.query.token === token) { |
60 | if (url.query.publish) { |
61 | return publish1(content, recps, function (err, msg) { |
62 | if (err) { |
63 | res.writeHead(500, {'Content-Type': 'text/html'}) |
64 | res.end('<!doctype html><html><head><meta charset=utf8><title>publish error</title></head><body>' |
65 | + '<h1>' + escapeHTML(err.name || err) + '</h1>' |
66 | + '<pre>' + escapeHTML(err.stack || '') + '</pre>' |
67 | + '</body></html>') |
68 | server.close() |
69 | return !getUrl && cb(err) |
70 | } |
71 | var json = JSON.stringify(msg, 0, 2) |
72 | if (redirectBase) { |
73 | var url = redirectBase + encodeURIComponent(msg.key) |
74 | res.writeHead(302, {'Location': url}) |
75 | res.end() |
76 | } else { |
77 | res.writeHead(200, {'Content-Type': 'text/html'}) |
78 | res.end('<!doctype html><html><head><meta charset=utf8><title>published</title></head><body>' |
79 | + '<pre>' + escapeHTML(json) + '</pre>' |
80 | + '</body></html>') |
81 | } |
82 | server.close() |
83 | return !getUrl && cb(null, msg) |
84 | }) |
85 | } |
86 | if (url.query.cancel) { |
87 | res.writeHead(200, {'Content-Type': 'text/html'}) |
88 | res.end('<!doctype html><html><head><meta charset=utf8><title>canceled</title></head><body>' |
89 | + '<p>Cancelled</p>' |
90 | + '</body></html>') |
91 | if (server) server.close() |
92 | return !getUrl && cb(new Error('User cancelled')) |
93 | } |
94 | } |
95 | |
96 | var contentJson = JSON.stringify(content, null, 2) |
97 | var recpsJson = JSON.stringify(recps, null, 2) |
98 | res.writeHead(200, {'Content-Type': 'text/html'}) |
99 | res.end('<!doctype html><html><head><meta charset=utf8><title>publish</title></head><body>' |
100 | + '<form action="/" method="get">' |
101 | + (recps ? '<pre>' + recpsJson + '</pre>' : '') |
102 | + '<pre>' + escapeHTML(contentJson) + '</pre>' |
103 | + '<input type="hidden" name="token" value="' + token + '">' |
104 | + '<input type="submit" name="publish" value="Publish"> ' |
105 | + '<input type="submit" name="cancel" value="Cancel">' |
106 | + '</form>' |
107 | + '</body></html>') |
108 | }).listen(0, '127.0.0.1', function () { |
109 | var port = this.address().port |
110 | var url = 'http://127.0.0.1:' + port + '/' |
111 | if (browser) proc.spawn(browser, [url], {stdio: 'inherit'}) |
112 | else cb(null, url) |
113 | }).on('error', cb) |
114 | } |
115 | |
116 | module.exports = function (opts) { |
117 | var publish = opts.publish |
118 | var privatePublish = opts.privatePublish |
119 | var config = opts.config || {} |
120 | var browser = config.browser || |
121 | (os.platform() === 'darwin' ? 'open' : 'xdg-open') |
122 | var name = opts.name || 'confirm' |
123 | |
124 | return { |
125 | publish: function (content, cb) { |
126 | confirm({ |
127 | publish: publish, |
128 | content: content, |
129 | browser: browser, |
130 | }, cb) |
131 | }, |
132 | privatePublish: function (content, recps, cb) { |
133 | confirm({ |
134 | privatePublish: privatePublish, |
135 | recps: recps, |
136 | content: content, |
137 | browser: browser, |
138 | }, cb) |
139 | }, |
140 | publishGetUrl: function (opts, cb) { |
141 | confirm({ |
142 | publish: publish, |
143 | content: opts.content, |
144 | redirectBase: opts.redirectBase, |
145 | getUrl: true, |
146 | }, cb) |
147 | }, |
148 | privatePublishGetUrl: function (opts, cb) { |
149 | confirm({ |
150 | privatePublish: privatePublish, |
151 | recps: opts.recps, |
152 | content: opts.content, |
153 | redirectBase: opts.redirectBase, |
154 | getUrl: true, |
155 | }, cb) |
156 | } |
157 | } |
158 | } |
159 |
Built with git-ssb-web