mirror of
https://github.com/rwinkhart/sshyp-labs.git
synced 2026-08-28 04:46:48 -04:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11f1fa2a0b | ||
|
|
2e3eb2fea3 | ||
|
|
4b0f45c5e2 | ||
|
|
619ea52f7a | ||
|
|
d63d77e69f | ||
|
|
a908beaa92 | ||
|
|
e40dd66d38 | ||
|
|
a22b803288 | ||
|
|
6e5a3b8f5b | ||
|
|
626ddcce30 | ||
|
|
0985a168db | ||
|
|
f62122d79f | ||
|
|
ab691c16d8 | ||
|
|
ada8a20a8f | ||
|
|
efcfe248ba | ||
|
|
e075f70ccf | ||
|
|
029032c74c | ||
|
|
b722321a6e | ||
|
|
4fa5b11fec | ||
|
|
044bf2b205 | ||
|
|
9b44f438d4 | ||
|
|
df9d32c715 | ||
|
|
e84e9569f3 | ||
|
|
cfe9dd1eef | ||
|
|
cb1aca70bc | ||
|
|
80425bec2e | ||
|
|
d72c4a5c12 | ||
|
|
d339e4c734 | ||
|
|
240939178e | ||
|
|
b98122f4d8 | ||
|
|
7be5509fa7 | ||
|
|
8413c305c2 |
+4
-1
@@ -1 +1,4 @@
|
||||
*
|
||||
/extra/conversion-scripts/gpgToRCW/1output
|
||||
/extra/conversion-scripts/gpgToRCW/gpgToRCW
|
||||
/extra/conversion-scripts/upgradeRCW/1output
|
||||
/extra/conversion-scripts/upgradeRCW/upgradeRCW
|
||||
@@ -1,7 +1,7 @@
|
||||
# sshyp-labs
|
||||
Extensions for the [sshyp password manager](https://github.com/rwinkhart/sshyp).
|
||||
|
||||
When new functionality is desired that goes outside of sshyp's primary goals or requires venturing outside of the Python standard library, said functionality is implemented as an extension.
|
||||
More recently, this repository has become a dumping ground for assets related to sshyp and its successor, MUTN.
|
||||
|
||||
# Installation
|
||||
For most sshyp-supported platforms, sshyp extensions should be installed from the `sshyp tweak` menu's "extension management" option.
|
||||
@@ -9,11 +9,15 @@ For most sshyp-supported platforms, sshyp extensions should be installed from th
|
||||
For **Haiku and Termux _ONLY_**, use the packages from the [releases page](https://github.com/rwinkhart/sshyp-labs/releases).
|
||||
|
||||
# Available Extensions
|
||||
[sshyp-mfa](https://github.com/rwinkhart/sshyp-labs/wiki/sshyp-mfa): read mfa data from sshyp entries to generate and copy totp keys to the clipboard (optional Steam support)
|
||||
[export-to-libmutton](https://github.com/rwinkhart/sshyp-labs/wiki/export%E2%80%90to%E2%80%90libmutton): export sshyp entries for usage in libmutton-based password managers
|
||||
|
||||
[sshyp-mfa](https://github.com/rwinkhart/sshyp-labs/wiki/sshyp-mfa): read mfa data from sshyp entries to generate and copy totp keys to the clipboard (includes Steam support)
|
||||
|
||||
[password-pasture](https://github.com/rwinkhart/sshyp-labs/wiki/password-pasture): a HIGHLY experimental GTK4 sshyp GUI - very incomplete (last updated for sshyp v1.1.x)
|
||||
|
||||
# Acknowledgements
|
||||
sshyp-mfa optionally depends on [ValvePython/steam](https://github.com/ValvePython/steam) for Steam support.
|
||||
|
||||
sshyp-mfa's TOTP support is partially derrived from [susam/mintotp](https://github.com/susam/mintotp).
|
||||
|
||||
sshyp-mfa's Steam support is partially derrived from [ValvePython/steam](https://github.com/ValvePython/steam).
|
||||
|
||||
These packages are _not_ required as dependencies; the necessary code from each is included in sshyp-mfa.
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
git add -f LICENSE README.md commit.sh extensions extra pointers .gitignore
|
||||
git commit -m "$1"
|
||||
git push
|
||||
@@ -0,0 +1,3 @@
|
||||
[config]
|
||||
input = export
|
||||
output = /usr/lib/sshyp/export-to-libmutton
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from os import path, remove, system, walk
|
||||
from pathlib import Path
|
||||
from shutil import rmtree
|
||||
from sshyp import decrypt
|
||||
|
||||
if __name__ == "__main__":
|
||||
_pasture = path.expanduser('~/.local/share/sshyp')
|
||||
|
||||
_gpg_id = input('\nWhat is the ID of the GPG key you would like to use for re-encryption?\n\nID: ')
|
||||
|
||||
# remove previous export if it exists
|
||||
if Path(f"{_pasture}.export").exists():
|
||||
rmtree(f"{_pasture}.export")
|
||||
|
||||
# prompt for unlock and display do not close warning
|
||||
decrypt(None)
|
||||
print('\nentry conversion may take some time (especially on slower devices) - do not terminate this process!\n')
|
||||
|
||||
# iterate over entires, exporting them in the libmutton format
|
||||
if path.isdir(_pasture):
|
||||
for _dirPath, _dirNames, _filenames in walk(_pasture):
|
||||
for _filename in sorted(_filenames):
|
||||
# ensure parent directory within export tree exists
|
||||
Path(_dirPath.replace(_pasture, _pasture + '.export')).mkdir(0o700, parents=True, exist_ok=True)
|
||||
|
||||
# remove the .gpg file extension, if it is present
|
||||
# prevents saving with the extension, as libmutton does not require it
|
||||
_og_extension = ''
|
||||
if _filename.endswith('.gpg'):
|
||||
_og_extension = '.gpg'
|
||||
_filename = _filename[:-4]
|
||||
|
||||
# decrypt to export directory, append .gpg to decrypted file to differentiate from new file
|
||||
system(f"gpg -d '{_dirPath}/{_filename}{_og_extension}' > '{_dirPath.replace(_pasture, _pasture + '.export')}/{_filename}.gpg'")
|
||||
|
||||
_old_contents, _new_contents = open(f"{_dirPath.replace(_pasture, _pasture + '.export')}/{_filename}.gpg", 'r').readlines(), ''
|
||||
|
||||
# extract sshyp-mfa data for new reserved line
|
||||
_secret = '\n'
|
||||
if len(_old_contents) >= 5:
|
||||
if _old_contents[4].startswith('otpauth://'):
|
||||
# check if sshyp-mfa data is standard TOTP or Steam
|
||||
if _old_contents[4][10:].startswith('steam'):
|
||||
print("\n\u001b[38;5;3mlibmutton uses a different form of secret key for Steam, and as such, your Steam TOTP secret must be migrated manually\u001b[0m\n")
|
||||
else:
|
||||
# extract TOTP secret
|
||||
_secret = _old_contents[4].split('?secret=')[1].split('&issuer=')[0]+'\n'
|
||||
|
||||
# temporarily expand _old_contents to avoid index errors (will be trimmed later)
|
||||
while len(_old_contents) < 6:
|
||||
_old_contents.append('\n')
|
||||
|
||||
# extract any possible notes from _old_contents (as a string)
|
||||
if _secret == '\n':
|
||||
_old_notes = ''.join(_old_contents[3:])
|
||||
else:
|
||||
# skip second notes line if sshyp-mfa data was found
|
||||
# skip first notes line if blank line
|
||||
if _old_contents[3] in ('\n', ' '):
|
||||
_old_contents[3] = ''
|
||||
_old_notes = _old_contents[3] + ''.join(_old_contents[5:])
|
||||
|
||||
# set _new_contents
|
||||
_new_contents = _old_contents[0] + _old_contents[1] + _secret + _old_contents[2] + _old_notes
|
||||
|
||||
# remove any trailing whitespace
|
||||
for _num in reversed(range(len(_new_contents))):
|
||||
if _new_contents[_num] in ('\n', '', ' '):
|
||||
_new_contents = _new_contents[:-1]
|
||||
else:
|
||||
break
|
||||
|
||||
# write and encrypt the output file
|
||||
open(f"{_dirPath.replace(_pasture, _pasture + '.export')}/{_filename}.gpg", 'w').writelines(_new_contents)
|
||||
system(f"gpg -er {str(_gpg_id)} -o '{_dirPath.replace(_pasture, _pasture + '.export')}/{_filename}' '{_dirPath.replace(_pasture, _pasture + '.export')}/{_filename}.gpg'")
|
||||
remove(f"{_dirPath.replace(_pasture, _pasture + '.export')}/{_filename}.gpg")
|
||||
else:
|
||||
print(f"\n\u001b[38;5;9merror: no entry folder ({_pasture}) found\u001b[0m\n")
|
||||
s_exit(2)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
version='1.5.0.2'
|
||||
version='1.5.1.3'
|
||||
if [ -z "$2" ]; then
|
||||
revision=1
|
||||
else
|
||||
@@ -34,8 +34,8 @@ urls {
|
||||
}
|
||||
" > output/haikutemp/.PackageInfo
|
||||
cp ./sshyp-mfa.py output/haikutemp/lib/sshyp/sshyp-mfa
|
||||
cp ./sshyp-mfa.ini output/haikutemp/lib/sshyp/extensions/
|
||||
sed -i '1 s/.*/#!\/bin\/env\ python3.10/' output/haikutemp/lib/sshyp/sshyp-mfa
|
||||
printf '[config]\ninput = copy -m\noutput = /system/lib/sshyp/sshyp-mfa\n' > ./output/haikutemp/lib/sshyp/extensions/sshyp-mfa.ini
|
||||
sed -i '1 s/.*/#!\/bin\/env\ python3.11/' output/haikutemp/lib/sshyp/sshyp-mfa
|
||||
cd output/haikutemp
|
||||
package create -b HAIKU-sshyp_mfa-"$version"-"$revision"_all.hpkg
|
||||
package add HAIKU-sshyp_mfa-"$version"-"$revision"_all.hpkg lib
|
||||
@@ -60,7 +60,7 @@ Priority: optional
|
||||
Installed-Size: 100
|
||||
" > output/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/DEBIAN/control
|
||||
cp ./sshyp-mfa.py output/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/lib/sshyp/sshyp-mfa
|
||||
cp ./sshyp-mfa.ini output/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/lib/sshyp/extensions/
|
||||
printf '[config]\ninput = copy -m\noutput = /data/data/com.termux/files/usr/lib/sshyp/sshyp-mfa\n' > ./output/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/lib/sshyp/extensions/sshyp-mfa.ini
|
||||
dpkg-deb --build --root-owner-group output/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/
|
||||
mv output/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux.deb output/TERMUX-sshyp-mfa_"$version"-"$revision"_all.deb
|
||||
rm -rf output/termuxtemp
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
from base64 import b32decode
|
||||
from configparser import ConfigParser
|
||||
from hmac import new as hmac_new
|
||||
from os import environ, listdir, uname
|
||||
from os.path import expanduser, isdir, isfile
|
||||
from sshyp import decrypt, whitelist_verify
|
||||
from struct import pack, unpack
|
||||
from subprocess import PIPE, Popen, run
|
||||
from sys import argv, exit as s_exit
|
||||
from time import sleep, strftime, time
|
||||
@@ -11,21 +13,31 @@ home = expanduser("~")
|
||||
|
||||
|
||||
def totp(_secret, _algo, _digits, _period): # uses provided information to generate a standard totp key
|
||||
from hmac import new as new_mac
|
||||
from struct import pack, unpack
|
||||
_secret = b32decode(_secret.upper() + '=' * ((8 - len(_secret)) % 8))
|
||||
_counter = pack('>Q', int(time() / _period))
|
||||
_mac = new_mac(_secret, _counter, _algo).digest()
|
||||
_offset = _mac[-1] & 0x0f
|
||||
_binary = unpack('>L', _mac[_offset:_offset + 4])[0] & 0x7fffffff
|
||||
_hmac = hmac_new(_secret, _counter, _algo).digest()
|
||||
_offset = _hmac[-1] & 0x0f
|
||||
_binary = unpack('>L', _hmac[_offset:_offset + 4])[0] & 0x7fffffff
|
||||
return str(_binary)[-_digits:].zfill(_digits)
|
||||
|
||||
|
||||
def steam_otp(_secret): # uses provided information to generate a Steam-compatible otp
|
||||
_hmac = hmac_new(bytes(_secret), msg=pack('>Q', int(time()//30)), digestmod='sha1').digest()
|
||||
_start = ord(_hmac[19:20]) & 0xF
|
||||
_codeint = unpack('>I', _hmac[_start:_start+4])[0] & 0x7fffffff
|
||||
_charset = '23456789BCDFGHJKMNPQRTVWXY'
|
||||
_code = ''
|
||||
for _ in range(5):
|
||||
_codeint, _i = divmod(_codeint, len(_charset))
|
||||
_code += _charset[_i]
|
||||
return _code
|
||||
|
||||
|
||||
def mfa_read_shortcut(): # extracts MFA info from the user-specified sshyp entry
|
||||
if not isfile(f"{directory}{arguments[0]}.gpg"):
|
||||
print(f"\n\u001b[38;5;9merror: entry ({arguments[0]}) does not exist\u001b[0m\n")
|
||||
s_exit(1)
|
||||
if quick_unlock_enabled == 'true':
|
||||
if quick_unlock_enabled:
|
||||
_mfa_data = decrypt(directory + arguments[0],
|
||||
_quick_pass=whitelist_verify(sshyp_data.get('SSHYNC', 'port'),
|
||||
sshyp_data.get('SSHYNC', 'user'),
|
||||
@@ -57,7 +69,7 @@ if __name__ == '__main__':
|
||||
sshyp_data = ConfigParser()
|
||||
sshyp_data.read(f"{home}/.config/sshyp/sshyp.ini")
|
||||
directory = f"{home}/.local/share/sshyp/"
|
||||
quick_unlock_enabled = sshyp_data.get('CLIENT-ONLINE', 'quick_unlock_enabled')
|
||||
quick_unlock_enabled = sshyp_data.getboolean('CLIENT-ONLINE', 'quick_unlock_enabled')
|
||||
|
||||
# main process: runs functions to generate MFA key, then continuously copies up-to-date MFA key to clipboard
|
||||
try:
|
||||
@@ -69,18 +81,13 @@ if __name__ == '__main__':
|
||||
if copied is None:
|
||||
copied = 1
|
||||
if mfa_data[0] == 'steam':
|
||||
try:
|
||||
from steam.guard import generate_twofactor_code as steam_totp
|
||||
_mfa_key = steam_totp(b32decode(mfa_data[1]))
|
||||
except ModuleNotFoundError:
|
||||
print('\n\u001b[38;5;9merror: steam module not found\n\ninstall with "pip install -U \'steam[client]\'"\u001b[0m\n')
|
||||
s_exit(6)
|
||||
_mfa_key = steam_otp(b32decode(mfa_data[1]))
|
||||
else:
|
||||
_mfa_key = totp(mfa_data[1], mfa_data[2], mfa_data[3], mfa_data[4])
|
||||
if 'WSL_DISTRO_NAME' in environ: # WSL clipboard detection
|
||||
run(('powershell.exe', '-c', 'Set-Clipboard', _mfa_key))
|
||||
run(('powershell.exe', '-c', "Set-Clipboard '" + _mfa_key + "'"))
|
||||
elif 'WAYLAND_DISPLAY' in environ: # Wayland clipboard detection
|
||||
run(('wl-copy', _mfa_key))
|
||||
run('wl-copy', stdin=Popen(('printf', _mfa_key), stdout=PIPE).stdout)
|
||||
elif uname()[0] == 'Haiku': # Haiku clipboard detection
|
||||
run(('clipboard', '-c', _mfa_key))
|
||||
elif uname()[0] == 'Darwin': # MacOS clipboard detection
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 353 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.8 MiB |
@@ -1 +0,0 @@
|
||||
89fbbcf15e7fb786db4e2551dc3234615c57f77e
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
# This script generates portable release binaries for the following platforms:
|
||||
# - Linux (x86_64_v1)
|
||||
# - Linux (aarch64)
|
||||
# - Windows (x86_64_v1)
|
||||
# - Windows (aarch64)
|
||||
|
||||
mkdir -p ./1output
|
||||
GOOS=linux CGO_ENABLED=0 GOAMD64=v1 go build -o ./1output/gpgToRCW-linux-x86_64_v1 -ldflags="-s -w" -trimpath .
|
||||
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o ./1output/gpgToRCW-linux-aarch64 -ldflags="-s -w" -trimpath .
|
||||
GOOS=windows CGO_ENABLED=0 GOAMD64=v1 go build -o ./1output/gpgToRCW-windows-x86_64_v1.exe -ldflags="-s -w" -trimpath .
|
||||
GOOS=windows GOARCH=arm64 CGO_ENABLED=0 go build -o ./1output/gpgToRCW-windows-aarch64.exe -ldflags="-s -w" -trimpath .
|
||||
@@ -0,0 +1,19 @@
|
||||
module gpgToRCW
|
||||
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
github.com/rwinkhart/go-boilerplate v0.3.1
|
||||
github.com/rwinkhart/libmutton v0.5.0
|
||||
github.com/rwinkhart/rcw v0.3.0
|
||||
)
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.48.0 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
golang.org/x/term v0.40.0 // indirect
|
||||
)
|
||||
|
||||
replace golang.org/x/sys => github.com/rwinkhart/sys v0.41.0
|
||||
|
||||
replace github.com/Microsoft/go-winio => github.com/rwinkhart/go-winio v0.1.1
|
||||
@@ -0,0 +1,12 @@
|
||||
github.com/rwinkhart/go-boilerplate v0.3.1 h1:vkVRuptO2s1yPzzwpvtiiB0c/hPB6yr0p1mzZ2Myb9E=
|
||||
github.com/rwinkhart/go-boilerplate v0.3.1/go.mod h1:ES13A2r9fnCVfyezwMBgY/RgA4pOIudOUXz3Jk/ikes=
|
||||
github.com/rwinkhart/libmutton v0.5.0 h1:Du/o5Hyb26uE6lubqBISN/ZF9JZ5oObHVveQjAqrP0E=
|
||||
github.com/rwinkhart/libmutton v0.5.0/go.mod h1:peh8A1f3gnaF97m8J06U28JloKv04Kw8WtFCH+Pcq6s=
|
||||
github.com/rwinkhart/rcw v0.3.0 h1:OdgA++IGcDrZqN6FzyYnzbz04fL8Q1MHvlgPjhtgJM4=
|
||||
github.com/rwinkhart/rcw v0.3.0/go.mod h1:UUY7kSku6kV2X1RWPUcK0Re+rQ6RvngWI8DVZJ11cqk=
|
||||
github.com/rwinkhart/sys v0.41.0 h1:pHB6HphVC132UXYZ6yeOk62abqgl+pyl5ZZnsk4iUKg=
|
||||
github.com/rwinkhart/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
|
||||
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
|
||||
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/rwinkhart/go-boilerplate/other"
|
||||
"github.com/rwinkhart/libmutton/global"
|
||||
)
|
||||
|
||||
// decryptGPG decrypts a GPG-encrypted file and returns the contents as a slice of (trimmed) strings.
|
||||
func decryptGPG(targetLocation string) []string {
|
||||
cmd := exec.Command("gpg", "--pinentry-mode", "loopback", "-q", "-d", targetLocation)
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
other.PrintError("Failed to decrypt \""+targetLocation+"\" - Ensure it is a valid GPG-encrypted file and that you entered your passphrase correctly", global.ErrorDecryption)
|
||||
}
|
||||
return strings.Split(string(output), "\n")
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/rwinkhart/go-boilerplate/back"
|
||||
"github.com/rwinkhart/go-boilerplate/front"
|
||||
"github.com/rwinkhart/go-boilerplate/other"
|
||||
"github.com/rwinkhart/libmutton/global"
|
||||
"github.com/rwinkhart/libmutton/synccommon"
|
||||
"github.com/rwinkhart/rcw/wrappers"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// get info from user
|
||||
var rcwPassphrase []byte
|
||||
for {
|
||||
rcwPassphrase = front.InputSecret("RCW passphrase:")
|
||||
if !bytes.Equal(rcwPassphrase, front.InputSecret("Confirm RCW passphrase:")) {
|
||||
fmt.Println(back.AnsiError + "Passphrases do not match" + back.AnsiReset)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// convert the entries
|
||||
fmt.Print("\nRe-encrypting entries. Please wait; do not force close this process.\n\nGPG may prompt you for a passphrase for decryption.\n\n")
|
||||
var outputDir = global.EntryRoot + "-new"
|
||||
entries, folders, err := synccommon.WalkEntryDir()
|
||||
if err != nil {
|
||||
other.PrintError("Failed to walk entry directory: "+err.Error(), back.ErrorRead)
|
||||
}
|
||||
for _, folder := range folders {
|
||||
err := os.MkdirAll(outputDir+strings.ReplaceAll(folder, "/", global.PathSeparator), 0700)
|
||||
if err != nil {
|
||||
other.PrintError("Failed to create directory: "+err.Error(), back.ErrorWrite)
|
||||
}
|
||||
}
|
||||
var decLines []string
|
||||
for _, entry := range entries {
|
||||
entry = strings.TrimSuffix(entry, ".gpg")
|
||||
decLines = decryptGPG(global.GetRealPath(entry))
|
||||
encBytes := wrappers.Encrypt([]byte(strings.Join(decLines, "\n")), rcwPassphrase, true, false)
|
||||
err := os.WriteFile(outputDir+strings.ReplaceAll(entry, "/", global.PathSeparator), encBytes, 0600)
|
||||
if err != nil {
|
||||
other.PrintError("Failed to write to file: "+err.Error(), back.ErrorWrite)
|
||||
}
|
||||
}
|
||||
|
||||
// swap the new directory with the old one
|
||||
err = os.Rename(global.EntryRoot, global.EntryRoot+"-old")
|
||||
if err != nil {
|
||||
other.PrintError("Failed to rename old directory: "+err.Error(), back.ErrorWrite)
|
||||
}
|
||||
err = os.Rename(outputDir, global.EntryRoot)
|
||||
if err != nil {
|
||||
other.PrintError("Failed to rename new directory: "+err.Error(), back.ErrorWrite)
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
# This script generates portable release binaries for the following platforms:
|
||||
# - Linux (x86_64_v1)
|
||||
# - Linux (aarch64)
|
||||
# - Windows (x86_64_v1)
|
||||
# - Windows (aarch64)
|
||||
|
||||
version=0.1.X-0.2.X
|
||||
|
||||
mkdir -p ./1output
|
||||
GOOS=linux CGO_ENABLED=0 GOAMD64=v1 go build -o "./1output/upgradeRCW-$version-linux-x86_64_v1" -ldflags="-s -w" -trimpath .
|
||||
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o "./1output/upgradeRCW-$version-linux-aarch64" -ldflags="-s -w" -trimpath .
|
||||
GOOS=windows CGO_ENABLED=0 GOAMD64=v1 go build -o "./1output/upgradeRCW-$version-windows-x86_64_v1.exe" -ldflags="-s -w" -trimpath .
|
||||
GOOS=windows GOARCH=arm64 CGO_ENABLED=0 go build -o "./1output/upgradeRCW-$version-windows-aarch64.exe" -ldflags="-s -w" -trimpath .
|
||||
@@ -0,0 +1,22 @@
|
||||
module upgradeRCW
|
||||
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
github.com/rwinkhart/convertroman v0.2.0 // DECOY TO TRICK GO INTO USING TWO VERSIONS OF RCW
|
||||
github.com/rwinkhart/go-boilerplate v0.3.1
|
||||
github.com/rwinkhart/libmutton v0.5.0
|
||||
github.com/rwinkhart/rcw v0.3.0
|
||||
)
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.48.0 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
golang.org/x/term v0.40.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/rwinkhart/convertroman => github.com/rwinkhart/rcw v0.1.2
|
||||
|
||||
replace golang.org/x/sys => github.com/rwinkhart/sys v0.41.0
|
||||
|
||||
replace github.com/Microsoft/go-winio => github.com/rwinkhart/go-winio v0.1.1
|
||||
@@ -0,0 +1,14 @@
|
||||
github.com/rwinkhart/go-boilerplate v0.3.1 h1:vkVRuptO2s1yPzzwpvtiiB0c/hPB6yr0p1mzZ2Myb9E=
|
||||
github.com/rwinkhart/go-boilerplate v0.3.1/go.mod h1:ES13A2r9fnCVfyezwMBgY/RgA4pOIudOUXz3Jk/ikes=
|
||||
github.com/rwinkhart/libmutton v0.5.0 h1:Du/o5Hyb26uE6lubqBISN/ZF9JZ5oObHVveQjAqrP0E=
|
||||
github.com/rwinkhart/libmutton v0.5.0/go.mod h1:peh8A1f3gnaF97m8J06U28JloKv04Kw8WtFCH+Pcq6s=
|
||||
github.com/rwinkhart/rcw v0.1.2 h1:JFNRx5Uc0VKZMbur05VbZBhfUtOp2KBjZ6UDeaCRYFI=
|
||||
github.com/rwinkhart/rcw v0.1.2/go.mod h1:LQ2/YJFQlkW+JkgrLpZ51NQP/unIEzPTWsLOpOuKdKU=
|
||||
github.com/rwinkhart/rcw v0.3.0 h1:OdgA++IGcDrZqN6FzyYnzbz04fL8Q1MHvlgPjhtgJM4=
|
||||
github.com/rwinkhart/rcw v0.3.0/go.mod h1:UUY7kSku6kV2X1RWPUcK0Re+rQ6RvngWI8DVZJ11cqk=
|
||||
github.com/rwinkhart/sys v0.41.0 h1:pHB6HphVC132UXYZ6yeOk62abqgl+pyl5ZZnsk4iUKg=
|
||||
github.com/rwinkhart/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
|
||||
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
|
||||
@@ -0,0 +1,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
oldwrap "github.com/rwinkhart/convertroman/wrappers"
|
||||
newwrap "github.com/rwinkhart/rcw/wrappers"
|
||||
|
||||
"github.com/rwinkhart/go-boilerplate/back"
|
||||
"github.com/rwinkhart/go-boilerplate/front"
|
||||
"github.com/rwinkhart/go-boilerplate/other"
|
||||
"github.com/rwinkhart/libmutton/global"
|
||||
"github.com/rwinkhart/libmutton/synccommon"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// get info from user
|
||||
var oldRCWPassphrase, newRCWPassphrase []byte
|
||||
for {
|
||||
oldRCWPassphrase = front.InputSecret("Old RCW passphrase:")
|
||||
if !bytes.Equal(oldRCWPassphrase, front.InputSecret("Confirm old RCW passphrase:")) {
|
||||
fmt.Println(back.AnsiError + "Passphrases do not match" + back.AnsiReset)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
for {
|
||||
newRCWPassphrase = front.InputSecret("New RCW passphrase:")
|
||||
if !bytes.Equal(newRCWPassphrase, front.InputSecret("Confirm new RCW passphrase:")) {
|
||||
fmt.Println(back.AnsiError + "Passphrases do not match" + back.AnsiReset)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// convert the entries
|
||||
fmt.Print("\nRe-encrypting entries. Please wait; do not force close this process.\n\n")
|
||||
var outputDir = global.EntryRoot + "-new"
|
||||
entries, folders, err := synccommon.WalkEntryDir()
|
||||
if err != nil {
|
||||
other.PrintError("Failed to walk entry directory: "+err.Error(), back.ErrorRead)
|
||||
}
|
||||
for _, folder := range folders {
|
||||
err := os.MkdirAll(outputDir+strings.ReplaceAll(folder, "/", global.PathSeparator), 0700)
|
||||
if err != nil {
|
||||
other.PrintError("Failed to create directory: "+err.Error(), back.ErrorWrite)
|
||||
}
|
||||
}
|
||||
for _, entry := range entries {
|
||||
oldEncBytes, err := os.ReadFile(global.GetRealPath(entry))
|
||||
if err != nil {
|
||||
other.PrintError("Failed to read file: "+err.Error(), back.ErrorRead)
|
||||
}
|
||||
decBytes, err := oldwrap.Decrypt(oldEncBytes, oldRCWPassphrase)
|
||||
if err != nil {
|
||||
other.PrintError("Failed to decrypt file: "+err.Error(), back.ErrorWrite)
|
||||
}
|
||||
newEncBytes := newwrap.Encrypt(decBytes, newRCWPassphrase, true, false)
|
||||
err = os.WriteFile(outputDir+strings.ReplaceAll(entry, "/", global.PathSeparator), newEncBytes, 0600)
|
||||
if err != nil {
|
||||
other.PrintError("Failed to write to file: "+err.Error(), back.ErrorWrite)
|
||||
}
|
||||
}
|
||||
|
||||
// swap the new directory with the old one
|
||||
err = os.Rename(global.EntryRoot, global.EntryRoot+"-old")
|
||||
if err != nil {
|
||||
other.PrintError("Failed to rename old directory: "+err.Error(), back.ErrorWrite)
|
||||
}
|
||||
err = os.Rename(outputDir, global.EntryRoot)
|
||||
if err != nil {
|
||||
other.PrintError("Failed to rename new directory: "+err.Error(), back.ErrorWrite)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
Require mutn
|
||||
Require gpg
|
||||
|
||||
Set Theme { "name": "GruvboxDarkMUTNCustom", "black": "#282828", "red": "#cc241d", "green": "#98971a", "yellow": "#d79921", "blue": "#458588", "magenta": "#b16286", "cyan": "#689d6a", "white": "#d5c4a1", "brightBlack": "#928374", "brightRed": "#fb4934", "brightGreen": "#b8bb26", "brightYellow": "#fabd2f", "brightBlue": "#83a598", "brightMagenta": "#d3869b", "brightCyan": "#8ec07c", "brightWhite": "#ebdbb2", "background": "#272727", "foreground": "#d5c4a1", "selection": "#665c54", "cursor": "#ebdbb2" }
|
||||
|
||||
Set Padding 5
|
||||
Set Framerate 30
|
||||
Set Height 675
|
||||
Set Width 1290
|
||||
Set Shell zsh
|
||||
|
||||
Output mutn-demo.gif
|
||||
|
||||
Sleep 1s
|
||||
Type "# start of loop | viewing my entry list :)"
|
||||
Sleep 800ms
|
||||
Backspace@25ms 42
|
||||
Type "mutn"
|
||||
Sleep 250ms
|
||||
Enter
|
||||
Sleep 2.25s
|
||||
Type "# syncing entries with the server :o"
|
||||
Sleep 500ms
|
||||
Backspace@25ms 36
|
||||
Type "mutn sync"
|
||||
Enter
|
||||
Sleep 1.25s
|
||||
Type "clear"
|
||||
Sleep 1.5s
|
||||
Enter
|
||||
Type "# reading my todo list :^)"
|
||||
Sleep 500ms
|
||||
Backspace@25ms 26
|
||||
Type "mutn /notes/personal/todo"
|
||||
Enter
|
||||
Sleep 1s
|
||||
Type "example"
|
||||
Enter
|
||||
Sleep 2s
|
||||
Type "clear"
|
||||
Sleep 2.5s
|
||||
Enter
|
||||
Type "# changing my github password :p"
|
||||
Sleep 500ms
|
||||
Backspace@25ms 32
|
||||
Type "mutn /development/github gen -u"
|
||||
Enter
|
||||
Sleep 500ms
|
||||
Type "69"
|
||||
Sleep 500ms
|
||||
Enter
|
||||
Sleep 500ms
|
||||
Type "y"
|
||||
Sleep 500ms
|
||||
Enter
|
||||
Sleep 2s
|
||||
Enter
|
||||
Type "# copying the new password :]"
|
||||
Sleep 500ms
|
||||
Backspace@25ms 29
|
||||
Up
|
||||
Sleep 500ms
|
||||
Backspace 6
|
||||
Sleep 500ms
|
||||
Type "copy"
|
||||
Enter
|
||||
Sleep 1s
|
||||
Enter
|
||||
Type "# darn, I need my totp token :/"
|
||||
Sleep 800ms
|
||||
Backspace@25ms 31
|
||||
Up
|
||||
Sleep 500ms
|
||||
Type " -t"
|
||||
Enter
|
||||
Sleep 1s
|
||||
Enter
|
||||
Type "as long as the process runs, the token will be refreshed | let's paste it: "
|
||||
Sleep 250ms
|
||||
Paste
|
||||
Sleep 1s
|
||||
Backspace@25ms 81
|
||||
Ctrl+c
|
||||
Sleep 1s
|
||||
Type "clear"
|
||||
Sleep 1.5s
|
||||
Enter
|
||||
Type "# editing my todo list :|"
|
||||
Sleep 500ms
|
||||
Backspace@25ms 25
|
||||
Type "mutn /notes/personal/todo edit -n"
|
||||
Sleep 500ms
|
||||
Enter
|
||||
Escape
|
||||
Sleep 1s
|
||||
Type "jj"
|
||||
Sleep 500ms
|
||||
Type "2dd"
|
||||
Sleep 1s
|
||||
Type ":wq"
|
||||
Sleep 500ms
|
||||
Enter
|
||||
Sleep 2s
|
||||
Type "clear"
|
||||
Sleep 2.5s
|
||||
Enter
|
||||
Type "# checking up on my homework :'("
|
||||
Sleep 500ms
|
||||
Backspace@25ms 32
|
||||
Type "mutn /notes/school/homework"
|
||||
Enter
|
||||
Sleep 2s
|
||||
Type "clear"
|
||||
Sleep 2.5s
|
||||
Enter
|
||||
Type "# giving my school notes a better name ;3"
|
||||
Sleep 500ms
|
||||
Backspace@25ms 41
|
||||
Type "mutn /notes/school/world\ history/MUTN\ public\ debut edit -r"
|
||||
Enter
|
||||
Sleep 1s
|
||||
Type "/notes/school/world history/the best day ever"
|
||||
Enter
|
||||
Sleep 1.5s
|
||||
Type "mutn"
|
||||
Sleep 250ms
|
||||
Enter
|
||||
Sleep 1s
|
||||
Type "# end of loop! (:"
|
||||
Sleep 3s
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
|
||||
lIYEZpmhGhYJKwYBBAHaRw8BAQdAtMOex5PpSNmm45m78oWwiyL7+HzpMXEfsJuo
|
||||
sVbQVkn+BwMCxhrqdwXRs/T/zvz/OO16ugFb9USURoP2Q9qxob5xHu/pitT2BKJ0
|
||||
AmqFgJ7d+XBhUYUgyghFs4ghnbJ+idc3M97gaUu3LTWVTN4z4WCDP7RFbGlibXV0
|
||||
dG9uLTE3MjEzNDQyODIgKGdwZy1saWJtdXR0b24pIDxnaXRodWIuY29tL3J3aW5r
|
||||
aGFydC9saWJtdXR0b24+iJMEExYKADsWIQRKkDJcKDRJ8GqC6UGj5HQatDKA/QUC
|
||||
ZpmhGgIbAwULCQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRCj5HQatDKA/YPC
|
||||
AP0a0uWYfPFt7ql6uqTF8ybH1CWlrcCdKH32Yt0TbzMFuQEAoILlIqeSznySva/v
|
||||
V/vEoKjghrlOxYS1XooR2VmLXg6ciwRmmaEaEgorBgEEAZdVAQUBAQdAjCCCC4Vq
|
||||
t6VILdm8aL8A1Lxld3QznrjastwbS5xGyw0DAQgH/gcDAiY9vEXhi4Uq/x3t0G8S
|
||||
iIbkoNaAe9r8jI/ju2FaqdDSo/kPGm/BdsifQqdfq8OuWIGYTsCItSk3nkfc6lYm
|
||||
zdIVFahsMVW9ATz8Jd8Gnp2IeAQYFgoAIBYhBEqQMlwoNEnwaoLpQaPkdBq0MoD9
|
||||
BQJmmaEaAhsMAAoJEKPkdBq0MoD9ulcBAN1jS5Nby4s1wGCGBfMFj4AxTBSvoWB9
|
||||
CUponolEwl5MAP9VS6scwf/sOkpohn3d9PBnCioGxR4+N4JNzrBQFE7ECQ==
|
||||
=bGiv
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
||||
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
„^ůRb dJ@ WwÔU=KŃ.ĆŃ‹ÝÖ>Ź":–0bÉţÔ•"0'‘fŰv�—šŔř=~ť#đÓźô•©ťáćvPšŘ
|
||||
␍ŰE˘z Ö{6'1ˇţpÔŻ Đ4®ŘÄ4SçŇ›ÖZú`dÎ�)ć$Šj|ÂŘŤg�_|ŤAłěâă7ż=‘§Ě/8č'žÜ†ěÇﱫ$$ă�¶ #»šTd;$]Ţ*?űŹÍż[ţTüĹ_ćW™á˛ĄŃ‰N:(Z«€łÝ°ÜµNąZü$Z`ë_扸x&4ť+ѵŮh˙x|üKF}źaŤ9NŤ+saĆkşKŕúÝéŇnw>EŚËë0“+
|
||||
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
„^ůRb dJ@Näë'”Éäňń¦GÝ|ŤÉźj˙ĄÜh@#␍Bő–<0ď5Á”˘GË}�=ÖúG2
|
||||
]ź?wµ˝ýÔs„ß¶D†qŦ?!hÄ�„&ľm,nÔM Í:V%`Ľ©ß(Woł05‘z'§NgdNÔą´_‹Ó2DXĎF’AÉ„ZUĐĆŐÖzÍ.>\Ä�_yJ‚Jßz“Z
|
||||
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
„^ùRb dJ@Vž„»)›fåäð:€ü¨Ýq7€¦C5�#¿WI“ß½0Ì—"æl6í>êr�9†I°ùæz*€ŒãMøUý̵V"dÔÚ[à“¹à«òÑÿqÔÀ0 $¾ó/ë^®þt½Ÿu]‹õ
|
||||
&ZaBqH:l}sR–b.ov?È!¢Ø¬C¢ü¥ÁƦdzŒÒ=Á§Ûá!v”Et²;PDÚxO•8ÝSï$%þíï|E^Ã/Á›Ü!Œ§¾¬ˆý6° ÙÌÑHÝä$JúCNÞ¹fEÈâí÷ŠV·U¼…�JÖtL¡{�ã“6‡è²—V*s]À×QTi]®Ö´cJON¹[¨O:NÍÙÒ:Ü#B´:™�A:¼úÌ.*}–R̽w©‘ 7H6×zí¸¼ÆÁýD7°Ú¶ñ¢‘u(9í‰Ð°ßaŠóì?
|
||||
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
„^ùRb dJ@Ô†W¢Ï›7¹ù¾áíN¨ËGïÑÄë²Ûö"õ×␍0 Þâ,Ö“ÝœoØr͘è˜!ÚrÿL³ÁITdEL*ˆK7BèÒ7ÿh4¢ó�ÔW >Û:A+ä?Aý~qÓ�+í»©#‚ F¸Áú!¦z`ánOò¦òG“XÕ‘G]Ú¦õ
|
||||
@£ínEz˜%’ØþóGRY’™AÖLÏ%y›åÕ-c
|
||||
@@ -0,0 +1,2 @@
|
||||
„^ùRb dJ@Ê‹Èaâ¥Þ!á¾4Ùäó†uÄä‘Ìß™ÎH¯ýp>t0Ų½—'ef¾I�päS•p¤!©þh¦ùN%šÃ).Û¯}µdÀªÌ¾c:êo?Wœ�eÔX £)«zÒKåf‰N(üt#df¡Á�™‡#±˜€ÙÆÜ�Eð¤Ðˆè_5I~�Nñ&%�c|AÃ
|
||||
¬Ã¾/tSUOo`Á¼>G‘«�6&k¥É¢-ö
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
„^щRb dJ@�WЎе кЇzЖ¬pУv•YЉЮџрсD®ЖЊдiоІ␍v0 dОВ]Њ)тт,jњЄЁвиЯ‹LVQ- ѓП:З¤ЯР¬"}‘Ф=Ѓрv'6Ър§Ф_ §AГокУҐЙѓp,шAvЂhї0‡„gW†JqDїЇ]и„fPдЂЮЯЦT-Щ¬"ґ«’с41ї6ъW1уz^MЯвоў[соФСЎb€OПаA „ 7–жH5
|
||||
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1 @@
|
||||
„^ùRb dJ@J�oä�pëÁ�È<õÔMßÑv§�‰µ¦ßJ¿'ª˜Z0åÞ5äö0ƒ UsÞA–Ø0&îS:ojÄb¡R!²�´ŸÏÀÙ`]Œ(áLØŽ÷TËäÔV Ó®ÌF¶ã ÚŒüt¦TOr‰Ô¦ìVàïu€«?çC49·áåö²Æ >…ˆ�1µ%GŠ|�Ã=¹‘_x^*OÎRüœ²¶?FA®?ùRà
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
„^שRb dJ@Bנֹמ!z,tgeֳ�›¢dW—}5J�oJ� ²Tָ0¼␍3L* �˜<תuw¼#£ˆd,M:zָg›µ)˜w��»›�9�5�®ל{װ“ ײtBד·#½V–Dמה(C*u�ֵZןQ°�TC§,�g—�„ֶ�ם]ם—;“£ֽ:ָd×�זVְ£ur£נ´ר2ט”7!�&oםם¶מboָ[& ₪�R¸,־rgq<ֶ"V<הװ«�j„ֲ�²M�‚בע¦Mן{QO?�h¿9װjz°P^
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
@@ -0,0 +1,14 @@
|
||||
# MUTN VHS Tape Creation
|
||||
1. Ensure `mutn` is in your path
|
||||
2. If `zsh` is not installed, either install it or change the shell in `cassette.tape` (for some reason the "Up" function only works in `zsh` for me)
|
||||
3. Import example.asc (if not done already) with password `example`
|
||||
4. Set up a client-server pair using the `libmutton` entries folder provided in this repo
|
||||
5. Run the following "reset" command from within this folder (it's okay if it throws errors; this is expected if running before using `vhs`):
|
||||
- `rm -rf ~/.local/share/libmutton && cp -r ./libmutton ~/.local/share/libmutton && mutn sync && mutn /notes/school/world\ history/the\ best\ day\ ever shear; rm ~/.local/share/libmutton/notes/school/ccnp\ networking/{chapter\ 4,chapter\ 5} && gpgconf --kill gpg-agent`
|
||||
6. Run `vhs ./cassette.tape`
|
||||
7. View mutn-demo.gif! Use the above "reset" command between each recording.
|
||||
|
||||
# Read for Production
|
||||
Before posting for production, I convert the GIF to an animated WEBP (to save space) using libwebp's `gif2webp`:
|
||||
|
||||
`gif2webp -min_size -q 100 -m 6 ./mutn-demo.gif -o ./mutn-demo.webp`
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
[sshyp-mfa]
|
||||
desc = read mfa data from sshyp entries to generate and copy totp keys to the clipboard (optional Steam support)
|
||||
usage = sshyp /<entry name> copy -m
|
||||
exe = https://raw.githubusercontent.com/rwinkhart/sshyp-labs/v1.5.1.1/extensions/sshyp-mfa/sshyp-mfa.py
|
||||
ini = https://raw.githubusercontent.com/rwinkhart/sshyp-labs/v1.5.1.1/extensions/sshyp-mfa/sshyp-mfa.ini
|
||||
exe = https://raw.githubusercontent.com/rwinkhart/sshyp-labs/v1.5.1.3/extensions/sshyp-mfa/sshyp-mfa.py
|
||||
ini = https://raw.githubusercontent.com/rwinkhart/sshyp-labs/v1.5.1.3/extensions/sshyp-mfa/sshyp-mfa.ini
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
[sshyp-mfa]
|
||||
desc = reads mfa/2fa secrets from sshyp entries to generate and copy totp/Steam otp keys to the clipboard
|
||||
usage = sshyp /<entry name> copy -m<br><br>to add mfa data to a sshyp entry, insert it into the SECOND notes line for a given entry using the following format:<br><br> otpauth://<OTP METHOD>/<ACCOUNT NAME, NOT USED>?secret=<SECRET>&issuer=<ISSUER, NOT USED>&algorithm=<ALGORITHM>&digits=<DIGITS>&period=<REFRESH PERIOD><br><br>what to put in each of the above spaces:<br><br> <OTP METHOD> is almost always 'totp', but in the case of Steam, it needs to be set to 'steam'.<br> <ACCOUNT NAME, NOT USED> is a part of the Authenticator backup format, but it is not used in sshyp-mfa. Set to anything.<br> <SECRET> refers to the secret used to generate your MFA key. This is usually directly provided by the issuer, but it is sometimes hidden and more easily retrieved by copying it from a QR-compatible MFA app (such as Aegis).<br> <ISSUER, NOT USED> is a part of the Authenticator backup format, but it is not used in sshyp-mfa. Set to anything.<br> <ALGORITHM> refers to the algorithm used to generate your MFA key based on your secret. This is almost always 'sha1'.<br> <DIGITS> refers to the intended length of your MFA key. This is almost always '6', but in the case of Steam, it needs to be set to '5'.<br> <REFRESH PERIOD> refers to the interval at which a new MFA key needs to be generated. This is almost always '30', for 30 seconds.<br><br>examples:<br><br> GitHub (standard 6-digit totp):<br> otpauth://totp/MyNameIsBob?secret=YUGBSG65SG9SDBSDF56SBFVSC86SBVD6&issuer=GitHub&algorithm=sha1&digits=6&period=30<br><br> Steam (5-character totp):<br> otpauth://steam/SteamUser?secret=VGVG34GH2GJHVCK7HGVS7&issuer=Steam&algorithm=sha1&digits=5&period=30<br><br>for more information, visit:<br><br> https://github.com/rwinkhart/sshyp-labs/wiki/sshyp-mfa
|
||||
exe = https://raw.githubusercontent.com/rwinkhart/sshyp-labs/v1.5.1.3/extensions/sshyp-mfa/sshyp-mfa.py
|
||||
ini = https://raw.githubusercontent.com/rwinkhart/sshyp-labs/v1.5.1.3/extensions/sshyp-mfa/sshyp-mfa.ini
|
||||
|
||||
[export-to-libmutton]
|
||||
desc = exports sshyp entries to ~/.local/share/sshyp.export for use with libmutton v0.3.X
|
||||
usage = sshyp export<br><br>this extension does not export to a format compatible with libmutton v0.4.X or later!!<br><br>for use with libmutton v0.4.X or later, run the output of this extension through the gpgToRCW binaries provided at https://github.com/rwinkhart/sshyp-labs/releases/tag/v2.0.0
|
||||
exe = https://raw.githubusercontent.com/rwinkhart/sshyp-labs/main/extensions/export-to-libmutton/export-to-libmutton.py
|
||||
ini = https://raw.githubusercontent.com/rwinkhart/sshyp-labs/main/extensions/export-to-libmutton/export-to-libmutton.ini
|
||||
Reference in New Issue
Block a user