mirror of
https://github.com/rwinkhart/sshyp.git
synced 2026-09-03 15:47:18 -04:00
Compare commits
253
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39316d04a2 | ||
|
|
3e9a4c0403 | ||
|
|
3bc07b48ef | ||
|
|
5234e8c048 | ||
|
|
b7c3535955 | ||
|
|
1f52c45c43 | ||
|
|
7723baa69e | ||
|
|
b680cc96d6 | ||
|
|
f750fe1e4d | ||
|
|
b96db3ad92 | ||
|
|
224fc1fc6d | ||
|
|
0bd2e45dba | ||
|
|
6410843911 | ||
|
|
3dda6d8428 | ||
|
|
4f31af5eff | ||
|
|
bfb830c5e5 | ||
|
|
790121e7ea | ||
|
|
4168b800f8 | ||
|
|
801d515697 | ||
|
|
379970d53b | ||
|
|
4abb3ed718 | ||
|
|
6690fd15c9 | ||
|
|
1582e73a98 | ||
|
|
dfe1703e62 | ||
|
|
7a76130b26 | ||
|
|
98dcbf57c6 | ||
|
|
a5946d558a | ||
|
|
30fb5ed041 | ||
|
|
fb1f5b92c3 | ||
|
|
61b2186b0a | ||
|
|
2113b93481 | ||
|
|
2030d90114 | ||
|
|
75071601e6 | ||
|
|
9a0a261d55 | ||
|
|
4ca2d89464 | ||
|
|
f90ec5c900 | ||
|
|
fa0a4fe0b8 | ||
|
|
c85a9d2ccd | ||
|
|
43351fd66f | ||
|
|
096bdb0773 | ||
|
|
330396c5f1 | ||
|
|
8576f63479 | ||
|
|
393f241538 | ||
|
|
c557d5bfee | ||
|
|
acca7d888c | ||
|
|
2f3b3c67ba | ||
|
|
88d2402e88 | ||
|
|
928aacc64a | ||
|
|
094bdcb418 | ||
|
|
419ff51e75 | ||
|
|
2111a0454e | ||
|
|
5d902f0324 | ||
|
|
505ffdb489 | ||
|
|
5cab1ad091 | ||
|
|
2e2404636b | ||
|
|
6cb5bd405f | ||
|
|
c93965c9a5 | ||
|
|
d685e07d32 | ||
|
|
192f58fef5 | ||
|
|
106f22f757 | ||
|
|
ae414dadda | ||
|
|
c9e99732a2 | ||
|
|
fc37368447 | ||
|
|
ca2bc98735 | ||
|
|
f44391612d | ||
|
|
8c0e9eb6df | ||
|
|
c03e818560 | ||
|
|
0b653000ef | ||
|
|
9f89dce42b | ||
|
|
e7b2e19039 | ||
|
|
80b6b4abd2 | ||
|
|
758e9f331c | ||
|
|
ba14c0e74b | ||
|
|
1991672618 | ||
|
|
9b600dabbf | ||
|
|
e42641079d | ||
|
|
7c6cbaec35 | ||
|
|
cb441933db | ||
|
|
dad1a34575 | ||
|
|
3a30812de5 | ||
|
|
e1930f9457 | ||
|
|
05df3dd903 | ||
|
|
5c1195f42d | ||
|
|
30aa3e2438 | ||
|
|
a8ea1eb444 | ||
|
|
8e053f25b8 | ||
|
|
a175a270e0 | ||
|
|
d116582144 | ||
|
|
f760b5420c | ||
|
|
6498a076f2 | ||
|
|
f4a0c52ca8 | ||
|
|
ffafbd2b91 | ||
|
|
d7bf7da177 | ||
|
|
13d466bb21 | ||
|
|
7aa9ea63e2 | ||
|
|
208bd8707b | ||
|
|
fb398333a6 | ||
|
|
b369f9a530 | ||
|
|
747f83819d | ||
|
|
2f1e693991 | ||
|
|
dd811cbe35 | ||
|
|
87dee4f197 | ||
|
|
bf86d72472 | ||
|
|
a3722e3c29 | ||
|
|
1f4d5b0591 | ||
|
|
e21faa8bbb | ||
|
|
309a471e77 | ||
|
|
968a7322f8 | ||
|
|
75e152ebfe | ||
|
|
15204fb0e9 | ||
|
|
5977367f28 | ||
|
|
96eb80226f | ||
|
|
9ede33d3d8 | ||
|
|
4093c36d48 | ||
|
|
947754f87c | ||
|
|
84bfefb7b1 | ||
|
|
7ac5cd723e | ||
|
|
68aa5eee04 | ||
|
|
f869e3b45d | ||
|
|
551f1e8f50 | ||
|
|
1687d9e1e2 | ||
|
|
930595ecad | ||
|
|
2d00da0e18 | ||
|
|
c84d52fb8d | ||
|
|
88fd9e77a9 | ||
|
|
4258ad85ab | ||
|
|
337e68d088 | ||
|
|
fb8c5be284 | ||
|
|
0293d273a7 | ||
|
|
40a43ed86d | ||
|
|
18c78743ca | ||
|
|
2f5080fec0 | ||
|
|
99e0d5f666 | ||
|
|
be19e271c5 | ||
|
|
20d2de338f | ||
|
|
e830d8486b | ||
|
|
5fc74ac2b3 | ||
|
|
24acd1cb87 | ||
|
|
0079934354 | ||
|
|
399e291902 | ||
|
|
66a026e327 | ||
|
|
b5f4e776e5 | ||
|
|
0056f60af1 | ||
|
|
41aa093685 | ||
|
|
30034be36f | ||
|
|
a43530d34f | ||
|
|
7d14c49490 | ||
|
|
462ba05833 | ||
|
|
e89bf06d9a | ||
|
|
d33d07894f | ||
|
|
cade83a0f0 | ||
|
|
100edd07ea | ||
|
|
d19651819a | ||
|
|
d951284bcd | ||
|
|
3c9b80ec80 | ||
|
|
0f3d9854b7 | ||
|
|
0c52149c40 | ||
|
|
f838af0b4e | ||
|
|
72f126d21d | ||
|
|
2385f669f8 | ||
|
|
b8896a6b58 | ||
|
|
51ec2143e3 | ||
|
|
4c1989287a | ||
|
|
daba737ca6 | ||
|
|
8cac27c6f6 | ||
|
|
19d37dfdb6 | ||
|
|
87a56a80bd | ||
|
|
5aaa284cbf | ||
|
|
a6aa0561b4 | ||
|
|
b08456e873 | ||
|
|
ef828b88a0 | ||
|
|
bde243c644 | ||
|
|
894f406fd2 | ||
|
|
00b935f1bb | ||
|
|
49608cb839 | ||
|
|
a417478aa0 | ||
|
|
344c74b728 | ||
|
|
fc0e4bb4a5 | ||
|
|
37867cb673 | ||
|
|
86aa7da038 | ||
|
|
9231257af8 | ||
|
|
102f22143f | ||
|
|
3dd12b4d6d | ||
|
|
a0b5dad073 | ||
|
|
2ba19f9a39 | ||
|
|
8af71ceb1a | ||
|
|
81c9b35c75 | ||
|
|
eeabc18f18 | ||
|
|
73128665fb | ||
|
|
607a4709f6 | ||
|
|
c643e861d9 | ||
|
|
23e7e375ae | ||
|
|
b8743d5fe2 | ||
|
|
e95aa85453 | ||
|
|
caf130568e | ||
|
|
f65adc17f3 | ||
|
|
fc2f42a1aa | ||
|
|
8403f4af98 | ||
|
|
4b24df0e97 | ||
|
|
ca007f55ac | ||
|
|
7afcfdb43d | ||
|
|
5178377827 | ||
|
|
ff9241368e | ||
|
|
6014de98dd | ||
|
|
6e7e42a69e | ||
|
|
0314bf36af | ||
|
|
93ac4ef824 | ||
|
|
65d10551f6 | ||
|
|
f6ddf2ad37 | ||
|
|
7f00570249 | ||
|
|
3d7f08e43e | ||
|
|
d82c9b5e02 | ||
|
|
9133a73553 | ||
|
|
ad039d6322 | ||
|
|
caa5fad0bc | ||
|
|
68ded52e8c | ||
|
|
85c59b302d | ||
|
|
954dd30361 | ||
|
|
65d1885311 | ||
|
|
5a7b45c3ac | ||
|
|
e5638255a8 | ||
|
|
2e32911470 | ||
|
|
4973d18034 | ||
|
|
6e13a6ebb3 | ||
|
|
dfbdc16079 | ||
|
|
3c4bf0115f | ||
|
|
762211bae0 | ||
|
|
d9adcac8ec | ||
|
|
1d9000ab16 | ||
|
|
bdea49268d | ||
|
|
187ea39861 | ||
|
|
ee8e7fc8a5 | ||
|
|
8a4ae469fa | ||
|
|
4330617060 | ||
|
|
54397dcd13 | ||
|
|
0e7595489b | ||
|
|
cd378aadc2 | ||
|
|
d26c2a5e08 | ||
|
|
b24bcdd413 | ||
|
|
b0fa1f99c9 | ||
|
|
2825b43659 | ||
|
|
49721cd39a | ||
|
|
715d58fb62 | ||
|
|
73307e2b3c | ||
|
|
ab739e3920 | ||
|
|
0253872c8d | ||
|
|
2d2b0aa0ec | ||
|
|
532784d817 | ||
|
|
6d1bf9f96c | ||
|
|
67a7c2e382 | ||
|
|
9f229e7ae7 | ||
|
|
e3b0d2dbe7 | ||
|
|
ce4e32c8f4 |
@@ -0,0 +1,72 @@
|
|||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
#
|
||||||
|
# ******** NOTE ********
|
||||||
|
# We have attempted to detect the languages in your repository. Please check
|
||||||
|
# the `language` matrix defined below to confirm you have the correct set of
|
||||||
|
# supported CodeQL languages.
|
||||||
|
#
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ "main" ]
|
||||||
|
schedule:
|
||||||
|
- cron: '34 22 * * 5'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [ 'python' ]
|
||||||
|
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||||
|
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v2
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
|
||||||
|
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||||
|
# queries: security-extended,security-and-quality
|
||||||
|
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
|
|
||||||
|
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||||
|
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||||
|
|
||||||
|
# - run: |
|
||||||
|
# echo "Run, Build Application using script"
|
||||||
|
# ./location_of_script_within_repo/buildscript.sh
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v2
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# Maintainer: Randall Winkhart <idgr at tutanota dot com>
|
|
||||||
|
|
||||||
pkgname=sshyp
|
|
||||||
pkgver=2022.01.10.fr2.3
|
|
||||||
pkgrel=1
|
|
||||||
pkgdesc='A light-weight, self-hosted, synchronized password manager'
|
|
||||||
url='https://github.com/rwinkhart/sshyp'
|
|
||||||
arch=('any')
|
|
||||||
license=('GPL3')
|
|
||||||
depends=( python gnupg openssh nano xclip wl-clipboard)
|
|
||||||
|
|
||||||
source=("https://github.com/rwinkhart/sshyp/releases/download/v$pkgver/sshyp-$pkgver.tar.xz")
|
|
||||||
sha512sums=('be6695cc231f4414322f2c4b919caf0759f4111e50259b3a6bbcb6e90a0ceba5d094c8766c287e5443c61adfdf414c1a93bc70e505dfd4bf34097c713b6e7d2f')
|
|
||||||
|
|
||||||
package() {
|
|
||||||
|
|
||||||
tar xf sshyp-"$pkgver".tar.xz -C "${pkgdir}"
|
|
||||||
chown -R "$USER" ${pkgdir}/var/lib/sshyp
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,16 @@
|
|||||||
# sshyp
|

|
||||||
A very simple self-hosted, synchronized password manager. Alternative to GNU pass.
|
|
||||||
|
|
||||||
"sshyp" stands for "sshync passwords", or "ssh sync passwords".
|
[](https://github.com/rwinkhart/sshyp/actions/workflows/codeql-analysis.yml)
|
||||||
"sshync" is the custom syncing backend (based on sftp) used by "sshyp".
|
|
||||||
|
sshyp is a very simple self-hosted, synchronized password manager for UNIX(-like) systems (currently Haiku/FreeBSD/Linux).
|
||||||
|
|
||||||
|
sshyp is compatible with entries created by pass/password-store, as its original goal was to be like pass/password-store, but far more user-friendly to synchronize with a self-hosted server.
|
||||||
|
|
||||||
|
sshyp is (as of writing) the only password-store compatible CLI password manager available for Haiku.
|
||||||
|
|
||||||
|
sshyp makes use of a custom sftp wrapper, called sshync (ssh+sync), to reliably sync user entries with a local or remote server.
|
||||||
|
|
||||||
|
The name "sshyp" is a combination of its syncing library, "sshync", and "passwords".
|
||||||
|
|
||||||
# WARNING
|
# WARNING
|
||||||
It is your responsibility to assess the security and stability of "sshyp" before using it and ensure it meets your needs.
|
It is your responsibility to assess the security and stability of "sshyp" before using it and ensure it meets your needs.
|
||||||
@@ -16,43 +24,57 @@ What sshyp can do:
|
|||||||
|
|
||||||
- securely manage a collection of encrypted passwords and notes via CLI
|
- securely manage a collection of encrypted passwords and notes via CLI
|
||||||
- generate new, secure passwords to the user's choice in length and complexity
|
- generate new, secure passwords to the user's choice in length and complexity
|
||||||
- securely sync said passwords and notes seamlessly between multiple POSIX compliant Unix devices
|
- securely sync said passwords and notes seamlessly between devices
|
||||||
|
- utilize [extensions](https://github.com/rwinkhart/sshyp-labs) to interact with your entries is additional ways (such as generating TOTP keys)
|
||||||
|
- everything above with entries created by pass/password-store!
|
||||||
|
- everything above on Haiku, FreeBSD, Linux, and Termux (an Android terminal emulator)!
|
||||||
|
|
||||||
What sshyp will do:
|
What sshyp will likely do:
|
||||||
|
|
||||||
- everything it already does, but also in a GUI for Linux/Android
|
- (planned v1.2.0) everything it already does, but also in a GUI for Linux/Haiku
|
||||||
- have a distinct retro theme
|
|
||||||
- receive many usability enhancements
|
|
||||||
|
|
||||||
What sshyp definitely won't do:
|
What sshyp definitely won't do:
|
||||||
|
|
||||||
- 2FA/MFA (for security purposes, this should not be handled by your password manager)
|
- Non-UNIX(-like) support, e.g. Windows (I'd be happy to link to third-party ports, if someone were to make them)
|
||||||
- Windows support (I don't use Windows and I have no interest in developing for it)
|
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
Arch Linux (all ISAs)
|
Please see the [installation guide](https://github.com/rwinkhart/sshyp/wiki/Installation) in the sshyp wiki for directions specific to your distribution/OS.
|
||||||
|
|
||||||
sshyp releases are available in the Arch User Repository as 'sshyp'.
|
Pre-built packages exist for Haiku, FreeBSD, Arch Linux, Debian/Ubuntu Linux, Fedora Linux, and Termux. These can be downloaded from the releases page.
|
||||||
|
|
||||||
Install with your preferred AUR helper or use:
|
Requests for additional distribution/OS support can be filed as issues.
|
||||||
|
|
||||||
|
Extensions are available in the [sshyp-labs](https://github.com/rwinkhart/sshyp-labs) repository.
|
||||||
|
|
||||||
|
# Building
|
||||||
|
Since sshyp is written entirely in Python, it doesn't need to be compiled. It does, however, need to be packaged for installation.
|
||||||
|
|
||||||
|
A packaging script is included in the root directory of the repo in order to package sshyp for your distribution. To package sshyp from source, simply run:
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://aur.archlinux.org/sshyp.git
|
git clone https://github.com/rwinkhart/sshyp.git
|
||||||
cd sshyp
|
cd sshyp
|
||||||
makepkg -si
|
./package.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Packaging for other distributions coming soon.
|
The packaging script has been tested on Arch Linux with "dpkg" as a dependency for Debian/Ubuntu and Termux packaging and "freebsd-pkg" as a dependency for FreeBSD packaging.
|
||||||
|
|
||||||
|
Haiku and Fedora packaging must be done on their own respective distributions.
|
||||||
|
|
||||||
|
The AUR version and the packages attatched to the release tags were already packaged using this script.
|
||||||
|
|
||||||
|
Currently, the script can create packages for Haiku, FreeBSD, Arch Linux (PKGBUILD), Debian/Ubuntu Linux, Fedora Linux, Termux, and generic.
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
Upon initial installation, be sure to run:
|
Upon initial installation (on both the server and client devices), be sure to run:
|
||||||
|
|
||||||
```
|
```
|
||||||
sshyp tweak
|
sshyp tweak
|
||||||
```
|
```
|
||||||
|
|
||||||
This command will allow you to configure the settings necessary for sshyp to function.
|
This command will allow you to configure the settings necessary for sshyp to function. To ensure configuration compatibility, it is a good idea to run 'sshyp tweak' after each major update.
|
||||||
As of right now, sshyp is rapidly changing, and as such, it is a good idea to run "sshyp tweak" after each update.
|
|
||||||
|
Please note that decrypting and reading entries is disabled on server devices for security reasons. Only devices configured as clients can use the gpg key to decrypt entries.
|
||||||
|
|
||||||
All available options can be found with:
|
All available options can be found with:
|
||||||
|
|
||||||
@@ -60,7 +82,7 @@ All available options can be found with:
|
|||||||
sshyp --help
|
sshyp --help
|
||||||
```
|
```
|
||||||
|
|
||||||
Or alternatively, in the new manpage:
|
Or alternatively, in the manpage:
|
||||||
|
|
||||||
```
|
```
|
||||||
man sshyp
|
man sshyp
|
||||||
@@ -69,22 +91,10 @@ man sshyp
|
|||||||
# Roadmap
|
# Roadmap
|
||||||
Short-term Goals:
|
Short-term Goals:
|
||||||
|
|
||||||
- create new file list w/color and w/o file extensions
|
- create minimal GUI app (Linux x86_64, Linux aarch64)
|
||||||
- overhaul argument system
|
- various optimizations/bug fixes
|
||||||
- fix lots of bugs!
|
|
||||||
- make lots of optimizations!
|
|
||||||
|
|
||||||
Medium-term Goals:
|
|
||||||
|
|
||||||
- create minimal GUI apps (Linux x86_64, Linux aarch64)
|
|
||||||
- auto-completion on tab for CLI version
|
|
||||||
|
|
||||||
Long-term Goals:
|
Long-term Goals:
|
||||||
|
|
||||||
|
- a fun surprise
|
||||||
- seize the thrones, shear the humans
|
- seize the thrones, shear the humans
|
||||||
|
|
||||||
# Known Issues
|
|
||||||
|
|
||||||
Currently, files deleted from a client or server may re-appear if another client that had the same file reconnects and later re-uploads it to the server. This will be addressed.
|
|
||||||
|
|
||||||
Currently, if a client is missing folders that exist on the server, the contents of the missing folders will fail to download. A temporary workaround is to manually create the folders on the client. This will be addressed.
|
|
||||||
|
|||||||
+37
-42
@@ -1,48 +1,44 @@
|
|||||||
#!/usr/bin/python3
|
#!/bin/python3
|
||||||
|
|
||||||
# sshync 2022.01.10.unreleased8
|
|
||||||
|
|
||||||
# external modules
|
# external modules
|
||||||
|
|
||||||
from os import system, remove, walk
|
from os import path, system, walk
|
||||||
from os.path import getmtime, join
|
from os.path import expanduser, getmtime, join
|
||||||
|
from pathlib import Path
|
||||||
from sys import exit as s_exit
|
from sys import exit as s_exit
|
||||||
|
|
||||||
|
|
||||||
# utility functions
|
# utility functions
|
||||||
|
|
||||||
def get_titles_mods(_directory, _destination, _user_data):
|
def get_titles_mods(_directory, _destination, _user_data): # fetches and returns lists of titles and their mod times
|
||||||
_title_list, _mod_list = [], []
|
_title_list, _mod_list = [], []
|
||||||
|
Path(path.expanduser('~/.config/sshync')).mkdir(0o700, parents=True, exist_ok=True) # create config directory
|
||||||
# local fetching
|
# local fetching
|
||||||
if _destination == 'l':
|
if _destination == 'l':
|
||||||
if type(_user_data) == str:
|
open(expanduser('~/.config/sshync/database'), 'w').write('') # blanks out database file
|
||||||
_user_data = str(_user_data).strip('(').strip(')').replace(' ', '').split(',')
|
|
||||||
try:
|
|
||||||
remove(_user_data[6] + 'sshync_database')
|
|
||||||
except FileNotFoundError:
|
|
||||||
pass
|
|
||||||
for _root, _directories, _files in walk(_directory):
|
for _root, _directories, _files in walk(_directory):
|
||||||
for _filename in _files:
|
for _filename in _files:
|
||||||
_title_list.append(join(_root.replace(_directory, '', 1), _filename))
|
_title_list.append(join(_root.replace(_directory, '', 1), _filename))
|
||||||
_mod_list.append(int(getmtime(join(_root, _filename))))
|
_mod_list.append(int(getmtime(join(_root, _filename))))
|
||||||
i = -1
|
|
||||||
for _title in _title_list:
|
for _title in _title_list:
|
||||||
open(_user_data[6] + 'sshync_database', 'a').write(str(_title) + '\n')
|
open(expanduser('~/.config/sshync/database'), 'a').write(str(_title) + '\n')
|
||||||
open(_user_data[6] + 'sshync_database', 'a').write('^&*\n')
|
open(expanduser('~/.config/sshync/database'), 'a').write('^&*\n')
|
||||||
for _mod in _mod_list:
|
for _mod in _mod_list:
|
||||||
open(_user_data[6] + 'sshync_database', 'a').write(str(_mod) + '\n')
|
open(expanduser('~/.config/sshync/database'), 'a').write(str(_mod) + '\n')
|
||||||
# remote fetching
|
# remote fetching
|
||||||
if _destination == 'r':
|
if _destination == 'r':
|
||||||
system(f"ssh -i '{_user_data[5]}' -p {_user_data[2]} {_user_data[0]}@{_user_data[1]} \"python -c 'import sshync"
|
system(f"ssh -i '{_user_data[5]}' -p {_user_data[2]} {_user_data[0]}@{_user_data[1]} \"cd /bin; python -c 'impo"
|
||||||
f"; sshync.get_titles_mods(\"'\"{_user_data[4]}\"'\", \"'\"l\"'\", \"'\"{_user_data}\"'\")'\"")
|
f"rt sshync; sshync.get_titles_mods(\"'\"{_user_data[4]}\"'\", \"'\"l\"'\", \"'\"{_user_data}\"'\")'\"")
|
||||||
system(f"sftp -P {_user_data[2]} {_user_data[0]}@{_user_data[1]}:'{_user_data[6]}sshync_database' "
|
system(f"scp -pqs -P {_user_data[2]} -i '{_user_data[5]}' {_user_data[0]}@{_user_data[1]}:"
|
||||||
f"'{_user_data[6]}sshync_database'")
|
f"'/home/{_user_data[0]}/.config/sshync/database' '{expanduser('~/.config/sshync/')}'")
|
||||||
_titles, _sep, _mods = ' '.join(open(_user_data[6] + 'sshync_database').readlines()).replace('\n', '').partition('^&*')
|
_titles, _sep, _mods = '*&^'.join(open(expanduser('~/.config/sshync/database')).readlines()).replace('\n', '')\
|
||||||
_title_list, _mod_list = _titles.split(' ')[:-1], _mods.split(' ')[1:]
|
.partition('^&*')
|
||||||
|
_title_list, _mod_list = _titles.split('*&^')[:-1], _mods.split('*&^')[1:]
|
||||||
return _title_list, _mod_list
|
return _title_list, _mod_list
|
||||||
|
|
||||||
|
|
||||||
def sort_titles_mods(_list_1, _list_2):
|
def sort_titles_mods(_list_1, _list_2): # creates and returns two lists (of titles and mod times) generated by sorting
|
||||||
|
# information from two different, provided lists
|
||||||
_title_list_2_sorted, _mod_list_2_sorted = [], []
|
_title_list_2_sorted, _mod_list_2_sorted = [], []
|
||||||
# title sorting
|
# title sorting
|
||||||
for _title in _list_1[0]:
|
for _title in _list_1[0]:
|
||||||
@@ -57,18 +53,18 @@ def sort_titles_mods(_list_1, _list_2):
|
|||||||
return _title_list_2_sorted, _mod_list_2_sorted
|
return _title_list_2_sorted, _mod_list_2_sorted
|
||||||
|
|
||||||
|
|
||||||
def make_profile(_profile_dir, _local_dir, _remote_dir, _identity, _ip, _port, _user):
|
def make_profile(_profile_dir, _local_dir, _remote_dir, _identity, _ip, _port, _user): # creates a sshync job profile
|
||||||
open(_profile_dir, 'w').write(_user + '\n' + _ip + '\n' + _port + '\n' + _local_dir + '\n' + _remote_dir + '\n' +
|
open(_profile_dir, 'w').write(_user + '\n' + _ip + '\n' + _port + '\n' + _local_dir + '\n' + _remote_dir + '\n' +
|
||||||
_identity + '\n')
|
_identity + '\n')
|
||||||
|
|
||||||
|
|
||||||
def get_profile(_profile_dir):
|
def get_profile(_profile_dir): # returns a list of data read from a sshync job profile
|
||||||
try:
|
try:
|
||||||
_profile_data = open(_profile_dir).readlines()
|
_profile_data = open(_profile_dir).readlines()
|
||||||
except (FileNotFoundError, IndexError):
|
except (FileNotFoundError, IndexError):
|
||||||
print('\nEither the profile does not exist, or it is corrupted.\n')
|
print('\n\u001b[38;5;9merror: the profile does not exist or is corrupted.\u001b[0m\n')
|
||||||
_profile_data = None
|
_profile_data = None
|
||||||
s_exit()
|
s_exit(1)
|
||||||
# extract data from profile
|
# extract data from profile
|
||||||
_user = _profile_data[0].replace('\n', '')
|
_user = _profile_data[0].replace('\n', '')
|
||||||
_ip = _profile_data[1].replace('\n', '')
|
_ip = _profile_data[1].replace('\n', '')
|
||||||
@@ -76,11 +72,10 @@ def get_profile(_profile_dir):
|
|||||||
_local_dir = _profile_data[3].replace('\n', '')
|
_local_dir = _profile_data[3].replace('\n', '')
|
||||||
_remote_dir = _profile_data[4].replace('\n', '')
|
_remote_dir = _profile_data[4].replace('\n', '')
|
||||||
_identity = _profile_data[5].replace('\n', '')
|
_identity = _profile_data[5].replace('\n', '')
|
||||||
_data_dir = ' '.join(_profile_dir.split('/')[:-1]).replace(' ', '/') + '/'
|
return _user, _ip, _port, _local_dir, _remote_dir, _identity
|
||||||
return _user, _ip, _port, _local_dir, _remote_dir, _identity, _data_dir
|
|
||||||
|
|
||||||
|
|
||||||
def run_profile(_profile_dir):
|
def run_profile(_profile_dir): # runs a sshync job profile
|
||||||
_user_data = get_profile(_profile_dir)
|
_user_data = get_profile(_profile_dir)
|
||||||
_remote_titles_mods_saver = get_titles_mods(_user_data[4], 'r', _user_data) # saved to prevent re-walking directory
|
_remote_titles_mods_saver = get_titles_mods(_user_data[4], 'r', _user_data) # saved to prevent re-walking directory
|
||||||
_index_l = sort_titles_mods(_remote_titles_mods_saver, get_titles_mods(_user_data[3], 'l', _user_data))
|
_index_l = sort_titles_mods(_remote_titles_mods_saver, get_titles_mods(_user_data[3], 'l', _user_data))
|
||||||
@@ -91,19 +86,19 @@ def run_profile(_profile_dir):
|
|||||||
if _title in _index_r[0]:
|
if _title in _index_r[0]:
|
||||||
# compare mod times and sync
|
# compare mod times and sync
|
||||||
if int(_index_l[1][_i]) > int(_index_r[1][_i]):
|
if int(_index_l[1][_i]) > int(_index_r[1][_i]):
|
||||||
print(f"[{_title}] Local is newer, uploading...")
|
print(f"\u001b[38;5;4m{_title[:-4]}\u001b[0m is newer locally, uploading...")
|
||||||
system(f"sftp -p -q -i '{_user_data[5]}' -P {_user_data[2]} {_user_data[0]}@{_user_data[1]}:"
|
system(f"scp -pqs -P {_user_data[2]} -i '{_user_data[5]}' '{_user_data[3]}{_title}' "
|
||||||
f"{_user_data[4]}{'/'.join(_title.split('/')[:-1]) + '/'} <<< $'put {_user_data[3]}{_title}'")
|
f"'{_user_data[0]}@{_user_data[1]}:{_user_data[4]}{'/'.join(_title.split('/')[:-1]) + '/'}'")
|
||||||
elif int(_index_l[1][_i]) < int(_index_r[1][_i]):
|
elif int(_index_l[1][_i]) < int(_index_r[1][_i]):
|
||||||
print(f"[{_title}] Remote is newer, downloading...")
|
print(f"\u001b[38;5;2m{_title[:-4]}\u001b[0m is newer remotely, downloading...")
|
||||||
system(f"sftp -p -q -i '{_user_data[5]}' -P {_user_data[2]} {_user_data[0]}@{_user_data[1]}:"
|
system(f"scp -pqs -P {_user_data[2]} -i '{_user_data[5]}' '{_user_data[0]}@{_user_data[1]}:"
|
||||||
f"'{_user_data[4]}'{_title} {_user_data[3]}{'/'.join(_title.split('/')[:-1]) + '/'}")
|
f"{_user_data[4]}{_title}' '{_user_data[3]}{'/'.join(_title.split('/')[:-1]) + '/'}'")
|
||||||
else:
|
else:
|
||||||
print(f"[{_title}] Not on remote server, uploading...")
|
print(f"\u001b[38;5;4m{_title[:-4]}\u001b[0m is not on remote server, uploading...")
|
||||||
system(f"sftp -p -q -i '{_user_data[5]}' -P {_user_data[2]} {_user_data[0]}@{_user_data[1]}:{_user_data[4]}"
|
system(f"scp -pqs -P {_user_data[2]} -i '{_user_data[5]}' '{_user_data[3]}{_title}' "
|
||||||
f"{'/'.join(_title.split('/')[:-1]) + '/'} <<< $'put {_user_data[3]}{_title}'")
|
f"'{_user_data[0]}@{_user_data[1]}:{_user_data[4]}{'/'.join(_title.split('/')[:-1]) + '/'}'")
|
||||||
for _title in _index_r[0]:
|
for _title in _index_r[0]:
|
||||||
if _title not in _index_l[0]:
|
if _title not in _index_l[0]:
|
||||||
print(f"[{_title}] Not in local directory, downloading...")
|
print(f"\u001b[38;5;2m{_title[:-4]}\u001b[0m is not in local directory, downloading...")
|
||||||
system(f"sftp -p -q -i '{_user_data[5]}' -P {_user_data[2]} {_user_data[0]}@{_user_data[1]}:"
|
system(f"scp -pqs -P {_user_data[2]} -i '{_user_data[5]}' '{_user_data[0]}@{_user_data[1]}:"
|
||||||
f"'{_user_data[4]}{_title}' {_user_data[3]}{'/'.join(_title.split('/')[:-1]) + '/'}")
|
f"{_user_data[4]}{_title}' '{_user_data[3]}{'/'.join(_title.split('/')[:-1]) + '/'}'")
|
||||||
|
|||||||
@@ -1,491 +0,0 @@
|
|||||||
#!/usr/bin/python3
|
|
||||||
|
|
||||||
# external modules
|
|
||||||
|
|
||||||
from os import environ, mkdir, remove, system
|
|
||||||
from shutil import copy, move, rmtree
|
|
||||||
from sys import argv, exit as s_exit
|
|
||||||
from pathlib import Path
|
|
||||||
import random
|
|
||||||
import sshync
|
|
||||||
import string
|
|
||||||
|
|
||||||
|
|
||||||
# utility functions
|
|
||||||
|
|
||||||
def replace_line(file_name, line_num, text): # replaces text in a given line with different text
|
|
||||||
_lines = open(file_name, 'r').readlines()
|
|
||||||
_lines[line_num] = text
|
|
||||||
open(file_name, 'w').writelines(_lines)
|
|
||||||
|
|
||||||
|
|
||||||
def shm_gen(): # generates random folder in /dev/shm for security and returns random names for the folder and temp file
|
|
||||||
_shm_folder_gen = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits)
|
|
||||||
for _ in range(random.randint(10, 30)))
|
|
||||||
_shm_entry_gen = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits)
|
|
||||||
for _ in range(random.randint(10, 30)))
|
|
||||||
mkdir(f"/dev/shm/{_shm_folder_gen}", 0o700)
|
|
||||||
return _shm_folder_gen, _shm_entry_gen
|
|
||||||
|
|
||||||
|
|
||||||
def encrypt(_shm_folder, _shm_entry, _location):
|
|
||||||
system(f"gpg -r {str(gpg_id)} -e '/dev/shm/{_shm_folder}/{_shm_entry}'")
|
|
||||||
move(f"/dev/shm/{_shm_folder}/{_shm_entry}.gpg", f"{directory}{_location}.gpg")
|
|
||||||
rmtree(f"/dev/shm/{_shm_folder}")
|
|
||||||
|
|
||||||
|
|
||||||
def edit_note(_shm_folder, _shm_entry):
|
|
||||||
lines = open(f"/dev/shm/{_shm_folder}/{_shm_entry}").readlines()
|
|
||||||
open(f"/dev/shm/{_shm_folder}/{_shm_entry}", 'w').writelines(lines[0:3])
|
|
||||||
open(f"/dev/shm/{_shm_folder}/{_shm_entry}-n", 'w').writelines(lines[4:-2])
|
|
||||||
system(f"nano /dev/shm/{_shm_folder}/{_shm_entry}-n")
|
|
||||||
edit_notes = open(f"/dev/shm/{_shm_folder}/{_shm_entry}-n").read()
|
|
||||||
open(f"/dev/shm/{_shm_folder}/{_shm_entry}", 'a').write('\n' + edit_notes + '\n\n')
|
|
||||||
|
|
||||||
|
|
||||||
# argument-specific functions
|
|
||||||
|
|
||||||
|
|
||||||
def tweak(): # runs configuration wizard
|
|
||||||
# storage directory creation
|
|
||||||
try:
|
|
||||||
mkdir(f"/home/{environ.get('USER')}/.password-pasture", 0o700)
|
|
||||||
except FileExistsError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# device type configuration
|
|
||||||
_device_type = input('\nIs this installation for a client or for a server? (C/s) ')
|
|
||||||
if _device_type.lower() == 's':
|
|
||||||
open("/var/lib/sshyp/sshyp-device", 'w').write(_device_type)
|
|
||||||
copy('/usr/bin/sshync.py', f"/home/{environ.get('USER')}/")
|
|
||||||
print('\nMake sure the ssh service is running and properly configured.\n\nConfiguration complete!\n')
|
|
||||||
s_exit()
|
|
||||||
else:
|
|
||||||
# device type configuration
|
|
||||||
_device_type = 'c' # ensure device type flag is properly set
|
|
||||||
open("/var/lib/sshyp/sshyp-device", 'w').write(_device_type)
|
|
||||||
|
|
||||||
# gpg configuration
|
|
||||||
_gpg_id = input('\nsshyp requires the use of a unique gpg key. Do you already have one that you are '
|
|
||||||
'willing to use? (y/N)')
|
|
||||||
if _gpg_id.lower() != 'y':
|
|
||||||
print('\nA unique gpg key has been generated for you.')
|
|
||||||
system('gpg --full-generate-key')
|
|
||||||
_gpg_id = str(input('\nPlease input the ID of your gpg key: '))
|
|
||||||
open("/var/lib/sshyp/sshyp-gpg", 'w').write(_gpg_id + '\n')
|
|
||||||
|
|
||||||
# lock file generation
|
|
||||||
try:
|
|
||||||
open('/var/lib/sshyp/lock', 'x').write('')
|
|
||||||
except FileExistsError:
|
|
||||||
pass
|
|
||||||
system(f"gpg -r {str(_gpg_id)} -e /var/lib/sshyp/lock")
|
|
||||||
remove('/var/lib/sshyp/lock')
|
|
||||||
|
|
||||||
# ssh key configuration
|
|
||||||
_ssh_gen = (input('\nMake sure the ssh service on the remote server is running and properly configured.'
|
|
||||||
'\n\nSync support requires a unique ssh key. Would you like to have this automatically '
|
|
||||||
'generated? (Y/n) '))
|
|
||||||
if _ssh_gen.lower() != 'n':
|
|
||||||
system('ssh-keygen -t ed25519 -f ~/.ssh/sshyp')
|
|
||||||
else:
|
|
||||||
print(f"\nEnsure that the key file you are using is located at /home/{environ.get('USER')}/.ssh/sshyp")
|
|
||||||
|
|
||||||
# ssh ip+port configuration
|
|
||||||
print('\nExample input: 10.10.10.10:9999\n')
|
|
||||||
_ip_port = str(input('What is the IP and ssh port of the remote server? '))
|
|
||||||
_ip, _sep, _port = _ip_port.partition(':')
|
|
||||||
|
|
||||||
# ssh user configuration
|
|
||||||
_username_ssh = str(input('\nWhat is the username of the remote server? '))
|
|
||||||
print(f"\nEntry directory: /home/{_username_ssh}/.password-pasture/")
|
|
||||||
|
|
||||||
# sshync profile generation
|
|
||||||
sshync.make_profile('/var/lib/sshyp/sshyp.sshync', f"/home/{environ.get('USER')}/.password-pasture/",
|
|
||||||
f"/home/{_username_ssh}/.password-pasture/", f"/home/{environ.get('USER')}/.ssh/sshyp",
|
|
||||||
_ip, _port, _username_ssh)
|
|
||||||
print('\nConfiguration complete!\n')
|
|
||||||
|
|
||||||
|
|
||||||
def print_info(): # prints help text based on argument
|
|
||||||
if argument == 'help' or argument == '--help' or argument == '-h':
|
|
||||||
print('\nsshyp Copyright (C) 2021 Randall Winkhart')
|
|
||||||
print("This is free software, and you are welcome to redistribute it under certain conditions;\nthis program "
|
|
||||||
"comes with ABSOLUTELY NO WARRANTY;\ntype `sshyp license' for details.")
|
|
||||||
print('\nUSAGE: sshyp [/<entry name>] [OPTION] [FLAG]\n')
|
|
||||||
print('Options: ')
|
|
||||||
print('help/--help/-h bring up this menu')
|
|
||||||
print('version/-v display sshyp version info')
|
|
||||||
print('tweak configure sshyp')
|
|
||||||
print('add add an entry')
|
|
||||||
print('gen generate a new password')
|
|
||||||
print('edit edit an existing entry')
|
|
||||||
print('copy copy details of an entry to your clipboard')
|
|
||||||
print('shear/-rm delete an existing entry')
|
|
||||||
print('sync/-s manually sync the entry directory via sshync\n')
|
|
||||||
print('Flags:')
|
|
||||||
print('add:')
|
|
||||||
print(' password/-p add a password entry')
|
|
||||||
print(' note/-n add a note entry')
|
|
||||||
print(' folder/-f add a new folder for entries')
|
|
||||||
print('edit:')
|
|
||||||
print(' rename/relocate/-r rename or relocate an entry')
|
|
||||||
print(' username/-u change the username of an entry')
|
|
||||||
print(' password/-p change the password of an entry')
|
|
||||||
print(' note/-n change the note attached to an entry')
|
|
||||||
print(' url/-l change the url attached to an entry')
|
|
||||||
print('copy:')
|
|
||||||
print(' username/-u copy the username of an entry to your clipboard')
|
|
||||||
print(' password/-p copy the password of an entry to your clipboard')
|
|
||||||
print(' url/-l copy the URL of an entry to your clipboard')
|
|
||||||
print(' note/-n copy the note of an entry to your clipboard')
|
|
||||||
print('gen:')
|
|
||||||
print(' update/-u generate a password for an existing entry\n')
|
|
||||||
print("Tip: You can quickly read an entry with 'sshyp /<entry name>'!")
|
|
||||||
print("When specifying entry names, do not include the file extension! '.gpg' is assumed!\n")
|
|
||||||
elif argument == 'version' or argument == '-v':
|
|
||||||
print('\n////////////////////////////////////////////////////////')
|
|
||||||
print('/ /')
|
|
||||||
print('/ sshyp Copyright (C) 2021 Randall Winkhart /')
|
|
||||||
print('/ /')
|
|
||||||
print('/ Version 2022.01.10.fr2.3 /')
|
|
||||||
print('/ The Lighter Update /')
|
|
||||||
print('/ /')
|
|
||||||
print('////////////////////////////////////////////////////////\n')
|
|
||||||
elif argument == 'license':
|
|
||||||
print('\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU '
|
|
||||||
'General\nPublic License as published by the Free Software Foundation, either version 3 of the License,'
|
|
||||||
'\nor (at your option) any later version.\n\nThis program is distributed in the hope that it will be '
|
|
||||||
'useful, but WITHOUT ANY WARRANTY;\nwithout even the implied warranty of MERCHANTABILITY or FITNESS FOR A'
|
|
||||||
' PARTICULAR PURPOSE.\nSee the GNU General Public License for more details.'
|
|
||||||
'\n\nhttps://opensource.org/licenses/GPL-3.0\n')
|
|
||||||
elif argument == 'add':
|
|
||||||
print('\nUSAGE: sshyp add [FLAG]')
|
|
||||||
print('Flags:')
|
|
||||||
print('add:')
|
|
||||||
print(' password/-p add a password entry')
|
|
||||||
print(' note/-n add a note entry')
|
|
||||||
print(' folder/-f add a new folder for entries\n')
|
|
||||||
elif argument == 'edit':
|
|
||||||
print('\nUSAGE: sshyp edit [FLAG]')
|
|
||||||
print('Flags:')
|
|
||||||
print('edit:')
|
|
||||||
print(' rename/relocate/-r rename or relocate an entry')
|
|
||||||
print(' username/-u change the username of an entry')
|
|
||||||
print(' password/-p change the password of an entry')
|
|
||||||
print(' url/-l change the url attached to an entry')
|
|
||||||
print(' note/-n change the note attached to an entry\n')
|
|
||||||
elif argument == 'copy':
|
|
||||||
print('\nUSAGE: sshyp copy [FLAG]')
|
|
||||||
print('Flags:')
|
|
||||||
print('copy:')
|
|
||||||
print(' username/-u copy the username of an entry to your clipboard')
|
|
||||||
print(' password/-p copy the password of an entry to your clipboard')
|
|
||||||
print(' url/-l copy the URL of an entry to your clipboard')
|
|
||||||
print(' note/-n copy the note of an entry to your clipboard\n')
|
|
||||||
|
|
||||||
|
|
||||||
def no_arg(): # displays a list of entries and gives an option to select one for viewing
|
|
||||||
print("\nFor a list of usable commands, run 'sshyp help'.\n")
|
|
||||||
system(f"cd {directory}; ls -1 *")
|
|
||||||
_read_entry = str(input('\nEntry to read: '))
|
|
||||||
system(f"gpg -d '{directory}{_read_entry.replace('/', '', 1)}.gpg'")
|
|
||||||
print()
|
|
||||||
|
|
||||||
|
|
||||||
def read_shortcut(): # shortcut to quickly read an entry
|
|
||||||
system(f"gpg -d '{directory}{argument.replace('/', '', 1)}.gpg'")
|
|
||||||
|
|
||||||
|
|
||||||
def sync(): # calls sshync to sync changes to the user's server
|
|
||||||
print('\nSyncing entries with the server device...\n')
|
|
||||||
# set permissions before uploading
|
|
||||||
system('find ' + directory + ' -type d -exec chmod -R 700 {} +')
|
|
||||||
system('find ' + directory + ' -type f -exec chmod -R 600 {} +')
|
|
||||||
sshync.run_profile('/var/lib/sshyp/sshyp.sshync')
|
|
||||||
|
|
||||||
|
|
||||||
def add_entry(): # adds a new entry
|
|
||||||
_shm_folder, _shm_entry = None, None # sets base-line values to avoid errors
|
|
||||||
_entry_name = str(input('\nName of entry: '))
|
|
||||||
if _entry_name.startswith('/'):
|
|
||||||
_entry_name = _entry_name.replace('/', '', 1)
|
|
||||||
if argument == 'add note' or argument == 'add -n':
|
|
||||||
_shm_folder, _shm_entry = shm_gen()
|
|
||||||
system(f"nano /dev/shm/{_shm_folder}/{_shm_entry}-n")
|
|
||||||
_notes = open(f"/dev/shm/{_shm_folder}/{_shm_entry}-n", 'r').read()
|
|
||||||
open(f"/dev/shm/{_shm_folder}/{_shm_entry}", 'w').writelines('\n\n\n\n' + _notes + '\n\n')
|
|
||||||
elif argument == 'add password' or argument == 'add -p':
|
|
||||||
_username = str(input('Username: '))
|
|
||||||
_password = str(input('Password: '))
|
|
||||||
_url = str(input('URL: '))
|
|
||||||
_add_note = input('Add a note to this entry? (y/N) ')
|
|
||||||
_shm_folder, _shm_entry = shm_gen()
|
|
||||||
if _add_note.lower() == 'y':
|
|
||||||
system(f"nano /dev/shm/{_shm_folder}/{_shm_entry}-n")
|
|
||||||
_notes = open(f"/dev/shm/{_shm_folder}/{_shm_entry}-n", 'r').read()
|
|
||||||
else:
|
|
||||||
_notes = ''
|
|
||||||
open(f"/dev/shm/{_shm_folder}/{_shm_entry}", 'w').writelines(_username + '\n' + _password + '\n' + _url + '\n\n'
|
|
||||||
+ _notes + '\n\n')
|
|
||||||
encrypt(_shm_folder, _shm_entry, _entry_name)
|
|
||||||
system(f"gpg -d '{directory}{_entry_name}.gpg'")
|
|
||||||
|
|
||||||
|
|
||||||
def add_folder(): # creates a new folder
|
|
||||||
_folder_name = str(input('Name of new folder: '))
|
|
||||||
mkdir(directory + _folder_name, 0o700)
|
|
||||||
system(f"ssh -p {port} {username_ssh}@{ip} \"mkdir -p '{directory_ssh}{_folder_name}'\"")
|
|
||||||
|
|
||||||
|
|
||||||
def rename(): # renames an entry or folder TODO delete original from server to prevent re-downloading
|
|
||||||
print()
|
|
||||||
system(f"cd {directory}; ls -1 *") # TODO replace with new list
|
|
||||||
_entry_name = str(input('\nWhat would you like to rename/relocate? '))
|
|
||||||
_new_name = str(input('New Name: '))
|
|
||||||
if _entry_name.startswith('/'):
|
|
||||||
if _entry_name.replace('/', '', 1).__contains__('/'):
|
|
||||||
_folder, _sep, _folder_entry = _entry_name.replace('/', '', 1).partition('/')
|
|
||||||
move(f"{directory}{_folder}/{_folder_entry}.gpg", f"{directory}/{_new_name}.gpg")
|
|
||||||
else:
|
|
||||||
move(f"{directory}{_entry_name.replace('/', '', 1)}.gpg", f"{directory}{_new_name.replace('/', '', 1)}.gpg")
|
|
||||||
else:
|
|
||||||
move(f"{directory}{_entry_name}.gpg", f"{directory}{_new_name}.gpg")
|
|
||||||
|
|
||||||
|
|
||||||
def edit(): # edits the contents of an entry
|
|
||||||
_shm_folder, _shm_entry = None, None # sets base-line values to avoid errors
|
|
||||||
print()
|
|
||||||
system(f"cd {directory}; ls -1 *") # TODO replace with new list
|
|
||||||
_entry_name = str(input('\nWhat file would you like to edit? '))
|
|
||||||
if not Path(f"{directory}{_entry_name}.gpg").is_file():
|
|
||||||
print("\nYou are trying to edit a file that does not exist!\n")
|
|
||||||
s_exit()
|
|
||||||
if _entry_name.startswith('/'):
|
|
||||||
_entry_name = _entry_name.replace('/', '', 1)
|
|
||||||
if argument == 'edit username' or argument == 'edit -u':
|
|
||||||
_detail = str(input('New Username: '))
|
|
||||||
_shm_folder, _shm_entry = shm_gen()
|
|
||||||
system(f"gpg -d --output /dev/shm/{_shm_folder}/{_shm_entry} '{directory}{_entry_name}.gpg'")
|
|
||||||
replace_line(f"/dev/shm/{_shm_folder}/{_shm_entry}", 0, _detail + '\n')
|
|
||||||
elif argument == 'edit password' or argument == 'edit -p':
|
|
||||||
_detail = str(input('New Password: '))
|
|
||||||
_shm_folder, _shm_entry = shm_gen()
|
|
||||||
system(f"gpg -d --output /dev/shm/{_shm_folder}/{_shm_entry} '{directory}{_entry_name}.gpg'")
|
|
||||||
replace_line(f"/dev/shm/{_shm_folder}/{_shm_entry}", 1, _detail + '\n')
|
|
||||||
elif argument == 'edit url' or argument == 'edit -l':
|
|
||||||
_detail = str(input('New URL: '))
|
|
||||||
_shm_folder, _shm_entry = shm_gen()
|
|
||||||
system(f"gpg -d --output /dev/shm/{_shm_folder}/{_shm_entry} '{directory}{_entry_name}.gpg'")
|
|
||||||
replace_line(f"/dev/shm/{_shm_folder}/{_shm_entry}", 2, _detail + '\n')
|
|
||||||
elif argument == 'edit note' or argument == 'edit -n':
|
|
||||||
_shm_folder, _shm_entry = shm_gen()
|
|
||||||
system(f"gpg -d --output /dev/shm/{_shm_folder}/{_shm_entry} '{directory}{_entry_name}.gpg'")
|
|
||||||
edit_note(_shm_folder, _shm_entry)
|
|
||||||
remove(f"{directory}{_entry_name}.gpg")
|
|
||||||
encrypt(_shm_folder, _shm_entry, _entry_name)
|
|
||||||
system(f"gpg -d '{directory}{_entry_name}.gpg'")
|
|
||||||
|
|
||||||
|
|
||||||
def gen(): # generates a password for a new or an existing entry
|
|
||||||
_username, _url, _notes = None, None, None # sets base-line values to avoid errors
|
|
||||||
if argument == 'gen update' or argument == 'gen -u':
|
|
||||||
print()
|
|
||||||
system(f"cd {directory}; ls -1 *") # TODO replace with new list
|
|
||||||
_entry_name = str(input('\nName of service: '))
|
|
||||||
if _entry_name.startswith('/'):
|
|
||||||
_entry_name = _entry_name.replace('/', '', 1)
|
|
||||||
if argument == 'gen update' or argument == 'gen -u':
|
|
||||||
if not Path(f"{directory}{_entry_name}.gpg").is_file():
|
|
||||||
print("\nYou are trying to edit a file that does not exist!\n")
|
|
||||||
s_exit()
|
|
||||||
if argument != 'gen update' and argument != 'gen -u':
|
|
||||||
_username = str(input('Username: '))
|
|
||||||
_pass_length = int(input('How many characters should be in the password? '))
|
|
||||||
_pass_type = str(input('Should the password be simple (for compatibility) or complex (for security)? (s/C) '))
|
|
||||||
if _pass_type.lower() == 's':
|
|
||||||
_pass_type = string.ascii_letters + string.digits
|
|
||||||
else:
|
|
||||||
_pass_type = string.ascii_letters + string.digits + string.punctuation
|
|
||||||
_pass_gen = ''.join(random.SystemRandom().choice(_pass_type) for _ in range(_pass_length))
|
|
||||||
if argument != 'gen update' and argument != 'gen -u':
|
|
||||||
_url = str(input('URL: '))
|
|
||||||
_add_note = input('Add a note to this entry? (y/N) ')
|
|
||||||
_shm_folder, _shm_entry = shm_gen()
|
|
||||||
if _add_note.lower() == 'y':
|
|
||||||
system(f"nano /dev/shm/{_shm_folder}/{_shm_entry}-n")
|
|
||||||
_notes = open(f"/dev/shm/{_shm_folder}/{_shm_entry}-n", 'r').read()
|
|
||||||
else:
|
|
||||||
_notes = ''
|
|
||||||
open(f"/dev/shm/{_shm_folder}/{_shm_entry}", 'w').writelines(_username + '\n' + _pass_gen + '\n' + _url + '\n\n'
|
|
||||||
+ _notes + '\n\n')
|
|
||||||
encrypt(_shm_folder, _shm_entry, _entry_name)
|
|
||||||
system(f"gpg -d '{directory}{_entry_name}.gpg'")
|
|
||||||
else:
|
|
||||||
_shm_folder, _shm_entry = shm_gen()
|
|
||||||
system(f"gpg -d --output /dev/shm/{_shm_folder}/{_shm_entry} '{directory}{_entry_name}.gpg'")
|
|
||||||
replace_line(f"/dev/shm/{_shm_folder}/{_shm_entry}", 1, _pass_gen + '\n')
|
|
||||||
remove(f"{directory}{_entry_name}.gpg")
|
|
||||||
encrypt(_shm_folder, _shm_entry, _entry_name)
|
|
||||||
system(f"gpg -d '{directory}{_entry_name}.gpg'")
|
|
||||||
|
|
||||||
|
|
||||||
def copy_data(): # copies a specified field of an entry to the clipboard
|
|
||||||
print()
|
|
||||||
system(f"cd {directory}; ls -1 *") # TODO replace with new list
|
|
||||||
_read_entry = str(input('\nEntry to copy: '))
|
|
||||||
if not Path(f"{directory}{_read_entry}.gpg").is_file():
|
|
||||||
print("\nThe file does not exist!\n")
|
|
||||||
s_exit()
|
|
||||||
_shm_folder, _shm_entry = shm_gen()
|
|
||||||
system(f"gpg -d --output /dev/shm/{_shm_folder}/{_shm_entry} '{directory}{_read_entry}.gpg'")
|
|
||||||
_copy_line = open(f"/dev/shm/{_shm_folder}/{_shm_entry}", 'r').readlines()
|
|
||||||
if environ.get('WAYLAND_DISPLAY') == 'wayland-0': # checks if the user is using Wayland or X for clipboard
|
|
||||||
if argument == 'copy username' or argument == 'copy -u':
|
|
||||||
system('wl-copy ' + "'" + _copy_line[0].replace('\n', '').replace("'", "'\\''") + "'")
|
|
||||||
elif argument == 'copy password' or argument == 'copy -p':
|
|
||||||
system('wl-copy ' + "'" + _copy_line[1].replace('\n', '').replace("'", "'\\''") + "'")
|
|
||||||
elif argument == 'copy url' or argument == 'copy -l':
|
|
||||||
system('wl-copy ' + "'" + _copy_line[2].replace('\n', '').replace("'", "'\\''") + "'")
|
|
||||||
elif argument == 'copy note' or argument == 'copy -n':
|
|
||||||
system('wl-copy ' + "'" + _copy_line[4].replace('\n', '').replace("'", "'\\''") + "'")
|
|
||||||
else:
|
|
||||||
if argument == 'copy username' or argument == 'copy -u':
|
|
||||||
system('echo -n ' + "'" + _copy_line[0].replace('\n', '').replace("'", "'\\''") + "'" + ' | xclip -sel c')
|
|
||||||
elif argument == 'copy password' or argument == 'copy -p':
|
|
||||||
system('echo -n ' + "'" + _copy_line[1].replace('\n', '').replace("'", "'\\''") + "'" + ' | xclip -sel c')
|
|
||||||
elif argument == 'copy url' or argument == 'copy -l':
|
|
||||||
system('echo -n ' + "'" + _copy_line[2].replace('\n', '').replace("'", "'\\''") + "'" + ' | xclip -sel c')
|
|
||||||
elif argument == 'copy note' or argument == 'copy -n':
|
|
||||||
system('echo -n ' + "'" + _copy_line[4].replace('\n', '').replace("'", "'\\''") + "'" + ' | xclip -sel c')
|
|
||||||
rmtree(f"/dev/shm/{_shm_folder}")
|
|
||||||
|
|
||||||
|
|
||||||
def remove_data(): # deletes an entry or folder from both the client and the server
|
|
||||||
print()
|
|
||||||
system(f"cd {directory}; ls -1 *") # TODO replace with new list
|
|
||||||
_entry_name = str(input('\nWhat would you like to delete? '))
|
|
||||||
if _entry_name.startswith('/'):
|
|
||||||
_entry_name = _entry_name.replace('/', '', 1)
|
|
||||||
try:
|
|
||||||
system('gpg -d --output /dev/shm/sshyp.lock /var/lib/sshyp/lock.gpg')
|
|
||||||
_unlock = open('/dev/shm/sshyp.lock', 'r').readlines()
|
|
||||||
remove('/dev/shm/sshyp.lock')
|
|
||||||
except FileNotFoundError:
|
|
||||||
print('\nAccess denied.\n')
|
|
||||||
s_exit()
|
|
||||||
if device_type == 'c':
|
|
||||||
system(f"ssh -p {port} {username_ssh}@{ip} \"rm -rf '{directory_ssh}{_entry_name}.gpg'\"")
|
|
||||||
remove(f"{directory}{_entry_name}.gpg")
|
|
||||||
|
|
||||||
|
|
||||||
# program start sequence
|
|
||||||
|
|
||||||
# retrieve typed argument
|
|
||||||
argument_list = argv
|
|
||||||
i, argument = 0, ''
|
|
||||||
for _ in argument_list:
|
|
||||||
while i < len(argument_list) - 1:
|
|
||||||
i += 1
|
|
||||||
argument += argument_list[i] + ' '
|
|
||||||
argument = argument[:-1]
|
|
||||||
|
|
||||||
# import saved userdata
|
|
||||||
if argument != 'tweak':
|
|
||||||
device_type = ''
|
|
||||||
try:
|
|
||||||
device_type = open('/var/lib/sshyp/sshyp-device').read().strip()
|
|
||||||
if device_type == 'c':
|
|
||||||
gpg_id = open('/var/lib/sshyp/sshyp-gpg').read().strip()
|
|
||||||
ssh_info = sshync.get_profile('/var/lib/sshyp/sshyp.sshync')
|
|
||||||
username_ssh = ssh_info[0].replace('\n', '')
|
|
||||||
ip = ssh_info[1].replace('\n', '')
|
|
||||||
port = ssh_info[2].replace('\n', '')
|
|
||||||
directory = str(ssh_info[3].replace('\n', ''))
|
|
||||||
directory_ssh = '/home/' + username_ssh + '/.password-pasture/'
|
|
||||||
except FileNotFoundError:
|
|
||||||
if device_type.lower() != 's':
|
|
||||||
print('\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
|
|
||||||
print("Not all necessary configuration files are present. Please run 'sshyp tweak'!")
|
|
||||||
print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n')
|
|
||||||
s_exit()
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
tweak()
|
|
||||||
s_exit()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print('\n')
|
|
||||||
s_exit()
|
|
||||||
|
|
||||||
# run function based on argument
|
|
||||||
error = 0 # create an error flag to determine if syncing should occur at end
|
|
||||||
if argument.startswith('/'):
|
|
||||||
read_shortcut()
|
|
||||||
elif argument == '':
|
|
||||||
try:
|
|
||||||
no_arg()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print('\n')
|
|
||||||
s_exit()
|
|
||||||
elif argument == 'help' or argument == '--help' or argument == '-h' or argument == 'license' or argument == 'version' \
|
|
||||||
or argument == '-v' or argument == 'add' or argument == 'edit' or argument == 'copy':
|
|
||||||
print_info()
|
|
||||||
elif argument == 'add note' or argument == 'add -n' or argument == 'add password' or argument == 'add -p':
|
|
||||||
try:
|
|
||||||
add_entry()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print('\n')
|
|
||||||
s_exit()
|
|
||||||
elif argument == 'add folder' or argument == 'add -f':
|
|
||||||
try:
|
|
||||||
add_folder()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print('\n')
|
|
||||||
s_exit()
|
|
||||||
elif argument == 'edit rename' or argument == 'edit relocate' or argument == 'edit -r':
|
|
||||||
try:
|
|
||||||
rename()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print('\n')
|
|
||||||
s_exit()
|
|
||||||
elif argument == 'edit username' or argument == 'edit -u' or argument == 'edit password' or argument == 'edit -p' or \
|
|
||||||
argument == 'edit url' or argument == 'edit -l' or argument == 'edit note' or argument == 'edit -n':
|
|
||||||
try:
|
|
||||||
edit()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print('\n')
|
|
||||||
s_exit()
|
|
||||||
elif argument == 'gen' or argument == 'gen update' or argument == 'gen -u':
|
|
||||||
try:
|
|
||||||
gen()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print('\n')
|
|
||||||
s_exit()
|
|
||||||
elif argument == 'copy username' or argument == 'copy -u' or argument == 'copy password' or argument == 'copy -p' or \
|
|
||||||
argument == 'copy url' or argument == 'copy -l' or argument == 'copy note' or argument == 'copy -n':
|
|
||||||
try:
|
|
||||||
copy_data()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print('\n')
|
|
||||||
s_exit()
|
|
||||||
elif argument == 'shear' or argument == '-rm':
|
|
||||||
try:
|
|
||||||
remove_data()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print('\n')
|
|
||||||
s_exit()
|
|
||||||
elif argument == 'sync' or argument == '-s':
|
|
||||||
sync()
|
|
||||||
else:
|
|
||||||
error = 1 # set error flag to 1 to stop syncing
|
|
||||||
print("\nArgument error! Please run 'sshyp help' for a list of usable commands.\n")
|
|
||||||
s_exit()
|
|
||||||
|
|
||||||
# sync at end of program if any changes were made
|
|
||||||
if argument != '' and argument != 'help' and argument != '--help' and argument != '-h' and argument != 'license' and \
|
|
||||||
argument != 'add' and argument != 'sync' and argument != 'edit' and argument != 'copy username' and argument \
|
|
||||||
!= 'copy -u' and argument != 'copy password' and argument != 'copy -p' and argument != 'copy url' and argument \
|
|
||||||
!= 'copy -l' and argument != 'copy note' and argument != 'copy -n' and argument != 'copy' and argument != \
|
|
||||||
'shear' and argument != '-rm' and argument != 'version' and argument != '-v' and error == 0 and \
|
|
||||||
argument.startswith('/') is False:
|
|
||||||
sync()
|
|
||||||
Executable
+768
@@ -0,0 +1,768 @@
|
|||||||
|
#!/bin/python3
|
||||||
|
|
||||||
|
# external modules
|
||||||
|
|
||||||
|
from os import environ, listdir, path, remove, system, uname, walk
|
||||||
|
from pathlib import Path
|
||||||
|
from random import randint, SystemRandom
|
||||||
|
from shutil import get_terminal_size, move, rmtree
|
||||||
|
import sshync
|
||||||
|
import string
|
||||||
|
from subprocess import CalledProcessError, Popen, PIPE, run
|
||||||
|
from sys import argv, exit as s_exit
|
||||||
|
from textwrap import fill
|
||||||
|
|
||||||
|
|
||||||
|
# BELOW - utility functions
|
||||||
|
|
||||||
|
def entry_list_gen(_directory=path.expanduser('~/.local/share/sshyp/')): # generates and prints full entry list
|
||||||
|
print('\n\u001b[38;5;0;48;5;15msshyp entries:\u001b[0m\n')
|
||||||
|
_entry_list, _color_alternator = [], 1
|
||||||
|
for _entry in sorted(listdir(_directory)):
|
||||||
|
if Path(f"{_directory}{_entry}").is_file():
|
||||||
|
if _color_alternator == 1:
|
||||||
|
_entry_list.append(f"{_entry.replace('.gpg', '')}")
|
||||||
|
_color_alternator = 2
|
||||||
|
else:
|
||||||
|
_entry_list.append(f"\u001b[38;5;8m{_entry.replace('.gpg', '')}\u001b[0m")
|
||||||
|
_color_alternator = 1
|
||||||
|
_real = len(' '.join(_entry_list)) - (5.5 * len(_entry_list))
|
||||||
|
if _real <= get_terminal_size()[0]:
|
||||||
|
_width = len(' '.join(_entry_list))
|
||||||
|
else:
|
||||||
|
_width = (len(' '.join(_entry_list)) / (_real / get_terminal_size()[0]) - 25)
|
||||||
|
try:
|
||||||
|
print(fill(' '.join(_entry_list), width=_width) + '\n')
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
for _root, _directories, _files in walk(_directory):
|
||||||
|
for _dir in sorted(_directories):
|
||||||
|
_inner_dir = f"{_root.replace(_directory, '')}/{_dir}"
|
||||||
|
print(f"\u001b[38;5;15;48;5;238m{_inner_dir}/\u001b[0m")
|
||||||
|
_entry_list, _color_alternator = [], 1
|
||||||
|
for _s_root, _s_directories, _s_files in walk(f"{_directory[:-1]}{_inner_dir}"):
|
||||||
|
for _entry in sorted(_s_files):
|
||||||
|
if _color_alternator == 1:
|
||||||
|
_entry_list.append(f"{_entry.replace('.gpg', '')}")
|
||||||
|
_color_alternator = 2
|
||||||
|
else:
|
||||||
|
_entry_list.append(f"\u001b[38;5;8m{_entry.replace('.gpg', '')}\u001b[0m")
|
||||||
|
_color_alternator = 1
|
||||||
|
_real = len(' '.join(_entry_list)) - (5.5 * len(_entry_list))
|
||||||
|
if _real <= get_terminal_size()[0]:
|
||||||
|
_width = len(' '.join(_entry_list))
|
||||||
|
else:
|
||||||
|
_width = (len(' '.join(_entry_list)) / (_real / get_terminal_size()[0]) - 25)
|
||||||
|
try:
|
||||||
|
print(fill(' '.join(_entry_list), width=_width) + '\n')
|
||||||
|
except ValueError:
|
||||||
|
print('\u001b[38;5;9m-empty directory-\u001b[0m\n')
|
||||||
|
|
||||||
|
|
||||||
|
def entry_reader(_decrypted_entry): # displays the contents of an entry in a readable format
|
||||||
|
_entry_lines, _notes_flag = open(_decrypted_entry, 'r').readlines(), 0
|
||||||
|
print()
|
||||||
|
for _num in range(len(_entry_lines)):
|
||||||
|
try:
|
||||||
|
if _num == 0 and _entry_lines[1] != '\n':
|
||||||
|
print(f"\u001b[38;5;15;48;5;238musername:\u001b[0m\n{_entry_lines[1].strip()}\n")
|
||||||
|
elif _num == 1 and _entry_lines[0] != '\n':
|
||||||
|
print(f"\u001b[38;5;15;48;5;238mpassword:\u001b[0m\n{_entry_lines[0].strip()}\n")
|
||||||
|
elif _num == 2 and _entry_lines[2] != '\n':
|
||||||
|
print(f"\u001b[38;5;15;48;5;238murl:\u001b[0m\n{_entry_lines[_num].strip()}\n")
|
||||||
|
elif _num >= 3 and _entry_lines[_num] != '\n' and _notes_flag != 1:
|
||||||
|
_notes_flag = 1
|
||||||
|
print(f"\u001b[38;5;15;48;5;238mnotes:\u001b[0m\n{_entry_lines[_num].strip()}")
|
||||||
|
elif _num >= 3 and _notes_flag == 1:
|
||||||
|
print(_entry_lines[_num].replace('\n', ''))
|
||||||
|
if _notes_flag == 1:
|
||||||
|
try:
|
||||||
|
_line_test = _entry_lines[_num + 1]
|
||||||
|
except IndexError:
|
||||||
|
print()
|
||||||
|
except IndexError:
|
||||||
|
if _num == 0:
|
||||||
|
print(f"\u001b[38;5;15;48;5;238mpassword:\u001b[0m\n{_entry_lines[0]}\n")
|
||||||
|
|
||||||
|
|
||||||
|
def entry_name_fetch(_entry_name_location): # fetches and returns entry name from user input or from provided argument
|
||||||
|
if type(_entry_name_location) == str:
|
||||||
|
entry_list_gen()
|
||||||
|
_entry_name = str(input(_entry_name_location))
|
||||||
|
else:
|
||||||
|
_entry_name_split = argument.split(' ')
|
||||||
|
del _entry_name_split[:_entry_name_location]
|
||||||
|
_entry_name = ' '.join(_entry_name_split)
|
||||||
|
if _entry_name.startswith('/'):
|
||||||
|
return _entry_name.replace('/', '', 1)
|
||||||
|
else:
|
||||||
|
return _entry_name
|
||||||
|
|
||||||
|
|
||||||
|
def shm_gen(_tmp_dir=path.expanduser('~/.config/sshyp/tmp/')): # creates a temporary directory for entry editing
|
||||||
|
_shm_folder_gen = ''.join(SystemRandom().choice(string.ascii_letters + string.digits)
|
||||||
|
for _ in range(randint(10, 30)))
|
||||||
|
_shm_entry_gen = ''.join(SystemRandom().choice(string.ascii_letters + string.digits)
|
||||||
|
for _ in range(randint(10, 30)))
|
||||||
|
Path(_tmp_dir + _shm_folder_gen).mkdir(0o700)
|
||||||
|
return _shm_folder_gen, _shm_entry_gen
|
||||||
|
|
||||||
|
|
||||||
|
def pass_gen(): # generates and returns a random password based on user-specified options
|
||||||
|
def _pass_gen_function(__complexity, __length):
|
||||||
|
if __complexity.lower() == 's':
|
||||||
|
__character_pool = string.ascii_letters + string.digits
|
||||||
|
else:
|
||||||
|
__character_pool = string.ascii_letters + string.digits + string.punctuation
|
||||||
|
__gen = ''.join(SystemRandom().choice(__character_pool) for _ in range(__length))
|
||||||
|
__min_special, __special = round(.2 * __length), 0
|
||||||
|
for __character in __gen:
|
||||||
|
if not __character.isalpha():
|
||||||
|
__special += 1
|
||||||
|
if __special < __min_special:
|
||||||
|
__gen = _pass_gen_function(__complexity, __length)
|
||||||
|
return __gen
|
||||||
|
try:
|
||||||
|
_length = int(input('password length: '))
|
||||||
|
except ValueError:
|
||||||
|
print(f"\n\u001b[38;5;9merror: a non-integer value was input for password length\u001b[0m\n")
|
||||||
|
_gen = pass_gen()
|
||||||
|
return _gen
|
||||||
|
if _length > 840:
|
||||||
|
_length = 840
|
||||||
|
print('\n\u001b[38;5;9mpassword length has been limited to the maximum of 840 characters\u001b[0m\n')
|
||||||
|
_complexity = str(input('password complexity - simple (for compatibility) or complex (for security)? (s/C) '))
|
||||||
|
_gen = _pass_gen_function(_complexity, _length)
|
||||||
|
return _gen
|
||||||
|
|
||||||
|
|
||||||
|
def encrypt(_entry_dir, _shm_folder, _shm_entry, _gpg_com, _gpg_id, _tmp_dir=path.expanduser('~/.config/sshyp/tmp/')):
|
||||||
|
# encrypts an entry and cleans up the temporary files
|
||||||
|
system(f"{_gpg_com} -qr {str(_gpg_id)} -e '{_tmp_dir}{_shm_folder}/{_shm_entry}'")
|
||||||
|
move(f"{_tmp_dir}{_shm_folder}/{_shm_entry}.gpg", f"{_entry_dir}.gpg")
|
||||||
|
rmtree(f"{_tmp_dir}{_shm_folder}")
|
||||||
|
|
||||||
|
|
||||||
|
def decrypt(_entry_dir, _shm_folder, _shm_entry, _gpg_command, _tmp_dir=path.expanduser('~/.config/sshyp/tmp/')):
|
||||||
|
# decrypts an entry to a temporary directory
|
||||||
|
if _shm_folder == 0 and _shm_entry == 0:
|
||||||
|
_command = f"{_gpg_command} -qd --output /dev/null {path.expanduser('~/.config/sshyp/lock.gpg')}"
|
||||||
|
else:
|
||||||
|
_command = f"{_gpg_command} -qd --output {_tmp_dir}{_shm_folder}/{_shm_entry} {_entry_dir}.gpg"
|
||||||
|
try:
|
||||||
|
run(_command, shell=True, stderr=PIPE, check=True, close_fds=True)
|
||||||
|
except CalledProcessError:
|
||||||
|
print(f"\n\u001b[38;5;9merror: could not decrypt - ensure the correct gpg key is present\u001b[0m\n")
|
||||||
|
s_exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def optimized_edit(_lines, _edit_data, _edit_line): # ensures an edited entry is optimized for best compatibility
|
||||||
|
while len(_lines) < _edit_line + 1:
|
||||||
|
_lines += ['\n']
|
||||||
|
if _edit_data is not None:
|
||||||
|
_lines[_edit_line] = _edit_data.strip('\n').rstrip() + '\n'
|
||||||
|
for _num in range(len(_lines)):
|
||||||
|
if not _lines[_num].endswith('\n'):
|
||||||
|
_lines[_num] += '\n'
|
||||||
|
for _num in reversed(range(len(_lines))):
|
||||||
|
if _lines[_num] == '\n':
|
||||||
|
_lines = _lines[:-1]
|
||||||
|
elif _lines[_num].endswith('\n'):
|
||||||
|
_lines[_num] = _lines[_num].rstrip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
return _lines
|
||||||
|
|
||||||
|
|
||||||
|
def edit_note(_shm_folder, _shm_entry, _lines): # edits the note attached to an entry
|
||||||
|
_reg_lines = _lines[0:3]
|
||||||
|
open(f"{tmp_dir}{_shm_folder}/{_shm_entry}-n", 'w').writelines(_lines[3:])
|
||||||
|
system(f"{editor} {tmp_dir}{_shm_folder}/{_shm_entry}-n")
|
||||||
|
_new_notes = open(f"{tmp_dir}{_shm_folder}/{_shm_entry}-n").readlines()
|
||||||
|
while len(_reg_lines) < 3:
|
||||||
|
_reg_lines += ['\n']
|
||||||
|
_noted_lines = _reg_lines + _new_notes
|
||||||
|
return _noted_lines
|
||||||
|
|
||||||
|
|
||||||
|
def copy_name_check(_port, _username_ssh, _ip, _client_device_name):
|
||||||
|
# attempts to connect to the user's server via ssh to register the device for syncing
|
||||||
|
_command = f"ssh -o ConnectTimeout=3 -i '{path.expanduser('~/.ssh/sshyp')}' -p {_port} {_username_ssh}@{_ip} " \
|
||||||
|
f"\"touch '/home/{_username_ssh}/.config/sshyp/devices/{_client_device_name}'\""
|
||||||
|
try:
|
||||||
|
run(_command, shell=True, stderr=PIPE, check=True, close_fds=True)
|
||||||
|
except CalledProcessError:
|
||||||
|
print('\n\u001b[38;5;9mwarning: ssh connection could not be made - ensure the public key (~/.ssh/sshyp.pub) is '
|
||||||
|
'registered on the remote server and that the entered ip, port, and username are correct\n\nsyncing '
|
||||||
|
'functionality will be disabled until this is addressed\u001b[0m\n')
|
||||||
|
open(path.expanduser('~/.config/sshyp/ssh-error'), 'w').write('1')
|
||||||
|
return 1
|
||||||
|
open(path.expanduser('~/.config/sshyp/ssh-error'), 'w').write('0')
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# BELOW - argument-specific functions
|
||||||
|
|
||||||
|
|
||||||
|
def tweak(): # runs configuration wizard
|
||||||
|
_divider = f"\n{'=' * (get_terminal_size()[0] - int((.5 * get_terminal_size()[0])))}\n\n"
|
||||||
|
# storage/config directory creation
|
||||||
|
Path(path.expanduser('~/.local/share/sshyp')).mkdir(0o700, parents=True, exist_ok=True)
|
||||||
|
Path(path.expanduser('~/.config/sshyp/devices')).mkdir(0o700, parents=True, exist_ok=True)
|
||||||
|
if not Path(f"{path.expanduser('~/.config/sshyp/tmp')}").exists():
|
||||||
|
if uname()[0] == 'Haiku' or uname()[0] == 'FreeBSD':
|
||||||
|
system(f"ln -s /tmp {path.expanduser('~/.config/sshyp/tmp')}")
|
||||||
|
elif Path("/data/data/com.termux").exists():
|
||||||
|
system(f"ln -s '/data/data/com.termux/files/usr/tmp' {path.expanduser('~/.config/sshyp/tmp')}")
|
||||||
|
else:
|
||||||
|
system(f"ln -s /dev/shm {path.expanduser('~/.config/sshyp/tmp')}")
|
||||||
|
# device type configuration
|
||||||
|
_device_type = input('\nclient or server installation? (C/s) ')
|
||||||
|
if _device_type.lower() == 's':
|
||||||
|
open(path.expanduser('~/.config/sshyp/sshyp-device'), 'w').write(_device_type)
|
||||||
|
Path(path.expanduser('~/.config/sshyp/deleted')).mkdir(0o700, parents=True, exist_ok=True)
|
||||||
|
print(f"\n\u001b[4;1mmake sure the ssh service is running and properly configured\u001b[0m\n"
|
||||||
|
f"{_divider}configuration complete\n")
|
||||||
|
s_exit(0)
|
||||||
|
else:
|
||||||
|
# device type configuration
|
||||||
|
_device_type = 'c' # ensure device type flag is properly set
|
||||||
|
open(path.expanduser('~/.config/sshyp/sshyp-device'), 'w').write(_device_type)
|
||||||
|
|
||||||
|
# gpg configuration
|
||||||
|
_gpg_id = input(f"{_divider}sshyp requires the use of a unique gpg key - use an (e)xisting key or (g)enerate "
|
||||||
|
f"a new one? (E/g) ")
|
||||||
|
if _gpg_id.lower() != 'g':
|
||||||
|
system(f"{gpg} -k")
|
||||||
|
_gpg_id = str(input('gpg key id: '))
|
||||||
|
else:
|
||||||
|
print('\na unique gpg key is being generated for you...')
|
||||||
|
if not Path(path.expanduser('~/.config/sshyp/gpg-gen')).is_file():
|
||||||
|
open(path.expanduser('~/.config/sshyp/gpg-gen'), 'w').writelines([
|
||||||
|
'Key-Type: 1\n', 'Key-Length: 4096\n', 'Key-Usage: sign encrypt\n', 'Name-Real: sshyp\n',
|
||||||
|
'Name-Comment: gpg-sshyp\n', 'Name-Email: https://github.com/rwinkhart/sshyp\n', 'Expire-Date: 0'])
|
||||||
|
if uname()[0] == 'Haiku':
|
||||||
|
run(gpg + ' --batch --generate-key --passphrase ' + "'" +
|
||||||
|
input('\ngpg passphrase: ') + "'" + " '" +
|
||||||
|
path.expanduser('~/.config/sshyp/gpg-gen') + "'", shell=True)
|
||||||
|
else:
|
||||||
|
run(f"{gpg} --batch --generate-key '{path.expanduser('~/.config/sshyp/gpg-gen')}'", shell=True)
|
||||||
|
remove(path.expanduser('~/.config/sshyp/gpg-gen'))
|
||||||
|
_gpg_id = run(f"{gpg} -k", shell=True, stdout=PIPE, text=True).stdout.split('\n')[-4].strip()
|
||||||
|
|
||||||
|
# lock file generation
|
||||||
|
if Path(path.expanduser('~/.config/sshyp/lock.gpg')).is_file():
|
||||||
|
remove(path.expanduser('~/.config/sshyp/lock.gpg'))
|
||||||
|
open(path.expanduser('~/.config/sshyp/lock'), 'w')
|
||||||
|
system(f"{gpg} -qr {str(_gpg_id)} -e {path.expanduser('~/.config/sshyp/lock')}")
|
||||||
|
remove(path.expanduser('~/.config/sshyp/lock'))
|
||||||
|
|
||||||
|
# ssh key configuration
|
||||||
|
_ssh_gen = (input(f"{_divider}make sure the ssh service on the remote server is running and properly "
|
||||||
|
f"configured\n\nsync support requires a unique ssh key - would you like to have this "
|
||||||
|
f"automatically generated? (Y/n) "))
|
||||||
|
if _ssh_gen.lower() != 'n':
|
||||||
|
if uname()[0] == 'Haiku':
|
||||||
|
Path(f"{path.expanduser('~')}/.ssh").mkdir(0o700, exist_ok=True)
|
||||||
|
system('ssh-keygen -t ed25519 -f ~/.ssh/sshyp')
|
||||||
|
else:
|
||||||
|
print(f"\n\u001b[4;1mensure that the key file you are using is located at "
|
||||||
|
f"{path.expanduser('~/.ssh/sshyp')}\u001b[0m")
|
||||||
|
|
||||||
|
# ssh ip+port configuration
|
||||||
|
_ip_port = str(input(f"{_divider}example input: 10.10.10.10:9999\n\nip and ssh port of the remote server: "))
|
||||||
|
_ip, _sep, _port = _ip_port.partition(':')
|
||||||
|
|
||||||
|
# ssh user configuration
|
||||||
|
_username_ssh = str(input('\nusername of the remote server: '))
|
||||||
|
|
||||||
|
# sshyp-only data storage
|
||||||
|
open(path.expanduser('~/.config/sshyp/sshyp-data'), 'w')\
|
||||||
|
.write(_gpg_id + '\n' + input(f"{_divider}example input: vim\n\npreferred text editor: "))
|
||||||
|
|
||||||
|
# sshync profile generation
|
||||||
|
sshync.make_profile(path.expanduser('~/.config/sshyp/sshyp.sshync'),
|
||||||
|
path.expanduser('~/.local/share/sshyp/'), f"/home/{_username_ssh}/.local/share/sshyp/",
|
||||||
|
path.expanduser('~/.ssh/sshyp'), _ip, _port, _username_ssh)
|
||||||
|
|
||||||
|
# device name configuration
|
||||||
|
for _name in listdir(path.expanduser('~/.config/sshyp/devices')): # remove existing device name
|
||||||
|
remove(f"{path.expanduser('~/.config/sshyp/devices/')}{_name}")
|
||||||
|
print(f"{_divider}\u001b[4;1mimportant:\u001b[0m this name \u001b[4;1mmust\u001b[0m be unique amongst your "
|
||||||
|
f"client devices\n\nthis is used to keep track of which devices have up-to-date databases\n")
|
||||||
|
_client_device_name = str(input('device name: '))
|
||||||
|
open(f"{path.expanduser('~/.config/sshyp/devices/')}{_client_device_name}", 'w')
|
||||||
|
copy_name_check(_port, _username_ssh, _ip, _client_device_name)
|
||||||
|
|
||||||
|
print(f"{_divider}configuration complete\n")
|
||||||
|
|
||||||
|
|
||||||
|
def print_info(): # prints help text based on argument
|
||||||
|
if argument_list[1] == 'help' or argument_list[1] == '--help' or argument_list[1] == '-h':
|
||||||
|
print('\n\u001b[1msshyp copyright (c) 2021-2022 randall winkhart\u001b[0m\n')
|
||||||
|
print("this is free software, and you are welcome to redistribute it under certain conditions;\nthis program "
|
||||||
|
"comes with absolutely no warranty;\ntype `sshyp license' for details")
|
||||||
|
print('\n\u001b[1musage:\u001b[0m sshyp [option [flag] [<entry name>]] | [/<entry name>]\n')
|
||||||
|
print('\u001b[1moptions:\u001b[0m')
|
||||||
|
print('help/--help/-h bring up this menu')
|
||||||
|
print('version/-v display sshyp version info')
|
||||||
|
print('tweak configure sshyp')
|
||||||
|
print('add add an entry')
|
||||||
|
print('gen generate a new password')
|
||||||
|
print('edit edit an existing entry')
|
||||||
|
print('copy copy details of an entry to your clipboard')
|
||||||
|
print('shear/-rm delete an existing entry')
|
||||||
|
print('sync/-s manually sync the entry directory via sshync\n')
|
||||||
|
print('\u001b[1mflags:\u001b[0m')
|
||||||
|
print('add:')
|
||||||
|
print(' password/-p add a password entry')
|
||||||
|
print(' note/-n add a note entry')
|
||||||
|
print(' folder/-f add a new folder for entries')
|
||||||
|
print('edit:')
|
||||||
|
print(' rename/relocate/-r rename or relocate an entry')
|
||||||
|
print(' username/-u change the username of an entry')
|
||||||
|
print(' password/-p change the password of an entry')
|
||||||
|
print(' note/-n change the note attached to an entry')
|
||||||
|
print(' url/-l change the url attached to an entry')
|
||||||
|
print('copy:')
|
||||||
|
print(' username/-u copy the username of an entry to your clipboard')
|
||||||
|
print(' password/-p copy the password of an entry to your clipboard')
|
||||||
|
print(' url/-l copy the url of an entry to your clipboard')
|
||||||
|
print(' note/-n copy the note of an entry to your clipboard')
|
||||||
|
print('gen:')
|
||||||
|
print(' update/-u generate a password for an existing entry\n')
|
||||||
|
print("\u001b[1mtip:\u001b[0m you can quickly read an entry with 'sshyp /<entry name>'")
|
||||||
|
elif argument_list[1] == 'version' or argument_list[1] == '-v':
|
||||||
|
print('\nsshyp is a simple, self-hosted, sftp-synchronized password manager\nfor unix(-like) systems (haiku/'
|
||||||
|
'freebsd/linux/termux)\n\nsshyp is a viable alternative to (and compatible with) pass/password-store\n')
|
||||||
|
print(" .. \u001b[38;5;9m♥♥ ♥♥\u001b[0m ..\n .''.''/()\\ \u001b[38;5;13m"
|
||||||
|
"♥♥♥♥♥♥♥\u001b[0m /()\\''.''.\n * : \u001b[38;5;9m♥♥♥♥♥\u001b[0m : *"
|
||||||
|
"\n `..'..' \u001b[38;5;13m♥♥♥\u001b[0m `..'..'\n // \\\\ "
|
||||||
|
"\u001b[38;5;9m♥\u001b[0m // \\\\")
|
||||||
|
print('\u001b[38;5;7;48;5;8m<><><><><><><><><><><><><><><><><><><><><><><><><><><><>\u001b[0m')
|
||||||
|
print('\u001b[38;5;7;48;5;8m/\u001b[38;5;15;48;5;15m '
|
||||||
|
'\u001b[38;5;7;48;5;8m/\u001b[0m')
|
||||||
|
print('\u001b[38;5;7;48;5;8m/\u001b[38;5;15;48;5;15m \u001b[38;5;15;48;5;8msshyp copyright (c) 2021-2022 '
|
||||||
|
'randall winkhart\u001b[38;5;15;48;5;15m \u001b[38;5;7;48;5;8m/\u001b[0m')
|
||||||
|
print('\u001b[38;5;7;48;5;8m/\u001b[38;5;15;48;5;15m '
|
||||||
|
'\u001b[38;5;7;48;5;8m/\u001b[0m')
|
||||||
|
print('\u001b[38;5;7;48;5;8m/\u001b[38;5;15;48;5;15m \u001b[38;5;15;48;5;8mversion 1.1.1'
|
||||||
|
'\u001b[38;5;15;48;5;15m \u001b[38;5;7;48;5;8m/\u001b[0m')
|
||||||
|
print('\u001b[38;5;7;48;5;8m/\u001b[38;5;15;48;5;15m \u001b[38;5;15;48;5;8mthe sheecrets '
|
||||||
|
'update\u001b[38;5;15;48;5;15m \u001b[38;5;7;48;5;8m/\u001b[0m')
|
||||||
|
print('\u001b[38;5;7;48;5;8m/\u001b[38;5;15;48;5;15m '
|
||||||
|
'\u001b[38;5;7;48;5;8m/\u001b[0m')
|
||||||
|
print('\u001b[38;5;7;48;5;8m<><><><><><><><><><><><><><><><><><><><><><><><><><><><>\u001b[0m\n')
|
||||||
|
print('see https://github.com/rwinkhart/sshyp for more information\n')
|
||||||
|
elif argument_list[1] == 'license':
|
||||||
|
print('\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU '
|
||||||
|
'General\nPublic License as published by the Free Software Foundation, either version 3 of the License,'
|
||||||
|
'\nor (at your option) any later version.\n\nThis program is distributed in the hope that it will be '
|
||||||
|
'useful, but WITHOUT ANY WARRANTY;\nwithout even the implied warranty of MERCHANTABILITY or FITNESS FOR A'
|
||||||
|
' PARTICULAR PURPOSE.\nSee the GNU General Public License for more details.'
|
||||||
|
'\n\nhttps://opensource.org/licenses/GPL-3.0\n')
|
||||||
|
elif argument_list[1] == 'add':
|
||||||
|
print('\n\u001b[1musage:\u001b[0m sshyp add [flag [<entry name>]]\u001b[0m\n')
|
||||||
|
print('\u001b[1mflags:\u001b[0m')
|
||||||
|
print('add:')
|
||||||
|
print(' password/-p add a password entry')
|
||||||
|
print(' note/-n add a note entry')
|
||||||
|
print(' folder/-f add a new folder for entries\n')
|
||||||
|
elif argument_list[1] == 'edit':
|
||||||
|
print('\n\u001b[1musage:\u001b[0m sshyp edit [flag [<entry name>]]\u001b[0m\n')
|
||||||
|
print('\u001b[1mflags:\u001b[0m')
|
||||||
|
print('edit:')
|
||||||
|
print(' rename/relocate/-r rename or relocate an entry')
|
||||||
|
print(' username/-u change the username of an entry')
|
||||||
|
print(' password/-p change the password of an entry')
|
||||||
|
print(' url/-l change the url attached to an entry')
|
||||||
|
print(' note/-n change the note attached to an entry\n')
|
||||||
|
elif argument_list[1] == 'copy':
|
||||||
|
print('\n\u001b[1musage:\u001b[0m sshyp copy [flag [<entry name>]]\u001b[0m\n')
|
||||||
|
print('\u001b[1mflags:\u001b[0m')
|
||||||
|
print('copy:')
|
||||||
|
print(' username/-u copy the username of an entry to your clipboard')
|
||||||
|
print(' password/-p copy the password of an entry to your clipboard')
|
||||||
|
print(' url/-l copy the url of an entry to your clipboard')
|
||||||
|
print(' note/-n copy the note of an entry to your clipboard\n')
|
||||||
|
|
||||||
|
|
||||||
|
def no_arg(): # displays a list of entries and gives an option to select one for viewing
|
||||||
|
print("\nfor a list of usable commands, run 'sshyp help'")
|
||||||
|
_entry_name = entry_name_fetch('entry to read: ')
|
||||||
|
if not Path(f"{directory}{_entry_name}.gpg").exists():
|
||||||
|
print(f"\n\u001b[38;5;9merror: entry ({_entry_name}) does not exist\u001b[0m\n")
|
||||||
|
s_exit(1)
|
||||||
|
_shm_folder, _shm_entry = shm_gen()
|
||||||
|
decrypt(directory + _entry_name, _shm_folder, _shm_entry, gpg)
|
||||||
|
entry_reader(f"{tmp_dir}{_shm_folder}/{_shm_entry}")
|
||||||
|
rmtree(f"{tmp_dir}{_shm_folder}")
|
||||||
|
|
||||||
|
|
||||||
|
def read_shortcut(): # shortcut to quickly read an entry
|
||||||
|
if not Path(f"{directory}{argument.replace('/', '', 1)}.gpg").exists():
|
||||||
|
print(f"\n\u001b[38;5;9merror: entry ({argument.replace('/', '', 1)}) does not exist\u001b[0m\n")
|
||||||
|
s_exit(1)
|
||||||
|
_shm_folder, _shm_entry = shm_gen()
|
||||||
|
decrypt(directory + argument.replace('/', '', 1), _shm_folder, _shm_entry, gpg)
|
||||||
|
entry_reader(f"{tmp_dir}{_shm_folder}/{_shm_entry}")
|
||||||
|
rmtree(f"{tmp_dir}{_shm_folder}")
|
||||||
|
|
||||||
|
|
||||||
|
def sync(): # calls sshync to sync changes to the user's server
|
||||||
|
print('\nsyncing entries with the server device...\n')
|
||||||
|
# check for deletions
|
||||||
|
system(f"ssh -i '{path.expanduser('~/.ssh/sshyp')}' -p {port} {username_ssh}@{ip} \"cd /bin; python -c "
|
||||||
|
f"'import sshypRemote; sshypRemote.deletion_check(\"'\"{client_device_name}\"'\")'\"")
|
||||||
|
system(f"scp -pqs -P {port} -i '{path.expanduser('~/.ssh/sshyp')}' {username_ssh}@{ip}:'/home/{username_ssh}"
|
||||||
|
f"/.config/sshyp/deletion_database' {path.expanduser('~/.config/sshyp/')}")
|
||||||
|
try:
|
||||||
|
_deletion_database = open(path.expanduser('~/.config/sshyp/deletion_database')).readlines()
|
||||||
|
except (FileNotFoundError, IndexError):
|
||||||
|
print('\n\u001b[38;5;9merror: the deletion database does not exist or is corrupted\u001b[0m\n')
|
||||||
|
_deletion_database = None
|
||||||
|
s_exit(1)
|
||||||
|
for _file in _deletion_database:
|
||||||
|
if _file[:-1].endswith('/'):
|
||||||
|
try:
|
||||||
|
if silent_sync != 1:
|
||||||
|
print(f"\u001b[38;5;208m{_file[:-1]}\u001b[0m has been sheared, removing...")
|
||||||
|
rmtree(f"{directory}{_file[:-1]}")
|
||||||
|
except FileNotFoundError:
|
||||||
|
if silent_sync != 1:
|
||||||
|
print('folder does not exist locally.')
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
if silent_sync != 1:
|
||||||
|
print(f"\u001b[38;5;208m{_file[:-1]}\u001b[0m has been sheared, removing...")
|
||||||
|
remove(f"{directory}{_file[:-1]}.gpg")
|
||||||
|
except (FileNotFoundError, IsADirectoryError):
|
||||||
|
if silent_sync != 1:
|
||||||
|
print('file does not exist locally.')
|
||||||
|
# check for new folders
|
||||||
|
system(f"ssh -i '{path.expanduser('~/.ssh/sshyp')}' -p {port} {username_ssh}@{ip} \"cd /bin; python -c "
|
||||||
|
f"'import sshypRemote; sshypRemote.folder_check()'\"")
|
||||||
|
system(f"scp -pqs -P {port} -i '{path.expanduser('~/.ssh/sshyp')}' {username_ssh}@{ip}:'/home/{username_ssh}"
|
||||||
|
f"/.config/sshyp/folder_database' {path.expanduser('~/.config/sshyp/')}")
|
||||||
|
try:
|
||||||
|
_folder_database = open(path.expanduser('~/.config/sshyp/folder_database')).readlines()
|
||||||
|
except (FileNotFoundError, IndexError):
|
||||||
|
print('\n\u001b[38;5;9merror: the folder database does not exist or is corrupted\u001b[0m\n')
|
||||||
|
_folder_database = None
|
||||||
|
s_exit(1)
|
||||||
|
for _folder in _folder_database:
|
||||||
|
if Path(f"{path.expanduser('~')}{_folder[:-1]}").is_dir():
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
print(f"\u001b[38;5;2m{_folder.replace('/.local/share/sshyp/', '')[:-1]}/\u001b[0m does not exist locally, "
|
||||||
|
f"creating...")
|
||||||
|
Path(f"{path.expanduser('~')}{_folder[:-1]}").mkdir(0o700, parents=True, exist_ok=True)
|
||||||
|
# set permissions before uploading
|
||||||
|
system('find ' + directory + ' -type d -exec chmod -R 700 {} +')
|
||||||
|
system('find ' + directory + ' -type f -exec chmod -R 600 {} +')
|
||||||
|
sshync.run_profile(path.expanduser('~/.config/sshyp/sshyp.sshync'))
|
||||||
|
|
||||||
|
|
||||||
|
def add_entry(): # adds a new entry
|
||||||
|
_shm_folder, _shm_entry = None, None # sets base-line values to avoid errors
|
||||||
|
if len(argument_list) < 4:
|
||||||
|
_entry_name = entry_name_fetch('name of new entry: ')
|
||||||
|
else:
|
||||||
|
_entry_name = entry_name_fetch(2)
|
||||||
|
if Path(f"{directory}{_entry_name}.gpg").is_file():
|
||||||
|
print(f"\n\u001b[38;5;9merror: entry ({_entry_name}) already exists\u001b[0m\n")
|
||||||
|
s_exit(1)
|
||||||
|
if argument_list[2] == 'note' or argument_list[2] == '-n':
|
||||||
|
_shm_folder, _shm_entry = shm_gen()
|
||||||
|
system(f"{editor} {tmp_dir}{_shm_folder}/{_shm_entry}-n")
|
||||||
|
_notes = open(f"{tmp_dir}{_shm_folder}/{_shm_entry}-n", 'r').read()
|
||||||
|
open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'w').writelines(optimized_edit(['', '', '', _notes], None, -1))
|
||||||
|
elif argument_list[2] == 'password' or argument_list[2] == '-p':
|
||||||
|
_username = str(input('username: '))
|
||||||
|
_password = str(input('password: '))
|
||||||
|
_url = str(input('url: '))
|
||||||
|
_add_note = input('add a note to this entry? (y/N) ')
|
||||||
|
_shm_folder, _shm_entry = shm_gen()
|
||||||
|
if _add_note.lower() == 'y':
|
||||||
|
system(f"{editor} {tmp_dir}{_shm_folder}/{_shm_entry}-n")
|
||||||
|
_notes = open(f"{tmp_dir}{_shm_folder}/{_shm_entry}-n", 'r').read()
|
||||||
|
else:
|
||||||
|
_notes = ''
|
||||||
|
open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'w')\
|
||||||
|
.writelines(optimized_edit([_password, _username, _url, _notes], None, -1))
|
||||||
|
print('\n\u001b[1mentry preview:\u001b[0m')
|
||||||
|
entry_reader(f"{tmp_dir}{_shm_folder}/{_shm_entry}")
|
||||||
|
encrypt(directory + _entry_name, _shm_folder, _shm_entry, gpg, gpg_id)
|
||||||
|
|
||||||
|
|
||||||
|
def add_folder(): # creates a new folder
|
||||||
|
if len(argument_list) < 4:
|
||||||
|
_entry_name = entry_name_fetch('name of new folder: ')
|
||||||
|
else:
|
||||||
|
_entry_name = entry_name_fetch(2)
|
||||||
|
Path(directory + _entry_name).mkdir(0o700)
|
||||||
|
system(f"ssh -i '{path.expanduser('~/.ssh/sshyp')}' -p {port} {username_ssh}@{ip} \"mkdir -p '{directory_ssh}"
|
||||||
|
f"{_entry_name}'\"")
|
||||||
|
|
||||||
|
|
||||||
|
def rename(): # renames an entry or folder
|
||||||
|
if argument == 'edit rename' or argument == 'edit relocate' or argument == 'edit -r':
|
||||||
|
_entry_name = entry_name_fetch('entry/folder to rename/relocate: ')
|
||||||
|
else:
|
||||||
|
_entry_name = entry_name_fetch(2)
|
||||||
|
if not Path(f"{directory}{_entry_name}.gpg").is_file() and not Path(f"{directory}{_entry_name}").is_dir():
|
||||||
|
print(f"\n\u001b[38;5;9merror: entry ({_entry_name}) does not exist\u001b[0m\n")
|
||||||
|
s_exit(1)
|
||||||
|
_new_name = str(input('new name: '))
|
||||||
|
print(f"{directory}{_new_name}")
|
||||||
|
if Path(f"{directory}{_new_name}.gpg").is_file() or Path(f"{directory}{_new_name}").is_dir():
|
||||||
|
print(f"\n\u001b[38;5;9merror: ({_new_name}) already exists\u001b[0m\n")
|
||||||
|
s_exit(1)
|
||||||
|
if _entry_name.endswith('/'):
|
||||||
|
move(f"{directory}{_entry_name}", f"{directory}{_new_name}")
|
||||||
|
system(f"ssh -i '{path.expanduser('~/.ssh/sshyp')}' -p {port} {username_ssh}@{ip} \"mkdir -p '{directory_ssh}"
|
||||||
|
f"{_new_name}'\"")
|
||||||
|
else:
|
||||||
|
move(f"{directory}{_entry_name}.gpg", f"{directory}{_new_name}.gpg")
|
||||||
|
system(f"ssh -i '{path.expanduser('~/.ssh/sshyp')}' -p {port} {username_ssh}@{ip} \"cd /bin; python -c "
|
||||||
|
f"'import sshypRemote; sshypRemote.delete(\"'\"{_entry_name}\"'\")'\"")
|
||||||
|
|
||||||
|
|
||||||
|
def edit(): # edits the contents of an entry
|
||||||
|
_shm_folder, _shm_entry, _detail, _edit_line = None, None, None, None # sets values to avoid PEP8 warnings
|
||||||
|
if len(argument_list) < 4:
|
||||||
|
_entry_name = entry_name_fetch('entry to edit: ')
|
||||||
|
else:
|
||||||
|
_entry_name = entry_name_fetch(2)
|
||||||
|
if not Path(f"{directory}{_entry_name}.gpg").is_file():
|
||||||
|
print(f"\n\u001b[38;5;9merror: entry ({_entry_name}) does not exist\u001b[0m\n")
|
||||||
|
s_exit(1)
|
||||||
|
_shm_folder, _shm_entry = shm_gen()
|
||||||
|
decrypt(directory + _entry_name, _shm_folder, _shm_entry, gpg)
|
||||||
|
if argument_list[2] == 'username' or argument_list[2] == '-u':
|
||||||
|
_detail, _edit_line = str(input('username: ')), 1
|
||||||
|
elif argument_list[2] == 'password' or argument_list[2] == '-p':
|
||||||
|
_detail, _edit_line = str(input('password: ')), 0
|
||||||
|
elif argument_list[2] == 'url' or argument_list[2] == '-l':
|
||||||
|
_detail, _edit_line = str(input('url: ')), 2
|
||||||
|
if argument_list[2] == 'note' or argument_list[2] == '-n':
|
||||||
|
_edit_line = 2
|
||||||
|
_new_lines = optimized_edit(edit_note(_shm_folder, _shm_entry,
|
||||||
|
open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'r').readlines()), None, -1)
|
||||||
|
else:
|
||||||
|
_new_lines = optimized_edit(open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'r').readlines(), _detail, _edit_line)
|
||||||
|
open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'w').writelines(_new_lines)
|
||||||
|
remove(f"{directory}{_entry_name}.gpg")
|
||||||
|
print('\n\u001b[1mentry preview:\u001b[0m')
|
||||||
|
entry_reader(f"{tmp_dir}{_shm_folder}/{_shm_entry}")
|
||||||
|
encrypt(directory + _entry_name, _shm_folder, _shm_entry, gpg, gpg_id)
|
||||||
|
|
||||||
|
|
||||||
|
def gen(): # generates a password for a new or an existing entry
|
||||||
|
_username, _url, _notes = None, None, None # sets base-line values to avoid errors
|
||||||
|
if argument == 'gen update' or argument == 'gen -u' or argument == 'gen':
|
||||||
|
_entry_name = entry_name_fetch('name of entry: ')
|
||||||
|
elif argument_list[2] == 'update' or argument_list[2] == '-u':
|
||||||
|
_entry_name = entry_name_fetch(2)
|
||||||
|
if not Path(f"{directory}{_entry_name}.gpg").is_file():
|
||||||
|
print(f"\n\u001b[38;5;9merror: entry ({_entry_name}) does not exist\u001b[0m\n")
|
||||||
|
s_exit(1)
|
||||||
|
else:
|
||||||
|
_entry_name = entry_name_fetch(1)
|
||||||
|
if len(argument_list) == 2 or (not argument_list[2] == 'update' and not argument_list[2] == '-u'):
|
||||||
|
if Path(f"{directory}{_entry_name}.gpg").is_file():
|
||||||
|
print(f"\n\u001b[38;5;9merror: entry ({_entry_name}) already exists\u001b[0m\n")
|
||||||
|
s_exit(1)
|
||||||
|
_username = str(input('username: '))
|
||||||
|
_password = pass_gen()
|
||||||
|
_url = str(input('url: '))
|
||||||
|
_add_note = input('add a note to this entry? (y/N) ')
|
||||||
|
_shm_folder, _shm_entry = shm_gen()
|
||||||
|
if _add_note.lower() == 'y':
|
||||||
|
system(f"{editor} {tmp_dir}{_shm_folder}/{_shm_entry}-n")
|
||||||
|
_notes = open(f"{tmp_dir}{_shm_folder}/{_shm_entry}-n", 'r').read()
|
||||||
|
else:
|
||||||
|
_notes = ''
|
||||||
|
open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'w')\
|
||||||
|
.writelines(optimized_edit([_password, _username, _url, _notes], None, -1))
|
||||||
|
else:
|
||||||
|
_shm_folder, _shm_entry = shm_gen()
|
||||||
|
decrypt(directory + _entry_name, _shm_folder, _shm_entry, gpg)
|
||||||
|
_new_lines = optimized_edit(open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'r').readlines(), pass_gen(), 0)
|
||||||
|
open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'w').writelines(_new_lines)
|
||||||
|
remove(f"{directory}{_entry_name}.gpg")
|
||||||
|
print('\n\u001b[1mentry preview:\u001b[0m')
|
||||||
|
entry_reader(f"{tmp_dir}{_shm_folder}/{_shm_entry}")
|
||||||
|
encrypt(directory + _entry_name, _shm_folder, _shm_entry, gpg, gpg_id)
|
||||||
|
|
||||||
|
|
||||||
|
def copy_data(): # copies a specified field of an entry to the clipboard
|
||||||
|
if len(argument_list) < 4:
|
||||||
|
_entry_name = entry_name_fetch('entry to copy: ')
|
||||||
|
else:
|
||||||
|
_entry_name = entry_name_fetch(2)
|
||||||
|
if not Path(f"{directory}{_entry_name}.gpg").is_file():
|
||||||
|
print(f"\n\u001b[38;5;9merror: entry ({_entry_name}) does not exist\u001b[0m\n")
|
||||||
|
s_exit(1)
|
||||||
|
_shm_folder, _shm_entry = shm_gen()
|
||||||
|
decrypt(directory + _entry_name, _shm_folder, _shm_entry, gpg)
|
||||||
|
_copy_line = open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'r').readlines()
|
||||||
|
if uname()[0] == 'Haiku': # Haiku clipboard detection
|
||||||
|
if argument_list[2] == 'username' or argument_list[2] == '-u':
|
||||||
|
system('clipboard -c ' + "'" + _copy_line[1].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
|
elif argument_list[2] == 'password' or argument_list[2] == '-p':
|
||||||
|
system('clipboard -c ' + "'" + _copy_line[0].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
|
elif argument_list[2] == 'url' or argument_list[2] == '-l':
|
||||||
|
system('clipboard -c ' + "'" + _copy_line[2].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
|
elif argument_list[2] == 'note' or argument_list[2] == '-n':
|
||||||
|
system('clipboard -c ' + "'" + _copy_line[3].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
|
Popen('sleep 30; clipboard -r', shell=True, close_fds=True)
|
||||||
|
elif Path("/data/data/com.termux").exists(): # Termux (Android) clipboard detection
|
||||||
|
if argument_list[2] == 'username' or argument_list[2] == '-u':
|
||||||
|
system('termux-clipboard-set ' + "'" + _copy_line[1].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
|
elif argument_list[2] == 'password' or argument_list[2] == '-p':
|
||||||
|
system('termux-clipboard-set ' + "'" + _copy_line[0].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
|
elif argument_list[2] == 'url' or argument_list[2] == '-l':
|
||||||
|
system('termux-clipboard-set ' + "'" + _copy_line[2].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
|
elif argument_list[2] == 'note' or argument_list[2] == '-n':
|
||||||
|
system('termux-clipboard-set ' + "'" + _copy_line[3].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
|
Popen("sleep 30; termux-clipboard-set ''", shell=True, close_fds=True)
|
||||||
|
elif environ.get('WAYLAND_DISPLAY') == 'wayland-0': # Wayland clipboard detection
|
||||||
|
if argument_list[2] == 'username' or argument_list[2] == '-u':
|
||||||
|
system('wl-copy ' + "'" + _copy_line[1].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
|
elif argument_list[2] == 'password' or argument_list[2] == '-p':
|
||||||
|
system('wl-copy ' + "'" + _copy_line[0].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
|
elif argument_list[2] == 'url' or argument_list[2] == '-l':
|
||||||
|
system('wl-copy ' + "'" + _copy_line[2].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
|
elif argument_list[2] == 'note' or argument_list[2] == '-n':
|
||||||
|
system('wl-copy ' + "'" + _copy_line[3].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
|
Popen('sleep 30; wl-copy -c', shell=True, close_fds=True)
|
||||||
|
else: # X11 clipboard detection
|
||||||
|
if argument_list[2] == 'username' or argument_list[2] == '-u':
|
||||||
|
system('echo -n ' + "'" + _copy_line[1].replace('\n', '').replace("'", "'\\''") + "'" + ' | xclip -sel c')
|
||||||
|
elif argument_list[2] == 'password' or argument_list[2] == '-p':
|
||||||
|
system('echo -n ' + "'" + _copy_line[0].replace('\n', '').replace("'", "'\\''") + "'" + ' | xclip -sel c')
|
||||||
|
elif argument_list[2] == 'url' or argument_list[2] == '-l':
|
||||||
|
system('echo -n ' + "'" + _copy_line[2].replace('\n', '').replace("'", "'\\''") + "'" + ' | xclip -sel c')
|
||||||
|
elif argument_list[2] == 'note' or argument_list[2] == '-n':
|
||||||
|
system('echo -n ' + "'" + _copy_line[3].replace('\n', '').replace("'", "'\\''") + "'" + ' | xclip -sel c')
|
||||||
|
Popen("sleep 30; echo -n '' | xclip -sel c", shell=True, close_fds=True)
|
||||||
|
rmtree(f"{tmp_dir}{_shm_folder}")
|
||||||
|
|
||||||
|
|
||||||
|
def remove_data(): # deletes an entry from the server and flags it for local deletion on sync
|
||||||
|
if argument == 'shear' or argument == '-rm':
|
||||||
|
_entry_name = entry_name_fetch('entry/folder to shear: ')
|
||||||
|
else:
|
||||||
|
_entry_name = entry_name_fetch(1)
|
||||||
|
decrypt(path.expanduser('~/.config/sshyp/lock.gpg'), 0, 0, gpg)
|
||||||
|
system(f"ssh -i '{path.expanduser('~/.ssh/sshyp')}' -p {port} {username_ssh}@{ip} \"cd /bin; python -c "
|
||||||
|
f"'import sshypRemote; sshypRemote.delete(\"'\"{_entry_name}\"'\")'\"")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
silent_sync, ssh_error = 0, 0
|
||||||
|
# retrieve typed argument
|
||||||
|
argument_list = argv
|
||||||
|
argument = ' '.join(argument_list[1:])
|
||||||
|
if uname()[0] == 'Haiku': # set proper gpg command for OS
|
||||||
|
gpg = 'gpg --pinentry-mode loopback'
|
||||||
|
else:
|
||||||
|
gpg = 'gpg'
|
||||||
|
|
||||||
|
# import saved userdata
|
||||||
|
if argument != 'tweak':
|
||||||
|
device_type = ''
|
||||||
|
tmp_dir = path.expanduser('~/.config/sshyp/tmp/')
|
||||||
|
try:
|
||||||
|
device_type = open(path.expanduser('~/.config/sshyp/sshyp-device')).read().strip()
|
||||||
|
if device_type == 'c':
|
||||||
|
ssh_info = sshync.get_profile(path.expanduser('~/.config/sshyp/sshyp.sshync'))
|
||||||
|
username_ssh = ssh_info[0].replace('\n', '')
|
||||||
|
ip = ssh_info[1].replace('\n', '')
|
||||||
|
port = ssh_info[2].replace('\n', '')
|
||||||
|
directory = str(ssh_info[3].replace('\n', ''))
|
||||||
|
directory_ssh = str(ssh_info[4].replace('\n', ''))
|
||||||
|
client_device_name = listdir(path.expanduser('~/.config/sshyp/devices'))[0]
|
||||||
|
sshyp_data = open(path.expanduser('~/.config/sshyp/sshyp-data')).readlines()
|
||||||
|
gpg_id = sshyp_data[0].replace('\n', '')
|
||||||
|
editor = sshyp_data[1].replace('\n', '')
|
||||||
|
ssh_error = int(open(path.expanduser('~/.config/sshyp/ssh-error')).read().strip())
|
||||||
|
if ssh_error != 0:
|
||||||
|
ssh_error = copy_name_check(port, username_ssh, ip, client_device_name)
|
||||||
|
else:
|
||||||
|
print('running as server, option disabled')
|
||||||
|
s_exit(0)
|
||||||
|
except (FileNotFoundError, IndexError):
|
||||||
|
if device_type.lower() != 's':
|
||||||
|
print('\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
|
||||||
|
print("not all necessary configuration files are present - please run 'sshyp tweak'")
|
||||||
|
print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n')
|
||||||
|
s_exit(1)
|
||||||
|
else:
|
||||||
|
tweak()
|
||||||
|
s_exit(0)
|
||||||
|
|
||||||
|
# run function based on arguments
|
||||||
|
if argument.startswith('/'):
|
||||||
|
read_shortcut()
|
||||||
|
elif argument == '':
|
||||||
|
no_arg()
|
||||||
|
elif argument == 'help' or argument == '--help' or argument == '-h' or argument == 'license' or argument \
|
||||||
|
== 'version' or argument == '-v':
|
||||||
|
print_info()
|
||||||
|
elif argument_list[1] == 'add':
|
||||||
|
if len(argument_list) == 2:
|
||||||
|
print_info()
|
||||||
|
elif argument_list[2] == 'note' or argument_list[2] == '-n' or argument_list[2] == 'password' or \
|
||||||
|
argument_list[2] == '-p':
|
||||||
|
add_entry()
|
||||||
|
elif argument_list[2] == 'folder' or argument_list[2] == '-f':
|
||||||
|
add_folder()
|
||||||
|
else:
|
||||||
|
print_info()
|
||||||
|
s_exit(0)
|
||||||
|
elif argument_list[1] == 'edit':
|
||||||
|
if len(argument_list) == 2:
|
||||||
|
print_info()
|
||||||
|
elif argument_list[2] == 'rename' or argument_list[2] == 'relocate' or argument_list[2] == '-r':
|
||||||
|
silent_sync = 1
|
||||||
|
rename()
|
||||||
|
elif argument_list[2] == 'username' or argument_list[2] == '-u' or argument_list[2] == 'password' or \
|
||||||
|
argument_list[2] == '-p' or argument_list[2] == 'url' or argument_list[2] == '-l' or \
|
||||||
|
argument_list[2] == 'note' or argument_list[2] == '-n':
|
||||||
|
edit()
|
||||||
|
else:
|
||||||
|
print_info()
|
||||||
|
s_exit(0)
|
||||||
|
elif argument_list[1] == 'gen':
|
||||||
|
gen()
|
||||||
|
elif argument_list[1] == 'copy':
|
||||||
|
if len(argument_list) == 2:
|
||||||
|
print_info()
|
||||||
|
elif argument_list[2] == 'username' or argument_list[2] == '-u' or argument_list[2] == 'password' or \
|
||||||
|
argument_list[2] == '-p' or argument_list[2] == 'url' or argument_list[2] == '-l' or \
|
||||||
|
argument_list[2] == 'note' or argument_list[2] == '-n':
|
||||||
|
copy_data()
|
||||||
|
else:
|
||||||
|
print_info()
|
||||||
|
elif argument_list[1] == 'shear' or argument_list[1] == '-rm':
|
||||||
|
remove_data()
|
||||||
|
elif argument_list[1] != 'sync' and argument_list[1] != '-s':
|
||||||
|
print(f"\n\u001b[38;5;9merror: invalid argument - run 'sshyp help' to list usable commands\u001b[0m\n")
|
||||||
|
s_exit(1)
|
||||||
|
|
||||||
|
# sync if any changes were made
|
||||||
|
if len(argument_list) > 1 and ssh_error == 0 and \
|
||||||
|
((argument_list[1] == 'sync' or argument_list[1] == '-s' or argument_list[1] == 'gen' or
|
||||||
|
argument_list[1] == 'shear' or argument_list[1] == '-rm') or ((argument_list[1] == 'add'
|
||||||
|
or argument_list[1] == 'edit')
|
||||||
|
and len(argument_list) > 2)):
|
||||||
|
sync()
|
||||||
|
|
||||||
|
s_exit(0)
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print('\n')
|
||||||
|
s_exit(0)
|
||||||
Executable
+45
@@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/python3
|
||||||
|
|
||||||
|
# external modules
|
||||||
|
|
||||||
|
from os import listdir, remove, walk
|
||||||
|
from os.path import expanduser
|
||||||
|
from shutil import rmtree
|
||||||
|
|
||||||
|
|
||||||
|
# utility functions
|
||||||
|
|
||||||
|
def delete(_file_path): # deletes an entry or folder, should be run remotely via ssh
|
||||||
|
if _file_path.endswith('/'):
|
||||||
|
try:
|
||||||
|
rmtree(f"{expanduser('~/.local/share/sshyp/')}{_file_path}")
|
||||||
|
except FileNotFoundError:
|
||||||
|
print('folder does not exist remotely')
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
remove(f"{expanduser('~/.local/share/sshyp/')}{_file_path}.gpg")
|
||||||
|
except FileNotFoundError:
|
||||||
|
print('file does not exist remotely')
|
||||||
|
for _device_name in listdir(expanduser('~/.config/sshyp/devices')):
|
||||||
|
open(f"{expanduser('~/.config/sshyp/deleted/')}{_file_path.replace('/', '@')}^&*{_device_name}", 'w')
|
||||||
|
|
||||||
|
|
||||||
|
def deletion_check(_client_device_name): # creates a list of entries and folders to be deleted from a local machine
|
||||||
|
open(expanduser('~/.config/sshyp/deletion_database'), 'w').write('')
|
||||||
|
for _file in listdir(expanduser('~/.config/sshyp/deleted')):
|
||||||
|
_file_path = _file.replace('@', '/').split('^&*')[0]
|
||||||
|
_device = _file.split('^&*')[1]
|
||||||
|
if _device == _client_device_name:
|
||||||
|
try:
|
||||||
|
remove(f"{expanduser('~/.config/sshyp/deleted/')}{_file}")
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
open(expanduser('~/.config/sshyp/deletion_database'), 'a').write(_file_path + '\n')
|
||||||
|
|
||||||
|
|
||||||
|
def folder_check(): # creates a list of folders to be compared with those of a local machine
|
||||||
|
open(expanduser('~/.config/sshyp/folder_database'), 'w').write('')
|
||||||
|
for _root, _directories, _files in walk(expanduser('~/.local/share/sshyp')):
|
||||||
|
for _dir in _directories:
|
||||||
|
open(expanduser('~/.config/sshyp/folder_database'), 'a')\
|
||||||
|
.write(f"{_root.replace(expanduser('~'), '')}/{_dir}\n")
|
||||||
+725
-2
@@ -1,3 +1,728 @@
|
|||||||
|
sshyp v1.1.1
|
||||||
|
|
||||||
|
the sheecrets update - patch one
|
||||||
|
|
||||||
|
this is a polish/bug fix release that makes tweaks to the entry format (without breaking compatibility)
|
||||||
|
|
||||||
|
compatibility-breaking changes:
|
||||||
|
|
||||||
|
- none; the entry format tweaks are backward compatible with sshyp v1.0.0+
|
||||||
|
^ the new format is slightly more efficient in terms of storage space
|
||||||
|
^ if you would like to upgrade to it, run this script (after updating to v1.1.1):
|
||||||
|
https://raw.githubusercontent.com/rwinkhart/sshyp-labs/main/extra/conversion-scripts/sshyp-refresh-1.1.1%2B.py
|
||||||
|
|
||||||
|
user-facing features:
|
||||||
|
|
||||||
|
- entries (when editing or adding) are now run through the new optimized_edit() function to strip trailing new lines
|
||||||
|
and ensure the format of the entries is fully compatible with all of sshyp's functions
|
||||||
|
|
||||||
|
fixes:
|
||||||
|
|
||||||
|
- when adding a note to an entry, there is no longer a chance the first note line will be added as a url
|
||||||
|
if the entry is using an older format/pass format
|
||||||
|
- the gpg auto-generation file temporarily created by sshyp no longer includes extra spaces
|
||||||
|
^ seems to serve no functional purpose - fixed for the sake of polish
|
||||||
|
|
||||||
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
|
sshyp v1.1.0
|
||||||
|
|
||||||
|
the sheecrets update
|
||||||
|
|
||||||
|
the main focus of this release was adding extension support (particularly for sshyp-mfa)
|
||||||
|
and cleaning up the configuration experience
|
||||||
|
|
||||||
|
compatibility-breaking changes:
|
||||||
|
|
||||||
|
- the entry directory has been moved from ~/.password-pasture to ~/.local/share/sshyp
|
||||||
|
as a means of complying with the XDG base directory spec
|
||||||
|
^ this requires the user to move their entry directory to the new location manually
|
||||||
|
^ if this is not done, sshyp will not be able to find entries made prior to v1.1.0
|
||||||
|
- due to a new configuration option (preferred text editor), 'sshyp tweak' must be run after updating
|
||||||
|
|
||||||
|
user-facing features:
|
||||||
|
|
||||||
|
- extension support
|
||||||
|
^ some of sshyp's critical functions can now be imported into other programs to extend
|
||||||
|
upon sshyp's functionality
|
||||||
|
^ the first usecase of this is sshyp-mfa, which can be found at https://github.com/rwinkhart/sshyp-labs
|
||||||
|
- a new configuration experience
|
||||||
|
^ the 'sshyp tweak' menu has been made much more readable, and now the automatically generated
|
||||||
|
gpg key has its id automatically input, making the process easier for the user
|
||||||
|
- customizable text editor
|
||||||
|
^ the text editor used for editing notes can now be set to any editor preferred by the user
|
||||||
|
^ this means that nano was dropped as a dependency
|
||||||
|
|
||||||
|
fixes:
|
||||||
|
|
||||||
|
- to avoid exceptions on server devices, all arguments (apart from 'tweak') have been disabled on servers
|
||||||
|
- fixed entry readout not printing blank lines between fields under certain conditions
|
||||||
|
- various optimizations
|
||||||
|
|
||||||
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
|
sshyp v1.0.1
|
||||||
|
|
||||||
|
The Polished Trotters Update - Patch 1
|
||||||
|
|
||||||
|
This is a hotfix for the Haiku decryption bug.
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
- subprocess.Popen has been replaced with subprocess.run where applicable
|
||||||
|
- stdout is no longer captured with any subprocess.Popen or subprocess.run usages
|
||||||
|
^ this fixes decryption on Haiku
|
||||||
|
|
||||||
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
|
sshyp v1.0.0
|
||||||
|
|
||||||
|
The Polished Trotters Update
|
||||||
|
|
||||||
|
This release brings 'sshyp' in line with the original goals of the project.
|
||||||
|
As such, it is being crowned "v1.0.0", and is considered a stable base for future expansions.
|
||||||
|
|
||||||
|
Features:
|
||||||
|
|
||||||
|
- sshyp has been modified to run on Haiku, an open-source re-implementation of BeOS
|
||||||
|
^ new package formats have been added for Haiku, FreeBSD, and Fedora Linux
|
||||||
|
- the entry format has been changed to support entries created in pass/password-store
|
||||||
|
^ this change requires existing entry libraries to be converted - see the sshyp v1.0.0 release page on GitHub for a conversion script
|
||||||
|
- majorly overhauled visual experience for sshyp
|
||||||
|
^ this includes a new entry list, a new entry readout, colored output, ascii art, and more!
|
||||||
|
- entries can now optionally be passed as arguments, directly
|
||||||
|
^ as opposed to the user being prompted for an entry name after running a command
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
- corrected outdated licensing and copyright information
|
||||||
|
- 'if __name__=="__main__":' convention is now used
|
||||||
|
- help screens have been overhauled
|
||||||
|
- improved password generator to guarantee more secure results
|
||||||
|
- fixed errors when trying to sync with a multi-word entry on the server
|
||||||
|
- sshync now uses 'scp' (via the sftp protocol), rather than 'sftp'
|
||||||
|
- rename function now properly allows for renaming folders
|
||||||
|
- renaming an entry/folder will now properly delete the old entry/folder from the server
|
||||||
|
- entry previews at the time of entry creation/editing no longer require entering the gpg password more times than necessary
|
||||||
|
- entries will no longer be overwritten if attempting to create a new entry that uses an already existing name
|
||||||
|
- the clipboard now automatically clears after 30 seconds
|
||||||
|
- sshyp server no longer needs to create copies of its libraries in ~/
|
||||||
|
- added more and improved existing exceptions
|
||||||
|
- the lock file is now decrypted to /dev/null
|
||||||
|
- ...and lots of minor (under the hood) changes!
|
||||||
|
|
||||||
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
|
sshyp 2022.02.16.fr4.7
|
||||||
|
|
||||||
|
The High-Tech Shears Update - Patch 7
|
||||||
|
|
||||||
|
This release enables recursive folder syncing.
|
||||||
|
|
||||||
|
Note: Upgrading from releases older than fr4.7 requires the configuration ("sshyp tweak") to be re-done, as the configuration process has changed.
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
- re-wrote folder checking function to fetch subdirectories recursively
|
||||||
|
- added in user-facing messages for when folders are being synced or entries are being removed
|
||||||
|
- fixed a typo preventing folder syncing from working (actually tested this time)
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next major update (fr5, The sshyp Doing a Split Update):
|
||||||
|
|
||||||
|
sshyp:
|
||||||
|
- sshyp has recieved a major visual overhaul
|
||||||
|
^ this includes the new file list and thematic text art
|
||||||
|
|
||||||
|
sshync:
|
||||||
|
- sshync has been split into a separate package and now has standalone functionality as a backup/syncing utility
|
||||||
|
^ more details will be available in the sshync repo, once it is created
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next, next major update (fr6, The Farmer Shearing the sshyp Update):
|
||||||
|
|
||||||
|
- imporove password generator to guarantee more secure results
|
||||||
|
- enforce permissions on the server-side
|
||||||
|
- allow for copying entire notes (not just first line)
|
||||||
|
- ability to pass entries as arguments for more functions
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Backlog:
|
||||||
|
|
||||||
|
- create separate gui frontend targetting mobile and desktop Linux
|
||||||
|
- auto-completion on tab (currently unsure of best way to make this work)
|
||||||
|
|
||||||
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
|
sshyp 2022.02.16.fr4.6
|
||||||
|
|
||||||
|
The High-Tech Shears Update - Patch 6
|
||||||
|
|
||||||
|
This release addresses a critical typo.
|
||||||
|
|
||||||
|
Note: Upgrading from releases older than fr4.6 requires the configuration ("sshyp tweak") to be re-done, as the configuration process has changed.
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
- corrected a typo error causing folder syncing issues
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next major update (fr5, The sshyp Doing a Split Update):
|
||||||
|
|
||||||
|
sshyp:
|
||||||
|
- sshyp has recieved a major visual overhaul
|
||||||
|
^ this includes the new file list and thematic text art
|
||||||
|
|
||||||
|
sshync:
|
||||||
|
- sshync has been split into a separate package and now has standalone functionality as a backup/syncing utility
|
||||||
|
^ more details will be available in the sshync repo, once it is created
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next, next major update (fr6, The Farmer Shearing the sshyp Update):
|
||||||
|
|
||||||
|
- when syncing, a check is made to see if any folders are not on all devices - if the check comes back true, it is corrected (in sshyp)
|
||||||
|
- imporove password generator to guarantee more secure results
|
||||||
|
- enforce permissions on the server-side
|
||||||
|
- allow for copying entire notes (not just first line)
|
||||||
|
- ability to pass entries as arguments for more functions
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Backlog:
|
||||||
|
|
||||||
|
- create separate gui frontend targetting mobile and desktop Linux
|
||||||
|
- auto-completion on tab (currently unsure of best way to make this work)
|
||||||
|
|
||||||
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
|
sshyp 2022.02.16.fr4.5
|
||||||
|
|
||||||
|
The High-Tech Shears Update - Patch 5
|
||||||
|
|
||||||
|
This release addresses a critical syntax error.
|
||||||
|
|
||||||
|
Note: Upgrading from releases older than fr4.5 requires the configuration ("sshyp tweak") to be re-done, as the configuration process has changed.
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
- corrected a syntax error causing critical functionality issues
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next major update (fr5, The sshyp Doing a Split Update):
|
||||||
|
|
||||||
|
sshyp:
|
||||||
|
- sshyp has recieved a major visual overhaul
|
||||||
|
^ this includes the new file list and thematic text art
|
||||||
|
|
||||||
|
sshync:
|
||||||
|
- sshync has been split into a separate package and now has standalone functionality as a backup/syncing utility
|
||||||
|
^ more details will be available in the sshync repo, once it is created
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next, next major update (fr6, The Farmer Shearing the sshyp Update):
|
||||||
|
|
||||||
|
- when syncing, a check is made to see if any folders are not on all devices - if the check comes back true, it is corrected (in sshyp)
|
||||||
|
- imporove password generator to guarantee more secure results
|
||||||
|
- enforce permissions on the server-side
|
||||||
|
- allow for copying entire notes (not just first line)
|
||||||
|
- ability to pass entries as arguments for more functions
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Backlog:
|
||||||
|
|
||||||
|
- create separate gui frontend targetting mobile and desktop Linux
|
||||||
|
- auto-completion on tab (currently unsure of best way to make this work)
|
||||||
|
|
||||||
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
|
sshyp 2022.02.16.fr4.4
|
||||||
|
|
||||||
|
The High-Tech Shears Update - Patch 4
|
||||||
|
|
||||||
|
This release automatically generates user-created folders on new client devices.
|
||||||
|
|
||||||
|
Note: Upgrading to releases in the fr4 series requires the configuration ("sshyp tweak") to be re-done, as a device name now must be set (for multi-client deletion). Even upgrading from fr4.3 to fr4.4 will require re-running "sshyp tweak" due to file name changes.
|
||||||
|
|
||||||
|
Features:
|
||||||
|
|
||||||
|
- implemented proper folder syncing for new clients and clients missing folders that exist server-side
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
- old device names are now automatically deleted (locally) when running "sshyp tweak", to prevent conflicts
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next major update (fr5, The sshyp Doing a Split Update):
|
||||||
|
|
||||||
|
sshyp:
|
||||||
|
- sshyp has recieved a major visual overhaul
|
||||||
|
^ this includes the new file list and thematic text art
|
||||||
|
|
||||||
|
sshync:
|
||||||
|
- sshync has been split into a separate package and now has standalone functionality as a backup/syncing utility
|
||||||
|
^ more details will be available in the sshync repo, once it is created
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next, next major update (fr6, The Farmer Shearing the sshyp Update):
|
||||||
|
|
||||||
|
- when syncing, a check is made to see if any folders are not on all devices - if the check comes back true, it is corrected (in sshyp)
|
||||||
|
- imporove password generator to guarantee more secure results
|
||||||
|
- enforce permissions on the server-side
|
||||||
|
- allow for copying entire notes (not just first line)
|
||||||
|
- ability to pass entries as arguments for more functions
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Backlog:
|
||||||
|
|
||||||
|
- create separate gui frontend targetting mobile and desktop Linux
|
||||||
|
- auto-completion on tab (currently unsure of best way to make this work)
|
||||||
|
|
||||||
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
|
sshyp 2022.02.16.fr4.3
|
||||||
|
|
||||||
|
The High-Tech Shears Update - Patch 3
|
||||||
|
|
||||||
|
This release addresses a bug with local entry deletion.
|
||||||
|
|
||||||
|
Note: Upgrading to releases in the fr4 series requires the configuration ("sshyp tweak") to be re-done, as a device name now must be set (for multi-client deletion).
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
- fixed an issue where entries could not be deleted locally
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next major update (fr5, The sshyp Doing a Split Update):
|
||||||
|
|
||||||
|
sshyp:
|
||||||
|
- sshyp has recieved a major visual overhaul
|
||||||
|
^ this includes the new file list and thematic text art
|
||||||
|
|
||||||
|
sshync:
|
||||||
|
- sshync has been split into a separate package and now has standalone functionality as a backup/syncing utility
|
||||||
|
^ more details will be available in the sshync repo, once it is created
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next, next major update (fr6, The Farmer Shearing the sshyp Update):
|
||||||
|
|
||||||
|
- when syncing, a check is made to see if any folders are not on all devices - if the check comes back true, it is corrected (in sshyp)
|
||||||
|
- imporove password generator to guarantee more secure results
|
||||||
|
- enforce permissions on the server-side
|
||||||
|
- allow for copying entire notes (not just first line)
|
||||||
|
- ability to pass entries as arguments for more functions
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Backlog:
|
||||||
|
|
||||||
|
- create separate gui frontend targetting mobile and desktop Linux
|
||||||
|
- auto-completion on tab (currently unsure of best way to make this work)
|
||||||
|
|
||||||
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
|
sshyp 2022.02.16.fr4.2
|
||||||
|
|
||||||
|
The High-Tech Shears Update - Patch 2
|
||||||
|
|
||||||
|
This release re-addresses a bug with local folder deletion.
|
||||||
|
|
||||||
|
Note: Upgrading to releases in the fr4 series requires the configuration ("sshyp tweak") to be re-done, as a device name now must be set (for multi-client deletion).
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
- fixed an issue where folders could not be deleted locally (actually, this time)
|
||||||
|
- properly handled an exception for when the user forgets a following '/' when attempting to delete a folder
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next major update (fr5, The sshyp Doing a Split Update):
|
||||||
|
|
||||||
|
sshyp:
|
||||||
|
- sshyp has recieved a major visual overhaul
|
||||||
|
^ this includes the new file list and thematic text art
|
||||||
|
|
||||||
|
sshync:
|
||||||
|
- sshync has been split into a separate package and now has standalone functionality as a backup/syncing utility
|
||||||
|
^ more details will be available in the sshync repo, once it is created
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next, next major update (fr6, The Farmer Shearing the sshyp Update):
|
||||||
|
|
||||||
|
- when syncing, a check is made to see if any folders are not on all devices - if the check comes back true, it is corrected (in sshyp)
|
||||||
|
- imporove password generator to guarantee more secure results
|
||||||
|
- enforce permissions on the server-side
|
||||||
|
- allow for copying entire notes (not just first line)
|
||||||
|
- ability to pass entries as arguments for more functions
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Backlog:
|
||||||
|
|
||||||
|
- create separate gui frontend targetting mobile and desktop Linux
|
||||||
|
- auto-completion on tab (currently unsure of best way to make this work)
|
||||||
|
|
||||||
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
|
sshyp 2022.02.16.fr4.1
|
||||||
|
|
||||||
|
The High-Tech Shears Update - Patch 1
|
||||||
|
|
||||||
|
This release addresses a bug with local folder deletion.
|
||||||
|
|
||||||
|
Note: Upgrading to releases in the fr4 series requires the configuration ("sshyp tweak") to be re-done, as a device name now must be set (for multi-client deletion).
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
- fixed an issue where folders could not be deleted locally
|
||||||
|
- optimized deletion flags
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next major update (fr5, The sshyp Doing a Split Update):
|
||||||
|
|
||||||
|
sshyp:
|
||||||
|
- sshyp has recieved a major visual overhaul
|
||||||
|
^ this includes the new file list and thematic text art
|
||||||
|
|
||||||
|
sshync:
|
||||||
|
- sshync has been split into a separate package and now has standalone functionality as a backup/syncing utility
|
||||||
|
^ more details will be available in the sshync repo, once it is created
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next, next major update (fr6, The Farmer Shearing the sshyp Update):
|
||||||
|
|
||||||
|
- when syncing, a check is made to see if any folders are not on all devices - if the check comes back true, it is corrected (in sshyp)
|
||||||
|
- imporove password generator to guarantee more secure results
|
||||||
|
- enforce permissions on the server-side
|
||||||
|
- allow for copying entire notes (not just first line)
|
||||||
|
- ability to pass entries as arguments for more functions
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Backlog:
|
||||||
|
|
||||||
|
- create separate gui frontend targetting mobile and desktop Linux
|
||||||
|
- auto-completion on tab (currently unsure of best way to make this work)
|
||||||
|
|
||||||
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
|
sshyp 2022.02.16.fr4
|
||||||
|
|
||||||
|
The High-Tech Shears Update
|
||||||
|
|
||||||
|
This release adds in a major feature: multi-client deletion (details below)
|
||||||
|
|
||||||
|
Note: This release requires the configuration ("sshyp tweak") to be re-done, as a device name now must be set (for multi-client deletion).
|
||||||
|
|
||||||
|
Features:
|
||||||
|
|
||||||
|
- added multi-client deletion
|
||||||
|
^ this means that when an entry is deleted from one client (and thus the server), if another client that has a copy of the deleted entry tries to sync, instead of re-uploading the deleted entry, it will now also have its entry deleted.
|
||||||
|
^ the current implementation requires a new Python script in addition to sshyp and sshync
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
- fixed an issue where sshyp would use the wrong SSH key when trying to delete entries from or create folders on the server
|
||||||
|
^ this is a fix that was recently applied to sshync - turns out I made the same mistake in sshyp
|
||||||
|
- deleting folders should now work properly with "sshyp shear" if the directory is entered with a following "/"
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next major update (fr5, The sshyp Doing a Split Update):
|
||||||
|
|
||||||
|
sshyp:
|
||||||
|
- sshyp has recieved a major visual overhaul
|
||||||
|
^ this includes the new file list and thematic text art
|
||||||
|
|
||||||
|
sshync:
|
||||||
|
- sshync has been split into a separate package and now has standalone functionality as a backup/syncing utility
|
||||||
|
^ more details will be available in the sshync repo, once it is created
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next, next major update (fr6, The Farmer Shearing the sshyp Update):
|
||||||
|
|
||||||
|
- when syncing, a check is made to see if any folders are not on all devices - if the check comes back true, it is corrected (in sshyp)
|
||||||
|
- imporove password generator to guarantee more secure results
|
||||||
|
- enforce permissions on the server-side
|
||||||
|
- allow for copying entire notes (not just first line)
|
||||||
|
- ability to pass entries as arguments for more functions
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Backlog:
|
||||||
|
|
||||||
|
- create separate gui frontend targetting mobile and desktop Linux
|
||||||
|
- auto-completion on tab (currently unsure of best way to make this work)
|
||||||
|
|
||||||
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
|
sshyp 2022.01.26.fr3.4
|
||||||
|
|
||||||
|
The Boxing Update - Patch 4
|
||||||
|
|
||||||
|
This release is a hotfix for 2022.01.17.fr3.3. It fixes a major bug with sshync.
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
- sshync now correctly uses the auto-generated SSH key in all operations
|
||||||
|
- an exception has been added for attempting to delete/shear a file that does not exist
|
||||||
|
- the manpage has been updated and now includes setup instructions
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next major update (fr4, The sshyp Doing a Split Update):
|
||||||
|
|
||||||
|
sshyp:
|
||||||
|
- sshyp has recieved a major visual overhaul
|
||||||
|
^ this includes the new file list and thematic text art
|
||||||
|
|
||||||
|
sshync:
|
||||||
|
- sshync has been split into a separate package and now has standalone functionality as a backup/syncing utility
|
||||||
|
^ more details will be available in the sshync repo, once it is created
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next, next major update (fr5, The Farmer Shearing the sshyp Update):
|
||||||
|
|
||||||
|
- allow for multi-client deletion... somehow (in sshync)
|
||||||
|
- when syncing, a check is made to see if any folders are not on all devices - if the check comes back true, it is corrected (in sshyp)
|
||||||
|
- imporove password generator to guarantee more secure results
|
||||||
|
- enforce permissions on the server-side
|
||||||
|
- allow for copying entire notes (not just first line)
|
||||||
|
- ability to pass entries as arguments for more functions
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Backlog:
|
||||||
|
|
||||||
|
- create separate gui frontend targetting mobile and desktop Linux
|
||||||
|
- auto-completion on tab (currently unsure of best way to make this work)
|
||||||
|
|
||||||
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
|
sshyp 2022.01.17.fr3.3
|
||||||
|
|
||||||
|
The Boxing Update - Patch 3
|
||||||
|
|
||||||
|
This release is a hotfix for 2022.01.16.fr3.2. It fixes major bugs, especially with Termux.
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
- the temporary directory for Termux is now sym-linked with its full path (no longer dangling)
|
||||||
|
- the copy function can now properly detect if Termux is being used
|
||||||
|
- ~/.config is created, if it does not already exist
|
||||||
|
- "sshyp shear" now functions again, as a bug with the lock file has been fixed
|
||||||
|
- sshync -should- now properly detect the database file on all platforms (was broken on Termux)
|
||||||
|
- total lines of code have been slightly reduced with various small optimizations
|
||||||
|
|
||||||
|
Additions planned for minor releases:
|
||||||
|
|
||||||
|
- updated the manpage with more information regarding how sshyp works and how to set it up
|
||||||
|
- ensured that it is now impossible for ghosts of entires to remain in /dev/shm
|
||||||
|
- reduced total lines of code with small optimizations
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next major update (fr4, The sshyp Doing a Split Update):
|
||||||
|
|
||||||
|
sshyp:
|
||||||
|
- sshyp has recieved a major visual overhaul
|
||||||
|
^ this includes the new file list and thematic text art
|
||||||
|
|
||||||
|
sshync:
|
||||||
|
- sshync has been split into a separate package and now has standalone functionality as a backup/syncing utility
|
||||||
|
^ more details will be available in the sshync repo, once it is created
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next, next major update (fr5, The Farmer Shearing the sshyp Update):
|
||||||
|
|
||||||
|
- allow for multi-client deletion... somehow (in sshync)
|
||||||
|
- when syncing, a check is made to see if any folders are not on all devices - if the check comes back true, it is corrected (in sshyp)
|
||||||
|
- imporove password generator to guarantee more secure results
|
||||||
|
- enforce permissions on the server-side
|
||||||
|
- allow for copying entire notes (not just first line)
|
||||||
|
- ability to pass entries as arguments for more functions
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Backlog:
|
||||||
|
|
||||||
|
- create separate gui frontend targetting mobile and desktop Linux
|
||||||
|
- auto-completion on tab (currently unsure of best way to make this work)
|
||||||
|
|
||||||
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
|
sshyp 2022.01.16.fr3.2
|
||||||
|
|
||||||
|
The Boxing Update - Patch 2
|
||||||
|
|
||||||
|
This release is a hotfix for 2022.01.16.fr3.1. It fixes major bugs, including one massively impacting Termux.
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
- sshyp now uses a symlink to the temporary storage directory, allowing for easy implementation of different temporary directories on different platforms
|
||||||
|
^ the first usage of this is enabling the use of temporary storage on Termux
|
||||||
|
- sshync now properly auto-generates its config directory
|
||||||
|
|
||||||
|
Additions planned for minor releases:
|
||||||
|
|
||||||
|
- updated the manpage with more information regarding how sshyp works and how to set it up
|
||||||
|
- ensured that it is now impossible for ghosts of entires to remain in /dev/shm
|
||||||
|
- reduced total lines of code with small optimizations
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next major update (fr4, The sshyp Doing a Split Update):
|
||||||
|
|
||||||
|
sshyp:
|
||||||
|
- sshyp has recieved a major visual overhaul
|
||||||
|
^ this includes the new file list and thematic text art
|
||||||
|
|
||||||
|
sshync:
|
||||||
|
- sshync has been split into a separate package and now has standalone functionality as a backup/syncing utility
|
||||||
|
^ more details will be available in the sshync repo, once it is created
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next, next major update (fr5, The Farmer Shearing the sshyp Update):
|
||||||
|
|
||||||
|
- allow for multi-client deletion... somehow (in sshync)
|
||||||
|
- when syncing, a check is made to see if any folders are not on all devices - if the check comes back true, it is corrected (in sshyp)
|
||||||
|
- imporove password generator to guarantee more secure results
|
||||||
|
- enforce permissions on the server-side
|
||||||
|
- allow for copying entire notes (not just first line)
|
||||||
|
- ability to pass entries as arguments for more functions
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Backlog:
|
||||||
|
|
||||||
|
- create separate gui frontend targetting mobile and desktop Linux
|
||||||
|
- auto-completion on tab (currently unsure of best way to make this work)
|
||||||
|
|
||||||
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
|
sshyp 2022.01.16.fr3.1
|
||||||
|
|
||||||
|
The Boxing Update - Patch 1
|
||||||
|
|
||||||
|
This release is a hotfix for 2022.01.13.fr3. It fixes sshync/syncing support after the changes in the last release.
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
- sshync has been updated to work with the new config directory
|
||||||
|
- sshync now uses its own directory to store the database file
|
||||||
|
^ this is preperation for separating sshync into its own package
|
||||||
|
- expanduser lines in sshyp have been simplified (no user-facing impact)
|
||||||
|
|
||||||
|
Additions planned for minor releases:
|
||||||
|
|
||||||
|
- updated the manpage with more information regarding how sshyp works and how to set it up
|
||||||
|
- ensured that it is now impossible for ghosts of entires to remain in /dev/shm
|
||||||
|
- reduced total lines of code with small optimizations
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next major update (fr4, The sshyp Doing a Split Update):
|
||||||
|
|
||||||
|
sshyp:
|
||||||
|
- sshyp has recieved a major visual overhaul
|
||||||
|
^ this includes the new file list and thematic text art
|
||||||
|
|
||||||
|
sshync:
|
||||||
|
- sshync has been split into a separate package and now has standalone functionality as a backup/syncing utility
|
||||||
|
^ more details will be available in the sshync repo, once it is created
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next, next major update (fr5, The Farmer Shearing the sshyp Update):
|
||||||
|
|
||||||
|
- allow for multi-client deletion... somehow (in sshync)
|
||||||
|
- when syncing, a check is made to see if any folders are not on all devices - if the check comes back true, it is corrected (in sshyp)
|
||||||
|
- imporove password generator to guarantee more secure results
|
||||||
|
- enforce permissions on the server-side
|
||||||
|
- allow for copying entire notes (not just first line)
|
||||||
|
- ability to pass entries as arguments for more functions
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Backlog:
|
||||||
|
|
||||||
|
- create separate gui frontend targetting mobile and desktop Linux
|
||||||
|
- auto-completion on tab (currently unsure of best way to make this work)
|
||||||
|
|
||||||
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
|
sshyp 2022.01.13.fr3
|
||||||
|
|
||||||
|
The Boxing Update
|
||||||
|
|
||||||
|
This release adapts sshyp to be compatible with Termux and allows for packaging for various distributions in addition to Arch Linux.
|
||||||
|
|
||||||
|
Features:
|
||||||
|
|
||||||
|
- the copy function now has support for termux-clipboard-set from termux-api
|
||||||
|
^ this allows clipboard functionality to work on Termux
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
- sshyp no longer writes to/reads from /var
|
||||||
|
^ configuration files are now stored under the user's home directory in ~/.config/sshyp
|
||||||
|
^ this change allows for compatibility with less standard environments, such as Termux on Android
|
||||||
|
|
||||||
|
Additions planned for minor releases:
|
||||||
|
|
||||||
|
- updated the manpage with more information regarding how sshyp works and how to set it up
|
||||||
|
- ensured that it is now impossible for ghosts of entires to remain in /dev/shm
|
||||||
|
- reduced total lines of code with small optimizations
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next major update (fr4, The sshyp Doing a Split Update):
|
||||||
|
|
||||||
|
sshyp:
|
||||||
|
- sshyp has recieved a major visual overhaul
|
||||||
|
^ this includes the new file list and thematic text art
|
||||||
|
|
||||||
|
sshync:
|
||||||
|
- sshync has been split into a separate package and now has standalone functionality as a backup/syncing utility
|
||||||
|
^ more details will be available in the sshync repo, once it is created
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Planned for next, next major update (fr5, The Farmer Shearing the sshyp Update):
|
||||||
|
|
||||||
|
- allow for multi-client deletion... somehow (in sshync)
|
||||||
|
- when syncing, a check is made to see if any folders are not on all devices - if the check comes back true, it is corrected (in sshyp)
|
||||||
|
- imporove password generator to guarantee more secure results
|
||||||
|
- enforce permissions on the server-side
|
||||||
|
- allow for copying entire notes (not just first line)
|
||||||
|
- ability to pass entries as arguments for more functions
|
||||||
|
|
||||||
|
&&
|
||||||
|
|
||||||
|
Backlog:
|
||||||
|
|
||||||
|
- create separate gui frontend targetting mobile and desktop Linux
|
||||||
|
- auto-completion on tab (currently unsure of best way to make this work)
|
||||||
|
|
||||||
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
sshyp 2022.01.10.fr2.3
|
sshyp 2022.01.10.fr2.3
|
||||||
@@ -511,5 +1236,3 @@ What is currently functional:
|
|||||||
- sort notes and passwords into folders
|
- sort notes and passwords into folders
|
||||||
- gpg encryption
|
- gpg encryption
|
||||||
- edit password/note entries
|
- edit password/note entries
|
||||||
|
|
||||||
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
|
||||||
|
|||||||
Regular → Executable
+42
-25
@@ -1,6 +1,6 @@
|
|||||||
.TH sshyp 1 "10 January 2022" "2021.12.01.fr2.3" "sshyp man page"
|
.TH sshyp 1 "21 July 2022" "v1.1.1" "sshyp man page"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
sshyp \- A very simple self-hosted, synchronized password manager. Alternative to GNU pass.
|
sshyp \- A very simple self-hosted, synchronized password manager for UNIX(-like) systems. Alternative to (and compatible with) pass/password-store.
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
sshyp [OPTION] [[FLAG]] [/<entry name>]
|
sshyp [OPTION] [[FLAG]] [/<entry name>]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
@@ -8,36 +8,33 @@ sshyp is a lightweight password and note management program written in Python. s
|
|||||||
.SH EXAMPLES
|
.SH EXAMPLES
|
||||||
Setting up sshyp for the first time or altering its configuration (also recommended after major updates):
|
Setting up sshyp for the first time or altering its configuration (also recommended after major updates):
|
||||||
sshyp tweak
|
sshyp tweak
|
||||||
*follow the prompts
|
|
||||||
|
|
||||||
Reading an existing entry saved as ~/.password-pasture/development/github.gpg:
|
Viewing the entry database:
|
||||||
|
sshyp
|
||||||
|
|
||||||
|
Reading an existing entry saved as ~/.local/share/sshyp/development/github.gpg:
|
||||||
sshyp /development/github
|
sshyp /development/github
|
||||||
|
|
||||||
Copying the password of an existing entry saved as ~/.password-pasture/financial/bank.gpg:
|
Copying the password of an existing entry saved as ~/.local/share/sshyp/financial/bank.gpg:
|
||||||
sshyp copy -p
|
sshyp copy -p /financial/bank
|
||||||
*answer the prompt with "/financial/bank"
|
|
||||||
*enter decryption password
|
|
||||||
|
|
||||||
Editing the username of an existing entry saved as ~/.password-pasture/game.gpg:
|
Editing the username of an existing entry saved as ~/.local/share/sshyp/game.gpg:
|
||||||
sshyp edit -u
|
sshyp edit -u game
|
||||||
*answer the first prompt with "game"
|
|
||||||
*follow the prompts
|
|
||||||
|
|
||||||
Making a new entry using the built-in password generator:
|
Making a new entry saved as ~/.local/share/sshyp/school/university.gpg using the built-in password generator:
|
||||||
sshyp gen
|
sshyp gen /school/university
|
||||||
*follow the prompts
|
|
||||||
|
|
||||||
Creating a note-only entry:
|
Creating a note-only entry saved as ~/.local/share/sshyp/notes/testNote.gpg:
|
||||||
sshyp add -n
|
sshyp add -n /notes/testNote
|
||||||
*follow the prompts
|
|
||||||
|
|
||||||
Syncing entries with the server:
|
Manually syncing entries with the server:
|
||||||
sshyp sync
|
sshyp sync
|
||||||
|
|
||||||
.SH OPTIONS
|
Removing an existing folder saved as ~/.local/share/sshyp/social:
|
||||||
In order to quickly read an existing entry, just run "sshyp </entry name>".
|
sshyp shear social/
|
||||||
|
|
||||||
Options for other operations are as follows:
|
.SH OPTIONS
|
||||||
|
USAGE: sshyp [OPTION [FLAG] [<entry name>]] | [/<entry name>]
|
||||||
|
|
||||||
help/--help/-h bring up the help menu
|
help/--help/-h bring up the help menu
|
||||||
version/-v display sshyp version info
|
version/-v display sshyp version info
|
||||||
@@ -66,9 +63,29 @@ copy:
|
|||||||
note/-n copy the note of an entry to your clipboard
|
note/-n copy the note of an entry to your clipboard
|
||||||
gen:
|
gen:
|
||||||
update/-u generate a password for an existing entry
|
update/-u generate a password for an existing entry
|
||||||
.SH BUGS
|
.SH LIMITATIONS
|
||||||
This is more of a current limitation than a bug, but:
|
The following characters/character sequences are not supported in entry/folder titles:
|
||||||
|
|
||||||
Currently, if multiple clients are connected to a single server and a client deletes an entry, the entry is correctly deleted from the client and the server, but since the entry still exists on the other client, the next time it syncs the file will be re-uploaded. This will be fixed in an upcoming release of the syncing backend, sshync.
|
@ ^&* *&^
|
||||||
|
.SH SETUP
|
||||||
|
sshyp operates on a client-server model, and thus requires you to have access to your own server (whether it be a physical home server or a cloud rental) with remote access via SSH.
|
||||||
|
|
||||||
|
The sshyp package includes modes for operating on both client and server devices, so only one package is necessary.
|
||||||
|
|
||||||
|
Server setup:
|
||||||
|
Configure an OpenSSH server (if sshyp was installed from the Debian package, the ssh server was not installed as a dependency and needs to be installed manually)
|
||||||
|
Allow remote access to the SSH server w/public key authentication (disabling password-only authentication recommended)
|
||||||
|
Install sshyp
|
||||||
|
Run "sshyp tweak" and set the device type as server
|
||||||
|
Done!
|
||||||
|
|
||||||
|
Client setup:
|
||||||
|
Install sshyp
|
||||||
|
Run "sshyp tweak" and follow the prompts
|
||||||
|
Copy the generated public SSH key (located at ~/.ssh/sshyp.pub) to the server using preferred method (manually adding to authorized_keys, ssh-copy-id, etc.)
|
||||||
|
If you already have entries on the server, sync them using "sshyp sync"
|
||||||
|
Done!
|
||||||
|
|
||||||
|
Please note that the server setup intentionally does not allow the reading of entries (it does not allow adding a gpg decryption key). For security purposes, only clients can read entries.
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
Randall Winkhart (https://github.com/rwinkhart)
|
Randall Winkhart (https://github.com/rwinkhart)
|
||||||
|
|||||||
Executable
+247
@@ -0,0 +1,247 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# This script packages sshyp (from source) for various UNIX(-like) environments.
|
||||||
|
# Dependencies (Arch Linux): dpkg (packaging for Debian/Termux), freebsd-pkg (packaging for FreeBSD)
|
||||||
|
# Dependencies (Fedora) (can only package for self): rpmdevtools
|
||||||
|
# NOTE It is recommended to instead use the latest officially packaged and tagged release.
|
||||||
|
|
||||||
|
echo -e '\nOptions (please enter the number only):'
|
||||||
|
echo -e '\nPackage Formats:\n\n1. Haiku\n2. Debian&Ubuntu Linux\n3. Fedora Linux\n4. FreeBSD\n5. Termux\n6. Generic (used for PKGBUILD/APKBUILD)'
|
||||||
|
echo -e '\nBuild Scripts:\n\n7. Arch Linux (PKGBUILD)'
|
||||||
|
echo -e '\nOther:\n\n8. All (generates all distribution packages (excluding Haiku and Fedora, as these must be packaged on their respective distributions) and build scripts)\n'
|
||||||
|
read -n 1 -r -p "Distribution: " distro
|
||||||
|
|
||||||
|
echo -e '\n\nThe value entered in this field will only affect the version reported to the package manager. The latest source is used regardless.\n'
|
||||||
|
read -r -p "Version number: " version
|
||||||
|
|
||||||
|
echo -e '\nThe value entered in this field will only affect the revision number for build scripts.\n'
|
||||||
|
read -r -p "Revision number: " revision
|
||||||
|
|
||||||
|
if [ "$distro" == "7" ] || [ "$distro" == "8" ]; then
|
||||||
|
echo -e '\nOptions (please enter the number only):'
|
||||||
|
echo -e '\n1. GitHub Release Tag\n2. Local\n'
|
||||||
|
read -r -p "Source (for build scripts): " source
|
||||||
|
|
||||||
|
if [ "$source" == "1" ]; then
|
||||||
|
source='https://github.com/rwinkhart/sshyp/releases/download/v$pkgver/sshyp-$pkgver.tar.xz'
|
||||||
|
else
|
||||||
|
source=local://sshyp-"$version".tar.xz
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p packages
|
||||||
|
|
||||||
|
if [ "$distro" == "1" ]; then
|
||||||
|
echo -e '\nPackaging for Haiku...\n'
|
||||||
|
mkdir -p packages/haikutemp/documentation/{man/man1,packages/sshyp}
|
||||||
|
echo "name sshyp
|
||||||
|
version "$version"-"$revision"
|
||||||
|
architecture any
|
||||||
|
summary \"A light-weight, self-hosted, synchronized password manager\"
|
||||||
|
description \"sshyp is the only password-store compatible CLI password manager available for Haiku - it is also available on Linux/Android (via Termux) so that you can sync your entries across all of your devices.\"
|
||||||
|
packager \"Randall Winkhart <idgr at tutanota dot com>\"
|
||||||
|
vendor \"Randall Winkhart\"
|
||||||
|
licenses {
|
||||||
|
\"GNU GPL v3\"
|
||||||
|
}
|
||||||
|
copyrights {
|
||||||
|
\"2021-2022 Randall Winkhart\"
|
||||||
|
}
|
||||||
|
provides {
|
||||||
|
sshyp = "$version"
|
||||||
|
cmd:sshyp
|
||||||
|
}
|
||||||
|
requires {
|
||||||
|
gnupg
|
||||||
|
openssh
|
||||||
|
python3
|
||||||
|
}
|
||||||
|
urls {
|
||||||
|
\"https://github.com/rwinkhart/sshyp\"
|
||||||
|
}
|
||||||
|
" > packages/haikutemp/.PackageInfo
|
||||||
|
cp -r bin packages/haikutemp/
|
||||||
|
ln -s /bin/sshyp.py packages/haikutemp/bin/sshyp
|
||||||
|
cp -r share/doc/sshyp/ packages/haikutemp/documentation/packages/
|
||||||
|
cp -r share/licenses/sshyp/ packages/haikutemp/documentation/packages/
|
||||||
|
cp extra/manpage packages/haikutemp/documentation/man/man1/sshyp.1
|
||||||
|
gzip packages/haikutemp/documentation/man/man1/sshyp.1
|
||||||
|
cd packages/haikutemp
|
||||||
|
package create -b sshyp-"$version"-"$revision"_all.hpkg
|
||||||
|
package add sshyp-"$version"-"$revision"_all.hpkg bin documentation
|
||||||
|
cd ../..
|
||||||
|
mv packages/haikutemp/sshyp-"$version"-"$revision"_all.hpkg packages/
|
||||||
|
rm -rf packages/haikutemp
|
||||||
|
echo -e "\nHaiku packaging complete.\n"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$distro" == "2" ] || [ "$distro" == "8" ]; then
|
||||||
|
echo -e '\nPackaging for Debian...\n'
|
||||||
|
mkdir -p packages/debiantemp/sshyp_"$version"-"$revision"_all/{DEBIAN,usr/share/man/man1}
|
||||||
|
echo "Package: sshyp
|
||||||
|
Version: $version
|
||||||
|
Section: utils
|
||||||
|
Architecture: all
|
||||||
|
Maintainer: Randall Winkhart <idgr at tutanota dot com>
|
||||||
|
Description: A light-weight, self-hosted, synchronized password manager
|
||||||
|
Depends: python3, gnupg, openssh-client, xclip, wl-clipboard
|
||||||
|
Priority: optional
|
||||||
|
Installed-Size: 185
|
||||||
|
" > packages/debiantemp/sshyp_"$version"-"$revision"_all/DEBIAN/control
|
||||||
|
cp -r bin packages/debiantemp/sshyp_"$version"-"$revision"_all/usr/
|
||||||
|
ln -s /usr/bin/sshyp.py packages/debiantemp/sshyp_"$version"-"$revision"_all/usr/bin/sshyp
|
||||||
|
cp -r share packages/debiantemp/sshyp_"$version"-"$revision"_all/usr/
|
||||||
|
cp extra/manpage packages/debiantemp/sshyp_"$version"-"$revision"_all/usr/share/man/man1/sshyp.1
|
||||||
|
gzip packages/debiantemp/sshyp_"$version"-"$revision"_all/usr/share/man/man1/sshyp.1
|
||||||
|
dpkg-deb --build --root-owner-group packages/debiantemp/sshyp_"$version"-"$revision"_all/
|
||||||
|
mv packages/debiantemp/sshyp_"$version"-"$revision"_all.deb packages/
|
||||||
|
rm -rf packages/debiantemp
|
||||||
|
echo -e "\nDebian packaging complete.\n"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$distro" == "5" ] || [ "$distro" == "8" ]; then
|
||||||
|
echo -e '\nPackaging for Termux...\n'
|
||||||
|
mkdir -p packages/termuxtemp/sshyp_"$version"-"$revision"_all_termux/{data/data/com.termux/files/usr/share/man/man1,DEBIAN}
|
||||||
|
echo "Package: sshyp
|
||||||
|
Version: $version
|
||||||
|
Section: utils
|
||||||
|
Architecture: all
|
||||||
|
Maintainer: Randall Winkhart <idgr at tutanota dot com>
|
||||||
|
Description: A light-weight, self-hosted, synchronized password manager
|
||||||
|
Depends: python, gnupg, openssh, termux-api, termux-am
|
||||||
|
Priority: optional
|
||||||
|
Installed-Size: 185
|
||||||
|
" > packages/termuxtemp/sshyp_"$version"-"$revision"_all_termux/DEBIAN/control
|
||||||
|
cp -r bin packages/termuxtemp/sshyp_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/
|
||||||
|
ln -s /data/data/com.termux/files/usr/bin/sshyp.py packages/termuxtemp/sshyp_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/bin/sshyp
|
||||||
|
cp -r share packages/termuxtemp/sshyp_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/
|
||||||
|
cp extra/manpage packages/termuxtemp/sshyp_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/share/man/man1/sshyp.1
|
||||||
|
gzip packages/termuxtemp/sshyp_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/share/man/man1/sshyp.1
|
||||||
|
dpkg-deb --build --root-owner-group packages/termuxtemp/sshyp_"$version"-"$revision"_all_termux/
|
||||||
|
mv packages/termuxtemp/sshyp_"$version"-"$revision"_all_termux.deb packages/
|
||||||
|
rm -rf packages/termuxtemp
|
||||||
|
echo -e "\nTermux packaging complete.\n"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$distro" == "3" ] || [ "$distro" == "4" ] || [ "$distro" == "6" ] || [ "$distro" == "7" ] || [ "$distro" == "8" ]; then
|
||||||
|
echo -e '\nPackaging as generic...\n'
|
||||||
|
mkdir -p packages/generictemp/usr/share/man/man1
|
||||||
|
cp -r bin packages/generictemp/usr/
|
||||||
|
ln -s /usr/bin/sshyp.py packages/generictemp/usr/bin/sshyp
|
||||||
|
cp -r share packages/generictemp/usr/
|
||||||
|
cp extra/manpage packages/generictemp/usr/share/man/man1/sshyp.1
|
||||||
|
gzip packages/generictemp/usr/share/man/man1/sshyp.1
|
||||||
|
tar -C packages/generictemp -cvf packages/sshyp-"$version".tar.xz usr/
|
||||||
|
rm -rf packages/generictemp
|
||||||
|
sha512="$(sha512sum packages/sshyp-"$version".tar.xz | awk '{print $1;}')"
|
||||||
|
echo -e "\nsha512 sum:\n$sha512"
|
||||||
|
echo -e "\nGeneric packaging complete.\n"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$distro" == "3" ]; then
|
||||||
|
echo -e '\nPackaging for Fedora...\n'
|
||||||
|
rm -rf ~/rpmbuild
|
||||||
|
rpmdev-setuptree
|
||||||
|
cp packages/sshyp-"$version".tar.xz ~/rpmbuild/SOURCES
|
||||||
|
echo "Name: sshyp
|
||||||
|
Version: "$version"
|
||||||
|
Release: "$revision"
|
||||||
|
Summary: A light-weight, self-hosted, synchronized password manager
|
||||||
|
BuildArch: noarch
|
||||||
|
|
||||||
|
License: GPLv3
|
||||||
|
URL: https://github.com/rwinkhart/sshyp
|
||||||
|
Source0: sshyp-"$version".tar.xz
|
||||||
|
|
||||||
|
Requires: python gnupg openssh wl-clipboard
|
||||||
|
|
||||||
|
%description
|
||||||
|
sshyp is a password-store compatible CLI password manager available for UNIX(-like) systems - its primary goal is to make syncing passwords and notes across devices as easy as possible via CLI.
|
||||||
|
|
||||||
|
%install
|
||||||
|
tar xf %{_sourcedir}/sshyp-"$version".tar.xz -C %{_sourcedir}
|
||||||
|
cp -r %{_sourcedir}/usr %{buildroot}
|
||||||
|
|
||||||
|
%files
|
||||||
|
/usr/bin/sshyp
|
||||||
|
/usr/bin/sshyp.py
|
||||||
|
/usr/bin/sshync.py
|
||||||
|
/usr/bin/sshypRemote.py
|
||||||
|
%license /usr/share/licenses/sshyp/license
|
||||||
|
%doc /usr/share/doc/sshyp/changelog
|
||||||
|
%doc /usr/share/man/man1/sshyp.1.gz
|
||||||
|
" > ~/rpmbuild/SPECS/sshyp.spec
|
||||||
|
rpmbuild -bb ~/rpmbuild/SPECS/sshyp.spec
|
||||||
|
mv ~/rpmbuild/RPMS/noarch/* packages/
|
||||||
|
rm -rf ~/rpmbuild
|
||||||
|
echo -e "\nFedora packaging complete.\n"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$distro" == "4" ] || [ "$distro" == "8" ]; then
|
||||||
|
echo -e '\nPackaging for FreeBSD...\n'
|
||||||
|
mkdir -p packages/FreeBSDtemp/bin
|
||||||
|
tar xf packages/sshyp-"$version".tar.xz -C packages/FreeBSDtemp
|
||||||
|
ln -s /usr/local/bin/python3 packages/FreeBSDtemp/bin/python3
|
||||||
|
echo "name: sshyp
|
||||||
|
version: \""$version"\"
|
||||||
|
abi = \"FreeBSD:13:*\";
|
||||||
|
arch = \"freebsd:13:*\";
|
||||||
|
origin: security/sshyp
|
||||||
|
comment: \"a password manager\"
|
||||||
|
desc: \"a light-weight, self-hosted, synchronized password manager\"
|
||||||
|
maintainer: <idgr at tutanota dot com>
|
||||||
|
www: https://github.com/rwinkhart/sshyp
|
||||||
|
prefix: /
|
||||||
|
\"deps\" : {
|
||||||
|
\"python\" : {
|
||||||
|
\"origin\" : \"lang/python\"
|
||||||
|
},
|
||||||
|
\"gnupg\" : {
|
||||||
|
\"origin\" : \"security/gnupg\"
|
||||||
|
},
|
||||||
|
\"xclip\" : {
|
||||||
|
\"origin\" : \"x11/xclip\"
|
||||||
|
},
|
||||||
|
\"wl-clipboard\" : {
|
||||||
|
\"origin\" : \"x11/wl-clipboard\"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
" > packages/FreeBSDtemp/+MANIFEST
|
||||||
|
echo "/bin/python3
|
||||||
|
/usr/bin/sshync.py
|
||||||
|
/usr/bin/sshyp
|
||||||
|
/usr/bin/sshyp.py
|
||||||
|
/usr/bin/sshypRemote.py
|
||||||
|
/usr/share/doc/sshyp/changelog
|
||||||
|
/usr/share/licenses/sshyp/license
|
||||||
|
/usr/share/man/man1/sshyp.1.gz
|
||||||
|
" > packages/FreeBSDtemp/plist
|
||||||
|
pkg create -m packages/FreeBSDtemp/ -r packages/FreeBSDtemp/ -p packages/FreeBSDtemp/plist -o packages/
|
||||||
|
rm -rf packages/FreeBSDtemp
|
||||||
|
echo -e "\nFreeBSD packaging complete.\n"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$distro" == "7" ] || [ "$distro" == "8" ]; then
|
||||||
|
echo -e '\nGenerating PKGBUILD...'
|
||||||
|
echo "# Maintainer: Randall Winkhart <idgr at tutanota dot com>
|
||||||
|
|
||||||
|
pkgname=sshyp
|
||||||
|
pkgver="$version"
|
||||||
|
pkgrel="$revision"
|
||||||
|
pkgdesc='A light-weight, self-hosted, synchronized password manager'
|
||||||
|
url='https://github.com/rwinkhart/sshyp'
|
||||||
|
arch=('any')
|
||||||
|
license=('GPL3')
|
||||||
|
depends=(python gnupg openssh xclip wl-clipboard)
|
||||||
|
|
||||||
|
source=(\""$source"\")
|
||||||
|
sha512sums=('"$sha512"')
|
||||||
|
|
||||||
|
package() {
|
||||||
|
|
||||||
|
tar xf sshyp-"\"\$pkgver\"".tar.xz -C "\"\${pkgdir}\""
|
||||||
|
|
||||||
|
}
|
||||||
|
" > packages/PKGBUILD
|
||||||
|
echo -e "\nPKGBUILD generated.\n"
|
||||||
|
fi
|
||||||
Regular → Executable
+16
-40
@@ -1,51 +1,27 @@
|
|||||||
sshyp 2022.01.10.fr2.3
|
sshyp v1.1.1
|
||||||
|
|
||||||
The Lighter Update - Patch 3
|
the sheecrets update - patch one
|
||||||
|
|
||||||
This release is a hotfix for 2021.12.01.fr2.2. It features critical security fixes and quality-of-life improvements.
|
this is a polish/bug fix release that makes tweaks to the entry format (without breaking compatibility)
|
||||||
|
|
||||||
New features:
|
compatibility-breaking changes:
|
||||||
|
|
||||||
- a man page has been added
|
- none; the entry format tweaks are backward compatible with sshyp v1.0.0+
|
||||||
|
^ the new format is slightly more efficient in terms of storage space
|
||||||
|
^ if you would like to upgrade to it, run this script (after updating to v1.1.1):
|
||||||
|
https://raw.githubusercontent.com/rwinkhart/sshyp-labs/main/extra/conversion-scripts/sshyp-refresh-1.1.1%2B.py
|
||||||
|
|
||||||
Changes:
|
user-facing features:
|
||||||
|
|
||||||
- folders in /dev/shm are no longer created before input from the user (fixes critical security flaws)
|
- entries (when editing or adding) are now run through the new optimized_edit() function to strip trailing new lines
|
||||||
- fixed syncing of files (specifically downloading) with special characters, such as '('
|
and ensure the format of the entries is fully compatible with all of sshyp's functions
|
||||||
- fixed program still continuing after trying to edit an entry that doesn't exist
|
|
||||||
- the gen command has been updated to use the newer notetaking system
|
|
||||||
- printing functions in sshyp have been combined into one function (arguments determine section to print, fewer lines of code)
|
|
||||||
- file not found exceptions have been re-implemented
|
|
||||||
- .lower() is now used to remove casing when checking inputs
|
|
||||||
- removed an old reference to "rsync" in the configuration dialog
|
|
||||||
|
|
||||||
Planned for next major update (The Fluffier Update):
|
fixes:
|
||||||
|
|
||||||
- new visual features
|
- when adding a note to an entry, there is no longer a chance the first note line will be added as a url
|
||||||
^ this includes the new file list and thematic text art. sshyp will be
|
if the entry is using an older format/pass format
|
||||||
getting a retro computing theme.
|
- the gpg auto-generation file temporarily created by sshyp no longer includes extra spaces
|
||||||
- packages for more environments
|
^ seems to serve no functional purpose - fixed for the sake of polish
|
||||||
^ "sshyp" will be officially packaged for Arch Linux, Alpine Linux, and Termux (Android).
|
|
||||||
Debian/Ubuntu and Fedora packaging will come later.
|
|
||||||
- imporove password generator to guarantee more secure results
|
|
||||||
- when syncing, a check is made to see if any folders are not on all devices - if the check comes back true, it is corrected (in sshyp)
|
|
||||||
|
|
||||||
Planned for next, next major update (The Shears Update Pt. 1):
|
|
||||||
|
|
||||||
- enforce permissions on the server-side
|
|
||||||
- allow for copying entire notes (not just first line)
|
|
||||||
- allow for multi-client deletion... somehow (in sshync)
|
|
||||||
- detatch sshync and make it a separate package
|
|
||||||
|
|
||||||
Planned for next, next, next major update (The Shears Update Pt. 2):
|
|
||||||
|
|
||||||
- ability to pass entries as arguments for more functions
|
|
||||||
- auto-completion on tab (currently unsure of best way to make this work)
|
|
||||||
|
|
||||||
Backlog:
|
|
||||||
|
|
||||||
- package for more Linux distributions, such as Debian and Fedora
|
|
||||||
- create separate gui frontend targetting mobile and desktop Linux
|
|
||||||
|
|
||||||
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
sshyp is a FOSS password manager that takes advantage of rsync
|
sshyp is a FOSS password manager that uses an sftp-based syncing back-end.
|
||||||
Copyright (C) 2021 Randall Winkhart idgr@tutanota.com
|
Copyright (C) 2022 Randall Winkhart idgr@tutanota.com
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
Reference in New Issue
Block a user