1
0
mirror of https://github.com/Tygs/0bin.git synced 2023-08-10 21:13:00 +03:00

Merge pull request #39 from mk-fg/add_zerobinpaste_cli_tool

Add simple "zerobinpaste" cli tool
This commit is contained in:
sametmax 2013-04-22 13:30:56 -07:00
commit 09d7bb4f24
9 changed files with 1362 additions and 5 deletions

4
.gitignore vendored
View File

@ -15,6 +15,10 @@
*.pyc
*.pyo
/tools/zerobinpaste.js
/tools/zerobinpaste.min
/tools/zerobinpaste
# files generated by setuptools
*.egg-info

View File

@ -57,7 +57,8 @@ Other features
- copy paste to clipboard in a click;
- get paste short URL in a click;
- own previous pastes history;
- visual hash of a paste to easily tell it apart from others in a list.
- visual hash of a paste to easily tell it apart from others in a list;
- optional command-line tool to encrypt and paste data from shell or scripts.
Technologies used
==================
@ -69,6 +70,7 @@ Technologies used
- Bootstrap_, the Twitter HTML5/CSS3 framework
- VizHash.js_ to create visual hashes from pastes
- Cherrypy_ (server only)
- `node.js`_ (for optional command-line tool only)
Known issues
@ -96,5 +98,6 @@ What does 0bin not implement?
.. _Bootstrap: http://twitter.github.com/bootstrap/
.. _VizHash.js: https://github.com/sametmax/VizHash.js
.. _Cherrypy: http://www.cherrypy.org/ (server only)
.. _node.js: http://nodejs.org/
.. _is not worth it: http://stackoverflow.com/questions/201705/how-many-random-elements-before-md5-produces-collisions
.. _WTF licence: http://en.wikipedia.org/wiki/WTFPL

View File

@ -45,7 +45,8 @@ Other features
- copy paste to clipboard in a click;
- get paste short URL in a click;
- own previous pastes history;
- visual hash of a paste to easily tell it apart from others in a list.
- visual hash of a paste to easily tell it apart from others in a list;
- `optional command-line tool`_ to encrypt and paste data from shell or scripts.
Technologies used
==================
@ -57,6 +58,7 @@ Technologies used
- Bootstrap_, the Twitter HTML5/CSS3 framework
- VizHash.js_ to create visual hashes from pastes
- Cherrypy_ (server only)
- `node.js`_ (for optional command-line tool only)
Known issues
@ -84,4 +86,6 @@ What does 0bin not implement?
.. _Bootstrap: http://twitter.github.com/bootstrap/
.. _VizHash.js: https://github.com/sametmax/VizHash.js
.. _Cherrypy: http://www.cherrypy.org/ (server only)
.. _node.js: http://nodejs.org/
.. _optional command-line tool: ./zerobinpaste_tool
.. _is not worth it: http://stackoverflow.com/questions/201705/how-many-random-elements-before-md5-produces-collisions

View File

@ -0,0 +1,100 @@
==============================
zerobinpaste command-line tool
==============================
zerobinpaste is a simple CLI tool (analogous to pastebinit or wgetpaste) to use
with files or shell redirection in terminal or simple scripts.
Example use-cases might look like::
% zerobinpaste README.rst
http://some.0bin.site/paste/0cc3d8a8...
% grep error /var/log/syslog | zerobinpaste
http://some.0bin.site/paste/81fd1324...
% zerobinpaste docs/en/*.rst
easy_install.rst http://some.0bin.site/paste/9adc576a...
apache_install.rst http://some.0bin.site/paste/01408cbd...
options.rst http://some.0bin.site/paste/921b2768...
...
% ps axlf | zerobinpaste | mail -s "Process tree on $(date)" root
Produced links can then be copy-pasted to some IRC channel or used in whatever
other conceivable way.
Tool does encryption by itself on the client machine and key (after hashmark) is
never sent to server or anywhere but the tool's stdout stream (e.g. terminal).
Tool has to be built with `node.js`_ separately (see below).
Usage
=====
At least the pastebin site (main URL where you'd paste stuff with the browser)
has to be specified for the tool to use either via -u (--url) option (can be
simplified with shell alias - e.g. ``alias zp='zerobinpaste -u http://some.0bin.site``)
or in the "~/.zerobinpasterc" configuration file (json format).
| Non-option arguments are interpreted as files to upload/paste contents of.
| If no arguments are specified, data to paste will be read from stdin stream.
Simple configuration file may look like this:
{"url": "http://some.0bin.site"}
Any options (in the long form, e.g. "url" for --url above) that are allowed on
the command-line can be specified there.
Run the tool with -h or --help option to see full list of supported parameters.
Build / Installation
====================
In essence:
0bin% cd tools
0bin/tools% make
...
0bin/tools% cp zerobinpaste ~/bin # install to PATH
"npm" binary (packaged and installed with node.js) is required to pull in build
dependencies, if necessary, and "node" binary is required for produced binary to
run.
Use "make" in "tools" path to produce non-minified runnable "zerobinpaste"
script there.
``make ugly`` command can be used instead of ``make`` to create "minified"
version (using/installing uglifyjs_, about 25% smaller in size).
Resulting "zerobinpaste" script requires only node.js ("node" binary) installed
to run and can be placed in any of the PATH dirs (e.g. "~/bin",
"/usr/local/bin") to be run just as "zerobinpaste".
Why node.js and not python
==========================
Unfortunately, it's fairly complex and unreliable to replicate non-trivial and
undocumented encryption protocol that SJCL_ convenience methods employ, and any
mistake in encryption is guaranteed to produce unreadable paste.
Current implementation uses same JavaScript code (and V8 node.js engine) that
browsers do, hence can be fairly simple and robust.
Future development plans include supporting configurable, less complex and more
widespread encryption schemas, allowing for simplier non-javascript client as
well.
See `related pull request`_ for more details.
.. _node.js: http://nodejs.org/
.. _uglifyjs: https://github.com/mishoo/UglifyJS
.. _SJCL: http://crypto.stanford.edu/sjcl/
.. _related pull request: https://github.com/sametmax/0bin/pull/39

View File

@ -22,10 +22,11 @@
| en/using_supervisor | fr/using_supervisor |
| en/theming | fr/theming |
| en/options | fr/options |
| en/zerobinpaste_tool | |
| | |
|`Report a bug`_ |`Signaler un bug`_ |
+-------------------------+--------------------------------+
.. _Signaler un bug: https://github.com/sametmax/0bin/issues
.. _Report a bug: https://github.com/sametmax/0bin/issues
.. _Report a bug: https://github.com/sametmax/0bin/issues

25
tools/Makefile Normal file
View File

@ -0,0 +1,25 @@
zerobinpaste: zerobinpaste.js commander.js ../zerobin/static/js/sjcl.js ../zerobin/static/js/lzw.js
echo '#!/usr/bin/env node' > zerobinpaste
cat commander.js ../zerobin/static/js/sjcl.js ../zerobin/static/js/lzw.js >> zerobinpaste
cat zerobinpaste.js >> zerobinpaste
chmod +x zerobinpaste
ugly: zerobinpaste
uglifyjs=$$(PATH="$$(npm bin):$$PATH" which uglifyjs 2>/dev/null) \
|| { npm install uglify-js; uglifyjs=$$(PATH="$$(npm bin):$$PATH" which uglifyjs); } \
&& sed -i 1d zerobinpaste \
&& $${uglifyjs} -o zerobinpaste.min zerobinpaste \
&& echo '#!/usr/bin/env node' > zerobinpaste \
&& cat zerobinpaste.min >> zerobinpaste \
&& chmod +x zerobinpaste
clean:
rm -f zerobinpaste{,.js,.min}
zerobinpaste.js: zerobinpaste.coffee
coffee=$$(PATH="$$(npm bin):$$PATH" which coffee 2>/dev/null) \
|| { npm install coffee-script; coffee=$$(PATH="$$(npm bin):$$PATH" which coffee); } \
&& $$coffee -c zerobinpaste.coffee
.PHONY: uglify

1118
tools/commander.js Normal file

File diff suppressed because it is too large Load Diff

103
tools/zerobinpaste.coffee Normal file
View File

@ -0,0 +1,103 @@
program
.version('0.0.1')
.usage('[options] [ file ... ]\n\n' + ' Paste contents of file(s) or stdin to 0bin site.')
.option('-u, --url [url]', 'URL of a 0bin site.')
.option('-e, --expire [period]',
'Expiration period - one of: 1_view, 1_day (default), 1_month, never.', '1_day')
.option('-c, --config [path]', 'Path to zerobin configuration file (default: ~/.zerobinpasterc).\n'\
+ ' Should be json-file with the same keys as can be specified on the command line.\n'\
+ ' Example contents: {"url": "http://some-0bin.com"}', '~/.zerobinpasterc')
.parse(process.argv);
[http, url, qs, fs, path] = ['http', 'url', 'querystring', 'fs', 'path'].map(require)
# Parse config file, if any
config = program.config.replace(/^~\/+/, '')
config = path.resolve(process.env.HOME, config)
try
if fs.statSync(config).isFile()
config = JSON.parse(fs.readFileSync(config))
(program[k] = v) for own k, v of config
# Sanity checks and option processing
if not program.url
console.error('ERROR: URL option must be specified.')
process.exit(1)
if program.expire == '1_view'
# "burn_after_reading" is too damn long for cli
program.expire = 'burn_after_reading'
expire_opts = ['burn_after_reading', '1_day', '1_month', 'never']
if program.expire not in expire_opts
console.error(
"ERROR: --expire value (provided: '#{program.expire}')"\
+ ' must be one of: ' + expire_opts.join(', ') + "." )
process.exit(1)
# Paste one dump and print URL, optionally prefixed with name
paste_file = (content, name) ->
content = sjcl.codec.utf8String.toBits(content)
content = sjcl.codec.base64.fromBits(content)
# content = lzw.compress(content)
key = sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 0), 0)
content = sjcl.encrypt(key, content)
content = qs.stringify
content: content
expiration: program.expire
# host.com -> http://host.com
if not program.url.match(/^https?:\/\//)
program.url = 'http://' + program.url.replace(/^\/+/, '')
req_opts = url.parse(program.url)
req_opts.method = 'POST'
req_opts.headers =
'Content-Type': 'application/x-www-form-urlencoded'
'Content-Length': content.length
req_url_base = req_opts.path
.replace(/\/paste\/create\/?$/, '').replace(/\/+$/, '')
req_opts.path = req_url_base + '/paste/create'
req = http.request req_opts, (res) ->
req_reply = ''
res.setEncoding('utf8')
res.on 'data', (chunk) -> req_reply += chunk
res.on 'end', ->
req_reply = JSON.parse(req_reply)
if req_reply.status != 'ok'
console.error("ERROR: failure posting #{name} - " + req_reply.message)
return
req_opts.pathname = req_url_base + '/paste/' + req_reply.paste
req_opts.hash = key
paste = url.format(req_opts)
console.log(if name then "#{name} #{paste}" else paste)
req.write(content)
req.end()
# Loop over file args or read stdin
if not program.args or not program.args.length
process.stdin.resume()
process.stdin.setEncoding('utf8')
stdin_data = ''
process.stdin.on 'data', (chunk) -> stdin_data += chunk
process.stdin.on 'end', -> paste_file(stdin_data)
else
for file in program.args
paste_file( fs.readFileSync(file, 'utf8'),
if program.args.length > 1 then path.basename(file) else null )

View File

@ -107,5 +107,4 @@ var lzw = {
}
return result;
}
}
};