confirm.jsView |
---|
| 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 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 … | +} |