diff --git a/README.md b/README.md index 72387b3..7017c52 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ proxy=http://127.0.0.1:3128 | auth_user | None | Basic authorization username | | auth_pass | None | Basic authorization password | | auth_custom | None | Custom authorization headers in JSON format, like `{'Authorization': 'Bearer token'}` | +| json | False | Print sending result in JSON format | # Usage diff --git a/README.rst b/README.rst index 0c41fed..7599144 100644 --- a/README.rst +++ b/README.rst @@ -128,6 +128,9 @@ List of OPTIONS available * - auth_custom - None - Custom authorization headers in JSON format, like ``{'Authorization': 'Bearer token'}`` + * - json + - False + - Print sending result in JSON format Usage diff --git a/pbincli/actions.py b/pbincli/actions.py index 8920b56..fdeae46 100644 --- a/pbincli/actions.py +++ b/pbincli/actions.py @@ -21,20 +21,20 @@ def send(args, api_client, settings=None): if args.text: text = args.text elif args.stdin: - print("Reading text from stdin…") + if not args.json: print("Reading text from stdin…") text = args.stdin.read() elif not args.file: PBinCLIError("Nothing to send!") else: text = "" - print("Preparing paste…") + if not args.json: print("Preparing paste…") paste = Paste(args.debug) if args.verbose: print("Used server: {}".format(api_client.getServer())) # get from server supported paste format version and update object - if args.verbose: print("Getting supported paste format version from server…") + if args.debug: print("Getting supported paste format version from server…") version = api_client.getVersion() paste.setVersion(version) @@ -61,15 +61,17 @@ def send(args, api_client, settings=None): discussion = settings['discus'], expiration = settings['expire']) - if args.verbose: print("Sending request to server…") + if args.verbose: print("Preparing request to server…") request = paste.getJSON() if args.debug: print("Passphrase:\t{}\nRequest:\t{}".format(paste.getHash(), request)) # If we use dry option, exit now - if args.dry: sys.exit(0) + if args.dry: + if not args.json: print("Dry mode: paste will not be uploaded. Exiting…") + sys.exit(0) - print("Uploading paste…") + if not args.json: print("Uploading paste…") result = api_client.post(request) if args.debug: print("Response:\t{}\n".format(result)) @@ -78,47 +80,92 @@ def send(args, api_client, settings=None): if not result['status']: # return code is zero passphrase = paste.getHash() - # Paste information - print("Paste uploaded!\nPasteID:\t{}\nPassword:\t{}\nDelete token:\t{}".format( - result['id'], - passphrase, - result['deletetoken'])) - - # Paste link - print("\nLink:\t\t{}?{}#{}".format( - settings['server'], - result['id'], - passphrase)) - - # Paste deletion link - print("Delete Link:\t{}?pasteid={}&deletetoken={}".format( - settings['server'], - result['id'], - result['deletetoken'])) - - # Print links to mirrors if present - if settings['mirrors']: - print("\nMirrors:") - urls = settings['mirrors'].split(',') - for x in urls: - print("\t\t{}?{}#{}".format( - validate_url_ending(x), - result['id'], - passphrase)) + if args.json: # JSON output + response = { + 'status': result['status'], + 'result': { + 'id': result['id'], + 'password': passphrase, + 'deletetoken': result['deletetoken'], + 'link': "{}?{}#{}".format( + settings['server'], + result['id'], + passphrase), + 'deletelink': "{}?pasteid={}&deletetoken={}".format( + settings['server'], + result['id'], + result['deletetoken']), + } + } + + if settings['mirrors']: + urls = settings['mirrors'].split(',') + mirrors = [] + for x in urls: + mirrors.append("{}?{}#{}".format( + validate_url_ending(x), + result['id'], + passphrase) + ) + response['result']['mirrors'] = mirrors + + if settings['short']: + try: + response['result']['short'] = shortener.getlink("{}?{}#{}".format( + settings['server'], + result['id'], + passphrase)) + except Exception as ex: + response['result']['short_error'] = ex + print(json_encode(response)) + sys.exit(0) + + else: + # Paste information + print("Paste uploaded!\nPasteID:\t{}\nPassword:\t{}\nDelete token:\t{}".format( + result['id'], + passphrase, + result['deletetoken'])) + + # Paste link + print("\nLink:\t\t{}?{}#{}".format( + settings['server'], + result['id'], + passphrase)) + + # Paste deletion link + print("Delete Link:\t{}?pasteid={}&deletetoken={}".format( + settings['server'], + result['id'], + result['deletetoken'])) + + # Print links to mirrors if present + if settings['mirrors']: + print("\nMirrors:") + urls = settings['mirrors'].split(',') + for x in urls: + print("\t\t{}?{}#{}".format( + validate_url_ending(x), + result['id'], + passphrase)) + + if settings['short']: + print("\nQuerying URL shortening service…") + try: + link = shortener.getlink("{}?{}#{}".format( + settings['server'], + result['id'], + passphrase)) + print("Short Link:\t{}".format(link)) + except Exception as ex: + PBinCLIError("Something went wrong…\nError:\t\t{}".format(ex)) + sys.exit(0) elif result['status']: # return code is other then zero PBinCLIError("Something went wrong…\nError:\t\t{}".format(result['message'])) else: # or here no status field in response or it is empty PBinCLIError("Something went wrong…\nError: Empty response.") - if settings['short']: - print("\nQuerying URL shortening service…") - shortener.getlink("{}?{}#{}".format( - settings['server'], - result['id'], - passphrase)) - - def get(args, api_client, settings=None): parseduri, isuri = uri_validator(args.pasteinfo) diff --git a/pbincli/api.py b/pbincli/api.py index 1b3facd..162450f 100644 --- a/pbincli/api.py +++ b/pbincli/api.py @@ -167,7 +167,7 @@ class Shortener: 'custom': self._custom } # run function selected by choosen API - servicesList[self.api](url) + return servicesList[self.api](url) def _yourls(self,url): @@ -196,7 +196,7 @@ class Shortener: if not 'shorturl' in response: PBinCLIError("YOURLS: Unknown error: {}".format(response['message'])) else: - print("Short Link:\t{}".format(response['shorturl'])) + return response['shorturl'] else: PBinCLIError("YOURLS: No status, statusCode or message fields in response! Received:\n{}".format(response)) @@ -208,7 +208,7 @@ class Shortener: result = self.session.post( url = "https://clck.ru/--", data = request) - print("Short Link:\t{}".format(result.text)) + return result.text except Exception as ex: PBinCLIError("clck.ru: unexcepted behavior: {}".format(ex)) @@ -220,7 +220,7 @@ class Shortener: result = self.session.post( url = "https://tinyurl.com/api-create.php", data = request) - print("Short Link:\t{}".format(result.text)) + return result.text except Exception as ex: PBinCLIError("TinyURL: unexcepted behavior: {}".format(ex)) @@ -242,7 +242,7 @@ class Shortener: response = result.json() if 'shorturl' in response: - print("Short Link:\t{}".format(response['shorturl'])) + return response['shorturl'] else: PBinCLIError("{}: got error {} from API: {}".format( "is.gd" if self.api == 'isgd' else 'v.gd', @@ -265,7 +265,7 @@ class Shortener: result = self.session.post( url = "https://cutt.ly/scripts/shortenUrl.php", data = request) - print("Short Link:\t{}".format(result.text)) + return result.text except Exception as ex: PBinCLIError("cutt.ly: unexcepted behavior: {}".format(ex)) @@ -281,6 +281,6 @@ class Shortener: try: result = self.session.get( url = rUrl) - print("Short Link:\t{}".format(result.text)) + return result.text except Exception as ex: PBinCLIError("Shorter: unexcepted behavior: {}".format(ex)) diff --git a/pbincli/cli.py b/pbincli/cli.py index 0e0183c..77ef4c9 100755 --- a/pbincli/cli.py +++ b/pbincli/cli.py @@ -90,7 +90,8 @@ def main(): ## send_parser.add_argument("-L", "--mirrors", default=argparse.SUPPRESS, help="Comma-separated list of mirrors of service with scheme (default: None)") send_parser.add_argument("-v", "--verbose", default=False, action="store_true", help="Enable verbose output") - send_parser.add_argument("-d", "--debug", default=False, action="store_true", help="Enable debug output") + send_parser.add_argument("-d", "--debug", default=False, action="store_true", help="Enable debug output. Includes verbose output") + send_parser.add_argument("--json", default=False, action="store_true", help="Print result in JSON format") send_parser.add_argument("--dry", default=False, action="store_true", help="Invoke dry run") send_parser.add_argument("stdin", help="Input paste text from stdin", nargs="?", type=argparse.FileType("r"), default=sys.stdin) send_parser.set_defaults(func=pbincli.actions.send) @@ -114,7 +115,8 @@ def main(): get_parser.add_argument("--auth-custom", default=argparse.SUPPRESS, help="Custom authorization header in JSON format") ## get_parser.add_argument("-v", "--verbose", default=False, action="store_true", help="Enable verbose output") - get_parser.add_argument("-d", "--debug", default=False, action="store_true", help="Enable debug output") + get_parser.add_argument("-d", "--debug", default=False, action="store_true", help="Enable debug output. Includes verbose output") + get_parser.add_argument("--json", default=False, action="store_true", help="Print result in JSON format") get_parser.set_defaults(func=pbincli.actions.get) # a delete command @@ -133,7 +135,8 @@ def main(): delete_parser.add_argument("--auth-custom", default=argparse.SUPPRESS, help="Custom authorization header in JSON format") ## delete_parser.add_argument("-v", "--verbose", default=False, action="store_true", help="Enable verbose output") - delete_parser.add_argument("-d", "--debug", default=False, action="store_true", help="Enable debug output") + delete_parser.add_argument("-d", "--debug", default=False, action="store_true", help="Enable debug output. Includes verbose output") + delete_parser.add_argument("--json", default=False, action="store_true", help="Print result in JSON format") delete_parser.set_defaults(func=pbincli.actions.delete) # Add argcomplete trigger @@ -164,7 +167,8 @@ def main(): 'auth': None, 'auth_user': None, 'auth_pass': None, - 'auth_custom': None + 'auth_custom': None, + 'json': False } # Configuration preference order: @@ -191,7 +195,9 @@ def main(): # Re-validate PrivateBin instance URL CONFIG['server'] = validate_url_ending(CONFIG['server']) - if args.debug: print("Whole configuration:\n{}\n".format(CONFIG)) + if args.debug: + print("Whole configuration:\n{}\n".format(CONFIG)) + args.verbose = True api_client = PrivateBin(CONFIG) if hasattr(args, "func"): diff --git a/requirements.txt b/requirements.txt index 43363bf..2219ad3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ sjcl base58 requests argcomplete +pysocks \ No newline at end of file