├── .gitignore ├── circle.yml ├── Makefile ├── test └── transfer ├── README.md └── src └── transfer /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | pre: 3 | - sudo add-apt-repository ppa:duggan/bats -y 4 | - sudo apt-get update 5 | - sudo apt-get install bats 6 | 7 | test: 8 | override: 9 | - make test 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .DEFAULT_GOAL := stub 2 | bindir ?= ./build/bin 3 | 4 | clean: | uninstall 5 | 6 | install: | stub 7 | @rsync -a src/ ${bindir}/ 8 | 9 | stub: 10 | @mkdir -p ${bindir} 11 | 12 | test: | install 13 | @bats test/transfer 14 | 15 | uninstall: 16 | @rm -rf ${bindir} 17 | 18 | .PHONY: clean install stub test uninstall 19 | -------------------------------------------------------------------------------- /test/transfer: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | @test 'upload via arguments should succeed' { 4 | run bash -c 'build/bin/transfer upload src/transfer 2> /dev/null' 5 | [ ${status} -eq 0 ] 6 | [ $(expr "${output}" : '^https://transfer.sh/[a-zA-Z0-9]*/transfer$') -gt 0 ] 7 | } 8 | 9 | @test 'upload with slug via arguments should succeed' { 10 | run bash -c 'build/bin/transfer upload src/transfer foo 2> /dev/null' 11 | [ ${status} -eq 0 ] 12 | [ $(expr "${output}" : '^https://transfer.sh/[a-zA-Z0-9]*/foo$') -gt 0 ] 13 | } 14 | 15 | @test 'upload via options should succeed' { 16 | run bash -c 'build/bin/transfer upload --file src/transfer 2> /dev/null' 17 | [ ${status} -eq 0 ] 18 | [ $(expr "${output}" : '^https://transfer.sh/[a-zA-Z0-9]*/transfer$') -gt 0 ] 19 | } 20 | 21 | @test 'upload with slug via options should succeed' { 22 | run bash -c 'build/bin/transfer upload --file src/transfer --slug foo 2> /dev/null' 23 | [ ${status} -eq 0 ] 24 | [ $(expr "${output}" : '^https://transfer.sh/[a-zA-Z0-9]*/foo$') -gt 0 ] 25 | } 26 | 27 | @test 'upload from pipe should succeed' { 28 | run bash -c 'cat src/transfer | build/bin/transfer upload --slug transfer 2> /dev/null' 29 | [ ${status} -eq 0 ] 30 | [ $(expr "${output}" : '^https://transfer.sh/[a-zA-Z0-9]*/transfer$') -gt 0 ] 31 | } 32 | 33 | @test 'upload of directory should succeed' { 34 | run bash -c 'build/bin/transfer upload src transfer.tar.gz 2> /dev/null' 35 | [ ${status} -eq 0 ] 36 | [ $(expr "${output}" : '^https://transfer.sh/[a-zA-Z0-9]*/transfer.tar.gz$') -gt 0 ] 37 | } 38 | 39 | @test 'download to file should succeed' { 40 | local up=$(build/bin/transfer upload src/transfer 2> /dev/null) 41 | run bash -c "build/bin/transfer download "${up}" build/.download 2> /dev/null" 42 | [ ${status} -eq 0 ] 43 | } 44 | 45 | @test 'download to pipe should succeed' { 46 | local up=$(build/bin/transfer upload src/transfer 2> /dev/null) 47 | run bash -c "build/bin/transfer download "${up}" 2> /dev/null" 48 | [ ${status} -eq 0 ] 49 | } 50 | 51 | @test '-h should output usage' { 52 | run build/bin/transfer -h 53 | [ ${status} -eq 0 ] 54 | [ "${#lines[@]}" -gt 1 ] 55 | } 56 | 57 | @test '--help should output usage' { 58 | run build/bin/transfer --help 59 | [ ${status} -eq 0 ] 60 | [ "${#lines[@]}" -gt 1 ] 61 | } 62 | 63 | @test '-v should output version' { 64 | run build/bin/transfer -v 65 | [ ${status} -eq 0 ] 66 | [ $(expr "${output}" : 'v*') -ne 0 ] 67 | } 68 | 69 | @test '--version should output version' { 70 | run build/bin/transfer --version 71 | [ ${status} -eq 0 ] 72 | [ $(expr "${output}" : 'v*') -ne 0 ] 73 | } 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # transfer-cli | Powerful transfer.sh CLI via pure bash 2 | [![version](http://img.shields.io/badge/version-v0.2.0-blue.svg)](https://github.com/rockymadden/transfer-cli/releases) 3 | [![versioning](http://img.shields.io/badge/versioning-semver-blue.svg)](http://semver.org/) 4 | [![branching](http://img.shields.io/badge/branching-github%20flow-blue.svg)](https://guides.github.com/introduction/flow/) 5 | [![license](http://img.shields.io/badge/license-mit-blue.svg)](https://opensource.org/licenses/MIT) 6 | [![pm](http://img.shields.io/badge/pm-zenhub-blue.svg)](https://www.zenhub.io/) 7 | [![chat](http://img.shields.io/badge/chat-slack-blue.svg)](https://rockymadden-slack.herokuapp.com/) 8 | [![circleci](https://circleci.com/gh/rockymadden/transfer-cli.svg?style=shield)](https://circleci.com/gh/rockymadden/transfer-cli) 9 | 10 | A pure bash, pipe friendly, encryption capable, feature rich, command line interface for 11 | [transfer.sh](https://transfer.sh). 12 | 13 | __Upload samples:__ 14 | 15 | ```bash 16 | $ # From file: 17 | $ transfer upload /path/to/file.log 18 | $ transfer upload --file=/path/to/file.log 19 | $ transfer upload --file /path/to/file.log 20 | $ transfer upload -f /path/to/file.log 21 | 22 | $ # From directory: 23 | $ transfer upload /path 24 | $ transfer upload --file=/path 25 | $ transfer upload --file /path 26 | $ transfer upload -f /path 27 | 28 | $ # From pipe: 29 | $ ls | transfer upload --slug=ls.log 30 | $ ls | transfer upload --slug ls.log 31 | $ ls | transfer upload -s ls.log 32 | 33 | $ # With encryption (symmetric): 34 | $ transfer upload /path/to/file.log --encrypt 35 | $ transfer upload /path/to/file.log -e 36 | $ transfer upload /path/to/file.log --encrypt --password password 37 | 38 | $ # With custom slug: 39 | $ transfer upload /path/to/file.log custom.log 40 | $ transfer upload --file=/path/to/file.log --slug=custom.log 41 | $ transfer upload --file /path/to/file.log --slug custom.log 42 | $ transfer upload -f /path/to/file.log -s custom.log 43 | ``` 44 | 45 | __Download samples:__ 46 | 47 | ```bash 48 | $ # To file: 49 | $ transfer download https://transfer.sh/abcXYZ/file.log /tmp/file.log 50 | $ transfer download --url=https://transfer.sh/abcXYZ/file.log --file=/tmp/file.log 51 | $ transfer download --url https://transfer.sh/abcXYZ/file.log --file /tmp/file.log 52 | $ transfer download -u https://transfer.sh/abcXYZ/file.log -f /tmp/file.log 53 | 54 | $ # To pipe: 55 | $ transfer download https://transfer.sh/abcXYZ/file.tar.gz | tar xz 56 | $ transfer download --url=https://transfer.sh/abcXYZ/file.tar.gz | tar xz 57 | $ transfer download --url https://transfer.sh/abcXYZ/file.tar.gz | tar xz 58 | $ transfer download -u https://transfer.sh/abcXYZ/file.tar.gz | tar xz 59 | 60 | $ # With decryption (symmetric): 61 | $ transfer download https://transfer.sh/abcXYZ/file.log --decrypt 62 | $ transfer download https://transfer.sh/abcXYZ/file.log -d 63 | $ transfer download https://transfer.sh/abcXYZ/file.log --decrypt --password password 64 | ``` 65 | 66 | ## Installation 67 | 68 | ### Via `brew`: 69 | 70 | ```bash 71 | $ brew tap rockymadden/rockymadden 72 | $ brew install transfer-cli 73 | ``` 74 | 75 | ### Via `curl`: 76 | 77 | ```bash 78 | $ curl -O https://raw.githubusercontent.com/rockymadden/transfer-cli/master/src/transfer 79 | $ chmod +x transfer 80 | ``` 81 | 82 | ### Via `make`: 83 | 84 | ```bash 85 | $ git clone git@github.com:rockymadden/transfer-cli.git 86 | $ cd transfer-cli 87 | $ make install bindir=/path/to/bin 88 | ``` 89 | 90 | ## Usage 91 | ```bash 92 | $ transfer --help 93 | Usage: 94 | transfer download [ [file]] 95 | [--decrypt|-d] [--file|-f ] [--password|-p ] [--trace|-x] 96 | [--url|-u ] 97 | 98 | transfer upload [ [slug]] 99 | [--encrypt|-e] [--file|-f ] [--password|-p ] [--slug|-s ] 100 | [--trace|-x] 101 | 102 | Commands: 103 | download Download from transfer.sh to file or piped output 104 | upload Upload a file, directory, or piped input to transfer.sh 105 | 106 | More Information: 107 | chat https://rockymadden-slack.herokuapp.com 108 | repo https://github.com/rockymadden/transfer-cli 109 | ``` 110 | 111 | ## License 112 | ``` 113 | The MIT License (MIT) 114 | 115 | Copyright (c) 2016 Rocky Madden (https://rockymadden.com/) 116 | 117 | Permission is hereby granted, free of charge, to any person obtaining a copy 118 | of this software and associated documentation files (the "Software"), to deal 119 | in the Software without restriction, including without limitation the rights 120 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 121 | copies of the Software, and to permit persons to whom the Software is 122 | furnished to do so, subject to the following conditions: 123 | 124 | The above copyright notice and this permission notice shall be included in 125 | all copies or substantial portions of the Software. 126 | 127 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 128 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 129 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 130 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 131 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 132 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 133 | THE SOFTWARE. 134 | ``` 135 | -------------------------------------------------------------------------------- /src/transfer: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # COMMAND PARSING ################################################################################# 4 | cmd="${1}" ; shift 5 | 6 | # STDIN FRIENDLINESS ############################################################################## 7 | case "${cmd}" in 8 | upload) [ -p /dev/stdin ] && stdin=$(cat <&0) ;; 9 | esac 10 | 11 | # ARGUMENT AND OPTION PARSING ##################################################################### 12 | while (( "$#" )); do 13 | case "${1}" in 14 | --decrypt|-d) decrypt=0 ; shift ;; 15 | --encrypt|-e) encrypt=0 ; shift ;; 16 | --file=*) file=${1/--file=/''} ; shift ;; 17 | --file*|-f*) file=${2} ; shift ; shift ;; 18 | --password=*) password=${1/--password=/''} ; shift ;; 19 | --password*|-p*) password=${2} ; shift ; shift ;; 20 | --slug=*) slug=${1/--slug=/''} ; shift ;; 21 | --slug*|-s*) slug=${2} ; shift ; shift ;; 22 | --trace|-x) trace='set -x' ; shift ;; 23 | --url=*) url=${1/--url=/''} ; shift ;; 24 | --url*|-u*) url=${2} ; shift ; shift ;; 25 | *) 26 | case "${cmd}" in 27 | download) 28 | [ -n "${1}" ] && [ -n "${url}" ] && [ -z "${file}" ] && file=${1} 29 | [ -n "${1}" ] && [ -z "${url}" ] && url=${1} 30 | ;; 31 | upload) 32 | [ -n "${1}" ] && [ -n "${file}" ] && [ -z "${slug}" ] && slug=${1} 33 | [ -n "${1}" ] && [ -z "${file}" ] && file=${1} 34 | ;; 35 | esac 36 | shift 37 | ;; 38 | esac 39 | done 40 | 41 | # TRACING ######################################################################################### 42 | ${trace} 43 | 44 | # ARGUMENT AND OPTION PROMPTING ################################################################### 45 | case "${cmd}" in 46 | download) 47 | [ -z "${url}" ] && read -e -p 'Enter url (e.g. https://transfer.sh/abcXYZ/file.log): ' url 48 | ;; 49 | upload) 50 | [ -z "${file}" ] && read -e -p 'Enter file (e.g. /path/to/file.log): ' file 51 | ;; 52 | esac 53 | 54 | # COMMAND FUNCTIONS ############################################################################### 55 | function download() { 56 | if [ -n "${file}" ]; then 57 | local path=$(greadlink -f "${file}" 2> /dev/null || readlink -f "${file}" 2> /dev/null) 58 | 59 | curl --progress-bar "${url}" | 60 | ([ -z "${decrypt}" ] && cat || openssl aes-256-cbc -d -a ${password:+-k "${password}"}) > "${path}" 61 | 62 | echo "${path}" 63 | if type pbcopy &> /dev/null; then echo -n ${path} | pbcopy; fi 64 | else 65 | curl --silent "${url}" 2> /dev/null | 66 | ([ -z "${decrypt}" ] && cat || openssl aes-256-cbc -d -a ${password:+-k "${password}"}) 67 | fi 68 | } 69 | 70 | function help() { 71 | local a=(${0//\// }) 72 | local bin=${a[${#a[@]}-1]} 73 | 74 | echo 'Usage:' 75 | echo " ${bin} download [ [file]]" 76 | echo ' [--decrypt|-d] [--file|-f ] [--password|-p ] [--trace|-x]' 77 | echo ' [--url|-u ]' 78 | echo 79 | echo " ${bin} upload [ [slug]]" 80 | echo ' [--encrypt|-e] [--file|-f ] [--password|-p ] [--slug|-s ]' 81 | echo ' [--trace|-x]' 82 | echo 83 | echo 'Commands:' 84 | echo ' download Download from transfer.sh to file or piped output' 85 | echo ' upload Upload a file, directory, or piped input to transfer.sh' 86 | echo 87 | echo 'More Information:' 88 | echo ' chat https://rockymadden-slack.herokuapp.com' 89 | echo ' repo https://github.com/rockymadden/transfer-cli' 90 | } 91 | 92 | function upload() { 93 | ! [ -d ${file} ] && ! [ -f "${file}" ] && { echo 'File should exist' ; return 1; } 94 | [ -z "${file}" ] && [ -z "${stdin}" ] && { echo 'File should be provided' ; return 1; } 95 | [ -z "${file}" ] && [ -n "${stdin}" ] && [ -z "${slug}" ] && { echo 'Slug should be provided' ; return 1; } 96 | 97 | local tmpurl=$(mktemp -t transfer.url.XXXXXXXX) 98 | trap "rm -f ${tmpurl}" 0 99 | 100 | if [ -n "${file}" ]; then 101 | if [ -d ${file} ]; then 102 | [ -z "${slug}" ] && slug="$(basename ${file} | sed -e 's/[^a-zA-Z0-9._-]/-/g').tar.gz" 103 | 104 | local tmptar=$(mktemp -t transfer.tar.gz.XXXXXXXX) 105 | trap "rm -f ${tmpurl} ; rm -f ${tmptar}" 0 106 | 107 | (cd $(dirname ${file}); tar -zcf ${tmptar} $(basename ${file})) 108 | 109 | cat "${tmptar}" | 110 | ([ -z "${encrypt}" ] && cat || openssl aes-256-cbc -a -salt ${password:+-k "${password}"}) | 111 | curl --progress-bar --upload-file - "https://transfer.sh/${slug}" > ${tmpurl} 112 | elif [ -f "${file}" ]; then 113 | [ -z "${slug}" ] && slug="$(basename ${file} | sed -e 's/[^a-zA-Z0-9._-]/-/g')" 114 | 115 | cat "${file}" | 116 | ([ -z "${encrypt}" ] && cat || openssl aes-256-cbc -a -salt ${password:+-k "${password}"}) | 117 | curl --progress-bar --upload-file - "https://transfer.sh/${slug}" > ${tmpurl} 118 | fi 119 | elif [ -n "${stdin}" ]; then 120 | echo "${stdin}" | 121 | ([ -z "${encrypt}" ] && cat || openssl aes-256-cbc -a -salt ${password:+-k "${password}"}) | 122 | curl --progress-bar --upload-file - "https://transfer.sh/${slug}" > ${tmpurl} 123 | fi 124 | 125 | cat ${tmpurl} 126 | if type pbcopy &> /dev/null; then cat ${tmpurl} | tr -d '\n' | pbcopy; fi 127 | } 128 | 129 | function version() { 130 | echo 'v0.2.0' 131 | } 132 | 133 | # COMMAND ROUTING ################################################################################# 134 | case "${cmd}" in 135 | --help|-h) help ; exit 0 ;; 136 | --version|-v) version ; exit 0 ;; 137 | download|upload) ${cmd} ; exit ${?} ;; 138 | *) help ; exit 1 ;; 139 | esac 140 | --------------------------------------------------------------------------------