mirror of
https://github.com/rwinkhart/sshyp.git
synced 2026-09-06 00:57:14 -04:00
Compare commits
109
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
@@ -1,5 +1,9 @@
|
||||
# sshyp
|
||||
A very simple self-hosted, synchronized password manager. Alternative to GNU pass.
|
||||
A very simple self-hosted, synchronized password manager for UNIX(-like) systems (currently Haiku/FreeBSD/Linux). Alternative to (and compatible with) pass/password-store.
|
||||
|
||||
Compatible with entries created by pass/password-store.
|
||||
|
||||
The only password-store compatible CLI password manager available for Haiku.
|
||||
|
||||
"sshyp" stands for "sshync passwords", or "ssh sync passwords".
|
||||
"sshync" is the custom syncing backend (based on sftp) used by "sshyp".
|
||||
@@ -16,18 +20,18 @@ What sshyp can do:
|
||||
|
||||
- securely manage a collection of encrypted passwords and notes via CLI
|
||||
- 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
|
||||
- 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
|
||||
- have a distinct retro theme
|
||||
- receive many usability enhancements
|
||||
- (planned v1.1.0) 2FA/MFA management (was previously not on the roadmap, but could be beneficial in reducing phone usage)
|
||||
- (planned v1.2.0) everything it already does, but also in a GUI for Linux/Haiku
|
||||
|
||||
What sshyp definitely won't do:
|
||||
|
||||
- 2FA/MFA (for security purposes, this should not be handled by your password manager)
|
||||
- Windows support (I don't use Windows and I have no interest in developing for it)
|
||||
- Non-UNIX(-like) support, e.g. Windows (I'd be happy to link to third-party ports, if someone were to make them)
|
||||
|
||||
# Installation
|
||||
Arch Linux (all ISAs)
|
||||
@@ -42,7 +46,7 @@ cd sshyp
|
||||
makepkg -si
|
||||
```
|
||||
|
||||
Pre-built packages exist for Arch, Debian, and Termux. These can be downloaded from the releases page.
|
||||
Pre-built packages exist for Haiku, FreeBSD, Arch Linux, Debian Linux, Red Hat Linux, and Termux. These can be downloaded from the releases page.
|
||||
|
||||
# Building
|
||||
Since sshyp is written entirely in Python, it doesn't need to be compiled. It does, however, need to be packaged for installation.
|
||||
@@ -55,11 +59,13 @@ cd sshyp
|
||||
./package.sh
|
||||
```
|
||||
|
||||
The packaging script has been tested on Arch Linux with dpkg as a dependency for Debian and Termux packaging.
|
||||
The packaging script has been tested on Arch Linux with "dpkg" as a dependency for Debian and Termux packaging and "freebsd-pkg" as a dependency for FreeBSD packaging.
|
||||
|
||||
Haiku packaging must be done from within Haiku.
|
||||
|
||||
The AUR version and the packages attatched to the release tags were already packaged using this script.
|
||||
|
||||
Currently, the script can create packages for Arch (PKGBUILD), Debian, Termux, and generic. Packaging for other distributions coming soon.
|
||||
Currently, the script can create packages for Haiku, FreeBSD, Arch Linux (PKGBUILD), Debian Linux, Red Hat Linux, Termux, and generic. Packaging for other systems coming soon.
|
||||
|
||||
# Usage
|
||||
Upon initial installation (on both the server and client devices), be sure to run:
|
||||
@@ -69,7 +75,7 @@ sshyp tweak
|
||||
```
|
||||
|
||||
This command will allow you to configure the settings necessary for sshyp to function.
|
||||
As of right now, sshyp is rapidly changing, and as such, it is a good idea to run "sshyp tweak" after each update.
|
||||
To ensure configuration compatibility, it is a good idea to run 'sshyp tweak' after each major 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.
|
||||
|
||||
@@ -79,7 +85,7 @@ All available options can be found with:
|
||||
sshyp --help
|
||||
```
|
||||
|
||||
Or alternatively, in the new manpage:
|
||||
Or alternatively, in the manpage:
|
||||
|
||||
```
|
||||
man sshyp
|
||||
@@ -88,20 +94,10 @@ man sshyp
|
||||
# Roadmap
|
||||
Short-term Goals:
|
||||
|
||||
- create new file list w/color and w/o file extensions
|
||||
- overhaul argument system
|
||||
- fix lots of bugs!
|
||||
- make lots of optimizations!
|
||||
|
||||
Medium-term Goals:
|
||||
|
||||
- 2FA/MFA management
|
||||
- create minimal GUI apps (Linux x86_64, Linux aarch64)
|
||||
- auto-completion on tab for CLI version
|
||||
- various optimizations/bug fixes
|
||||
|
||||
Long-term Goals:
|
||||
|
||||
- seize the thrones, shear the humans
|
||||
|
||||
# Known Issues
|
||||
|
||||
Currently, the entry list displays each entry with the file extension ".gpg" visible (which you do not type when reading, modifying, or creating an entry). This will be corrected when the new entry list is added.
|
||||
|
||||
+23
-25
@@ -1,13 +1,11 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
# sshync 2022.01.17.unreleased13
|
||||
#!/bin/python3
|
||||
|
||||
# external modules
|
||||
|
||||
from os import path, system, walk
|
||||
from os.path import getmtime, join, expanduser
|
||||
from sys import exit as s_exit
|
||||
from os.path import expanduser, getmtime, join
|
||||
from pathlib import Path
|
||||
from sys import exit as s_exit
|
||||
|
||||
|
||||
# utility functions
|
||||
@@ -29,13 +27,13 @@ def get_titles_mods(_directory, _destination, _user_data):
|
||||
open(expanduser('~/.config/sshync/database'), 'a').write(str(_mod) + '\n')
|
||||
# remote fetching
|
||||
if _destination == 'r':
|
||||
system(f"ssh -i '{_user_data[5]}' -p {_user_data[2]} {_user_data[0]}@{_user_data[1]} \"python -c 'import sshync"
|
||||
f"; sshync.get_titles_mods(\"'\"{_user_data[4]}\"'\", \"'\"l\"'\", \"'\"{_user_data}\"'\")'\"")
|
||||
system(f"sftp -i '{_user_data[5]}' -P {_user_data[2]} {_user_data[0]}@{_user_data[1]}:"
|
||||
f"'{expanduser(f'/home/{_user_data[0]}/.config/sshync/database')}' '{expanduser('~/.config/sshync/')}'")
|
||||
_titles, _sep, _mods = ' '.join(open(expanduser('~/.config/sshync/database')).readlines()).replace('\n', '')\
|
||||
system(f"ssh -i '{_user_data[5]}' -p {_user_data[2]} {_user_data[0]}@{_user_data[1]} \"cd /bin; python -c 'impo"
|
||||
f"rt sshync; sshync.get_titles_mods(\"'\"{_user_data[4]}\"'\", \"'\"l\"'\", \"'\"{_user_data}\"'\")'\"")
|
||||
system(f"scp -pqs -P {_user_data[2]} -i '{_user_data[5]}' {_user_data[0]}@{_user_data[1]}:"
|
||||
f"'/home/{_user_data[0]}/.config/sshync/database' '{expanduser('~/.config/sshync/')}'")
|
||||
_titles, _sep, _mods = '*&^'.join(open(expanduser('~/.config/sshync/database')).readlines()).replace('\n', '')\
|
||||
.partition('^&*')
|
||||
_title_list, _mod_list = _titles.split(' ')[:-1], _mods.split(' ')[1:]
|
||||
_title_list, _mod_list = _titles.split('*&^')[:-1], _mods.split('*&^')[1:]
|
||||
return _title_list, _mod_list
|
||||
|
||||
|
||||
@@ -63,9 +61,9 @@ def get_profile(_profile_dir):
|
||||
try:
|
||||
_profile_data = open(_profile_dir).readlines()
|
||||
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
|
||||
s_exit()
|
||||
s_exit(1)
|
||||
# extract data from profile
|
||||
_user = _profile_data[0].replace('\n', '')
|
||||
_ip = _profile_data[1].replace('\n', '')
|
||||
@@ -87,19 +85,19 @@ def run_profile(_profile_dir):
|
||||
if _title in _index_r[0]:
|
||||
# compare mod times and sync
|
||||
if int(_index_l[1][_i]) > int(_index_r[1][_i]):
|
||||
print(f"[{_title}] Local is newer, uploading...")
|
||||
system(f"sftp -p -q -i '{_user_data[5]}' -P {_user_data[2]} {_user_data[0]}@{_user_data[1]}:"
|
||||
f"{_user_data[4]}{'/'.join(_title.split('/')[:-1]) + '/'} <<< $'put {_user_data[3]}{_title}'")
|
||||
print(f"\u001b[38;5;4m{_title[:-4]}\u001b[0m is newer locally, uploading...")
|
||||
system(f"scp -pqs -P {_user_data[2]} -i '{_user_data[5]}' '{_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]):
|
||||
print(f"[{_title}] Remote is newer, downloading...")
|
||||
system(f"sftp -p -q -i '{_user_data[5]}' -P {_user_data[2]} {_user_data[0]}@{_user_data[1]}:"
|
||||
f"'{_user_data[4]}'{_title} {_user_data[3]}{'/'.join(_title.split('/')[:-1]) + '/'}")
|
||||
print(f"\u001b[38;5;2m{_title[:-4]}\u001b[0m is newer remotely, downloading...")
|
||||
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]) + '/'}'")
|
||||
else:
|
||||
print(f"[{_title}] 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]}"
|
||||
f"{'/'.join(_title.split('/')[:-1]) + '/'} <<< $'put {_user_data[3]}{_title}'")
|
||||
print(f"\u001b[38;5;4m{_title[:-4]}\u001b[0m is not on remote server, uploading...")
|
||||
system(f"scp -pqs -P {_user_data[2]} -i '{_user_data[5]}' '{_user_data[3]}{_title}' "
|
||||
f"'{_user_data[0]}@{_user_data[1]}:{_user_data[4]}{'/'.join(_title.split('/')[:-1]) + '/'}'")
|
||||
for _title in _index_r[0]:
|
||||
if _title not in _index_l[0]:
|
||||
print(f"[{_title}] Not in local directory, downloading...")
|
||||
system(f"sftp -p -q -i '{_user_data[5]}' -P {_user_data[2]} {_user_data[0]}@{_user_data[1]}:"
|
||||
f"'{_user_data[4]}{_title}' {_user_data[3]}{'/'.join(_title.split('/')[:-1]) + '/'}")
|
||||
print(f"\u001b[38;5;2m{_title[:-4]}\u001b[0m is not in local directory, downloading...")
|
||||
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]) + '/'}'")
|
||||
|
||||
@@ -1,24 +1,112 @@
|
||||
#!/usr/bin/python3
|
||||
#!/bin/python3
|
||||
|
||||
# external modules
|
||||
|
||||
from os import environ, listdir, path, remove, system
|
||||
from shutil import copy, move, rmtree
|
||||
from sys import argv, exit as s_exit
|
||||
from os import environ, listdir, path, remove, system, uname, walk
|
||||
from pathlib import Path
|
||||
import random
|
||||
from shutil import get_terminal_size, move, rmtree
|
||||
import sshync
|
||||
import string
|
||||
from subprocess import Popen, PIPE, STDOUT
|
||||
from sys import argv, exit as s_exit
|
||||
from textwrap import fill
|
||||
|
||||
|
||||
# utility functions
|
||||
|
||||
def entry_list_gen(): # generates and prints a list of all folders and entries
|
||||
print('\n\u001b[38;5;0;48;5;15msshyp entries:\u001b[0m\n')
|
||||
_entry_list, _color_alternator = [], 1
|
||||
for _entry in sorted(listdir(path.expanduser('~/.password-pasture'))):
|
||||
if Path(path.expanduser(f"~/.password-pasture/{_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(path.expanduser('~/.password-pasture')):
|
||||
for _dir in sorted(_directories):
|
||||
_inner_dir = f"{_root.replace(path.expanduser('~/.password-pasture'), '')}/{_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(path.expanduser(f"~/.password-pasture{_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):
|
||||
_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]}")
|
||||
elif _num == 1 and _entry_lines[0] != '\n':
|
||||
print(f"\u001b[38;5;15;48;5;238mpassword:\u001b[0m\n{_entry_lines[0]}")
|
||||
elif _num == 2 and _entry_lines[2] != '\n':
|
||||
print(f"\u001b[38;5;15;48;5;238murl:\u001b[0m\n{_entry_lines[_num]}")
|
||||
elif _num >= 3 and _entry_lines[_num] != '\n' and _notes_flag != 1:
|
||||
_notes_flag = 1
|
||||
print('\u001b[38;5;15;48;5;238mnotes:\u001b[0m\n' + _entry_lines[_num].replace('\n', ''))
|
||||
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]}")
|
||||
|
||||
|
||||
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 entry_name_fetch(_entry_name_location):
|
||||
if type(_entry_name_location) == str:
|
||||
entry_list_gen()
|
||||
_entry_name = str(input(_entry_name_location))
|
||||
elif _entry_name_location == 0:
|
||||
_entry_name = argument
|
||||
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(): # generates a random temporary folder 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)))
|
||||
@@ -28,21 +116,71 @@ def shm_gen(): # generates a random temporary folder for security and returns r
|
||||
return _shm_folder_gen, _shm_entry_gen
|
||||
|
||||
|
||||
def pass_gen():
|
||||
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(random.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
|
||||
_length = int(input('password length: '))
|
||||
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(_shm_folder, _shm_entry, _location):
|
||||
system(f"gpg -r {str(gpg_id)} -e '{tmp_dir}{_shm_folder}/{_shm_entry}'")
|
||||
system(f"{gpg} -qr {str(gpg_id)} -e '{tmp_dir}{_shm_folder}/{_shm_entry}'")
|
||||
move(f"{tmp_dir}{_shm_folder}/{_shm_entry}.gpg", f"{directory}{_location}.gpg")
|
||||
rmtree(f"{tmp_dir}{_shm_folder}")
|
||||
|
||||
|
||||
def decrypt(_entry_dir, _shm_folder, _shm_entry):
|
||||
if _shm_folder == 0 and _shm_entry == 0:
|
||||
_command = f"{gpg} -qd --output /dev/null {path.expanduser('~/.config/sshyp/lock.gpg')}"
|
||||
else:
|
||||
_command = f"{gpg} -qd --output {tmp_dir}{_shm_folder}/{_shm_entry} {_entry_dir}.gpg"
|
||||
_output = Popen(_command, shell=True, stdout=PIPE, stderr=STDOUT, close_fds=True)
|
||||
_block = _output.communicate()[0].strip()
|
||||
if _output.returncode == 2:
|
||||
print(f"\n\u001b[38;5;9merror: could not decrypt - ensure the correct gpg key is present\u001b[0m\n")
|
||||
s_exit(1)
|
||||
|
||||
|
||||
def edit_note(_shm_folder, _shm_entry):
|
||||
lines = open(f"{tmp_dir}{_shm_folder}/{_shm_entry}").readlines()
|
||||
open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'w').writelines(lines[0:3])
|
||||
open(f"{tmp_dir}{_shm_folder}/{_shm_entry}-n", 'w').writelines(lines[4:-2])
|
||||
open(f"{tmp_dir}{_shm_folder}/{_shm_entry}-n", 'w').writelines(lines[3:])
|
||||
system(f"nano {tmp_dir}{_shm_folder}/{_shm_entry}-n")
|
||||
edit_notes = open(f"{tmp_dir}{_shm_folder}/{_shm_entry}-n").read()
|
||||
open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'a').write('\n' + edit_notes + '\n\n')
|
||||
open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'a').write(edit_notes)
|
||||
|
||||
|
||||
def copy_name_check(_port, _username_ssh, _ip, _client_device_name):
|
||||
_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}'\""
|
||||
_output = Popen(_command, shell=True, stdout=PIPE, stderr=STDOUT, close_fds=True)
|
||||
_block = _output.communicate()[0].strip()
|
||||
if _output.returncode != 0:
|
||||
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
|
||||
else:
|
||||
open(path.expanduser('~/.config/sshyp/ssh-error'), 'w').write('0')
|
||||
return 0
|
||||
|
||||
# argument-specific functions
|
||||
|
||||
|
||||
@@ -51,55 +189,56 @@ def tweak(): # runs configuration wizard
|
||||
Path(path.expanduser('~/.password-pasture')).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 Path("/data/data/com.termux").exists():
|
||||
if uname()[0] == 'Haiku':
|
||||
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('\nIs this installation for a client or for a server? (C/s) ')
|
||||
_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)
|
||||
copy('/usr/bin/sshync.py', path.expanduser('~/'))
|
||||
copy('/usr/bin/sshypRemote.py', path.expanduser('~/sshypRemote.py'))
|
||||
print('\nMake sure the ssh service is running and properly configured.\n\nConfiguration complete!\n')
|
||||
s_exit()
|
||||
print('\nmake sure the ssh service is running and properly configured\n\nconfiguration 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('\nsshyp requires the use of a unique gpg key. Do you already have one that you are '
|
||||
'willing to use? (y/N)')
|
||||
_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: '))
|
||||
print('\na unique gpg key has been generated for you.')
|
||||
system(f"{gpg} --full-generate-key")
|
||||
_gpg_id = str(input('\nplease input the id of your gpg key: '))
|
||||
open(path.expanduser('~/.config/sshyp/sshyp-gpg'), 'w').write(_gpg_id + '\n')
|
||||
|
||||
# lock file generation
|
||||
open(path.expanduser('~/.config/sshyp/lock'), 'w')
|
||||
system(f"gpg -r {str(_gpg_id)} -e {path.expanduser('~/.config/sshyp/lock')}")
|
||||
system(f"{gpg} -qr {str(_gpg_id)} -e {path.expanduser('~/.config/sshyp/lock')}")
|
||||
remove(f"{path.expanduser('~/.config/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 '
|
||||
_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':
|
||||
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"\nEnsure that the key file you are using is located at {path.expanduser('~/.ssh/sshyp')}")
|
||||
print(f"\nensure that the key file you are using is located at {path.expanduser('~/.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_port = str(input('\nexample 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('\nWhat is the username of the remote server? '))
|
||||
print(f"\nEntry directory: /home/{_username_ssh}/.password-pasture/")
|
||||
_username_ssh = str(input('\nusername of the remote server: '))
|
||||
print(f"\nentry directory: /home/{_username_ssh}/.password-pasture/")
|
||||
|
||||
# sshync profile generation
|
||||
sshync.make_profile(path.expanduser('~/.config/sshyp/sshyp.sshync'),
|
||||
@@ -109,23 +248,22 @@ def tweak(): # runs configuration wizard
|
||||
# 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('\nIMPORTANT: This name MUST be unique amongst your client devices. '
|
||||
'\nThis is used to keep track of which devices have up-to-date databases.\n')
|
||||
_client_device_name = str(input('What would you like to name this device? '))
|
||||
print('\n\u001b[4;1mimportant:\u001b[0m This name \u001b[4;1mmust\u001b[0m be unique amongst your 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')
|
||||
system(f"ssh -i '{path.expanduser('~/.ssh/sshyp')}' -p {_port} {_username_ssh}@{_ip} "
|
||||
f"\"touch '/home/{_username_ssh}/.config/sshyp/devices/{_client_device_name}'\"")
|
||||
copy_name_check(_port, _username_ssh, _ip, _client_device_name)
|
||||
|
||||
print('\nConfiguration complete!\n')
|
||||
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: ')
|
||||
if argument_list[0] == 'help' or argument_list[0] == '--help' or argument_list[0] == '-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')
|
||||
@@ -135,7 +273,7 @@ def print_info(): # prints help text based on argument
|
||||
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('\u001b[1mflags:\u001b[0m')
|
||||
print('add:')
|
||||
print(' password/-p add a password entry')
|
||||
print(' note/-n add a note entry')
|
||||
@@ -149,106 +287,136 @@ def print_info(): # prints help text based on argument
|
||||
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(' 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-2022 Randall Winkhart /')
|
||||
print('/ /')
|
||||
print('/ Version 2022.02.16.fr4.6 /')
|
||||
print('/ The High-Tech Shears Update /')
|
||||
print('/ /')
|
||||
print('////////////////////////////////////////////////////////\n')
|
||||
elif argument == 'license':
|
||||
print("\u001b[1mtip:\u001b[0m you can quickly read an entry with 'sshyp /<entry name>'")
|
||||
elif argument_list[0] == 'version' or argument_list[0] == '-v':
|
||||
print('\nsshyp is a simple, self-hosted, sftp-synchronized password manager\nfor unix(-like) systems (currently'
|
||||
' haiku/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.0.0'
|
||||
'\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 polished trotters '
|
||||
'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[0] == '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:')
|
||||
elif argument_list[0] == '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 == 'edit':
|
||||
print('\nUSAGE: sshyp edit [FLAG]')
|
||||
print('Flags:')
|
||||
elif argument_list[0] == '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 == 'copy':
|
||||
print('\nUSAGE: sshyp copy [FLAG]')
|
||||
print('Flags:')
|
||||
elif argument_list[0] == '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(' 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()
|
||||
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)
|
||||
entry_reader(f"{tmp_dir}{_shm_folder}/{_shm_entry}")
|
||||
rmtree(f"{tmp_dir}{_shm_folder}")
|
||||
|
||||
|
||||
def read_shortcut(): # shortcut to quickly read an entry
|
||||
system(f"gpg -d '{directory}{argument.replace('/', '', 1)}.gpg'")
|
||||
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)
|
||||
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')
|
||||
print('\nsyncing entries with the server device...\n')
|
||||
# check for deletions
|
||||
system(f"ssh -i '{path.expanduser('~/.ssh/sshyp')}' -p {port} {username_ssh}@{ip} \"python -c 'import sshypRemote"
|
||||
f"; sshypRemote.deletion_check(\"'\"{client_device_name}\"'\")'\"")
|
||||
system(f"sftp -p -q -i '{path.expanduser('~/.ssh/sshyp')}' -P {port} {username_ssh}@{ip}:"
|
||||
f"'/home/{username_ssh}/.config/sshyp/deletion_database' {path.expanduser('~/.config/sshyp/')}")
|
||||
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('\nThe deletion database does not exist or is corrupted.\n')
|
||||
print('\n\u001b[38;5;9merror: the deletion database does not exist or is corrupted.\u001b[0m\n')
|
||||
_deletion_database = None
|
||||
s_exit()
|
||||
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"{path.expanduser('~/.password-pasture/')}{_file[:-1]}")
|
||||
except FileNotFoundError:
|
||||
print('Folder does not exist locally.\n')
|
||||
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"{path.expanduser('~/.password-pasture/')}{_file[:-1]}.gpg")
|
||||
except (FileNotFoundError, IsADirectoryError):
|
||||
print('File does not exist locally.\n')
|
||||
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} \"python -c 'import sshypRemote"
|
||||
f"; sshypRemote.folder_check()'\"")
|
||||
system(f"sftp -p -q -i '{path.expanduser('~/.ssh/sshyp')}' -P {port} {username_ssh}@{ip}:"
|
||||
f"'/home/{username_ssh}/.config/sshyp/folder_database' {path.expanduser('~/.config/sshyp/')}")
|
||||
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('\nThe folder database does not exist or is corrupted.\n')
|
||||
print('\n\u001b[38;5;9merror: the folder database does not exist or is corrupted.\u001b[0m\n')
|
||||
_folder_database = None
|
||||
s_exit()
|
||||
s_exit(1)
|
||||
for _folder in _folder_database:
|
||||
if Path(f"{path.expanduser('~/.password-pasture/')}{_folder[:-1]}").is_dir():
|
||||
if Path(f"{path.expanduser('~')}{_folder[:-1]}").is_dir():
|
||||
pass
|
||||
else:
|
||||
Path(f"{path.expanduser('~/.password-pasture/')}{_folder[:-1]}").mkdir(0o700, parents=True, exist_ok=True)
|
||||
print(f"\u001b[38;5;2m{_folder.replace('/.password-pasture/', '')[:-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 {} +')
|
||||
@@ -257,206 +425,220 @@ def sync(): # calls sshync to sync changes to the user's server
|
||||
|
||||
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':
|
||||
if len(argument_list) < 3:
|
||||
_entry_name = entry_name_fetch('name of new entry: ')
|
||||
else:
|
||||
_entry_name = entry_name_fetch(2)
|
||||
if argument_list[1] == 'note' or argument_list[1] == '-n':
|
||||
_shm_folder, _shm_entry = shm_gen()
|
||||
system(f"nano {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('\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) ')
|
||||
open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'w').writelines('\n\n\n' + _notes)
|
||||
elif argument_list[1] == 'password' or argument_list[1] == '-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 {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(_username + '\n' + _password + '\n' + _url + '\n\n'
|
||||
+ _notes + '\n\n')
|
||||
open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'w').writelines(_password + '\n' + _username + '\n' + _url +
|
||||
'\n' + _notes)
|
||||
print('\n\u001b[1mentry preview:\u001b[0m')
|
||||
entry_reader(f"{tmp_dir}{_shm_folder}/{_shm_entry}")
|
||||
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: '))
|
||||
Path(directory + _folder_name).mkdir(0o700)
|
||||
system(f"ssh -i '{path.expanduser('~/.ssh/sshyp')}' -p {port} {username_ssh}@{ip} \"mkdir -p '{directory_ssh}"
|
||||
f"{_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")
|
||||
if len(argument_list) < 3:
|
||||
_entry_name = entry_name_fetch('name of new folder: ')
|
||||
else:
|
||||
move(f"{directory}{_entry_name.replace('/', '', 1)}.gpg", f"{directory}{_new_name.replace('/', '', 1)}.gpg")
|
||||
_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").exists():
|
||||
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: '))
|
||||
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 = 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 len(argument_list) < 3:
|
||||
_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("\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: '))
|
||||
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()
|
||||
system(f"gpg -d --output {tmp_dir}{_shm_folder}/{_shm_entry} '{directory}{_entry_name}.gpg'")
|
||||
replace_line(f"{tmp_dir}{_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 {tmp_dir}{_shm_folder}/{_shm_entry} '{directory}{_entry_name}.gpg'")
|
||||
decrypt(directory + _entry_name, _shm_folder, _shm_entry)
|
||||
|
||||
# compatibility check for GNU pass entries (ensuring they have at least four lines)
|
||||
_lines = open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'r').readlines()
|
||||
if len(_lines) < 3:
|
||||
while len(_lines) < 3:
|
||||
_lines.append('\n')
|
||||
open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'w').writelines(_lines)
|
||||
|
||||
if argument_list[1] == 'username' or argument_list[1] == '-u':
|
||||
_detail = str(input('new username: '))
|
||||
replace_line(f"{tmp_dir}{_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 {tmp_dir}{_shm_folder}/{_shm_entry} '{directory}{_entry_name}.gpg'")
|
||||
elif argument_list[1] == 'password' or argument_list[1] == '-p':
|
||||
_detail = str(input('new password: '))
|
||||
replace_line(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 0, _detail + '\n')
|
||||
elif argument_list[1] == 'url' or argument_list[1] == '-l':
|
||||
_detail = str(input('new url: '))
|
||||
replace_line(f"{tmp_dir}{_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 {tmp_dir}{_shm_folder}/{_shm_entry} '{directory}{_entry_name}.gpg'")
|
||||
elif argument_list[1] == 'note' or argument_list[1] == '-n':
|
||||
edit_note(_shm_folder, _shm_entry)
|
||||
remove(f"{directory}{_entry_name}.gpg")
|
||||
print('\n\u001b[1mentry preview:\u001b[0m')
|
||||
entry_reader(f"{tmp_dir}{_shm_folder}/{_shm_entry}")
|
||||
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 argument == 'gen update' or argument == 'gen -u' or argument == 'gen':
|
||||
_entry_name = entry_name_fetch('name of entry: ')
|
||||
elif argument_list[1] == 'update' or argument_list[1] == '-u':
|
||||
_entry_name = entry_name_fetch(2)
|
||||
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
|
||||
print(f"\n\u001b[38;5;9merror: entry ({_entry_name}) does not exist\u001b[0m\n")
|
||||
s_exit(1)
|
||||
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) ')
|
||||
_entry_name = entry_name_fetch(1)
|
||||
_username = str(input('username: '))
|
||||
_password = pass_gen()
|
||||
if not argument_list[1] == 'update' and not argument_list[1] == '-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 {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(_username + '\n' + _pass_gen + '\n' + _url + '\n\n'
|
||||
+ _notes + '\n\n')
|
||||
open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'w').writelines(_password + '\n' + _username + '\n' + _url + '\n'
|
||||
+ _notes)
|
||||
print('\n\u001b[1mentry preview:\u001b[0m')
|
||||
entry_reader(f"{tmp_dir}{_shm_folder}/{_shm_entry}")
|
||||
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 {tmp_dir}{_shm_folder}/{_shm_entry} '{directory}{_entry_name}.gpg'")
|
||||
replace_line(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 1, _pass_gen + '\n')
|
||||
decrypt(directory + _entry_name, _shm_folder, _shm_entry)
|
||||
replace_line(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 0, _password + '\n')
|
||||
remove(f"{directory}{_entry_name}.gpg")
|
||||
print('\n\u001b[1mentry preview:\u001b[0m')
|
||||
entry_reader(f"{tmp_dir}{_shm_folder}/{_shm_entry}")
|
||||
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 {tmp_dir}{_shm_folder}/{_shm_entry} '{directory}{_read_entry}.gpg'")
|
||||
_copy_line = open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'r').readlines()
|
||||
if Path("/data/data/com.termux").exists(): # checks for Termux, Wayland, or X
|
||||
if argument == 'copy username' or argument == 'copy -u':
|
||||
system('termux-clipboard-set ' + "'" + _copy_line[0].replace('\n', '').replace("'", "'\\''") + "'")
|
||||
elif argument == 'copy password' or argument == 'copy -p':
|
||||
system('termux-clipboard-set ' + "'" + _copy_line[1].replace('\n', '').replace("'", "'\\''") + "'")
|
||||
elif argument == 'copy url' or argument == 'copy -l':
|
||||
system('termux-clipboard-set ' + "'" + _copy_line[2].replace('\n', '').replace("'", "'\\''") + "'")
|
||||
elif argument == 'copy note' or argument == 'copy -n':
|
||||
system('termux-clipboard-set ' + "'" + _copy_line[4].replace('\n', '').replace("'", "'\\''") + "'")
|
||||
elif environ.get('WAYLAND_DISPLAY') == 'wayland-0':
|
||||
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("'", "'\\''") + "'")
|
||||
if len(argument_list) < 3:
|
||||
_entry_name = entry_name_fetch('entry to copy: ')
|
||||
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':
|
||||
_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)
|
||||
_copy_line = open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'r').readlines()
|
||||
if uname()[0] == 'Haiku': # Haiku clipboard detection
|
||||
if argument_list[1] == 'username' or argument_list[1] == '-u':
|
||||
system('clipboard -c ' + "'" + _copy_line[1].replace('\n', '').replace("'", "'\\''") + "'")
|
||||
elif argument_list[1] == 'password' or argument_list[1] == '-p':
|
||||
system('clipboard -c ' + "'" + _copy_line[0].replace('\n', '').replace("'", "'\\''") + "'")
|
||||
elif argument_list[1] == 'url' or argument_list[1] == '-l':
|
||||
system('clipboard -c ' + "'" + _copy_line[2].replace('\n', '').replace("'", "'\\''") + "'")
|
||||
elif argument_list[1] == 'note' or argument_list[1] == '-n':
|
||||
system('clipboard -c ' + "'" + _copy_line[3].replace('\n', '').replace("'", "'\\''") + "'")
|
||||
Popen('sleep 30; clipboard -r', shell=True)
|
||||
elif Path("/data/data/com.termux").exists(): # Termux (Android) clipboard detection
|
||||
if argument_list[1] == 'username' or argument_list[1] == '-u':
|
||||
system('termux-clipboard-set ' + "'" + _copy_line[1].replace('\n', '').replace("'", "'\\''") + "'")
|
||||
elif argument_list[1] == 'password' or argument_list[1] == '-p':
|
||||
system('termux-clipboard-set ' + "'" + _copy_line[0].replace('\n', '').replace("'", "'\\''") + "'")
|
||||
elif argument_list[1] == 'url' or argument_list[1] == '-l':
|
||||
system('termux-clipboard-set ' + "'" + _copy_line[2].replace('\n', '').replace("'", "'\\''") + "'")
|
||||
elif argument_list[1] == 'note' or argument_list[1] == '-n':
|
||||
system('termux-clipboard-set ' + "'" + _copy_line[3].replace('\n', '').replace("'", "'\\''") + "'")
|
||||
Popen("sleep 30; termux-clipboard-set ''", shell=True)
|
||||
elif environ.get('WAYLAND_DISPLAY') == 'wayland-0': # Wayland clipboard detection
|
||||
if argument_list[1] == 'username' or argument_list[1] == '-u':
|
||||
system('wl-copy ' + "'" + _copy_line[1].replace('\n', '').replace("'", "'\\''") + "'")
|
||||
elif argument_list[1] == 'password' or argument_list[1] == '-p':
|
||||
system('wl-copy ' + "'" + _copy_line[0].replace('\n', '').replace("'", "'\\''") + "'")
|
||||
elif argument_list[1] == 'url' or argument_list[1] == '-l':
|
||||
system('wl-copy ' + "'" + _copy_line[2].replace('\n', '').replace("'", "'\\''") + "'")
|
||||
elif argument_list[1] == 'note' or argument_list[1] == '-n':
|
||||
system('wl-copy ' + "'" + _copy_line[3].replace('\n', '').replace("'", "'\\''") + "'")
|
||||
Popen('sleep 30; wl-copy -c', shell=True)
|
||||
else: # X11 clipboard detection
|
||||
if argument_list[1] == 'username' or argument_list[1] == '-u':
|
||||
system('echo -n ' + "'" + _copy_line[1].replace('\n', '').replace("'", "'\\''") + "'" + ' | xclip -sel c')
|
||||
elif argument == 'copy url' or argument == 'copy -l':
|
||||
elif argument_list[1] == 'password' or argument_list[1] == '-p':
|
||||
system('echo -n ' + "'" + _copy_line[0].replace('\n', '').replace("'", "'\\''") + "'" + ' | xclip -sel c')
|
||||
elif argument_list[1] == 'url' or argument_list[1] == '-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')
|
||||
elif argument_list[1] == 'note' or argument_list[1] == '-n':
|
||||
system('echo -n ' + "'" + _copy_line[3].replace('\n', '').replace("'", "'\\''") + "'" + ' | xclip -sel c')
|
||||
Popen("sleep 30; echo -n '' | xclip -sel c", shell=True)
|
||||
rmtree(f"{tmp_dir}{_shm_folder}")
|
||||
|
||||
|
||||
def remove_data(): # deletes an entry from the server and flags it for local deletion on sync
|
||||
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)
|
||||
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)
|
||||
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:
|
||||
system(f"gpg -d --output {tmp_dir}sshyp.lock {path.expanduser('~/.config/sshyp/lock.gpg')}")
|
||||
_unlock = open(f"{tmp_dir}sshyp.lock", 'r').readlines()
|
||||
remove(f"{tmp_dir}sshyp.lock")
|
||||
except FileNotFoundError:
|
||||
print('\nAccess denied.\n')
|
||||
s_exit()
|
||||
system(f"ssh -i '{path.expanduser('~/.ssh/sshyp')}' -p {port} {username_ssh}@{ip} \"python -c 'import sshypRemote"
|
||||
f"; sshypRemote.delete(\"'\"{_entry_name}\"'\")'\"")
|
||||
silent_sync, ssh_error = 0, 0
|
||||
# retrieve typed argument
|
||||
argument_list, argument = argv, ''
|
||||
del argument_list[0]
|
||||
for _argument in argument_list:
|
||||
argument += _argument + ' '
|
||||
argument = argument[:-1]
|
||||
if uname()[0] == 'Haiku': # set proper gpg command for OS
|
||||
gpg = 'gpg --pinentry-mode loopback'
|
||||
else:
|
||||
gpg = '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':
|
||||
# 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':
|
||||
gpg_id = open(path.expanduser('~/.config/sshyp/sshyp-gpg')).read().strip()
|
||||
ssh_info = sshync.get_profile(path.expanduser('~/.config/sshyp/sshyp.sshync'))
|
||||
username_ssh = ssh_info[0].replace('\n', '')
|
||||
ip = ssh_info[1].replace('\n', '')
|
||||
@@ -464,89 +646,79 @@ if argument != 'tweak':
|
||||
directory = str(ssh_info[3].replace('\n', ''))
|
||||
directory_ssh = '/home/' + username_ssh + '/.password-pasture/'
|
||||
client_device_name = listdir(path.expanduser('~/.config/sshyp/devices'))[0]
|
||||
except FileNotFoundError:
|
||||
gpg_id = open(path.expanduser('~/.config/sshyp/sshyp-gpg')).read().strip()
|
||||
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)
|
||||
except (FileNotFoundError, IndexError):
|
||||
if device_type.lower() != 's':
|
||||
print('\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
|
||||
print("Not all necessary configuration files are present. Please run 'sshyp tweak'!")
|
||||
print("not all necessary configuration files are present - please run 'sshyp tweak'")
|
||||
print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n')
|
||||
s_exit()
|
||||
else:
|
||||
try:
|
||||
s_exit(1)
|
||||
else:
|
||||
tweak()
|
||||
s_exit()
|
||||
except KeyboardInterrupt:
|
||||
print('\n')
|
||||
s_exit()
|
||||
s_exit(0)
|
||||
|
||||
# run function based on argument
|
||||
error = 0 # create an error flag to determine if syncing should occur at end
|
||||
if argument.startswith('/'):
|
||||
# run function based on arguments
|
||||
if argument.startswith('/'):
|
||||
read_shortcut()
|
||||
elif argument == '':
|
||||
try:
|
||||
elif argument == '':
|
||||
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':
|
||||
elif argument == 'help' or argument == '--help' or argument == '-h' or argument == 'license' or argument \
|
||||
== 'version' or argument == '-v':
|
||||
print_info()
|
||||
elif argument == 'add note' or argument == 'add -n' or argument == 'add password' or argument == 'add -p':
|
||||
try:
|
||||
elif argument_list[0] == 'add':
|
||||
if len(argument_list) == 1:
|
||||
print_info()
|
||||
elif argument_list[1] == 'note' or argument_list[1] == '-n' or argument_list[1] == 'password' or \
|
||||
argument_list[1] == '-p':
|
||||
add_entry()
|
||||
except KeyboardInterrupt:
|
||||
print('\n')
|
||||
s_exit()
|
||||
elif argument == 'add folder' or argument == 'add -f':
|
||||
try:
|
||||
elif argument_list[1] == 'folder' or argument_list[1] == '-f':
|
||||
add_folder()
|
||||
except KeyboardInterrupt:
|
||||
print('\n')
|
||||
s_exit()
|
||||
elif argument == 'edit rename' or argument == 'edit relocate' or argument == 'edit -r':
|
||||
try:
|
||||
else:
|
||||
print_info()
|
||||
s_exit(0)
|
||||
elif argument_list[0] == 'edit':
|
||||
if len(argument_list) == 1:
|
||||
print_info()
|
||||
elif argument_list[1] == 'rename' or argument_list[1] == 'relocate' or argument_list[1] == '-r':
|
||||
silent_sync = 1
|
||||
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:
|
||||
elif argument_list[1] == 'username' or argument_list[1] == '-u' or argument_list[1] == 'password' or \
|
||||
argument_list[1] == '-p' or argument_list[1] == 'url' or argument_list[1] == '-l' or \
|
||||
argument_list[1] == 'note' or argument_list[1] == '-n':
|
||||
edit()
|
||||
except KeyboardInterrupt:
|
||||
print('\n')
|
||||
s_exit()
|
||||
elif argument == 'gen' or argument == 'gen update' or argument == 'gen -u':
|
||||
try:
|
||||
else:
|
||||
print_info()
|
||||
s_exit(0)
|
||||
elif argument_list[0] == 'gen':
|
||||
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:
|
||||
elif argument_list[0] == 'copy':
|
||||
if len(argument_list) == 1:
|
||||
print_info()
|
||||
elif argument_list[1] == 'username' or argument_list[1] == '-u' or argument_list[1] == 'password' or \
|
||||
argument_list[1] == '-p' or argument_list[1] == 'url' or argument_list[1] == '-l' or \
|
||||
argument_list[1] == 'note' or argument_list[1] == '-n':
|
||||
copy_data()
|
||||
except KeyboardInterrupt:
|
||||
print('\n')
|
||||
s_exit()
|
||||
elif argument == 'shear' or argument == '-rm':
|
||||
try:
|
||||
else:
|
||||
print_info()
|
||||
elif argument_list[0] == 'shear' or argument_list[0] == '-rm':
|
||||
remove_data()
|
||||
elif argument_list[0] != 'sync' and argument_list[0] != '-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) > 0 and ssh_error == 0 and \
|
||||
((argument_list[0] == 'sync' or argument_list[0] == '-s' or argument_list[0] == 'gen' or
|
||||
argument_list[0] == 'shear' or argument_list[0] == '-rm') or ((argument_list[0] == 'add'
|
||||
or argument_list[0] == 'edit')
|
||||
and len(argument_list) > 1)):
|
||||
sync()
|
||||
|
||||
s_exit(0)
|
||||
|
||||
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 \
|
||||
!= 'version' and argument != '-v' and error == 0 and \
|
||||
argument.startswith('/') is False:
|
||||
sync()
|
||||
s_exit(0)
|
||||
|
||||
+9
-8
@@ -1,9 +1,9 @@
|
||||
#!/usr/bin/python3
|
||||
#!/bin/python3
|
||||
|
||||
# external modules
|
||||
|
||||
from os import remove, listdir
|
||||
from os.path import expanduser, isdir, join
|
||||
from os import listdir, remove, walk
|
||||
from os.path import expanduser
|
||||
from shutil import rmtree
|
||||
|
||||
|
||||
@@ -14,12 +14,12 @@ def delete(_file_path):
|
||||
try:
|
||||
rmtree(f"{expanduser('~/.password-pasture/')}{_file_path}")
|
||||
except FileNotFoundError:
|
||||
print('\nFolder does not exist remotely.')
|
||||
print('folder does not exist remotely')
|
||||
else:
|
||||
try:
|
||||
remove(f"{expanduser('~/.password-pasture/')}{_file_path}.gpg")
|
||||
except FileNotFoundError:
|
||||
print('\nFile does not exist remotely.')
|
||||
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')
|
||||
|
||||
@@ -39,6 +39,7 @@ def deletion_check(_client_device_name):
|
||||
|
||||
def folder_check():
|
||||
open(expanduser('~/.config/sshyp/folder_database'), 'w').write('')
|
||||
for _file in listdir(expanduser('~/.password-pasture')):
|
||||
if isdir(join('~/.config/sshyp/folder_database/', _file)):
|
||||
open(expanduser('~/.config/sshyp/folder_database'), 'a').write(_file + '\n')
|
||||
for _root, _directories, _files in walk(expanduser('~/.password-pasture')):
|
||||
for _dir in _directories:
|
||||
open(expanduser('~/.config/sshyp/folder_database'), 'a')\
|
||||
.write(f"{_root.replace(expanduser('~'), '')}/{_dir}\n")
|
||||
|
||||
+206
-127
@@ -1,3 +1,84 @@
|
||||
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 Red Hat distributions (such as Fedora)
|
||||
- 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
|
||||
- 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
|
||||
@@ -15,29 +96,29 @@ Changes:
|
||||
Planned for next major update (fr5, The sshyp Doing a Split Update):
|
||||
|
||||
sshyp:
|
||||
** sshyp has recieved a major visual overhaul
|
||||
- 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
|
||||
- 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
|
||||
- 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)
|
||||
- create separate gui frontend targetting mobile and desktop Linux
|
||||
- auto-completion on tab (currently unsure of best way to make this work)
|
||||
|
||||
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||
|
||||
@@ -58,29 +139,29 @@ Changes:
|
||||
Planned for next major update (fr5, The sshyp Doing a Split Update):
|
||||
|
||||
sshyp:
|
||||
** sshyp has recieved a major visual overhaul
|
||||
- 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
|
||||
- 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
|
||||
- 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)
|
||||
- create separate gui frontend targetting mobile and desktop Linux
|
||||
- auto-completion on tab (currently unsure of best way to make this work)
|
||||
|
||||
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||
|
||||
@@ -105,29 +186,29 @@ Changes:
|
||||
Planned for next major update (fr5, The sshyp Doing a Split Update):
|
||||
|
||||
sshyp:
|
||||
** sshyp has recieved a major visual overhaul
|
||||
- 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
|
||||
- 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
|
||||
- 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)
|
||||
- create separate gui frontend targetting mobile and desktop Linux
|
||||
- auto-completion on tab (currently unsure of best way to make this work)
|
||||
|
||||
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||
|
||||
@@ -148,29 +229,29 @@ Changes:
|
||||
Planned for next major update (fr5, The sshyp Doing a Split Update):
|
||||
|
||||
sshyp:
|
||||
** sshyp has recieved a major visual overhaul
|
||||
- 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
|
||||
- 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
|
||||
- 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)
|
||||
- create separate gui frontend targetting mobile and desktop Linux
|
||||
- auto-completion on tab (currently unsure of best way to make this work)
|
||||
|
||||
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||
|
||||
@@ -192,29 +273,29 @@ Changes:
|
||||
Planned for next major update (fr5, The sshyp Doing a Split Update):
|
||||
|
||||
sshyp:
|
||||
** sshyp has recieved a major visual overhaul
|
||||
- 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
|
||||
- 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
|
||||
- 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)
|
||||
- create separate gui frontend targetting mobile and desktop Linux
|
||||
- auto-completion on tab (currently unsure of best way to make this work)
|
||||
|
||||
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||
|
||||
@@ -236,29 +317,29 @@ Changes:
|
||||
Planned for next major update (fr5, The sshyp Doing a Split Update):
|
||||
|
||||
sshyp:
|
||||
** sshyp has recieved a major visual overhaul
|
||||
- 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
|
||||
- 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
|
||||
- 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)
|
||||
- create separate gui frontend targetting mobile and desktop Linux
|
||||
- auto-completion on tab (currently unsure of best way to make this work)
|
||||
|
||||
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||
|
||||
@@ -287,29 +368,29 @@ Changes:
|
||||
Planned for next major update (fr5, The sshyp Doing a Split Update):
|
||||
|
||||
sshyp:
|
||||
** sshyp has recieved a major visual overhaul
|
||||
- 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
|
||||
- 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
|
||||
- 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)
|
||||
- create separate gui frontend targetting mobile and desktop Linux
|
||||
- auto-completion on tab (currently unsure of best way to make this work)
|
||||
|
||||
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||
|
||||
@@ -330,30 +411,30 @@ Changes:
|
||||
Planned for next major update (fr4, The sshyp Doing a Split Update):
|
||||
|
||||
sshyp:
|
||||
** sshyp has recieved a major visual overhaul
|
||||
- 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
|
||||
- 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
|
||||
- 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)
|
||||
- create separate gui frontend targetting mobile and desktop Linux
|
||||
- auto-completion on tab (currently unsure of best way to make this work)
|
||||
|
||||
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||
|
||||
@@ -374,39 +455,39 @@ Changes:
|
||||
|
||||
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
|
||||
- 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
|
||||
- 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
|
||||
- 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
|
||||
- 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)
|
||||
- create separate gui frontend targetting mobile and desktop Linux
|
||||
- auto-completion on tab (currently unsure of best way to make this work)
|
||||
|
||||
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||
|
||||
@@ -424,39 +505,39 @@ Changes:
|
||||
|
||||
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
|
||||
- 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
|
||||
- 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
|
||||
- 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
|
||||
- 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)
|
||||
- create separate gui frontend targetting mobile and desktop Linux
|
||||
- auto-completion on tab (currently unsure of best way to make this work)
|
||||
|
||||
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||
|
||||
@@ -475,39 +556,39 @@ Changes:
|
||||
|
||||
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
|
||||
- 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
|
||||
- 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
|
||||
- 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
|
||||
- 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)
|
||||
- create separate gui frontend targetting mobile and desktop Linux
|
||||
- auto-completion on tab (currently unsure of best way to make this work)
|
||||
|
||||
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||
|
||||
@@ -530,39 +611,39 @@ Changes:
|
||||
|
||||
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
|
||||
- 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
|
||||
- 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
|
||||
- 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
|
||||
- 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)
|
||||
- create separate gui frontend targetting mobile and desktop Linux
|
||||
- auto-completion on tab (currently unsure of best way to make this work)
|
||||
|
||||
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||
|
||||
@@ -1077,5 +1158,3 @@ What is currently functional:
|
||||
- sort notes and passwords into folders
|
||||
- gpg encryption
|
||||
- edit password/note entries
|
||||
|
||||
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||
|
||||
+15
-27
@@ -1,6 +1,6 @@
|
||||
.TH sshyp 1 "16 February 2022" "2022.02.16.fr4.5" "sshyp man page"
|
||||
.TH sshyp 1 "17 June 2022" "v1.0.0" "sshyp man page"
|
||||
.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
|
||||
sshyp [OPTION] [[FLAG]] [/<entry name>]
|
||||
.SH DESCRIPTION
|
||||
@@ -8,40 +8,33 @@ sshyp is a lightweight password and note management program written in Python. s
|
||||
.SH EXAMPLES
|
||||
Setting up sshyp for the first time or altering its configuration (also recommended after major updates):
|
||||
sshyp tweak
|
||||
*follow the prompts
|
||||
|
||||
Viewing the entry database:
|
||||
sshyp
|
||||
|
||||
Reading an existing entry saved as ~/.password-pasture/development/github.gpg:
|
||||
sshyp /development/github
|
||||
|
||||
Copying the password of an existing entry saved as ~/.password-pasture/financial/bank.gpg:
|
||||
sshyp copy -p
|
||||
*answer the prompt with "/financial/bank"
|
||||
*enter decryption password
|
||||
sshyp copy -p /financial/bank
|
||||
|
||||
Editing the username of an existing entry saved as ~/.password-pasture/game.gpg:
|
||||
sshyp edit -u
|
||||
*answer the first prompt with "game"
|
||||
*follow the prompts
|
||||
sshyp edit -u game
|
||||
|
||||
Making a new entry using the built-in password generator:
|
||||
sshyp gen
|
||||
*follow the prompts
|
||||
Making a new entry saved as ~/.password-pasture/school/university.gpg using the built-in password generator:
|
||||
sshyp gen /school/university
|
||||
|
||||
Creating a note-only entry:
|
||||
sshyp add -n
|
||||
*follow the prompts
|
||||
Creating a note-only entry saved as ~/.password-pasture/notes/testNote.gpg:
|
||||
sshyp add -n /notes/testNote
|
||||
|
||||
Syncing entries with the server:
|
||||
Manually syncing entries with the server:
|
||||
sshyp sync
|
||||
|
||||
Removing an existing folder saved as ~/.password-pasture/social:
|
||||
sshyp shear
|
||||
*when prompted for what to delete, since you are deleting a folder, be sure to enter your choice with a following "/", e.g. "social/" or "/social/"
|
||||
sshyp shear social/
|
||||
|
||||
.SH OPTIONS
|
||||
In order to quickly read an existing entry, just run "sshyp </entry name>".
|
||||
|
||||
Options for other operations are as follows:
|
||||
USAGE: sshyp [OPTION [FLAG] [<entry name>]] | [/<entry name>]
|
||||
|
||||
help/--help/-h bring up the help menu
|
||||
version/-v display sshyp version info
|
||||
@@ -71,13 +64,9 @@ copy:
|
||||
gen:
|
||||
update/-u generate a password for an existing entry
|
||||
.SH LIMITATIONS
|
||||
The following limitations will be corrected in future updates:
|
||||
|
||||
Currently, the entry list displays each entry with the file extension ".gpg" visible (which you do not type when reading, modifying, or creating an entry). This will be corrected when the new entry list is added.
|
||||
|
||||
The following characters/character sequences are not supported in entry/folder titles:
|
||||
|
||||
@ ^&*
|
||||
@ ^&* *&^
|
||||
.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.
|
||||
|
||||
@@ -94,7 +83,6 @@ Client setup:
|
||||
Install sshyp
|
||||
Run "sshyp tweak" and follow the prompts
|
||||
Copy the generated public SSH key to the server using preferred method (manually adding to authorized_keys, ssh-copy-id, etc.)
|
||||
**this step will be automated in the future: if an entry library already exists on the server, make sure to manually recreate any folders that exist on the server in the ~/.password-pasture directory
|
||||
If you already have entries on the server, sync them using "sshyp sync"
|
||||
Done!
|
||||
|
||||
|
||||
Executable
+48
@@ -0,0 +1,48 @@
|
||||
#!/bin/python3
|
||||
|
||||
from os import path, remove, system, walk
|
||||
from pathlib import Path
|
||||
from shutil import move, rmtree
|
||||
|
||||
if __name__ == "__main__":
|
||||
gpg_id = input('\nWhat is the ID of the GPG key you would like to use for re-encryption?\n\nID: ')
|
||||
pasture = path.expanduser('~/.password-pasture')
|
||||
if Path(f"{pasture}.new").exists():
|
||||
rmtree(f"{pasture}.new")
|
||||
if Path(f"{pasture}.old").exists():
|
||||
rmtree(f"{pasture}.old")
|
||||
if path.isdir(pasture):
|
||||
for dirPath, dirNames, filenames in walk(pasture):
|
||||
for filename in sorted(filenames):
|
||||
Path(dirPath.replace(pasture, pasture + '.new')).mkdir(0o700, parents=True, exist_ok=True)
|
||||
system(f"gpg -d '{dirPath}/{filename}' "
|
||||
f"> '{dirPath.replace(pasture, pasture + '.new')}/{filename[:-4]}'")
|
||||
_old_contents, _new_contents = \
|
||||
open(f"{dirPath.replace(pasture, pasture + '.new')}/{filename[:-4]}", 'r').readlines(), ''
|
||||
for _num in range(len(_old_contents)):
|
||||
if _num == 0:
|
||||
try:
|
||||
_new_contents += _old_contents[1]
|
||||
except IndexError:
|
||||
_new_contents += '\n'
|
||||
elif _num == 1:
|
||||
_new_contents += _old_contents[0]
|
||||
elif _num == 3:
|
||||
if _old_contents[_num] == ' ' or _old_contents[_num] == '\n':
|
||||
pass
|
||||
else:
|
||||
_new_contents += _old_contents[_num]
|
||||
else:
|
||||
_new_contents += _old_contents[_num]
|
||||
for _num in reversed(range(len(_new_contents))):
|
||||
if _new_contents[_num] == '\n' or _new_contents[_num] == '':
|
||||
_new_contents = _new_contents[:-1]
|
||||
else:
|
||||
break
|
||||
open(f"{dirPath.replace(pasture, pasture + '.new')}/{filename[:-4]}", 'w').writelines(_new_contents)
|
||||
system(f"gpg -qr {str(gpg_id)} -e '{dirPath.replace(pasture, pasture + '.new')}/{filename[:-4]}'")
|
||||
remove(f"{dirPath.replace(pasture, pasture + '.new')}/{filename[:-4]}")
|
||||
else:
|
||||
print(f"\nError: no entry folder ({pasture}) found\n")
|
||||
move(pasture, f"{pasture}.old")
|
||||
move(f"{pasture}.new", pasture)
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#!/bin/python3
|
||||
|
||||
from os import path, remove, system, walk
|
||||
from pathlib import Path
|
||||
from shutil import move, rmtree
|
||||
|
||||
if __name__ == "__main__":
|
||||
gpg_id = input('\nWhat is the ID of the GPG key you would like to use for re-encryption?\n\nID: ')
|
||||
pasture = path.expanduser('~/.password-pasture')
|
||||
if Path(f"{pasture}.new").exists():
|
||||
rmtree(f"{pasture}.new")
|
||||
if Path(f"{pasture}.old").exists():
|
||||
rmtree(f"{pasture}.old")
|
||||
if path.isdir(pasture):
|
||||
for dirPath, dirNames, filenames in walk(pasture):
|
||||
for filename in sorted(filenames):
|
||||
Path(dirPath.replace(pasture, pasture + '.new')).mkdir(0o700, parents=True, exist_ok=True)
|
||||
system(f"gpg -d '{dirPath}/{filename}' "
|
||||
f"> '{dirPath.replace(pasture, pasture + '.new')}/{filename[:-4]}'")
|
||||
_old_contents, _new_contents = \
|
||||
open(f"{dirPath.replace(pasture, pasture + '.new')}/{filename[:-4]}", 'r').readlines(), ''
|
||||
for _num in range(len(_old_contents)):
|
||||
if _num == 3:
|
||||
if _old_contents[_num] == ' ' or _old_contents[_num] == '\n':
|
||||
pass
|
||||
else:
|
||||
_new_contents += _old_contents[_num]
|
||||
else:
|
||||
_new_contents += _old_contents[_num]
|
||||
for _num in reversed(range(len(_new_contents))):
|
||||
if _new_contents[_num] == '\n' or _new_contents[_num] == '':
|
||||
_new_contents = _new_contents[:-1]
|
||||
else:
|
||||
break
|
||||
open(f"{dirPath.replace(pasture, pasture + '.new')}/{filename[:-4]}", 'w').writelines(_new_contents)
|
||||
system(f"gpg -qr {str(gpg_id)} -e '{dirPath.replace(pasture, pasture + '.new')}/{filename[:-4]}'")
|
||||
remove(f"{dirPath.replace(pasture, pasture + '.new')}/{filename[:-4]}")
|
||||
else:
|
||||
print(f"\nError: no entry folder ({pasture}) found\n")
|
||||
move(pasture, f"{pasture}.old")
|
||||
move(f"{pasture}.new", pasture)
|
||||
+140
-20
@@ -1,15 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script packages sshyp (from source) for various Linux environments.
|
||||
|
||||
# This script packages sshyp (from source) for various UNIX environments.
|
||||
# Dependencies (Arch Linux): dpkg (packaging for Debian/Termux), rpmdevtools (packaging for Red Hat), freebsd-pkg (packaging for FreeBSD)
|
||||
# NOTE It is recommended to instead use the latest officially packaged and tagged release.
|
||||
# NOTE If using Arch, it is recommended to install from the AUR or from the PKGBUILD attatched to the latest official release.
|
||||
# NOTE As of release fr4, sshync will become a separate package and thus a dependency for sshyp. sshync is automatically installed with the PKGBUILD version.
|
||||
|
||||
echo -e '\nOptions (please enter the number only):'
|
||||
echo -e '\nDistribution Packages:\n\n1. Debian\n2. Termux\n3. Generic (used for PKGBUILD/APKBUILD)'
|
||||
echo -e '\nBuild Scripts:\n\n4. Alpine Linux (APKBUILD)\n5. Arch Linux (PKGBUILD, also builds local generic package)'
|
||||
echo -e '\nOther:\n\n6. All (generates all distribution packages and build scripts)\n'
|
||||
echo -e '\nPackage Formats:\n\n1. Haiku\n2. Debian\n3. Red Hat\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, as this must be done on Haiku) 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'
|
||||
@@ -18,7 +16,7 @@ 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" == "4" ] || [ "$distro" == "5" ] || [ "$distro" == "6" ]; then
|
||||
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
|
||||
@@ -32,10 +30,53 @@ fi
|
||||
|
||||
mkdir -p packages
|
||||
|
||||
if [ "$distro" == "1" ] || [ "$distro" == "6" ]; then
|
||||
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
|
||||
nano
|
||||
}
|
||||
urls {
|
||||
\"https://github.com/rwinkhart/sshyp\"
|
||||
}
|
||||
" > packages/haikutemp/.PackageInfo
|
||||
cp -r bin packages/haikutemp/
|
||||
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}
|
||||
mkdir -p packages/debiantemp/sshyp_"$version"-"$revision"_all/usr/share/man/man1
|
||||
mkdir -p packages/debiantemp/sshyp_"$version"-"$revision"_all/{DEBIAN,usr/share/man/man1}
|
||||
echo "Package: sshyp
|
||||
Version: $version
|
||||
Section: utils
|
||||
@@ -56,7 +97,7 @@ Installed-Size: 35
|
||||
echo -e "\nDebian packaging complete.\n"
|
||||
fi
|
||||
|
||||
if [ "$distro" == "2" ] || [ "$distro" == "6" ]; then
|
||||
if [ "$distro" == "5" ] || [ "$distro" == "8" ]; then
|
||||
echo -e '\nPackaging for Termux...\n'
|
||||
mkdir -p packages/termuxtemp/sshyp_"$version"-"$revision"_all_termux/{data,DEBIAN}
|
||||
mkdir -p packages/termuxtemp/sshyp_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/share/man/man1
|
||||
@@ -80,12 +121,11 @@ Installed-Size: 35
|
||||
echo -e "\nTermux packaging complete.\n"
|
||||
fi
|
||||
|
||||
if [ "$distro" == "3" ] || [ "$distro" == "5" ] || [ "$distro" == "6" ]; then
|
||||
if [ "$distro" == "3" ] || [ "$distro" == "4" ] || [ "$distro" == "6" ] || [ "$distro" == "7" ] || [ "$distro" == "8" ]; then
|
||||
echo -e '\nPackaging as generic...\n'
|
||||
mkdir -p packages/archtemp/usr
|
||||
mkdir -p packages/archtemp/usr/share/man/man1
|
||||
cp -r bin packages/archtemp/usr/
|
||||
cp -r share packages/archtemp/usr/
|
||||
mkdir -p packages/archtemp/usr/share/man/man1
|
||||
cp extra/manpage packages/archtemp/usr/share/man/man1/sshyp.1
|
||||
gzip packages/archtemp/usr/share/man/man1/sshyp.1
|
||||
tar -C packages/archtemp -cvf packages/sshyp-"$version".tar.xz usr/
|
||||
@@ -95,7 +135,91 @@ if [ "$distro" == "3" ] || [ "$distro" == "5" ] || [ "$distro" == "6" ]; then
|
||||
echo -e "\nGeneric packaging complete.\n"
|
||||
fi
|
||||
|
||||
if [ "$distro" == "5" ] || [ "$distro" == "6" ]; then
|
||||
if [ "$distro" == "3" ] || [ "$distro" == "8" ]; then
|
||||
echo -e '\nPackaging for Red Hat...\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: GPL3
|
||||
URL: https://github.com/rwinkhart/sshyp
|
||||
Source0: sshyp-"$version".tar.xz
|
||||
|
||||
Requires: python gnupg openssh nano 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/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 "\nRed Hat 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\"
|
||||
},
|
||||
\"nano\" : {
|
||||
\"origin\" : \"editors/nano\"
|
||||
},
|
||||
\"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/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>
|
||||
|
||||
@@ -119,7 +243,3 @@ package() {
|
||||
" > packages/PKGBUILD
|
||||
echo -e "\nPKGBUILD generated.\n"
|
||||
fi
|
||||
|
||||
if [ "$distro" == "4" ]; then
|
||||
echo -e '\nThis packaging format is not yet supported, but will be in the near future!\n'
|
||||
fi
|
||||
|
||||
+28
-36
@@ -1,43 +1,37 @@
|
||||
sshyp 2022.02.16.fr4.6
|
||||
sshyp v1.0.0
|
||||
|
||||
The High-Tech Shears Update - Patch 6
|
||||
The Polished Trotters Update
|
||||
|
||||
This release addresses a critical typo.
|
||||
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.
|
||||
|
||||
Note: Upgrading from releases older than fr4.6 requires the configuration ("sshyp tweak") to be re-done, as the configuration process has changed.
|
||||
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 Red Hat distributions (such as Fedora)
|
||||
- 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 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)
|
||||
- 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
|
||||
- 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!
|
||||
|
||||
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||
|
||||
@@ -46,7 +40,5 @@ https://raw.githubusercontent.com/rwinkhart/sshyp/main/extra/changelog-total
|
||||
|
||||
Legend:
|
||||
|
||||
** = feature/change not yet finished/implemented
|
||||
- = feature/change implemented and pushed upstream
|
||||
^ = note regarding the above feature/change
|
||||
&& = visual separater for patch notes for different planned major version releases
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
sshyp is a FOSS password manager that takes advantage of rsync
|
||||
Copyright (C) 2021 Randall Winkhart idgr@tutanota.com
|
||||
sshyp is a FOSS password manager that uses an sftp-based syncing back-end.
|
||||
Copyright (C) 2022 Randall Winkhart idgr@tutanota.com
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user