Skip to content

Commit

Permalink
feat(main): unixify omnihash cmd not hash args as str if file missing
Browse files Browse the repository at this point in the history
+ Improve help-messages.
+ `Omnihash` behaves like unix (ie `sha1sum`), so no prompt appear when
reading STDIN.
+ `oh` heuristic behavior on existence of files/urls behaves unchanged.

FIX Miserlou#10
  • Loading branch information
ankostis committed Dec 18, 2016
1 parent 34dcb65 commit 9233b31
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 107 deletions.
96 changes: 20 additions & 76 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,16 @@ Please note that on *Windows*, those two libraries do not yet exist (as of Aug 2

## Usage

For strings:
After installation you have 2 new commands:

$ omnihash "correct horse battery staple"
- `omnihash [OPTIONS] [FILE_OR_URL]...`: hash cmd-line arguments as files/URLs;
- `oh [OPTIONS] [HASHME]...`: checks if HASHME is an existent file or URL, and fallback to hashing as string.

In both cases is omni-hashes <stdin> when no args are given.

Use `oh` or `omnihash -s` for strings:

$ oh "correct horse battery staple"
Hashing string 'correct horse battery staple'..
DSA: abf7aad6438836dbe526aa231abde2d0eef74d42
DSA-SHA: abf7aad6438836dbe526aa231abde2d0eef74d42
Expand All @@ -50,7 +57,7 @@ For strings:

And files:

$ omnihash /etc/hosts
$ oh /etc/hosts
Hashing file '/etc/hosts'..
DSA: 0ec93cf2b8000b5b339d0c5435251ad14f85b553
DSA-SHA: 0ec93cf2b8000b5b339d0c5435251ad14f85b553
Expand All @@ -77,7 +84,7 @@ And files:

And URLs:

$ omnihash https://cryptome.org
$ oh https://cryptome.org
Hashing content of URL 'https://cryptome.org'..
DSA: f63c8212d4769f2740306d30df6e56e4d773c412
DSA-SHA: f63c8212d4769f2740306d30df6e56e4d773c412
Expand All @@ -102,6 +109,11 @@ And URLs:
BLAKE2s: f4b0dd61772776ba04a4f0c94975a92acc41eb61ac2745e60b3adb7a08dc88d4
BLAKE2b: c1635df205326331b565959edb4b3b64a81a352ec594c869d35a2373ee8f1b8288e9135c0627b6cc44d54378a4b1f1fb39e124065644b7b9a62f57dd0e16e8ab2c23f27128614351712d3e2851c9c24763499512117ceb55b3f277863880767a11272ec5abe5527a9ae08cdea367264aa31b9160da148c00f732806200076954

Or prefer `omnihash` to avoid surprises in case of typos:

$ omnihash BAD_FILE
No such file or directory: BAD_FILE


## Advanced usage

Expand All @@ -111,7 +123,7 @@ You can also hash items from the standard input like so:

You can pass multiple inputs at any time (ex, `omnihash *`).

You can force string-hashing (not falling-back to files) with `-s`.
You can force string-hashing of cmd-line arguments (not falling-back to files) with `-s`.

You may limit the number of algorithms using the `-f` (*"family"*) option:

Expand All @@ -122,89 +134,21 @@ You may limit the number of algorithms using the `-f` (*"family"*) option:

You can filter for string matches using `-m`, like so:

$ omnihash "correct horse battery staple" -m 9cc2
$ oh "correct horse battery staple" -m 9cc2
Hashing string correct horse battery staple..
MD5: 9cc2ae8a1ba7a93da39b46fc1019c481

You can output in machine readable JSON with `-j`, like so:

$ omnihash "correct horse battery staple" -j -m 9cc2
$ oh "correct horse battery staple" -j -m 9cc2
{
"MD5": "9cc2ae8a1ba7a93da39b46fc1019c481"
}

It's aliased so you can actually just call `oh` if you're as lazy as I am.

You can also see the value for various CRC checks by using `-c`:

$ omnihash "correct horse battery staple" -c
Hashing string 'correct horse battery staple'..
DSA: abf7aad6438836dbe526aa231abde2d0eef74d42
DSA-SHA: abf7aad6438836dbe526aa231abde2d0eef74d42
MD4: 131adffe1d8712c1b624ba62b5bcf3fd
MD5: 9cc2ae8a1ba7a93da39b46fc1019c481
MDC2: b41edfd5e9cb278433a4a5c740898ffb
RIPEMD160: 5e708aa85ae8b0d080837c50bd63634d584edc00
SHA: 99add446c4eed3772a92fabe3ab2c56fc2c9a26e
SHA1: abf7aad6438836dbe526aa231abde2d0eef74d42
SHA224: 636f080709f287ec5c5ea79442fc4bb914924cd5c6ca8ff84e3410c4
SHA256: c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a
SHA384: c24b92449c871f33bbbf1fc1989e5e1037cfa9a3dfdb17947f8172226181e7825ebb4c750763915835bf125a590e05ae
SHA512: be5ef7679d88ab9a9045f6267e55f5e5784b4b8cd764b5cd855a5244f91c626953cd46c43d7668873fd6efbd3b221249315580031963472a078781fe046e62ae
dsaEncryption: abf7aad6438836dbe526aa231abde2d0eef74d42
dsaWithSHA: abf7aad6438836dbe526aa231abde2d0eef74d42
ecdsa-with-SHA1: abf7aad6438836dbe526aa231abde2d0eef74d42
whirlpool: 8c0e81ff1650da90c70a859319ba923b8807ad26af0940f8562fd62e75878eed13f434ba47860223ac55d92d91a169b3f9a1cbd4f10f3fca1b877088e5675891
SHA3_224: 5ee454bfad2d1e25ba74884af244379d17bf50ef46dbe644e7587fc8
SHA3_256: af9ac3dac56b02f1ea017e7657a9bb7e1778274e31509f134f023e41a5953866
SHA3_384: 5a1caac1441d4d002d6650f558b6bb10593095fe4664496b8f1665f239d923e69f95cbd141c5dcf833770542ff2322e8
SHA3_512: 4b65d7b7acc886f9add07db3a5d42bf0032fe0109a1fd56f623c7093e8a59689f9246918a4f388034ddf393231eaba0742b3dc1840e4556270a729ce56098f35
BLAKE2s: 239dd0a7e138f5fced884939c200b9ed35e092c17cd27f6049a5d0bda9fd7b8b
BLAKE2b: 84793833af5cf79ef9548fd505dbb6633e54c1b4ec2c4f577c3a0ae41764e50ce8278ab8f6e0edd3e90ab6ef0914ff0e49329e0703ecc2fb7fdac12a4823fea7
CRC-16: 0x72bc
CRC-16-BUYPASS: 0xed6e
CRC-16-DDS-110: 0x929c
CRC-16-DECT: 0x73e5
CRC-16-DNP: 0xfd30
CRC-16-EN-13757: 0x2ae7
CRC-16-GENIBUS: 0x493a
CRC-16-MAXIM: 0x8d43
CRC-16-MCRF4XX: 0xdbf8
CRC-16-RIELLO: 0xb464
CRC-16-T10-DIF: 0x2510
CRC-16-TELEDISK: 0xdd3d
CRC-16-USB: 0x67eb
CRC-24: 0xbe455f
CRC-24-FLEXRAY-A: 0xad0a8a
CRC-24-FLEXRAY-B: 0x5d6e72
CRC-32: 0xcb7e6e10L
CRC-32-BZIP2: 0x8f6407fL
CRC-32C: 0xbd9d695aL
CRC-32D: 0xd42e1822L
CRC-32-MPEG: 0xf709bf80L
CRC-32Q: 0xafc633bfL
CRC-64: 0x98aa19c00b783c4L
CRC-64-JONES: 0xc1c681b1fee4d316L
CRC-64-WE: 0x41097f04e906dfecL
CRC-8: 0xb9
CRC-8-DARC: 0xe1
CRC-8-I-CODE: 0x99
CRC-8-ITU: 0xec
CRC-8-MAXIM: 0xec
CRC-8-ROHC: 0x31
CRC-8-WCDMA: 0xd6
CRC-AUG-CCITT: 0x301f
CRC-CCITT-FALSE: 0xb6c5
JAMCRC: 0x348191efL
KERMIT: 0x22cd
MODBUS: 0x9814
POSIX: 0x60e7b181L
X-25: 0x2407
XFER: 0x8648a5a9L
XMODEM: 0x1a5a

More information can be found with `--help`.


## Extension plugins

You may extend the supported hashing algorithms using
Expand Down
9 changes: 9 additions & 0 deletions omnihash/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ def next(self):
def iterate_bytechunks(hashme, is_string, use_json, hash_many):
"""
Return iterable bytes and content-length if possible.
:param is_string:
if true, do not search if `hashme` is URL/file,
if ``False``, ``hashme`` assume to be either a URL or a file,
if ``None``, try URL/file or fallback to string.
"""

# URL
Expand Down Expand Up @@ -80,6 +85,10 @@ def iterate_bytechunks(hashme, is_string, use_json, hash_many):
fsize = os.stat(hashme).st_size
bytechunks = FileIter(open(hashme, mode='rb'))
# String
elif is_string is False:
if not use_json:
click.echo("No such file or directory: " + click.style(hashme, bold=True), err=not hash_many)
return None
else:
if not use_json:
click.echo("Hashing string " + click.style(hashme, bold=True) + "..", err=not hash_many)
Expand Down
75 changes: 62 additions & 13 deletions omnihash/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,73 @@ def next(self):
##

@click.command()
@click.argument('hashmes', nargs=-1)
@click.argument('file-or-url', nargs=-1)
@click.option('--version', '-v', is_flag=True, default=False, help="Show version and quit.")
@click.option('--as-str', '-s', is_flag=True, default=False,
help="Hash cmd-line args as strings.")
@click.option('--family', '-f', is_flag=False, default=False, multiple=True,
help=("Select only algorithm-families having TEXT in their names."
"Use it multiple times to select more families."))
@click.option('--x-family', '-x', is_flag=False, default=False, multiple=True,
help=("Exclude algorithm-families algorithms having TEXT in their names."
"Use it multiple times to exclude more families."))
@click.option('--match', '-m', is_flag=False, default=False, help="Match input string.")
@click.option('--json', '-j', is_flag=True, default=False, help="Output result in JSON format.")
@click.pass_context
def main(click_context, file_or_url, version, as_str, family, x_family, match, json):
"""
Read HASHME file/URL and omni-hash it. Read <stdin> if no args given.
"""
# Print version and quit
if version:
version = pkg_resources.require("omnihash")[0].version
click.echo(version)
return

match = match and match.lower()
digfacts = omnihash.collect_digester_factories(family, x_family)

results = []
if not file_or_url:
stdin = click.get_binary_stream('stdin')
bytechunks = iter(lambda: stdin.read(io.DEFAULT_BUFFER_SIZE), b'')
results.append([omnihash.produce_hashes(None, bytechunks, digfacts, match=match, use_json=json)])
else:
hash_many = len(file_or_url) > 1
for arg in file_or_url:
result = {}
data = omnihash.iterate_bytechunks(arg, is_string=as_str, use_json=json, hash_many=hash_many)
if data:
length, bytechunks = data
result = omnihash.produce_hashes(length, bytechunks, digfacts, match=match, use_json=json)
if result:
result['NAME'] = arg
results.append(result)

if results and json:
import json

print(json.dumps(results, indent=4, sort_keys=True))


@click.command()
@click.argument('hashme', nargs=-1)
@click.option('--version', '-v', is_flag=True, default=False, help="Show version and quit.")
@click.option('--as-str', '-s', is_flag=True, default=None,
help="Hash cmd-line args as strings, even if there are files named like that.")
@click.option('--family', '-f', is_flag=False, default=False, multiple=True,
help=("Select a family of algorithms: "
"include only algos having TEXT in their names."
help=("Select only algorithm-families having TEXT in their names."
"Use it multiple times to select more families."))
@click.option('--x-family', '-x', is_flag=False, default=False, multiple=True,
help=("Exclude a family of algorithms: "
"skip algos having TEXT in their names."
help=("Exclude algorithm-families having TEXT in their names."
"Use it multiple times to exclude more families."))
@click.option('--match', '-m', is_flag=False, default=False, help="Match input string.")
@click.option('--json', '-j', is_flag=True, default=False, help="Output result in JSON format.")
@click.pass_context
def main(click_context, hashmes, version, as_str, family, x_family, match, json):
def main_fallback_to_str(click_context, hashme, version, as_str, family, x_family, match, json):
"""
If there is a file at `hashme`, read and omnihash that.
Otherwise, assume `hashme` is a string.
If HASHME is an existent file or a URL, read and omni-hash it.
Otherwise, omni-hash HASHME as a string. Read <stdin> if no args given.
"""

# Print version and quit
Expand All @@ -61,7 +109,7 @@ def main(click_context, hashmes, version, as_str, family, x_family, match, json)
digfacts = omnihash.collect_digester_factories(family, x_family)

results = []
if not hashmes:
if not hashme:
# If no stdin, just help and quit.
if not sys.stdin.isatty():
stdin = click.get_binary_stream('stdin')
Expand All @@ -73,22 +121,23 @@ def main(click_context, hashmes, version, as_str, family, x_family, match, json)
print(click_context.get_help())
return
else:
hash_many = len(hashmes) > 1
for hashme in hashmes:
hash_many = len(hashme) > 1
for arg in hashme:
result = {}
data = omnihash.iterate_bytechunks(hashme, as_str, json, hash_many)
data = omnihash.iterate_bytechunks(arg, as_str, json, hash_many)
if data:
length, bytechunks = data
result = omnihash.produce_hashes(length, bytechunks, digfacts, match=match, use_json=json)
if result:
result['NAME'] = hashme
result['NAME'] = arg
results.append(result)

if results and json:
import json

print(json.dumps(results, indent=4, sort_keys=True))


##
# Entrypoint
##
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def read_project_version():
entry_points={
'console_scripts': [
'omnihash = omnihash.__main__:main',
'oh = omnihash.__main__:main',
'oh = omnihash.__main__:main_fallback_to_str',
],
'omnihash.plugins': [
'a_sha3 = omnihash.plugin:plugin_sha3_digesters [sha3]',
Expand Down
Loading

0 comments on commit 9233b31

Please sign in to comment.