├── .github └── workflows │ └── release.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── screenshots ├── seclip-screenshot-big.png └── seclip-screenshot.png └── src └── main.rs /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Seclip release Action 2 | 3 | on: 4 | push: 5 | 6 | jobs: 7 | build-ubuntu: 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v2 13 | 14 | - name: Install latest rust toolchain 15 | uses: actions-rs/toolchain@v1 16 | with: 17 | toolchain: stable 18 | default: true 19 | override: true 20 | 21 | - name: Install Dependencies 22 | run: sudo apt update && sudo apt install libxcb1-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev -y 23 | - name: Build 24 | run: cargo build --all --release && strip target/release/seclip && mv target/release/seclip target/release/seclip_amd64 25 | 26 | 27 | - name: Release 28 | uses: softprops/action-gh-release@v1 29 | if: startsWith(github.ref, 'refs/tags/') 30 | with: 31 | files: | 32 | target/release/seclip_amd64 33 | env: 34 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 35 | 36 | build-win: 37 | runs-on: windows-latest 38 | 39 | steps: 40 | - name: Checkout 41 | uses: actions/checkout@v2 42 | 43 | - name: Install latest rust toolchain 44 | uses: actions-rs/toolchain@v1 45 | with: 46 | toolchain: stable 47 | default: true 48 | override: true 49 | 50 | - name: Build 51 | run: cargo build --all --release 52 | 53 | - name: Release 54 | uses: softprops/action-gh-release@v1 55 | if: startsWith(github.ref, 'refs/tags/') 56 | with: 57 | files: target/release/seclip.exe 58 | env: 59 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 60 | 61 | build-mac: 62 | runs-on: macos-latest 63 | 64 | steps: 65 | - name: Checkout 66 | uses: actions/checkout@v2 67 | 68 | - name: Install latest rust toolchain 69 | uses: actions-rs/toolchain@v1 70 | with: 71 | toolchain: stable 72 | target: x86_64-apple-darwin 73 | default: true 74 | override: true 75 | 76 | - name: Build for mac 77 | run: cargo build --all --release && strip target/release/seclip && mv target/release/seclip target/release/seclip_darwin 78 | 79 | - name: Release 80 | uses: softprops/action-gh-release@v1 81 | if: startsWith(github.ref, 'refs/tags/') 82 | with: 83 | files: | 84 | target/release/seclip_darwin 85 | env: 86 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 87 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "seclip" 3 | version = "1.0.0" 4 | authors = ["Mufeed VH "] 5 | description = "A CLI utility to secretly copy secrets to clipboard." 6 | keywords = ["cli", "security", "privacy", "clipboard", "pgp"] 7 | categories = ["command-line-utilities"] 8 | homepage = "https://github.com/mufeedvh/seclip" 9 | documentation = "https://github.com/mufeedvh/seclip" 10 | repository = "https://github.com/mufeedvh/seclip" 11 | license = "MIT" 12 | readme = "README.md" 13 | exclude = [".github/*", "screenshots/*"] 14 | edition = "2018" 15 | 16 | [[bin]] 17 | name = "seclip" 18 | test = false 19 | bench = false 20 | 21 | [dependencies] 22 | clap = "2.33.3" 23 | clipboard = "0.5.0" 24 | colored = "2" 25 | 26 | [profile.release] 27 | lto = "thin" 28 | panic = 'abort' 29 | codegen-units = 1 30 | 31 | [package.metadata.deb] 32 | section = "utility" 33 | assets = [ 34 | ["target/release/seclip", "/usr/bin/", "755"], 35 | ] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Mufeed VH 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `seclip` :lock::memo: 2 | 3 | A CLI utility to secretly copy secrets to your clipboard. :crab: 4 | 5 | [![crates.io](https://img.shields.io/crates/v/seclip.svg)](https://crates.io/crates/seclip) 6 | [![LICENSE](https://img.shields.io/github/license/mufeedvh/seclip.svg)](https://github.com/mufeedvh/seclip/blob/master/LICENSE) 7 | [![tweet](https://img.shields.io/twitter/url/https/github.com/mufeedvh/seclip.svg?style=social)](https://twitter.com/intent/tweet?text=seclip%20-%20A%20CLI%20utility%20to%20secretly%20copy%20secrets%20to%20clipboard:&url=https%3A%2F%2Fgithub.com%2Fmufeedvh%2Fseclip) 8 | 9 |

10 | seclip 11 |

12 | 13 | ## Table of Contents 14 | 15 | * [Features](#features) 16 | * [Installation](#installation) 17 | * [Usage](#usage) 18 | * [Build From Source](#build-from-source) 19 | * [Contribution](#contribution) 20 | * [License](#license) 21 | * [Support The Author](#liked-the-project) 22 | 23 | ## Features 24 | 25 | - **Cross-platform**. 26 | - Copy secret values from files. (`ssh key`, `pgp key`, `github/gitlab token`, `private keys`, etc.) 27 | - Copy secret values from environment variables. 28 | - **Self-destruct:** Automatically clear clipboard after a given timeout. 29 | 30 | ## Installation 31 | 32 | On Linux you'll need the `xcb`, `xcb-render`, `xcb-shape`, and `xcb-xfixes` X11 libraries at compile time. On Ubuntu, you can install these with: 33 | 34 | ```bash 35 | $ sudo apt-get install libxcb1-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev 36 | ``` 37 | 38 | Download the latest binary for your OS from [Releases](https://github.com/mufeedvh/seclip/releases) OR install with `cargo`: 39 | 40 | $ cargo install seclip 41 | 42 | ## Usage 43 | 44 | Get utility info and the list of all the arguments: 45 | 46 | $ seclip -h 47 | 48 | Copy a value from a file 49 | 50 | $ seclip ~/.ssh/id_rsa 51 | 52 | Copy a value from environment variable 53 | 54 | $ seclip ENV_VAR 55 | 56 | Copy a value and self-destruct the value from clipboard after a given timeout (in seconds) **(-c/--clear)** 57 | 58 | $ seclip ~/.ssh/id_rsa -c 20 59 | 60 | ## How is it useful? 61 | 62 | When working in shared environments, sharing your screen, or you're at a public place, reading secret tokens could expose it to prying eyes, that's where `seclip` can help you. Just give the path to the private key or the environment variable, the secret value will be copied to your clipboard. In instances where you might forget that you copied a secret value, you can use the `-c` / `--clear` feature to automatically clear your clipboard in a given time. 63 | 64 | You can also use this as a fast shortcut to copy any file contents to clipboard! 65 | 66 | ## Build From Source 67 | 68 | ### Prerequisites 69 | 70 | On Linux you'll need the `xcb`, `xcb-render`, `xcb-shape`, and `xcb-xfixes` X11 libraries at compile time. On Ubuntu, you can install these with: 71 | 72 | ```bash 73 | $ sudo apt-get install libxcb1-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev 74 | ``` 75 | 76 | For building `seclip` from source, you need to have these tools installed 77 | 78 | * [Git](https://git-scm.org/downloads) 79 | * [Rust](https://rust-lang.org/tools/install) 80 | * Cargo (Automatically installed when installing Rust) 81 | * A C linker (Only for Linux, generally comes pre-installed) 82 | 83 | ``` 84 | $ git clone https://github.com/mufeedvh/seclip.git 85 | $ cd seclip/ 86 | $ cargo build --release 87 | ``` 88 | 89 | The first command clones the `seclip` repository in your local machine. The next two commands changes into the `seclip` directory and builds it in release mode. 90 | 91 | ## Contribution 92 | 93 | Ways to contribute 94 | - Suggest a feature 95 | - Report a bug 96 | - Fix something and open a pull request 97 | - Help me document the code 98 | - Spread the word 99 | 100 | ## License 101 | 102 | Licensed under the MIT License, see LICENSE for more information. 103 | -------------------------------------------------------------------------------- /screenshots/seclip-screenshot-big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mufeedvh/seclip/f9b2ae205796d7afac1760d87ae6d2157c5deed4/screenshots/seclip-screenshot-big.png -------------------------------------------------------------------------------- /screenshots/seclip-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mufeedvh/seclip/f9b2ae205796d7afac1760d87ae6d2157c5deed4/screenshots/seclip-screenshot.png -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::process; 3 | use std::{thread, time}; 4 | use std::fs::File; 5 | use std::io::BufReader; 6 | use std::io::prelude::*; 7 | use std::path::Path; 8 | 9 | use clap::{Arg, App}; 10 | 11 | use clipboard::ClipboardProvider; 12 | use clipboard::ClipboardContext; 13 | 14 | use colored::*; 15 | 16 | // function to set the value to clipboard 17 | fn copy_to_clipboard(value: String, clear: Option) { 18 | // initiate OS clipboard context 19 | let mut clipboard: ClipboardContext = ClipboardProvider::new().unwrap(); 20 | 21 | // set the contents of the clipboard as the value 22 | clipboard.set_contents(value.to_owned()).unwrap(); 23 | 24 | // verify the clipboard copy 25 | if clipboard.get_contents().unwrap() == value { 26 | // successfully exit after setting the value 27 | println!( 28 | "{}{}{} {}", 29 | "[".bold().white(), 30 | "✓".bold().green(), 31 | "]".bold().white(), 32 | "value has been secretly copied to clipboard.".green() 33 | ); 34 | 35 | // handle clearing the clipboard 36 | if clear != None { 37 | let seconds = clear.unwrap(); 38 | 39 | println!( 40 | "{}{}{} {}", 41 | "[".bold().white(), 42 | "i".bold().yellow(), 43 | "]".bold().white(), 44 | format!("value will be cleared from clipboard after {} seconds.", seconds).cyan() 45 | ); 46 | 47 | // wait for given `seconds` 48 | thread::sleep(time::Duration::from_secs(seconds)); 49 | 50 | // clear the clipboard after the timeout 51 | clipboard.set_contents("".to_owned()).unwrap(); 52 | 53 | // verify clearance 54 | if clipboard.get_contents().unwrap() != "" { 55 | println!( 56 | "{}{}{} {}", 57 | "[".bold().white(), 58 | "!".bold().red(), 59 | "]".bold().white(), 60 | "failed to clear clipboard.".red() 61 | ); 62 | } 63 | } 64 | 65 | process::exit(0) 66 | } else { 67 | // gracefully exit with `code 1` if the clipboard copy failed 68 | println!( 69 | "{}{}{} {}", 70 | "[".bold().white(), 71 | "!".bold().red(), 72 | "]".bold().white(), 73 | "failed to set value.".red() 74 | ); 75 | 76 | process::exit(1) 77 | } 78 | } 79 | 80 | fn main() -> std::io::Result<()> { 81 | // CLI app interface and parsed arguments 82 | let cli_matches = App::new("seclip") 83 | .version("1.0.0") 84 | .author("Mufeed VH ") 85 | .about("A CLI utility to secretly copy secrets to clipboard.") 86 | .arg(Arg::with_name("clear") 87 | .short("c") 88 | .long("clear") 89 | .value_name("SECONDS") 90 | .help("Sets a timeout (in seconds) to clear the value from clipboard and exit. (default: 20)") 91 | .takes_value(true)) 92 | .arg(Arg::with_name("KEY") 93 | .help("Sets the input key (file or environment variable).") 94 | .required(true) 95 | .index(1)) 96 | .get_matches(); 97 | 98 | // value file/variable key from the user 99 | let key: &str = cli_matches.value_of("KEY").unwrap(); 100 | 101 | // get the clear timeout seconds 102 | let clear_opt: Option; 103 | if cli_matches.is_present("clear") { 104 | // get the timeout seconds from the user 105 | let clear_value = cli_matches.value_of("clear").unwrap(); 106 | 107 | // default to 20 seconds if the input is invalid 108 | let timeout_seconds = clear_value.parse::().unwrap_or(20); 109 | clear_opt = Some(timeout_seconds) 110 | } else { 111 | // set to `None` if the clear option is not specified 112 | clear_opt = None 113 | } 114 | 115 | // search for file 116 | if Path::new(key).exists() { 117 | // read the file contents 118 | let file = File::open(key)?; 119 | let mut buf_reader = BufReader::new(file); 120 | let mut contents = String::new(); 121 | buf_reader.read_to_string(&mut contents)?; 122 | 123 | // remove leading and trailing whitespace from file contents 124 | contents = contents.trim().to_string(); 125 | 126 | // pass the contents of the file to save to clipboard 127 | copy_to_clipboard(contents, clear_opt) 128 | } 129 | 130 | // get environment variable 131 | match env::var(key) { 132 | Ok(value) => copy_to_clipboard(value, clear_opt), 133 | Err(_e) => { 134 | println!( 135 | "{}{}{} {}", 136 | "[".bold().white(), 137 | "!".bold().red(), 138 | "]".bold().white(), 139 | "value does not exist.".red() 140 | ); 141 | 142 | process::exit(1) 143 | }, 144 | } 145 | 146 | Ok(()) 147 | } 148 | --------------------------------------------------------------------------------