mirror of
https://github.com/rwinkhart/sshyp.git
synced 2026-09-03 15:47:18 -04:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43351fd66f | ||
|
|
096bdb0773 | ||
|
|
330396c5f1 | ||
|
|
8576f63479 | ||
|
|
393f241538 | ||
|
|
c557d5bfee | ||
|
|
acca7d888c | ||
|
|
2f3b3c67ba | ||
|
|
88d2402e88 | ||
|
|
928aacc64a | ||
|
|
094bdcb418 | ||
|
|
419ff51e75 | ||
|
|
2111a0454e | ||
|
|
5d902f0324 | ||
|
|
505ffdb489 | ||
|
|
5cab1ad091 | ||
|
|
2e2404636b | ||
|
|
6cb5bd405f | ||
|
|
c93965c9a5 | ||
|
|
d685e07d32 | ||
|
|
192f58fef5 | ||
|
|
106f22f757 | ||
|
|
ae414dadda | ||
|
|
c9e99732a2 | ||
|
|
fc37368447 | ||
|
|
ca2bc98735 | ||
|
|
f44391612d |
@@ -0,0 +1,72 @@
|
|||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
#
|
||||||
|
# ******** NOTE ********
|
||||||
|
# We have attempted to detect the languages in your repository. Please check
|
||||||
|
# the `language` matrix defined below to confirm you have the correct set of
|
||||||
|
# supported CodeQL languages.
|
||||||
|
#
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ "main" ]
|
||||||
|
schedule:
|
||||||
|
- cron: '34 22 * * 5'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [ 'python' ]
|
||||||
|
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||||
|
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v2
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
|
||||||
|
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||||
|
# queries: security-extended,security-and-quality
|
||||||
|
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
|
|
||||||
|
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||||
|
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||||
|
|
||||||
|
# - run: |
|
||||||
|
# echo "Run, Build Application using script"
|
||||||
|
# ./location_of_script_within_repo/buildscript.sh
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v2
|
||||||
@@ -1,12 +1,16 @@
|
|||||||
# sshyp
|

|
||||||
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.
|
[](https://github.com/rwinkhart/sshyp/actions/workflows/codeql-analysis.yml)
|
||||||
|
|
||||||
The only password-store compatible CLI password manager available for Haiku.
|
sshyp is a very simple self-hosted, synchronized password manager for UNIX(-like) systems (currently Haiku/FreeBSD/Linux).
|
||||||
|
|
||||||
"sshyp" stands for "sshync passwords", or "ssh sync passwords".
|
sshyp is compatible with entries created by pass/password-store, as its original goal was to be like pass/password-store, but far more user-friendly to synchronize with a self-hosted server.
|
||||||
"sshync" is the custom syncing backend (based on sftp) used by "sshyp".
|
|
||||||
|
sshyp is (as of writing) the only password-store compatible CLI password manager available for Haiku.
|
||||||
|
|
||||||
|
sshyp makes use of a custom sftp wrapper, called sshync (ssh+sync), to reliably sync user entries with a local or remote server.
|
||||||
|
|
||||||
|
The name "sshyp" is a combination of its syncing library, "sshync", and "passwords".
|
||||||
|
|
||||||
# WARNING
|
# WARNING
|
||||||
It is your responsibility to assess the security and stability of "sshyp" before using it and ensure it meets your needs.
|
It is your responsibility to assess the security and stability of "sshyp" before using it and ensure it meets your needs.
|
||||||
@@ -26,7 +30,7 @@ What sshyp can do:
|
|||||||
|
|
||||||
What sshyp will likely do:
|
What sshyp will likely do:
|
||||||
|
|
||||||
- (planned v1.1.0) 2FA/MFA management (was previously not on the roadmap, but could be beneficial in reducing phone usage)
|
- (planned v1.1.0) 2FA/MFA management (beneficial for reducing phone usage)
|
||||||
- (planned v1.2.0) everything it already does, but also in a GUI for Linux/Haiku
|
- (planned v1.2.0) everything it already does, but also in a GUI for Linux/Haiku
|
||||||
|
|
||||||
What sshyp definitely won't do:
|
What sshyp definitely won't do:
|
||||||
@@ -34,19 +38,11 @@ What sshyp definitely won't do:
|
|||||||
- Non-UNIX(-like) support, e.g. Windows (I'd be happy to link to third-party ports, if someone were to make them)
|
- Non-UNIX(-like) support, e.g. Windows (I'd be happy to link to third-party ports, if someone were to make them)
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
Arch Linux (all ISAs)
|
Please see the [installation guide](https://github.com/rwinkhart/sshyp/wiki/Installation) in the sshyp wiki for directions specific to your distribution/OS.
|
||||||
|
|
||||||
sshyp releases are available in the Arch User Repository as 'sshyp'.
|
Pre-built packages exist for Haiku, FreeBSD, Arch Linux, Debian/Ubuntu Linux, Fedora Linux, and Termux. These can be downloaded from the releases page.
|
||||||
|
|
||||||
Install with your preferred AUR helper or use:
|
Requests for additional distribution/OS support can be filed as issues.
|
||||||
|
|
||||||
```
|
|
||||||
git clone https://aur.archlinux.org/sshyp.git
|
|
||||||
cd sshyp
|
|
||||||
makepkg -si
|
|
||||||
```
|
|
||||||
|
|
||||||
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
|
# Building
|
||||||
Since sshyp is written entirely in Python, it doesn't need to be compiled. It does, however, need to be packaged for installation.
|
Since sshyp is written entirely in Python, it doesn't need to be compiled. It does, however, need to be packaged for installation.
|
||||||
@@ -59,13 +55,13 @@ cd sshyp
|
|||||||
./package.sh
|
./package.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
The packaging script has been tested on Arch Linux with "dpkg" as a dependency for Debian/Ubuntu and Termux packaging and "freebsd-pkg" as a dependency for FreeBSD packaging.
|
||||||
|
|
||||||
Haiku packaging must be done from within Haiku.
|
Haiku and Fedora packaging must be done on their own respective distributions.
|
||||||
|
|
||||||
The AUR version and the packages attatched to the release tags were already packaged using this script.
|
The AUR version and the packages attatched to the release tags were already packaged using this script.
|
||||||
|
|
||||||
Currently, the script can create packages for Haiku, FreeBSD, Arch Linux (PKGBUILD), Debian Linux, Red Hat Linux, Termux, and generic. Packaging for other systems coming soon.
|
Currently, the script can create packages for Haiku, FreeBSD, Arch Linux (PKGBUILD), Debian/Ubuntu Linux, Fedora Linux, Termux, and generic.
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
Upon initial installation (on both the server and client devices), be sure to run:
|
Upon initial installation (on both the server and client devices), be sure to run:
|
||||||
@@ -74,8 +70,7 @@ Upon initial installation (on both the server and client devices), be sure to ru
|
|||||||
sshyp tweak
|
sshyp tweak
|
||||||
```
|
```
|
||||||
|
|
||||||
This command will allow you to configure the settings necessary for sshyp to function.
|
This command will allow you to configure the settings necessary for sshyp to function. To ensure configuration compatibility, it is a good idea to run 'sshyp tweak' after each major update.
|
||||||
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.
|
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.
|
||||||
|
|
||||||
@@ -95,7 +90,7 @@ man sshyp
|
|||||||
Short-term Goals:
|
Short-term Goals:
|
||||||
|
|
||||||
- 2FA/MFA management
|
- 2FA/MFA management
|
||||||
- create minimal GUI apps (Linux x86_64, Linux aarch64)
|
- create minimal GUI apps (Linux x86_64, Linux aarch64, Haiku x86_64)
|
||||||
- various optimizations/bug fixes
|
- various optimizations/bug fixes
|
||||||
|
|
||||||
Long-term Goals:
|
Long-term Goals:
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import random
|
|||||||
from shutil import get_terminal_size, move, rmtree
|
from shutil import get_terminal_size, move, rmtree
|
||||||
import sshync
|
import sshync
|
||||||
import string
|
import string
|
||||||
from subprocess import Popen, PIPE, STDOUT
|
from subprocess import CalledProcessError, Popen, PIPE, run
|
||||||
from sys import argv, exit as s_exit
|
from sys import argv, exit as s_exit
|
||||||
from textwrap import fill
|
from textwrap import fill
|
||||||
|
|
||||||
@@ -130,7 +130,12 @@ def pass_gen():
|
|||||||
if __special < __min_special:
|
if __special < __min_special:
|
||||||
__gen = _pass_gen_function(__complexity, __length)
|
__gen = _pass_gen_function(__complexity, __length)
|
||||||
return __gen
|
return __gen
|
||||||
_length = int(input('password length: '))
|
try:
|
||||||
|
_length = int(input('password length: '))
|
||||||
|
except ValueError:
|
||||||
|
print(f"\n\u001b[38;5;9merror: a non-integer value was input for password length\u001b[0m\n")
|
||||||
|
_gen = pass_gen()
|
||||||
|
return _gen
|
||||||
if _length > 840:
|
if _length > 840:
|
||||||
_length = 840
|
_length = 840
|
||||||
print('\n\u001b[38;5;9mpassword length has been limited to the maximum of 840 characters\u001b[0m\n')
|
print('\n\u001b[38;5;9mpassword length has been limited to the maximum of 840 characters\u001b[0m\n')
|
||||||
@@ -150,9 +155,9 @@ def decrypt(_entry_dir, _shm_folder, _shm_entry):
|
|||||||
_command = f"{gpg} -qd --output /dev/null {path.expanduser('~/.config/sshyp/lock.gpg')}"
|
_command = f"{gpg} -qd --output /dev/null {path.expanduser('~/.config/sshyp/lock.gpg')}"
|
||||||
else:
|
else:
|
||||||
_command = f"{gpg} -qd --output {tmp_dir}{_shm_folder}/{_shm_entry} {_entry_dir}.gpg"
|
_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)
|
try:
|
||||||
_block = _output.communicate()[0].strip()
|
run(_command, shell=True, stderr=PIPE, check=True, close_fds=True)
|
||||||
if _output.returncode == 2:
|
except CalledProcessError:
|
||||||
print(f"\n\u001b[38;5;9merror: could not decrypt - ensure the correct gpg key is present\u001b[0m\n")
|
print(f"\n\u001b[38;5;9merror: could not decrypt - ensure the correct gpg key is present\u001b[0m\n")
|
||||||
s_exit(1)
|
s_exit(1)
|
||||||
|
|
||||||
@@ -169,17 +174,16 @@ def edit_note(_shm_folder, _shm_entry):
|
|||||||
def copy_name_check(_port, _username_ssh, _ip, _client_device_name):
|
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} " \
|
_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}'\""
|
f"\"touch '/home/{_username_ssh}/.config/sshyp/devices/{_client_device_name}'\""
|
||||||
_output = Popen(_command, shell=True, stdout=PIPE, stderr=STDOUT, close_fds=True)
|
try:
|
||||||
_block = _output.communicate()[0].strip()
|
run(_command, shell=True, stderr=PIPE, check=True, close_fds=True)
|
||||||
if _output.returncode != 0:
|
except CalledProcessError:
|
||||||
print('\n\u001b[38;5;9mwarning: ssh connection could not be made - ensure the public key (~/.ssh/sshyp.pub) is '
|
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 '
|
'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')
|
'functionality will be disabled until this is addressed\u001b[0m\n')
|
||||||
open(path.expanduser('~/.config/sshyp/ssh-error'), 'w').write('1')
|
open(path.expanduser('~/.config/sshyp/ssh-error'), 'w').write('1')
|
||||||
return 1
|
return 1
|
||||||
else:
|
open(path.expanduser('~/.config/sshyp/ssh-error'), 'w').write('0')
|
||||||
open(path.expanduser('~/.config/sshyp/ssh-error'), 'w').write('0')
|
return 0
|
||||||
return 0
|
|
||||||
|
|
||||||
# argument-specific functions
|
# argument-specific functions
|
||||||
|
|
||||||
@@ -189,7 +193,7 @@ def tweak(): # runs configuration wizard
|
|||||||
Path(path.expanduser('~/.password-pasture')).mkdir(0o700, parents=True, exist_ok=True)
|
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)
|
Path(path.expanduser('~/.config/sshyp/devices')).mkdir(0o700, parents=True, exist_ok=True)
|
||||||
if not Path(f"{path.expanduser('~/.config/sshyp/tmp')}").exists():
|
if not Path(f"{path.expanduser('~/.config/sshyp/tmp')}").exists():
|
||||||
if uname()[0] == 'Haiku':
|
if uname()[0] == 'Haiku' or uname()[0] == 'FreeBSD':
|
||||||
system(f"ln -s /tmp {path.expanduser('~/.config/sshyp/tmp')}")
|
system(f"ln -s /tmp {path.expanduser('~/.config/sshyp/tmp')}")
|
||||||
elif Path("/data/data/com.termux").exists():
|
elif Path("/data/data/com.termux").exists():
|
||||||
system(f"ln -s '/data/data/com.termux/files/usr/tmp' {path.expanduser('~/.config/sshyp/tmp')}")
|
system(f"ln -s '/data/data/com.termux/files/usr/tmp' {path.expanduser('~/.config/sshyp/tmp')}")
|
||||||
@@ -293,8 +297,8 @@ def print_info(): # prints help text based on argument
|
|||||||
print(' update/-u generate a password for an existing entry\n')
|
print(' update/-u generate a password for an existing entry\n')
|
||||||
print("\u001b[1mtip:\u001b[0m you can quickly read an entry with 'sshyp /<entry name>'")
|
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':
|
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'
|
print('\nsshyp is a simple, self-hosted, sftp-synchronized password manager\nfor unix(-like) systems (haiku/'
|
||||||
' haiku/linux/termux)\n\nsshyp is a viable alternative to (and compatible with) pass/password-store\n')
|
'freebsd/linux/termux)\n\nsshyp is a viable alternative to (and compatible with) pass/password-store\n')
|
||||||
print(" .. \u001b[38;5;9m♥♥ ♥♥\u001b[0m ..\n .''.''/()\\ \u001b[38;5;13m"
|
print(" .. \u001b[38;5;9m♥♥ ♥♥\u001b[0m ..\n .''.''/()\\ \u001b[38;5;13m"
|
||||||
"♥♥♥♥♥♥♥\u001b[0m /()\\''.''.\n * : \u001b[38;5;9m♥♥♥♥♥\u001b[0m : *"
|
"♥♥♥♥♥♥♥\u001b[0m /()\\''.''.\n * : \u001b[38;5;9m♥♥♥♥♥\u001b[0m : *"
|
||||||
"\n `..'..' \u001b[38;5;13m♥♥♥\u001b[0m `..'..'\n // \\\\ "
|
"\n `..'..' \u001b[38;5;13m♥♥♥\u001b[0m `..'..'\n // \\\\ "
|
||||||
@@ -306,7 +310,7 @@ def print_info(): # prints help text based on argument
|
|||||||
'randall winkhart\u001b[38;5;15;48;5;15m \u001b[38;5;7;48;5;8m/\u001b[0m')
|
'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 '
|
print('\u001b[38;5;7;48;5;8m/\u001b[38;5;15;48;5;15m '
|
||||||
'\u001b[38;5;7;48;5;8m/\u001b[0m')
|
'\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'
|
print('\u001b[38;5;7;48;5;8m/\u001b[38;5;15;48;5;15m \u001b[38;5;15;48;5;8mversion 1.0.1'
|
||||||
'\u001b[38;5;15;48;5;15m \u001b[38;5;7;48;5;8m/\u001b[0m')
|
'\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 '
|
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')
|
'update\u001b[38;5;15;48;5;15m \u001b[38;5;7;48;5;8m/\u001b[0m')
|
||||||
@@ -379,7 +383,7 @@ def sync(): # calls sshync to sync changes to the user's server
|
|||||||
try:
|
try:
|
||||||
_deletion_database = open(path.expanduser('~/.config/sshyp/deletion_database')).readlines()
|
_deletion_database = open(path.expanduser('~/.config/sshyp/deletion_database')).readlines()
|
||||||
except (FileNotFoundError, IndexError):
|
except (FileNotFoundError, IndexError):
|
||||||
print('\n\u001b[38;5;9merror: the deletion database does not exist or is corrupted.\u001b[0m\n')
|
print('\n\u001b[38;5;9merror: the deletion database does not exist or is corrupted\u001b[0m\n')
|
||||||
_deletion_database = None
|
_deletion_database = None
|
||||||
s_exit(1)
|
s_exit(1)
|
||||||
for _file in _deletion_database:
|
for _file in _deletion_database:
|
||||||
@@ -407,7 +411,7 @@ def sync(): # calls sshync to sync changes to the user's server
|
|||||||
try:
|
try:
|
||||||
_folder_database = open(path.expanduser('~/.config/sshyp/folder_database')).readlines()
|
_folder_database = open(path.expanduser('~/.config/sshyp/folder_database')).readlines()
|
||||||
except (FileNotFoundError, IndexError):
|
except (FileNotFoundError, IndexError):
|
||||||
print('\n\u001b[38;5;9merror: the folder database does not exist or is corrupted.\u001b[0m\n')
|
print('\n\u001b[38;5;9merror: the folder database does not exist or is corrupted\u001b[0m\n')
|
||||||
_folder_database = None
|
_folder_database = None
|
||||||
s_exit(1)
|
s_exit(1)
|
||||||
for _folder in _folder_database:
|
for _folder in _folder_database:
|
||||||
@@ -429,6 +433,9 @@ def add_entry(): # adds a new entry
|
|||||||
_entry_name = entry_name_fetch('name of new entry: ')
|
_entry_name = entry_name_fetch('name of new entry: ')
|
||||||
else:
|
else:
|
||||||
_entry_name = entry_name_fetch(2)
|
_entry_name = entry_name_fetch(2)
|
||||||
|
if Path(f"{directory}{_entry_name}.gpg").is_file():
|
||||||
|
print(f"\n\u001b[38;5;9merror: entry ({_entry_name}) already exists\u001b[0m\n")
|
||||||
|
s_exit(1)
|
||||||
if argument_list[1] == 'note' or argument_list[1] == '-n':
|
if argument_list[1] == 'note' or argument_list[1] == '-n':
|
||||||
_shm_folder, _shm_entry = shm_gen()
|
_shm_folder, _shm_entry = shm_gen()
|
||||||
system(f"nano {tmp_dir}{_shm_folder}/{_shm_entry}-n")
|
system(f"nano {tmp_dir}{_shm_folder}/{_shm_entry}-n")
|
||||||
@@ -467,10 +474,14 @@ def rename(): # renames an entry or folder
|
|||||||
_entry_name = entry_name_fetch('entry/folder to rename/relocate: ')
|
_entry_name = entry_name_fetch('entry/folder to rename/relocate: ')
|
||||||
else:
|
else:
|
||||||
_entry_name = entry_name_fetch(2)
|
_entry_name = entry_name_fetch(2)
|
||||||
if not Path(f"{directory}{_entry_name}.gpg").exists():
|
if not Path(f"{directory}{_entry_name}.gpg").is_file() and not Path(f"{directory}{_entry_name}").is_dir():
|
||||||
print(f"\n\u001b[38;5;9merror: entry ({_entry_name}) does not exist\u001b[0m\n")
|
print(f"\n\u001b[38;5;9merror: entry ({_entry_name}) does not exist\u001b[0m\n")
|
||||||
s_exit(1)
|
s_exit(1)
|
||||||
_new_name = str(input('new name: '))
|
_new_name = str(input('new name: '))
|
||||||
|
print(f"{directory}{_new_name}")
|
||||||
|
if Path(f"{directory}{_new_name}.gpg").is_file() or Path(f"{directory}{_new_name}").is_dir():
|
||||||
|
print(f"\n\u001b[38;5;9merror: ({_new_name}) already exists\u001b[0m\n")
|
||||||
|
s_exit(1)
|
||||||
if _entry_name.endswith('/'):
|
if _entry_name.endswith('/'):
|
||||||
move(f"{directory}{_entry_name}", f"{directory}{_new_name}")
|
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}"
|
system(f"ssh -i '{path.expanduser('~/.ssh/sshyp')}' -p {port} {username_ssh}@{ip} \"mkdir -p '{directory_ssh}"
|
||||||
@@ -528,9 +539,12 @@ def gen(): # generates a password for a new or an existing entry
|
|||||||
s_exit(1)
|
s_exit(1)
|
||||||
else:
|
else:
|
||||||
_entry_name = entry_name_fetch(1)
|
_entry_name = entry_name_fetch(1)
|
||||||
|
if len(argument_list) == 1 or (not argument_list[1] == 'update' and not argument_list[1] == '-u'):
|
||||||
|
if Path(f"{directory}{_entry_name}.gpg").is_file():
|
||||||
|
print(f"\n\u001b[38;5;9merror: entry ({_entry_name}) already exists\u001b[0m\n")
|
||||||
|
s_exit(1)
|
||||||
_username = str(input('username: '))
|
_username = str(input('username: '))
|
||||||
_password = pass_gen()
|
_password = pass_gen()
|
||||||
if not argument_list[1] == 'update' and not argument_list[1] == '-u':
|
|
||||||
_url = str(input('url: '))
|
_url = str(input('url: '))
|
||||||
_add_note = input('add a note to this entry? (y/N) ')
|
_add_note = input('add a note to this entry? (y/N) ')
|
||||||
_shm_folder, _shm_entry = shm_gen()
|
_shm_folder, _shm_entry = shm_gen()
|
||||||
@@ -545,6 +559,7 @@ def gen(): # generates a password for a new or an existing entry
|
|||||||
entry_reader(f"{tmp_dir}{_shm_folder}/{_shm_entry}")
|
entry_reader(f"{tmp_dir}{_shm_folder}/{_shm_entry}")
|
||||||
encrypt(_shm_folder, _shm_entry, _entry_name)
|
encrypt(_shm_folder, _shm_entry, _entry_name)
|
||||||
else:
|
else:
|
||||||
|
_password = pass_gen()
|
||||||
_shm_folder, _shm_entry = shm_gen()
|
_shm_folder, _shm_entry = shm_gen()
|
||||||
decrypt(directory + _entry_name, _shm_folder, _shm_entry)
|
decrypt(directory + _entry_name, _shm_folder, _shm_entry)
|
||||||
replace_line(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 0, _password + '\n')
|
replace_line(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 0, _password + '\n')
|
||||||
@@ -574,7 +589,7 @@ def copy_data(): # copies a specified field of an entry to the clipboard
|
|||||||
system('clipboard -c ' + "'" + _copy_line[2].replace('\n', '').replace("'", "'\\''") + "'")
|
system('clipboard -c ' + "'" + _copy_line[2].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
elif argument_list[1] == 'note' or argument_list[1] == '-n':
|
elif argument_list[1] == 'note' or argument_list[1] == '-n':
|
||||||
system('clipboard -c ' + "'" + _copy_line[3].replace('\n', '').replace("'", "'\\''") + "'")
|
system('clipboard -c ' + "'" + _copy_line[3].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
Popen('sleep 30; clipboard -r', shell=True)
|
Popen('sleep 30; clipboard -r', shell=True, close_fds=True)
|
||||||
elif Path("/data/data/com.termux").exists(): # Termux (Android) clipboard detection
|
elif Path("/data/data/com.termux").exists(): # Termux (Android) clipboard detection
|
||||||
if argument_list[1] == 'username' or argument_list[1] == '-u':
|
if argument_list[1] == 'username' or argument_list[1] == '-u':
|
||||||
system('termux-clipboard-set ' + "'" + _copy_line[1].replace('\n', '').replace("'", "'\\''") + "'")
|
system('termux-clipboard-set ' + "'" + _copy_line[1].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
@@ -584,7 +599,7 @@ def copy_data(): # copies a specified field of an entry to the clipboard
|
|||||||
system('termux-clipboard-set ' + "'" + _copy_line[2].replace('\n', '').replace("'", "'\\''") + "'")
|
system('termux-clipboard-set ' + "'" + _copy_line[2].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
elif argument_list[1] == 'note' or argument_list[1] == '-n':
|
elif argument_list[1] == 'note' or argument_list[1] == '-n':
|
||||||
system('termux-clipboard-set ' + "'" + _copy_line[3].replace('\n', '').replace("'", "'\\''") + "'")
|
system('termux-clipboard-set ' + "'" + _copy_line[3].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
Popen("sleep 30; termux-clipboard-set ''", shell=True)
|
Popen("sleep 30; termux-clipboard-set ''", shell=True, close_fds=True)
|
||||||
elif environ.get('WAYLAND_DISPLAY') == 'wayland-0': # Wayland clipboard detection
|
elif environ.get('WAYLAND_DISPLAY') == 'wayland-0': # Wayland clipboard detection
|
||||||
if argument_list[1] == 'username' or argument_list[1] == '-u':
|
if argument_list[1] == 'username' or argument_list[1] == '-u':
|
||||||
system('wl-copy ' + "'" + _copy_line[1].replace('\n', '').replace("'", "'\\''") + "'")
|
system('wl-copy ' + "'" + _copy_line[1].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
@@ -594,7 +609,7 @@ def copy_data(): # copies a specified field of an entry to the clipboard
|
|||||||
system('wl-copy ' + "'" + _copy_line[2].replace('\n', '').replace("'", "'\\''") + "'")
|
system('wl-copy ' + "'" + _copy_line[2].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
elif argument_list[1] == 'note' or argument_list[1] == '-n':
|
elif argument_list[1] == 'note' or argument_list[1] == '-n':
|
||||||
system('wl-copy ' + "'" + _copy_line[3].replace('\n', '').replace("'", "'\\''") + "'")
|
system('wl-copy ' + "'" + _copy_line[3].replace('\n', '').replace("'", "'\\''") + "'")
|
||||||
Popen('sleep 30; wl-copy -c', shell=True)
|
Popen('sleep 30; wl-copy -c', shell=True, close_fds=True)
|
||||||
else: # X11 clipboard detection
|
else: # X11 clipboard detection
|
||||||
if argument_list[1] == 'username' or argument_list[1] == '-u':
|
if argument_list[1] == 'username' or argument_list[1] == '-u':
|
||||||
system('echo -n ' + "'" + _copy_line[1].replace('\n', '').replace("'", "'\\''") + "'" + ' | xclip -sel c')
|
system('echo -n ' + "'" + _copy_line[1].replace('\n', '').replace("'", "'\\''") + "'" + ' | xclip -sel c')
|
||||||
@@ -604,7 +619,7 @@ def copy_data(): # copies a specified field of an entry to the clipboard
|
|||||||
system('echo -n ' + "'" + _copy_line[2].replace('\n', '').replace("'", "'\\''") + "'" + ' | xclip -sel c')
|
system('echo -n ' + "'" + _copy_line[2].replace('\n', '').replace("'", "'\\''") + "'" + ' | xclip -sel c')
|
||||||
elif argument_list[1] == 'note' or argument_list[1] == '-n':
|
elif argument_list[1] == 'note' or argument_list[1] == '-n':
|
||||||
system('echo -n ' + "'" + _copy_line[3].replace('\n', '').replace("'", "'\\''") + "'" + ' | xclip -sel c')
|
system('echo -n ' + "'" + _copy_line[3].replace('\n', '').replace("'", "'\\''") + "'" + ' | xclip -sel c')
|
||||||
Popen("sleep 30; echo -n '' | xclip -sel c", shell=True)
|
Popen("sleep 30; echo -n '' | xclip -sel c", shell=True, close_fds=True)
|
||||||
rmtree(f"{tmp_dir}{_shm_folder}")
|
rmtree(f"{tmp_dir}{_shm_folder}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+16
-1
@@ -1,3 +1,17 @@
|
|||||||
|
sshyp v1.0.1
|
||||||
|
|
||||||
|
The Polished Trotters Update - Patch 1
|
||||||
|
|
||||||
|
This is a hotfix for the Haiku decryption bug.
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
- subprocess.Popen has been replaced with subprocess.run where applicable
|
||||||
|
- stdout is no longer captured with any subprocess.Popen or subprocess.run usages
|
||||||
|
^ this fixes decryption on Haiku
|
||||||
|
|
||||||
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
sshyp v1.0.0
|
sshyp v1.0.0
|
||||||
|
|
||||||
The Polished Trotters Update
|
The Polished Trotters Update
|
||||||
@@ -8,7 +22,7 @@ As such, it is being crowned "v1.0.0", and is considered a stable base for futur
|
|||||||
Features:
|
Features:
|
||||||
|
|
||||||
- sshyp has been modified to run on Haiku, an open-source re-implementation of BeOS
|
- 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)
|
^ new package formats have been added for Haiku, FreeBSD, and Fedora Linux
|
||||||
- the entry format has been changed to support entries created in pass/password-store
|
- 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
|
^ 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
|
- majorly overhauled visual experience for sshyp
|
||||||
@@ -27,6 +41,7 @@ Changes:
|
|||||||
- rename function now properly allows for renaming folders
|
- rename function now properly allows for renaming folders
|
||||||
- renaming an entry/folder will now properly delete the old entry/folder from the server
|
- 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
|
- entry previews at the time of entry creation/editing no longer require entering the gpg password more times than necessary
|
||||||
|
- entries will no longer be overwritten if attempting to create a new entry that uses an already existing name
|
||||||
- the clipboard now automatically clears after 30 seconds
|
- the clipboard now automatically clears after 30 seconds
|
||||||
- sshyp server no longer needs to create copies of its libraries in ~/
|
- sshyp server no longer needs to create copies of its libraries in ~/
|
||||||
- added more and improved existing exceptions
|
- added more and improved existing exceptions
|
||||||
|
|||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
.TH sshyp 1 "17 June 2022" "v1.0.0" "sshyp man page"
|
.TH sshyp 1 "20 June 2022" "v1.0.0" "sshyp man page"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
sshyp \- A very simple self-hosted, synchronized password manager for UNIX(-like) systems. Alternative to (and compatible with) pass/password-store.
|
sshyp \- A very simple self-hosted, synchronized password manager for UNIX(-like) systems. Alternative to (and compatible with) pass/password-store.
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@@ -73,7 +73,7 @@ sshyp operates on a client-server model, and thus requires you to have access to
|
|||||||
The sshyp package includes modes for operating on both client and server devices, so only one package is necessary.
|
The sshyp package includes modes for operating on both client and server devices, so only one package is necessary.
|
||||||
|
|
||||||
Server setup:
|
Server setup:
|
||||||
Configure an openssh server (if sshyp was installed from the Debian package, the ssh server was not installed as a dependency and needs to be installed manually)
|
Configure an OpenSSH server (if sshyp was installed from the Debian package, the ssh server was not installed as a dependency and needs to be installed manually)
|
||||||
Allow remote access to the SSH server w/public key authentication (disabling password-only authentication recommended)
|
Allow remote access to the SSH server w/public key authentication (disabling password-only authentication recommended)
|
||||||
Install sshyp
|
Install sshyp
|
||||||
Run "sshyp tweak" and set the device type as server
|
Run "sshyp tweak" and set the device type as server
|
||||||
@@ -82,7 +82,7 @@ Server setup:
|
|||||||
Client setup:
|
Client setup:
|
||||||
Install sshyp
|
Install sshyp
|
||||||
Run "sshyp tweak" and follow the prompts
|
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.)
|
Copy the generated public SSH key (located at ~/.ssh/sshyp.pub) to the server using preferred method (manually adding to authorized_keys, ssh-copy-id, etc.)
|
||||||
If you already have entries on the server, sync them using "sshyp sync"
|
If you already have entries on the server, sync them using "sshyp sync"
|
||||||
Done!
|
Done!
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
af6236472791614ed41bf13318a2d1c41228855c
|
||||||
+10
-9
@@ -1,13 +1,14 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# This script packages sshyp (from source) for various UNIX environments.
|
# This script packages sshyp (from source) for various UNIX(-like) environments.
|
||||||
# Dependencies (Arch Linux): dpkg (packaging for Debian/Termux), rpmdevtools (packaging for Red Hat), freebsd-pkg (packaging for FreeBSD)
|
# Dependencies (Arch Linux): dpkg (packaging for Debian/Termux), freebsd-pkg (packaging for FreeBSD)
|
||||||
|
# Dependencies (Fedora) (can only package for self): rpmdevtools
|
||||||
# NOTE It is recommended to instead use the latest officially packaged and tagged release.
|
# NOTE It is recommended to instead use the latest officially packaged and tagged release.
|
||||||
|
|
||||||
echo -e '\nOptions (please enter the number only):'
|
echo -e '\nOptions (please enter the number only):'
|
||||||
echo -e '\nPackage Formats:\n\n1. Haiku\n2. Debian\n3. Red Hat\n4. FreeBSD\n5. Termux\n6. Generic (used for PKGBUILD/APKBUILD)'
|
echo -e '\nPackage Formats:\n\n1. Haiku\n2. Debian&Ubuntu Linux\n3. Fedora Linux\n4. FreeBSD\n5. Termux\n6. Generic (used for PKGBUILD/APKBUILD)'
|
||||||
echo -e '\nBuild Scripts:\n\n7. Arch Linux (PKGBUILD)'
|
echo -e '\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'
|
echo -e '\nOther:\n\n8. All (generates all distribution packages (excluding Haiku and Fedora, as these must be packaged on their respective distributions) and build scripts)\n'
|
||||||
read -n 1 -r -p "Distribution: " distro
|
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'
|
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'
|
||||||
@@ -85,7 +86,7 @@ Maintainer: Randall Winkhart <idgr at tutanota dot com>
|
|||||||
Description: A light-weight, self-hosted, synchronized password manager
|
Description: A light-weight, self-hosted, synchronized password manager
|
||||||
Depends: python3, gnupg, openssh-client, nano, xclip, wl-clipboard
|
Depends: python3, gnupg, openssh-client, nano, xclip, wl-clipboard
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Installed-Size: 35
|
Installed-Size: 185
|
||||||
" > packages/debiantemp/sshyp_"$version"-"$revision"_all/DEBIAN/control
|
" > packages/debiantemp/sshyp_"$version"-"$revision"_all/DEBIAN/control
|
||||||
cp -r bin packages/debiantemp/sshyp_"$version"-"$revision"_all/usr/
|
cp -r bin packages/debiantemp/sshyp_"$version"-"$revision"_all/usr/
|
||||||
cp -r share packages/debiantemp/sshyp_"$version"-"$revision"_all/usr/
|
cp -r share packages/debiantemp/sshyp_"$version"-"$revision"_all/usr/
|
||||||
@@ -109,7 +110,7 @@ Maintainer: Randall Winkhart <idgr at tutanota dot com>
|
|||||||
Description: A light-weight, self-hosted, synchronized password manager
|
Description: A light-weight, self-hosted, synchronized password manager
|
||||||
Depends: python, gnupg, openssh, nano, termux-api, termux-am
|
Depends: python, gnupg, openssh, nano, termux-api, termux-am
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Installed-Size: 35
|
Installed-Size: 185
|
||||||
" > packages/termuxtemp/sshyp_"$version"-"$revision"_all_termux/DEBIAN/control
|
" > packages/termuxtemp/sshyp_"$version"-"$revision"_all_termux/DEBIAN/control
|
||||||
cp -r bin packages/termuxtemp/sshyp_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/
|
cp -r bin packages/termuxtemp/sshyp_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/
|
||||||
cp -r share packages/termuxtemp/sshyp_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/
|
cp -r share packages/termuxtemp/sshyp_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/
|
||||||
@@ -135,8 +136,8 @@ if [ "$distro" == "3" ] || [ "$distro" == "4" ] || [ "$distro" == "6" ] || [ "$d
|
|||||||
echo -e "\nGeneric packaging complete.\n"
|
echo -e "\nGeneric packaging complete.\n"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$distro" == "3" ] || [ "$distro" == "8" ]; then
|
if [ "$distro" == "3" ]; then
|
||||||
echo -e '\nPackaging for Red Hat...\n'
|
echo -e '\nPackaging for Fedora...\n'
|
||||||
rm -rf ~/rpmbuild
|
rm -rf ~/rpmbuild
|
||||||
rpmdev-setuptree
|
rpmdev-setuptree
|
||||||
cp packages/sshyp-"$version".tar.xz ~/rpmbuild/SOURCES
|
cp packages/sshyp-"$version".tar.xz ~/rpmbuild/SOURCES
|
||||||
@@ -170,7 +171,7 @@ cp -r %{_sourcedir}/usr %{buildroot}
|
|||||||
rpmbuild -bb ~/rpmbuild/SPECS/sshyp.spec
|
rpmbuild -bb ~/rpmbuild/SPECS/sshyp.spec
|
||||||
mv ~/rpmbuild/RPMS/noarch/* packages/
|
mv ~/rpmbuild/RPMS/noarch/* packages/
|
||||||
rm -rf ~/rpmbuild
|
rm -rf ~/rpmbuild
|
||||||
echo -e "\nRed Hat packaging complete.\n"
|
echo -e "\nFedora packaging complete.\n"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$distro" == "4" ] || [ "$distro" == "8" ]; then
|
if [ "$distro" == "4" ] || [ "$distro" == "8" ]; then
|
||||||
|
|||||||
@@ -1,3 +1,17 @@
|
|||||||
|
sshyp v1.0.1
|
||||||
|
|
||||||
|
The Polished Trotters Update - Patch 1
|
||||||
|
|
||||||
|
This is a hotfix for the Haiku decryption bug.
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
|
||||||
|
- subprocess.Popen has been replaced with subprocess.run where applicable
|
||||||
|
- stdout is no longer captured with any subprocess.Popen or subprocess.run usages
|
||||||
|
^ this fixes decryption on Haiku
|
||||||
|
|
||||||
|
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
|
||||||
|
|
||||||
sshyp v1.0.0
|
sshyp v1.0.0
|
||||||
|
|
||||||
The Polished Trotters Update
|
The Polished Trotters Update
|
||||||
@@ -8,7 +22,7 @@ As such, it is being crowned "v1.0.0", and is considered a stable base for futur
|
|||||||
Features:
|
Features:
|
||||||
|
|
||||||
- sshyp has been modified to run on Haiku, an open-source re-implementation of BeOS
|
- 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)
|
^ new package formats have been added for Haiku, FreeBSD, and Fedora Linux
|
||||||
- the entry format has been changed to support entries created in pass/password-store
|
- 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
|
^ 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
|
- majorly overhauled visual experience for sshyp
|
||||||
@@ -27,6 +41,7 @@ Changes:
|
|||||||
- rename function now properly allows for renaming folders
|
- rename function now properly allows for renaming folders
|
||||||
- renaming an entry/folder will now properly delete the old entry/folder from the server
|
- 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
|
- entry previews at the time of entry creation/editing no longer require entering the gpg password more times than necessary
|
||||||
|
- entries will no longer be overwritten if attempting to create a new entry that uses an already existing name
|
||||||
- the clipboard now automatically clears after 30 seconds
|
- the clipboard now automatically clears after 30 seconds
|
||||||
- sshyp server no longer needs to create copies of its libraries in ~/
|
- sshyp server no longer needs to create copies of its libraries in ~/
|
||||||
- added more and improved existing exceptions
|
- added more and improved existing exceptions
|
||||||
|
|||||||
Reference in New Issue
Block a user