45 Commits
Author SHA1 Message Date
RandyTheSilly da6b1658a4 sshyp-mfa - Correct revision number for Alpine Linux conventions 2023-03-04 22:28:35 -05:00
RandyTheSilly 5df741726f sshyp-mfa - Specify config file location for Fedora and FreeBSD packages 2023-03-04 22:16:14 -05:00
RandyTheSilly ea020c4bf1 sshyp-mfa - Updated copyright data 2023-03-04 22:10:33 -05:00
RandyTheSilly 3568601520 sshyp-mfa - Updated date in man page 2023-03-04 22:08:34 -05:00
RandyTheSilly e9ee114452 Update documentation for release v1.4.0.1 2023-03-04 21:31:56 -05:00
RandyTheSilly 8c1a3c340c Removed unused import statement 2023-03-01 10:26:28 -05:00
RandyTheSilly 0ad86a1040 sshyp-mfa - Removed interactive entry prompt and updated help text 2023-03-01 10:21:45 -05:00
RandyTheSilly 931d7a0494 sshyp-mfa - Optimized argument handling 2023-02-26 18:04:02 -05:00
RandyTheSilly f0eb398f07 sshyp-mfa - Added extension config file for sshyp v1.4.0 integration 2023-02-26 16:52:16 -05:00
RandyTheSilly 1216d06975 Bump version for v1.3.0.1 2022-12-14 12:37:37 -05:00
RandyTheSilly 8e45b15fee Removed use of os.system, implemented new clipboard functionality from sshyp v1.3.0 2022-12-07 23:28:34 -05:00
RandyTheSilly 6ee49d6b95 sshyp-mfa - sshyp v1.3.0 compatibility (no longer pass gpg to decrypt()) 2022-12-07 23:15:17 -05:00
RandyTheSilly 7b03cfdc5e Fixed Alpine APKBUILD sha512 information 2022-11-06 15:11:49 -05:00
RandyTheSilly 45caab270e Fixed Debian/Termux packaging 2022-11-06 14:53:12 -05:00
RandyTheSilly 1c6150afe4 Only load rarely used imports when needed 2022-11-06 11:03:06 -05:00
RandyTheSilly 8916f9b2e2 Fixed license location in Haiku 2022-11-06 10:51:42 -05:00
RandyTheSilly c0281a4dc3 Removed executable bits where they are not needed 2022-11-06 10:40:51 -05:00
RandyTheSilly 37efe8f96a Brought packaging in-line with sshyp 2022-11-06 10:37:50 -05:00
RandyTheSilly 2271281683 Removed unnecessary blank lines in packaging script 2022-11-03 22:52:07 -04:00
RandyTheSilly c5c3600e6d Fix symlink at /usr/bin/sshyp not being created in generic package 2022-11-01 12:02:17 -04:00
RandyTheSilly a97aa6052a Added source for build scripts 2022-11-01 11:54:13 -04:00
RandyTheSilly d133406de9 Move to /usr/lib/sshyp for sshyp v1.2.0 compatibility 2022-11-01 11:49:24 -04:00
RandyTheSilly 25f608dd1e Update license to GPL-3.0-only 2022-10-26 11:49:47 -04:00
RandyTheSilly a957d80a67 Packaging parity with sshyp 2022-10-26 11:45:53 -04:00
RandyTheSilly 521714fd12 sshyp-mfa - Pass device_id to whitelist_verify 2022-10-24 15:32:51 -04:00
RandyTheSilly 3c80d72a36 Support for quick-unlock in sshyp 1.2.0 2022-10-20 16:38:17 -04:00
RandyTheSilly 68c370be55 Added support for updated sshyp decrypt() function (still not fully functional) 2022-10-19 15:52:51 -04:00
RandyTheSilly bd09ab32cd password-pasture - Added delete button functionality 2022-08-11 19:06:34 -04:00
RandyTheSilly 755b1183e3 password-pasture - Added copy button functionality 2022-08-11 17:08:13 -04:00
RandyTheSilly 9c67f41199 password-pasture - Entries are now sorted alphabetically 2022-08-11 15:09:34 -04:00
RandyTheSilly 951cb5adc5 password-pasture - User entries are now displayed on the entries page 2022-08-10 19:34:13 -04:00
RandyTheSilly 4227a264c8 password-pasture - General code clean-up 2022-08-09 21:58:10 -04:00
RandyTheSilly d19cc1ed2c password-pasture - Allow build script to use all cores 2022-08-08 05:07:35 -04:00
RandyTheSilly 04ab10fdd9 password-pasture - Hide debug button 2022-08-08 01:21:34 -04:00
RandyTheSilly fd5266351e password-pasture - Initial demo of entry selector 2022-08-08 01:12:30 -04:00
RandyTheSilly 73947dd7ef password-pasture - Re-design to fit better on the PinePhone at 200% scaling 2022-08-04 04:00:16 -04:00
RandyTheSilly fcf43986a8 password-pasture - Remove artwork (already exists in extra/) 2022-08-04 03:23:25 -04:00
RandyTheSilly dfb90ca294 password-pasture (GUI) - Initial commit 2022-08-04 03:22:01 -04:00
RandyTheSilly 42ef63c0d9 sshyp-mfa - Added Alpine Linux packaging 2022-08-01 20:48:27 -04:00
RandyTheSilly 939d07e804 Corrected generic package archival format 2022-08-01 05:31:21 -04:00
RandyTheSilly be41d32f78 sshyp-mfa - Updated Haiku packaging for compatibility with new shebang 2022-08-01 05:21:32 -04:00
RandyTheSilly ba2ac73965 Switched shebang to '#!/usr/bin/env python3' for greater compatibility 2022-08-01 04:52:09 -04:00
RandyTheSilly ebb420d30f extra/artwork: added a retro-themed sshyp gif 2022-07-21 05:09:02 -04:00
RandyTheSilly 8cf5728c42 Updated refresh script (changes gpg id, optimizes entries) to take advantage of sshyp v1.1.1 2022-07-21 01:49:30 -04:00
RandyTheSilly 9e0c121843 No longer remove leading new lines from notes (interfered with sshyp-mfa) 2022-07-16 22:36:02 -04:00
18 changed files with 669 additions and 232 deletions
Executable → Regular
View File
Executable → Regular
+8 -3
View File
@@ -1,16 +1,21 @@
# sshyp-labs # sshyp-labs
Experimental extensions for the sshyp password manager. Experimental extensions for the sshyp password manager.
sshyp-labs is currently the home of sshyp-mfa, and soon to be the home of password-pasture (sshyp-gui). sshyp-labs is currently the home of sshyp-mfa and password-pasture (sshyp-gui).
# Available Extensions # Available Extensions
sshyp-mfa - [installation and usage instructions](https://github.com/rwinkhart/sshyp-labs/wiki/sshyp-mfa) sshyp-mfa - [installation and usage instructions](https://github.com/rwinkhart/sshyp-labs/wiki/sshyp-mfa)
sshyp-mfa is a unique approach to generating multi-factor authentication keys. Upon running `sshyp-mfa <target entry>`, sshyp-mfa is a unique approach to generating multi-factor authentication keys. Upon running `sshyp </entry name> copy -m`,
an MFA key will be generated and copied to your clipboard. sshyp-mfa will continue to run in the background and copy a an MFA key will be generated and copied to your clipboard. sshyp-mfa will continue to run in the background and copy a
new key to your clipboard every time the actively copied one expires. Never worry about a TOTP timer expiring, again! new key to your clipboard every time the actively copied one expires. Never worry about a TOTP timer expiring again!
At any time, sshyp-mfa can be closed with ctrl+c to stop this process. At any time, sshyp-mfa can be closed with ctrl+c to stop this process.
password-pasture - [installation and usage instructions](https://github.com/rwinkhart/sshyp-labs/wiki/password-pasture)
password-pasture is an incredibly experimental GTK4 GUI interface for sshyp. It is currently not in a usable state
and has not been updated since sshyp v1.1.X. Development is set to resume after sshyp is more feature-complete.
# Acknowledgements # Acknowledgements
sshyp-mfa relies on [ValvePython/steam](https://github.com/ValvePython/steam) for Steam support. sshyp-mfa relies on [ValvePython/steam](https://github.com/ValvePython/steam) for Steam support.
Executable → Regular
View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

@@ -1,41 +0,0 @@
#!/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: ')
directory = path.expanduser('~/.local/share/sshyp')
if Path(f"{directory}.new").exists():
rmtree(f"{directory}.new")
if Path(f"{directory}.old").exists():
rmtree(f"{directory}.old")
if path.isdir(directory):
for dirPath, dirNames, filenames in walk(directory):
for filename in sorted(filenames):
Path(dirPath.replace(directory, directory + '.new')).mkdir(0o700, parents=True, exist_ok=True)
system(f"gpg -d '{dirPath}/{filename}' "
f"> '{dirPath.replace(directory, directory + '.new')}/{filename[:-4]}'")
_old_contents, _new_contents = \
open(f"{dirPath.replace(directory, directory + '.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(directory, directory + '.new')}/{filename[:-4]}", 'w').writelines(_new_contents)
system(f"gpg -qr {str(gpg_id)} -e '{dirPath.replace(directory, directory + '.new')}/{filename[:-4]}'")
remove(f"{dirPath.replace(directory, directory + '.new')}/{filename[:-4]}")
else:
print(f"\nError: no entry folder ({directory}) found\n")
move(directory, f"{directory}.old")
move(f"{directory}.new", directory)
@@ -1,4 +1,4 @@
#!/bin/python3 #!/usr/bin/env python3
from os import path, remove, system, walk from os import path, remove, system, walk
from pathlib import Path from pathlib import Path
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env python3
from os import path, system, uname, walk
from pathlib import Path
from shutil import move, rmtree
from sshyp import decrypt, encrypt, optimized_edit, shm_gen
if __name__ == "__main__":
directory, tmp_dir = path.expanduser('~/.local/share/sshyp'), path.expanduser('~/.config/sshyp/tmp/')
if uname()[0] == 'Haiku': # set proper gpg command for OS
gpg = 'gpg --pinentry-mode loopback'
else:
gpg = 'gpg'
system(f"{gpg} -k")
gpg_id = input('\ngpg id for re-encryption: ')
if Path(f"{directory}.new").exists():
rmtree(f"{directory}.new")
if Path(f"{directory}.old").exists():
rmtree(f"{directory}.old")
if path.isdir(directory):
print('\nconverting... please wait, do not force close this process')
for dirPath, dirNames, filenames in walk(directory):
for filename in sorted(filenames):
Path(dirPath.replace(directory, directory + '.new')).mkdir(0o700, parents=True, exist_ok=True)
_shm_folder, _shm_entry = shm_gen()
decrypt(f"{dirPath}/{filename[:-4]}", _shm_folder, _shm_entry, gpg)
_new_lines = optimized_edit(open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'r').readlines(), None, -1)
open(f"{tmp_dir}{_shm_folder}/{_shm_entry}", 'w').writelines(_new_lines)
encrypt(f"{dirPath.replace(directory, directory + '.new', 1)}/{filename[:-4]}",
_shm_folder, _shm_entry, gpg, gpg_id)
move(directory, f"{directory}.old")
move(f"{directory}.new", directory)
else:
print(f"\nError: no entry folder ({directory}) found\n")
+16
View File
@@ -0,0 +1,16 @@
cmake_minimum_required(VERSION 3.23)
project(password_pasture C)
set(CMAKE_C_STANDARD 17)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK4 REQUIRED gtk4)
include_directories(${GTK4_INCLUDE_DIRS})
link_directories(${GTK4_LIBRARY_DIRS})
add_definitions(${GTK4_CFLAGS_OTHER})
add_executable(password_pasture main.c)
target_link_libraries(password_pasture ${GTK4_LIBRARIES})
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/env sh
rm -rf CMakeFiles cmake_install.cmake CMakeCache.txt Makefile
cmake ./
sleep 10 # prevents clock skew
make -j$(nproc)
+380
View File
@@ -0,0 +1,380 @@
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <stddef.h>
#include <gtk/gtk.h>
GtkWidget *label_selected; GtkListBox *list_box;
char entries[1024][1024]; int entry_array_count = 0;
void str_remove(char *str, const char *sub) {
char *p, *q, *r;
if (*sub && (q = r = strstr(str, sub)) != 0) {
size_t len = strlen(sub);
while ((r = strstr(p = r + len, sub)) != 0) {
while (p < r)
*q++ = *p++;
}
while ((*q++ = *p++) != '\0')
continue;
}
}
void gen_entry_array(char *path, size_t size, const char *path_orig) {
DIR *dir;
struct dirent *entry;
size_t len = strlen(path);
if (!(dir = opendir(path))) {
return; }
while ((entry = readdir(dir)) != 0) {
char *name = entry->d_name;
if (entry->d_type == DT_DIR) {
if (!strcmp(name, ".") || !strcmp(name, "..")) {
continue; }
path[len] = '/';
strcpy(path + len + 1, name);
gen_entry_array(path, size, path_orig);
path[len] = '\0';
} else {
char path_filtered[1024];
strcpy(path_filtered, path);
str_remove(path_filtered, path_orig);
size_t name_len = strlen(name);
name[name_len-4] = 0;
char sshyp_path[1024]; strcpy(sshyp_path, path_filtered); strcat(sshyp_path, "/"); strcat(sshyp_path, name);
strcpy(entries[entry_array_count], sshyp_path);
entry_array_count++;
}
}
closedir(dir);
}
void password_convert(GtkEntryBuffer *buffer) {
const char *password = gtk_entry_buffer_get_text(buffer);
char *sub1 = "gpg --pinentry-mode loopback --batch --passphrase-fd 0 --armor -qd --output /dev/null ~/.config/sshyp/lock.gpg <<< '", *sub2 = "'", *command = (char *) malloc(2048);
strcpy(command, sub1); strcat(command, password); strcat(command, sub2);
system(command);
free(command);
}
void gpg_lock() {
system("gpgconf --reload gpg-agent");
}
void password_prompt(GtkWindow *window) {
GtkWidget *dialog, *dialog_header, *box_header; // main window and header bar
GtkWidget *button_unlock, *button_cancel, *button_lock; // header bar buttons
GtkWidget *content_area, *password_entry; // content area and widgets
dialog = gtk_dialog_new();
password_entry = gtk_entry_new();
gtk_entry_set_visibility(GTK_ENTRY(password_entry), FALSE);
gtk_entry_set_placeholder_text(GTK_ENTRY(password_entry), "passphrase");
dialog_header = gtk_header_bar_new();
gtk_header_bar_set_show_title_buttons(GTK_HEADER_BAR(dialog_header), FALSE);
box_header = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_halign(box_header, GTK_ALIGN_CENTER);
button_unlock = gtk_button_new_with_label("unlock");
button_cancel = gtk_button_new_with_label("cancel");
button_lock = gtk_button_new_from_icon_name("changes-prevent");
gtk_widget_set_size_request(button_lock, 20, -1);
gtk_box_append(GTK_BOX(box_header), button_unlock);
gtk_box_append(GTK_BOX(box_header), button_cancel);
gtk_box_append(GTK_BOX(box_header), button_lock);
gtk_header_bar_set_title_widget(GTK_HEADER_BAR(dialog_header), box_header);
gtk_window_set_title(GTK_WINDOW(dialog), "");
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(window));
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
gtk_window_set_default_size(GTK_WINDOW(dialog), 50, 50);
// add password entry to dialog content area
content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
gtk_box_append(GTK_BOX(content_area), password_entry);
gtk_window_set_titlebar(GTK_WINDOW(dialog), dialog_header);
gtk_widget_show(dialog);
// button actions
g_signal_connect_swapped(button_unlock, "clicked", G_CALLBACK(password_convert), gtk_entry_get_buffer(GTK_ENTRY(password_entry)));
g_signal_connect_swapped(button_unlock, "clicked", G_CALLBACK(gtk_window_close), dialog);
g_signal_connect_swapped(button_cancel, "clicked", G_CALLBACK(gtk_window_close), dialog);
g_signal_connect(button_lock, "clicked", G_CALLBACK(gpg_lock), 0);
g_signal_connect_swapped(button_lock, "clicked", G_CALLBACK(gtk_window_close), dialog);
}
void copy_item(GtkWidget *button) {
char *command = malloc(2048); const char *button_label = gtk_button_get_label(GTK_BUTTON(button));
strcpy(command, "sshyp copy ");
strcat(command, button_label); strcat(command, " ");
strcat(command, gtk_label_get_text((GtkLabel *) label_selected));
system(command);
free(command);
}
void copy_edit_field_prompt(GtkWidget *button, gpointer *window) {
GtkWidget *dialog, *dialog_header; // main window and header bar
GtkWidget *button_cancel; // header bar buttons
GtkWidget *content_area, *button_pwd, *button_usr, *button_url, *button_nte, *button_mfa; // content area and widgets
int mode; // copy/edit mode flag
// set mode based on button pressed, copy = 1, edit = 2
const char *button_label = gtk_button_get_icon_name(GTK_BUTTON(button));
if (strcmp(button_label, "edit-copy") == 0) {
mode = 1;
} else {
mode = 2;
}
dialog = gtk_dialog_new();
dialog_header = gtk_header_bar_new();
gtk_header_bar_set_show_title_buttons(GTK_HEADER_BAR(dialog_header), FALSE);
button_cancel = gtk_button_new_with_label("cancel");
gtk_header_bar_set_title_widget(GTK_HEADER_BAR(dialog_header), button_cancel);
gtk_window_set_title(GTK_WINDOW(dialog), "");
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(window));
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
gtk_window_set_default_size(GTK_WINDOW(dialog), 50, 50);
// add options to dialog content area
content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
button_pwd = gtk_button_new_with_label("password");
button_usr = gtk_button_new_with_label("username");
button_url = gtk_button_new_with_label("url");
button_nte = gtk_button_new_with_label("note");
button_mfa = gtk_button_new_with_label("mfa");
gtk_box_append(GTK_BOX(content_area), button_pwd);
gtk_box_append(GTK_BOX(content_area), button_usr);
gtk_box_append(GTK_BOX(content_area), button_url);
gtk_box_append(GTK_BOX(content_area), button_nte);
gtk_box_append(GTK_BOX(content_area), button_mfa);
gtk_window_set_titlebar(GTK_WINDOW(dialog), dialog_header);
gtk_widget_show(dialog);
// button actions
if (mode == 1) {
g_signal_connect(button_pwd, "clicked", G_CALLBACK(copy_item), 0);
g_signal_connect(button_usr, "clicked", G_CALLBACK(copy_item), 0);
g_signal_connect(button_url, "clicked", G_CALLBACK(copy_item), 0);
g_signal_connect(button_nte, "clicked", G_CALLBACK(copy_item), 0);
g_signal_connect(button_mfa, "clicked", G_CALLBACK(copy_item), 0);
}
g_signal_connect_swapped(button_cancel, "clicked", G_CALLBACK(gtk_window_close), dialog);
g_signal_connect_swapped(button_pwd, "clicked", G_CALLBACK(gtk_window_close), dialog);
g_signal_connect_swapped(button_usr, "clicked", G_CALLBACK(gtk_window_close), dialog);
g_signal_connect_swapped(button_url, "clicked", G_CALLBACK(gtk_window_close), dialog);
g_signal_connect_swapped(button_nte, "clicked", G_CALLBACK(gtk_window_close), dialog);
g_signal_connect_swapped(button_mfa, "clicked", G_CALLBACK(gtk_window_close), dialog);
}
void set_selection_label(GtkWidget *button, gpointer *label) {
const char *button_label = gtk_button_get_label(GTK_BUTTON(button));
gtk_label_set_text(GTK_LABEL(label), button_label);
}
void entry_list_gen() {
GtkWidget *entry_button;
GtkWidget *iter = gtk_widget_get_first_child ((GtkWidget *) list_box);
while (iter != 0) {
GtkWidget *next = gtk_widget_get_next_sibling (iter);
gtk_list_box_remove (list_box, iter);
iter = next;
}
char path[1024]; char *user_home = getenv("HOME"); strcpy(path, user_home); strcat(path, "/.local/share/sshyp");
char path_orig[1024]; strcpy(path_orig, path); strcat(path_orig, "/");
gen_entry_array(path, sizeof path, path_orig);
// bubble sort entries array
char *temp = (char *) malloc(1024);
for(int i=0; i<entry_array_count; i++){
for(int j=0; j<entry_array_count-1-i; j++){
if(strcmp(entries[j], entries[j+1]) > 0){
strcpy(temp, entries[j]);
strcpy(entries[j], entries[j+1]);
strcpy(entries[j+1], temp);
}
}
}
free(temp);
strcpy(entries[entry_array_count], "\0");
for (int i_2 = 0; strcmp(entries[i_2], "\0") != 0; i_2++) {
entry_button = gtk_button_new_with_label(entries[i_2]);
gtk_label_set_xalign(GTK_LABEL(gtk_button_get_child(GTK_BUTTON(entry_button))), GTK_JUSTIFY_LEFT);
gtk_button_set_has_frame(GTK_BUTTON(entry_button), FALSE);
g_signal_connect(entry_button, "clicked", G_CALLBACK(set_selection_label), (gpointer *)label_selected);
gtk_list_box_append(list_box, gtk_separator_new(GTK_ORIENTATION_HORIZONTAL));
gtk_list_box_append(list_box, entry_button);
}
}
void sshyp_sync() {
system("sshyp sync");
entry_array_count = 0;
entry_list_gen();
}
void delete_entry() {
char *command = (char *) malloc(2048);
strcpy(command, "sshyp shear "); strcat(command, gtk_label_get_text(GTK_LABEL(label_selected)));
system(command);
free(command);
entry_array_count = 0;
entry_list_gen();
}
void are_they_sure(GtkWindow *window) {
GtkWidget *dialog, *dialog_header, *box_header; // main window and header bar
GtkWidget *button_delete, *button_cancel; // header bar buttons
GtkWidget *content_area, *label_sure; // content area and widgets
dialog = gtk_dialog_new();
dialog_header = gtk_header_bar_new();
gtk_header_bar_set_show_title_buttons(GTK_HEADER_BAR(dialog_header), FALSE);
box_header = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_halign(box_header, GTK_ALIGN_CENTER);
button_delete = gtk_button_new_with_label("delete");
button_cancel = gtk_button_new_with_label("cancel");
gtk_box_append(GTK_BOX(box_header), button_delete);
gtk_box_append(GTK_BOX(box_header), button_cancel);
gtk_header_bar_set_title_widget(GTK_HEADER_BAR(dialog_header), box_header);
gtk_window_set_title(GTK_WINDOW(dialog), "");
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(window));
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
gtk_window_set_default_size(GTK_WINDOW(dialog), 50, 50);
// add label to dialog content area
content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
gtk_widget_set_halign(content_area, GTK_ALIGN_CENTER);
char *label_text = malloc(2048);
strcpy(label_text, "this will delete:\n");
strcat(label_text, gtk_label_get_text(GTK_LABEL(label_selected)));
strcat(label_text, "\nare you sure?");
label_sure = gtk_label_new(label_text);
free(label_text);
gtk_label_set_justify(GTK_LABEL(label_sure), GTK_JUSTIFY_CENTER);
gtk_box_append(GTK_BOX(content_area), label_sure);
// button actions
g_signal_connect(button_delete, "clicked", G_CALLBACK(delete_entry), 0);
g_signal_connect_swapped(button_delete, "clicked", G_CALLBACK(gtk_window_close), dialog);
g_signal_connect_swapped(button_cancel, "clicked", G_CALLBACK(gtk_window_close), dialog);
gtk_window_set_titlebar(GTK_WINDOW(dialog), dialog_header);
gtk_widget_show(dialog);
}
static void activate(GtkApplication* app) {
GtkWidget *window, *header_bar; // main window and header bar
GtkWidget *button_sync, *button_unlock; // header bar buttons
GtkWidget *stack, *stack_switcher; GtkStackPage *page_info; // stack widgets
GtkWidget *box_info, *sshyp_logo, *label_home1; // info page widgets
GtkWidget *box_browse_page, *box_browse_controls; // browse page boxes
GtkWidget *button_shear, *button_read, *button_edit, *button_copy; // browse buttons
GtkWidget *scrollable; // scrollable entry list container
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "");
gtk_window_set_default_size(GTK_WINDOW(window), 360, 720);
header_bar = gtk_header_bar_new();
gtk_header_bar_set_show_title_buttons(GTK_HEADER_BAR(header_bar), FALSE);
// !!start main stack stuff!!
// create the stack
stack = gtk_stack_new();
gtk_stack_set_transition_type(GTK_STACK(stack), GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT);
// attach the stack to the main window
gtk_window_set_child(GTK_WINDOW(window), stack);
// browse
button_shear = gtk_button_new_from_icon_name("edit-delete");
gtk_widget_set_hexpand(button_shear, FALSE);
gtk_widget_set_size_request(button_shear, 50, -1);
g_signal_connect_swapped(button_shear, "clicked", G_CALLBACK(are_they_sure), window);
button_read = gtk_button_new_from_icon_name("mail-read");
gtk_widget_set_hexpand(button_read, TRUE);
button_edit = gtk_button_new_from_icon_name("document-edit");
gtk_widget_set_hexpand(button_edit, TRUE);
g_signal_connect(button_edit, "clicked", G_CALLBACK(copy_edit_field_prompt), (gpointer *) window);
button_copy = gtk_button_new_from_icon_name("edit-copy");
gtk_widget_set_hexpand(button_copy, TRUE);
g_signal_connect(button_copy, "clicked", G_CALLBACK(copy_edit_field_prompt), (gpointer *) window);
box_browse_page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
label_selected = gtk_label_new("no entry selected");
gtk_widget_set_hexpand(label_selected, TRUE);
gtk_widget_set_halign(label_selected, GTK_ALIGN_CENTER);
box_browse_controls = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_valign(box_browse_controls, GTK_ALIGN_START);
gtk_widget_set_size_request(box_browse_controls, -1, 50);
gtk_box_append(GTK_BOX(box_browse_controls), button_shear);
gtk_box_append(GTK_BOX(box_browse_controls), button_read);
gtk_box_append(GTK_BOX(box_browse_controls), button_edit);
gtk_box_append(GTK_BOX(box_browse_controls), button_copy);
gtk_box_append(GTK_BOX(box_browse_page), label_selected);
gtk_box_append(GTK_BOX(box_browse_page), box_browse_controls);
// !!start scrollable list!!
scrollable = gtk_scrolled_window_new();
list_box = (GtkListBox *) gtk_list_box_new();
gtk_widget_set_vexpand(GTK_WIDGET(list_box), TRUE);
entry_list_gen();
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrollable), GTK_WIDGET(list_box));
// !!end scrollable list!!
gtk_box_append(GTK_BOX(box_browse_page), GTK_WIDGET(scrollable));
// info
box_info = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
sshyp_logo = gtk_image_new_from_file("PLACEHOLDER");
gtk_image_set_pixel_size(GTK_IMAGE(sshyp_logo), 300);
label_home1 = gtk_label_new("password pasture\nexperimental gui client for sshyp");
gtk_label_set_justify(GTK_LABEL(label_home1), GTK_JUSTIFY_CENTER);
gtk_label_set_markup(GTK_LABEL(label_home1), "<span size='large'><b>password pasture</b></span>\n<span size='small'>experimental gui client for sshyp</span>");
gtk_box_append(GTK_BOX(box_info), sshyp_logo);
gtk_box_append(GTK_BOX(box_info), label_home1);
stack_switcher = gtk_stack_switcher_new();
page_info = gtk_stack_add_titled(GTK_STACK(stack), box_info, "info", "info");
gtk_stack_page_set_icon_name(GTK_STACK_PAGE(page_info), "help-about");
gtk_stack_add_titled(GTK_STACK(stack), box_browse_page, "browse", "browse");
gtk_stack_switcher_set_stack(GTK_STACK_SWITCHER(stack_switcher), GTK_STACK(stack));
gtk_header_bar_pack_start(GTK_HEADER_BAR(header_bar), stack_switcher);
// !!end main stack stuff!!
// header bar buttons
button_sync = gtk_button_new_from_icon_name("view-refresh");
g_signal_connect(button_sync, "clicked", G_CALLBACK(sshyp_sync), 0);
gtk_header_bar_pack_end(GTK_HEADER_BAR(header_bar), button_sync);
button_unlock = gtk_button_new_from_icon_name("changes-allow");
g_signal_connect_swapped(button_unlock, "clicked", G_CALLBACK(password_prompt), window);
gtk_header_bar_pack_end(GTK_HEADER_BAR(header_bar), button_unlock);
//GtkWidget *button_debug = gtk_button_new_from_icon_name("applications-science");
//g_signal_connect(button_debug, "clicked", G_CALLBACK(0), 0);
//gtk_header_bar_pack_end(GTK_HEADER_BAR(header_bar), button_debug);
gtk_window_set_titlebar(GTK_WINDOW(window), header_bar);
gtk_widget_show(window);
}
int main(int argc,
char **argv) {
GtkApplication *app = gtk_application_new("org.rwinkhart.sshyp", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(activate), 0);
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
+3
View File
@@ -0,0 +1,3 @@
arch: base-devel gtk4 cmake make gcc
alpine: build-base gtk4.0 gtk4.0-dev cmake make gcc binutils abuild
Executable → Regular
+5 -5
View File
@@ -1,15 +1,15 @@
.TH sshyp-mfa 1 "12 July 2022" "rolling" "sshyp-mfa man page" .TH sshyp-mfa 1 "04 March 2023" "v1.4.0.1" "sshyp-mfa man page"
.SH NAME .SH NAME
sshyp-mfa \- An MFA (TOTP/Steam) key generator for the sshyp password manager. sshyp-mfa \- An MFA (TOTP/Steam) key generator for the sshyp password manager.
.SH SYNOPSIS .SH SYNOPSIS
sshyp-mfa [/<entry name>] Extension Usage: sshyp </entry name> copy -m
Direct Usage: sshyp-mfa </entry name>
.SH DESCRIPTION .SH DESCRIPTION
sshyp-mfa is an extension for the sshyp password manager that reads MFA data from sshyp entries and generates generic TOTP and Steam keys. sshyp-mfa is an extension for the sshyp password manager that reads MFA data from sshyp entries and generates generic TOTP and Steam keys.
.SH EXAMPLES .SH EXAMPLES
Viewing the entry database:
sshyp-mfa
Generating and copying an MFA key for an existing entry saved as ~/.local/share/sshyp-mfa/development/github.gpg Generating and copying an MFA key for an existing entry saved as ~/.local/share/sshyp-mfa/development/github.gpg
sshyp /development/github copy -m
sshyp-mfa /development/github sshyp-mfa /development/github
.SH SETUP .SH SETUP
+3
View File
@@ -0,0 +1,3 @@
[config]
input = copy -m
output = sshyp-mfa
@@ -1,22 +1,18 @@
#!/bin/python3 #!/usr/bin/env python3
from base64 import b32decode from base64 import b32decode
from hmac import new as new_mac from os import environ, listdir, path, uname
from os import environ, path, system, uname
from pathlib import Path from pathlib import Path
from shutil import rmtree
from sshync import get_profile from sshync import get_profile
from sshyp import decrypt, entry_list_gen, shm_gen from sshyp import decrypt, shm_gen, whitelist_verify
from struct import pack, unpack from subprocess import PIPE, Popen, run
from sys import argv, exit as s_exit from sys import argv, exit as s_exit
from time import sleep, strftime, time from time import sleep, strftime, time
try:
from steam.guard import generate_twofactor_code as steam_totp
except (ModuleNotFoundError, ImportError):
pass
def totp(_secret, _algo, _digits, _period): # uses provided information to generate a standard totp key 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)) _secret = b32decode(_secret.upper() + '=' * ((8 - len(_secret)) % 8))
_counter = pack('>Q', int(time() / _period)) _counter = pack('>Q', int(time() / _period))
_mac = new_mac(_secret, _counter, _algo).digest() _mac = new_mac(_secret, _counter, _algo).digest()
@@ -25,12 +21,16 @@ def totp(_secret, _algo, _digits, _period): # uses provided information to gene
return str(_binary)[-_digits:].zfill(_digits) return str(_binary)[-_digits:].zfill(_digits)
def mfa_read_shortcut(): # reads and extracts MFA info from the user-specified sshyp entry def mfa_read_shortcut(): # extracts MFA info from the user-specified sshyp entry
if not Path(f"{directory}{argument}.gpg").exists(): from shutil import rmtree
print(f"\n\u001b[38;5;9merror: entry ({argument}) does not exist\u001b[0m\n") if not Path(f"{directory}{arguments[0]}.gpg").exists():
print(f"\n\u001b[38;5;9merror: entry ({arguments[0]}) does not exist\u001b[0m\n")
s_exit(1) s_exit(1)
_shm_folder, _shm_entry = shm_gen() _shm_folder, _shm_entry = shm_gen()
decrypt(directory + argument, _shm_folder, _shm_entry, gpg) if quick_unlock_enabled == 'y':
decrypt(directory + arguments[0], _shm_folder, _shm_entry, whitelist_verify(port, username_ssh, ip, device_id))
else:
decrypt(directory + arguments[0], _shm_folder, _shm_entry, False)
try: try:
_mfa_data = open(f"{path.expanduser('~/.config/sshyp/tmp/')}{_shm_folder}/{_shm_entry}", 'r').readlines() _mfa_data = open(f"{path.expanduser('~/.config/sshyp/tmp/')}{_shm_folder}/{_shm_entry}", 'r').readlines()
_type = _mfa_data[4].split('otpauth://')[1].split('/')[0] _type = _mfa_data[4].split('otpauth://')[1].split('/')[0]
@@ -41,32 +41,29 @@ def mfa_read_shortcut(): # reads and extracts MFA info from the user-specified
rmtree(f"{path.expanduser('~/.config/sshyp/tmp/')}{_shm_folder}") rmtree(f"{path.expanduser('~/.config/sshyp/tmp/')}{_shm_folder}")
return _type, _secret, _algo, _digits, _period return _type, _secret, _algo, _digits, _period
except IndexError: except IndexError:
print(f"\n\u001b[38;5;9merror: entry ({argument}) does not contain valid mfa data\u001b[0m\n") print(f"\n\u001b[38;5;9merror: entry ({arguments[0]}) does not contain valid mfa data\u001b[0m\n")
rmtree(f"{path.expanduser('~/.config/sshyp/tmp/')}{_shm_folder}") rmtree(f"{path.expanduser('~/.config/sshyp/tmp/')}{_shm_folder}")
s_exit(1) s_exit(1)
if __name__ == '__main__': if __name__ == '__main__':
# argument fetcher # argument fetcher
argument_list = argv arguments = argv[1:]
if not len(argv) == 1 and not argv[1].strip().startswith('/'): if len(arguments) < 1 or not arguments[0].startswith('/'):
print(f"\n\u001b[38;5;9merror: invalid argument - run 'man sshyp-mfa' for usage information\u001b[0m\n") print("\nsshyp-mfa extension usage: sshyp </entry name> copy -m\n\nrun 'man sshyp-mfa' for more information\n")
s_exit(1) s_exit(1)
# user data fetcher # user data fetcher
device_id = listdir(path.expanduser('~/.config/sshyp/devices'))[0]
quick_unlock_enabled = open(path.expanduser('~/.config/sshyp/sshyp-data')).readlines()[3].rstrip()
ssh_info = get_profile(path.expanduser('~/.config/sshyp/sshyp.sshync')) ssh_info = get_profile(path.expanduser('~/.config/sshyp/sshyp.sshync'))
directory = str(ssh_info[3].replace('\n', '')) username_ssh = str(ssh_info[0].rstrip())
if uname()[0] == 'Haiku': # set proper gpg command for OS ip = str(ssh_info[1].rstrip())
gpg = 'gpg --pinentry-mode loopback' port = str(ssh_info[2].rstrip())
else: directory = str(ssh_info[3].rstrip())
gpg = 'gpg'
# main process; runs functions to generate MFA key, then continuously copies up-to-date MFA key to clipboard # main process: runs functions to generate MFA key, then continuously copies up-to-date MFA key to clipboard
try: try:
if len(argument_list) == 1:
entry_list_gen()
argument_list.append(input('entry to read: '))
argument = ' '.join(argument_list[1:]).replace('/', '', 1)
mfa_data, copied = mfa_read_shortcut(), None mfa_data, copied = mfa_read_shortcut(), None
print('\nmfa key copied to clipboard\n\nuntil this process is closed, your clipboard will be automatically ' print('\nmfa key copied to clipboard\n\nuntil this process is closed, your clipboard will be automatically '
'updated with the newest mfa key') 'updated with the newest mfa key')
@@ -75,18 +72,19 @@ if __name__ == '__main__':
if copied is None: if copied is None:
copied = 1 copied = 1
if mfa_data[0] == 'steam': if mfa_data[0] == 'steam':
from steam.guard import generate_twofactor_code as steam_totp
_mfa_key = steam_totp(b32decode(mfa_data[1])) _mfa_key = steam_totp(b32decode(mfa_data[1]))
else: else:
_mfa_key = totp(mfa_data[1], mfa_data[2], mfa_data[3], mfa_data[4]) _mfa_key = totp(mfa_data[1], mfa_data[2], mfa_data[3], mfa_data[4])
if uname()[0] == 'Haiku': # Haiku clipboard detection if 'WAYLAND_DISPLAY' in environ: # Wayland clipboard detection
system(f"clipboard -c '{_mfa_key}'") run(['wl-copy', _mfa_key])
elif uname()[0] == 'Haiku': # Haiku clipboard detection
run(['clipboard', '-c', _mfa_key])
elif Path("/data/data/com.termux").exists(): # Termux (Android) clipboard detection elif Path("/data/data/com.termux").exists(): # Termux (Android) clipboard detection
system(f"termux-clipboard-set '{_mfa_key}'") run(['termux-clipboard-set', _mfa_key])
elif environ.get('WAYLAND_DISPLAY') == 'wayland-0': # Wayland clipboard detection
system(f"wl-copy '{_mfa_key}'")
else: # X11 clipboard detection else: # X11 clipboard detection
system(f"echo -n '{_mfa_key}' | xclip -sel c") run(['xclip', '-sel', 'c'], stdin=Popen(['echo', '-n', _mfa_key], stdout=PIPE).stdout)
sleep(1) sleep(1)
except KeyboardInterrupt: except KeyboardInterrupt:
print('\n') print('\n')
s_exit() s_exit(0)
+176 -142
View File
@@ -1,39 +1,81 @@
#!/bin/bash #!/usr/bin/env bash
# This script packages sshyp-mfa (from source) for various UNIX(-like) environments. version=$(sed -n '1{p;q}' ../version)
# Dependencies (Arch Linux): dpkg (packaging for Debian/Termux), freebsd-pkg (packaging for FreeBSD) if [ -z "$2" ]; then
# Dependencies (Fedora) (can only package for self): rpmdevtools revision=1
# NOTE It is recommended to instead use the latest officially packaged and tagged release. else
revision="$2"
echo -e '\nOptions (please enter the number only):'
echo -e '\nPackage Formats:\n\n1. Haiku\n2. Debian&Ubuntu Linux\n3. Fedora Linux\n4. FreeBSD\n5. Termux\n6. Generic (used for PKGBUILD/APKBUILD)'
echo -e '\nBuild Scripts:\n\n7. Arch Linux (PKGBUILD)'
echo -e '\nOther:\n\n8. All (generates all distribution packages (excluding Haiku and Fedora, as these must be packaged on their respective distributions) and build scripts)\n'
read -n 1 -r -p "Distribution: " distro
echo -e '\n\nThe value entered in this field will only affect the version reported to the package manager. The latest source is used regardless.\n'
read -r -p "Version number: " version
echo -e '\nThe value entered in this field will only affect the revision number for build scripts.\n'
read -r -p "Revision number: " revision
if [ "$distro" == "7" ] || [ "$distro" == "8" ]; then
echo -e '\nOptions (please enter the number only):'
echo -e '\n1. GitHub Release Tag\n2. Local\n'
read -r -p "Source (for build scripts): " source
if [ "$source" == "1" ]; then
source='https://github.com/rwinkhart/sshyp-labs/releases/download/v$pkgver/sshyp-mfa-$pkgver.tar.xz'
else
source=local://sshyp-mfa-"$version".tar.xz
fi
fi fi
mkdir -p packages _create_generic() {
echo -e '\npackaging as generic...\n'
mkdir -p output/generictemp/usr/{bin,lib/sshyp,share/man/man1}
cp -r lib/. output/generictemp/usr/lib/sshyp/
ln -s /usr/lib/sshyp/sshyp-mfa.py output/generictemp/usr/bin/sshyp-mfa
cp -r share output/generictemp/usr/
cp extra/manpage output/generictemp/usr/share/man/man1/sshyp-mfa.1
gzip output/generictemp/usr/share/man/man1/sshyp-mfa.1
tar -C output/generictemp -cvJf output/sshyp-mfa-"$version".tar.xz usr/
rm -rf output/generictemp
sha512="$(sha512sum output/sshyp-mfa-"$version".tar.xz | awk '{print $1;}')"
echo -e "\nsha512 sum:\n$sha512"
echo -e "\ngeneric packaging complete\n"
} &&
if [ "$distro" == "1" ]; then _create_pkgbuild() {
echo -e '\nPackaging for Haiku...\n' source='https://github.com/rwinkhart/sshyp-labs/releases/download/v$pkgver/sshyp-mfa-$pkgver.tar.xz'
mkdir -p packages/haikutemp/documentation/{man/man1,packages/sshyp-mfa} echo -e '\ngenerating PKGBUILD...'
echo "# Maintainer: Randall Winkhart <idgr at tutanota dot com>
pkgname=sshyp-mfa
pkgver="$version"
pkgrel="$revision"
pkgdesc='An MFA (TOTP/Steam) key generator for the sshyp password manager'
url='https://github.com/rwinkhart/sshyp-labs'
arch=('any')
license=('GPL-3.0-only')
depends=(sshyp)
source=(\""$source"\")
sha512sums=('"$sha512"')
package() {
tar xf sshyp-mfa-"\"\$pkgver\"".tar.xz -C "\"\${pkgdir}\""
}
" > output/PKGBUILD
echo -e "\nPKGBUILD generated\n"
} &&
_create_apkbuild() {
source='https://github.com/rwinkhart/sshyp-labs/releases/download/v$pkgver/sshyp-mfa-$pkgver.tar.xz'
echo -e '\ngenerating APKBUILD...'
echo "# Maintainer: Randall Winkhart <idgr@tutanota.com>
pkgname=sshyp-mfa
pkgver="$version"
pkgrel="$((revision-1))"
pkgdesc='An MFA (TOTP/Steam) key generator for the sshyp password manager'
options=!check
url='https://github.com/rwinkhart/sshyp-labs'
arch='noarch'
license='GPL-3.0-only'
depends='sshyp'
source=\""$source"\"
package() {
mkdir -p "\"\$pkgdir\""
cp -r "\"\$srcdir/usr/"\" "\"\$pkgdir\""
}
sha512sums=\"
"$sha512' 'sshyp-mfa-\"\$pkgver\".tar.xz"
\"
" > output/APKBUILD
echo -e "\nAPKBUILD generated\n"
} &&
_create_hpkg() {
echo -e '\npackaging for Haiku...\n'
mkdir -p output/haikutemp/{bin,lib/sshyp,documentation/{man/man1,packages/sshyp-mfa}}
echo "name sshypmfa echo "name sshypmfa
version "$version"-"$revision" version "$version"-"$revision"
architecture any architecture any
@@ -42,7 +84,7 @@ description \"sshyp-mfa is an extension for the sshyp password manager that rea
packager \"Randall Winkhart <idgr at tutanota dot com>\" packager \"Randall Winkhart <idgr at tutanota dot com>\"
vendor \"Randall Winkhart\" vendor \"Randall Winkhart\"
licenses { licenses {
\"GNU GPL v3\" \"GNU GPL v3\"
} }
copyrights { copyrights {
\"2021-2022 Randall Winkhart\" \"2021-2022 Randall Winkhart\"
@@ -53,129 +95,109 @@ provides {
} }
requires { requires {
sshyp sshyp
python3
} }
urls { urls {
\"https://github.com/rwinkhart/sshyp-labs\" \"https://github.com/rwinkhart/sshyp-labs\"
} }
" > packages/haikutemp/.PackageInfo " > output/haikutemp/.PackageInfo
cp -r bin packages/haikutemp/ cp -r lib/. output/haikutemp/lib/sshyp/
ln -s /bin/sshyp-mfa.py packages/haikutemp/bin/sshyp-mfa sed -i '1 s/.*/#!\/bin\/env\ python3.10/' output/haikutemp/lib/sshyp/sshyp-mfa.py
cp -r share/licenses/sshyp-mfa/ packages/haikutemp/documentation/packages/ ln -s /system/lib/sshyp/sshyp-mfa.py output/haikutemp/bin/sshyp-mfa
cp extra/manpage packages/haikutemp/documentation/man/man1/sshyp-mfa.1 cp -r share/licenses/sshyp-mfa/. output/haikutemp/documentation/packages/sshyp-mfa/
gzip packages/haikutemp/documentation/man/man1/sshyp-mfa.1 cp extra/manpage output/haikutemp/documentation/man/man1/sshyp-mfa.1
cd packages/haikutemp gzip output/haikutemp/documentation/man/man1/sshyp-mfa.1
cd output/haikutemp
package create -b sshyp-mfa-"$version"-"$revision"_all.hpkg package create -b sshyp-mfa-"$version"-"$revision"_all.hpkg
package add sshyp-mfa-"$version"-"$revision"_all.hpkg bin documentation package add sshyp-mfa-"$version"-"$revision"_all.hpkg bin lib documentation
cd ../.. cd ../..
mv packages/haikutemp/sshyp-mfa-"$version"-"$revision"_all.hpkg packages/ mv output/haikutemp/sshyp-mfa-"$version"-"$revision"_all.hpkg output/
rm -rf packages/haikutemp rm -rf output/haikutemp
echo -e "\nHaiku packaging complete.\n" echo -e "\nHaiku packaging complete\n"
fi } &&
if [ "$distro" == "2" ] || [ "$distro" == "8" ]; then _create_deb() {
echo -e '\nPackaging for Debian...\n' echo -e '\npackaging for Debian/Ubuntu...\n'
mkdir -p packages/debiantemp/sshyp-mfa_"$version"-"$revision"_all/{DEBIAN,usr/share/man/man1} mkdir -p output/debiantemp/sshyp-mfa_"$version"-"$revision"_all/{DEBIAN,usr/{lib/sshyp,bin,share/man/man1}}
echo "Package: sshyp-mfa echo "Package: sshyp-mfa
Version: $version Version: $version
Section: utils Section: utils
Architecture: all Architecture: all
Maintainer: Randall Winkhart <idgr at tutanota dot com> Maintainer: Randall Winkhart <idgr at tutanota dot com>
Description: An MFA (TOTP/Steam) key generator for the sshyp password manager Description: An MFA (TOTP/Steam) key generator for the sshyp password manager
Depends: sshyp, python3 Depends: sshyp
Priority: optional Priority: optional
Installed-Size: 100 Installed-Size: 100
" > packages/debiantemp/sshyp-mfa_"$version"-"$revision"_all/DEBIAN/control " > output/debiantemp/sshyp-mfa_"$version"-"$revision"_all/DEBIAN/control
cp -r bin packages/debiantemp/sshyp-mfa_"$version"-"$revision"_all/usr/ cp -r lib/. output/debiantemp/sshyp-mfa_"$version"-"$revision"_all/usr/lib/sshyp/
ln -s /usr/bin/sshyp-mfa.py packages/debiantemp/sshyp-mfa_"$version"-"$revision"_all/usr/bin/sshyp-mfa ln -s /usr/lib/sshyp/sshyp-mfa.py output/debiantemp/sshyp-mfa_"$version"-"$revision"_all/usr/bin/sshyp-mfa
cp -r share packages/debiantemp/sshyp-mfa_"$version"-"$revision"_all/usr/ cp -r share output/debiantemp/sshyp-mfa_"$version"-"$revision"_all/usr/
cp extra/manpage packages/debiantemp/sshyp-mfa_"$version"-"$revision"_all/usr/share/man/man1/sshyp-mfa.1 cp extra/manpage output/debiantemp/sshyp-mfa_"$version"-"$revision"_all/usr/share/man/man1/sshyp-mfa.1
gzip packages/debiantemp/sshyp-mfa_"$version"-"$revision"_all/usr/share/man/man1/sshyp-mfa.1 gzip output/debiantemp/sshyp-mfa_"$version"-"$revision"_all/usr/share/man/man1/sshyp-mfa.1
dpkg-deb --build --root-owner-group packages/debiantemp/sshyp-mfa_"$version"-"$revision"_all/ dpkg-deb --build --root-owner-group output/debiantemp/sshyp-mfa_"$version"-"$revision"_all/
mv packages/debiantemp/sshyp-mfa_"$version"-"$revision"_all.deb packages/ mv output/debiantemp/sshyp-mfa_"$version"-"$revision"_all.deb output/
rm -rf packages/debiantemp rm -rf output/debiantemp
echo -e "\nDebian packaging complete.\n" echo -e "\nDebian/Ubuntu packaging complete\n"
fi } &&
if [ "$distro" == "5" ] || [ "$distro" == "8" ]; then _create_termux() {
echo -e '\nPackaging for Termux...\n' echo -e '\npackaging for Termux...\n'
mkdir -p packages/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/{data/data/com.termux/files/usr/share/man/man1,DEBIAN} mkdir -p output/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/{DEBIAN,data/data/com.termux/files/usr/{lib/sshyp,bin,share/man/man1}}
echo "Package: sshyp-mfa echo "Package: sshyp-mfa
Version: $version Version: $version
Section: utils Section: utils
Architecture: all Architecture: all
Maintainer: Randall Winkhart <idgr at tutanota dot com> Maintainer: Randall Winkhart <idgr at tutanota dot com>
Description: An MFA (TOTP/Steam) key generator for the sshyp password manager Description: An MFA (TOTP/Steam) key generator for the sshyp password manager
Depends: sshyp, python3 Depends: sshyp
Priority: optional Priority: optional
Installed-Size: 100 Installed-Size: 100
" > packages/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/DEBIAN/control " > output/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/DEBIAN/control
cp -r bin packages/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/ cp -r lib/. output/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/lib/sshyp/
ln -s /data/data/com.termux/files/usr/bin/sshyp-mfa.py packages/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/bin/sshyp-mfa ln -s /data/data/com.termux/files/usr/lib/sshyp/sshyp-mfa.py output/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/bin/sshyp-mfa
cp -r share packages/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/ cp -r share output/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/
cp extra/manpage packages/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/share/man/man1/sshyp-mfa.1 cp extra/manpage output/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/share/man/man1/sshyp-mfa.1
gzip packages/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/share/man/man1/sshyp-mfa.1 gzip output/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/data/data/com.termux/files/usr/share/man/man1/sshyp-mfa.1
dpkg-deb --build --root-owner-group packages/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/ dpkg-deb --build --root-owner-group output/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux/
mv packages/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux.deb packages/ mv output/termuxtemp/sshyp-mfa_"$version"-"$revision"_all_termux.deb output/
rm -rf packages/termuxtemp rm -rf output/termuxtemp
echo -e "\nTermux packaging complete.\n" echo -e "\nTermux packaging complete\n"
fi } &&
if [ "$distro" == "3" ] || [ "$distro" == "4" ] || [ "$distro" == "6" ] || [ "$distro" == "7" ] || [ "$distro" == "8" ]; then _create_rpm() {
echo -e '\nPackaging as generic...\n' echo -e '\npackaging for Fedora...\n'
mkdir -p packages/generictemp/usr/share/man/man1
cp -r bin packages/generictemp/usr/
ln -s /usr/bin/sshyp-mfa.py packages/generictemp/usr/bin/sshyp-mfa
cp -r share packages/generictemp/usr/
cp extra/manpage packages/generictemp/usr/share/man/man1/sshyp-mfa.1
gzip packages/generictemp/usr/share/man/man1/sshyp-mfa.1
tar -C packages/generictemp -cvf packages/sshyp-mfa-"$version".tar.xz usr/
rm -rf packages/generictemp
sha512="$(sha512sum packages/sshyp-mfa-"$version".tar.xz | awk '{print $1;}')"
echo -e "\nsha512 sum:\n$sha512"
echo -e "\nGeneric packaging complete.\n"
fi
if [ "$distro" == "3" ]; then
echo -e '\nPackaging for Fedora...\n'
rm -rf ~/rpmbuild rm -rf ~/rpmbuild
rpmdev-setuptree rpmdev-setuptree
cp packages/sshyp-mfa-"$version".tar.xz ~/rpmbuild/SOURCES cp output/sshyp-mfa-"$version".tar.xz ~/rpmbuild/SOURCES
echo "Name: sshyp-mfa echo "Name: sshyp-mfa
Version: "$version" Version: "$version"
Release: "$revision" Release: "$revision"
Summary: An MFA (TOTP/Steam) key generator for the sshyp password manager Summary: An MFA (TOTP/Steam) key generator for the sshyp password manager
BuildArch: noarch BuildArch: noarch
License: GPL-3.0-only
License: GPLv3
URL: https://github.com/rwinkhart/sshyp-labs URL: https://github.com/rwinkhart/sshyp-labs
Source0: sshyp-mfa-"$version".tar.xz Source0: sshyp-mfa-"$version".tar.xz
Requires: sshyp
Requires: sshyp python
%description %description
sshyp-mfa is an extension for the sshyp password manager that reads MFA data from sshyp entries and generates generic TOTP and Steam keys. sshyp-mfa is an extension for the sshyp password manager that reads MFA data from sshyp entries and generates generic TOTP and Steam keys.
%install %install
tar xf %{_sourcedir}/sshyp-mfa-"$version".tar.xz -C %{_sourcedir} tar xf %{_sourcedir}/sshyp-mfa-"$version".tar.xz -C %{_sourcedir}
cp -r %{_sourcedir}/usr %{buildroot} cp -r %{_sourcedir}/usr %{buildroot}
%files %files
/usr/bin/sshyp-mfa /usr/bin/sshyp-mfa
/usr/bin/sshyp-mfa.py /usr/lib/sshyp/sshyp-mfa.py
/usr/lib/sshyp/extensions/sshyp-mfa
%license /usr/share/licenses/sshyp-mfa/license %license /usr/share/licenses/sshyp-mfa/license
%doc /usr/share/man/man1/sshyp-mfa.1.gz %doc /usr/share/man/man1/sshyp-mfa.1.gz
" > ~/rpmbuild/SPECS/sshyp-mfa.spec " > ~/rpmbuild/SPECS/sshyp-mfa.spec
rpmbuild -bb ~/rpmbuild/SPECS/sshyp-mfa.spec rpmbuild -bb ~/rpmbuild/SPECS/sshyp-mfa.spec
mv ~/rpmbuild/RPMS/noarch/* packages/ mv ~/rpmbuild/RPMS/noarch/* output/
rm -rf ~/rpmbuild rm -rf ~/rpmbuild
echo -e "\nFedora packaging complete.\n" echo -e "\nFedora packaging complete\n"
fi } &&
if [ "$distro" == "4" ] || [ "$distro" == "8" ]; then _create_freebsd_pkg() {
echo -e '\nPackaging for FreeBSD...\n' echo -e '\npackaging for FreeBSD...\n'
mkdir -p packages/FreeBSDtemp/bin mkdir -p output/freebsdtemp/usr/{lib/sshyp,bin,share/man/man1}
tar xf packages/sshyp-mfa-"$version".tar.xz -C packages/FreeBSDtemp
echo "name: sshyp-mfa echo "name: sshyp-mfa
version: \""$version"\" version: \""$version"\"
abi = \"FreeBSD:13:*\"; abi = \"FreeBSD:13:*\";
@@ -190,42 +212,54 @@ prefix: /
\"sshyp\" : { \"sshyp\" : {
\"origin\" : \"security/sshyp\" \"origin\" : \"security/sshyp\"
}, },
\"python\" : {
\"origin\" : \"lang/python\"
},
}, },
" > packages/FreeBSDtemp/+MANIFEST " > output/freebsdtemp/+MANIFEST
echo "/usr/bin/sshyp-mfa echo "/usr/bin/sshyp-mfa
/usr/bin/sshyp-mfa.py /usr/lib/sshyp/sshyp-mfa.py
/usr/lib/sshyp/extensions/sshyp-mfa
/usr/share/licenses/sshyp-mfa/license /usr/share/licenses/sshyp-mfa/license
/usr/share/man/man1/sshyp-mfa.1.gz /usr/share/man/man1/sshyp-mfa.1.gz
" > packages/FreeBSDtemp/plist " > output/freebsdtemp/plist
pkg create -m packages/FreeBSDtemp/ -r packages/FreeBSDtemp/ -p packages/FreeBSDtemp/plist -o packages/ cp -r lib/. output/freebsdtemp/usr/lib/sshyp/
rm -rf packages/FreeBSDtemp ln -s /usr/lib/sshyp/sshyp-mfa.py output/freebsdtemp/usr/bin/sshyp-mfa
echo -e "\nFreeBSD packaging complete.\n" cp -r share output/freebsdtemp/usr/
fi cp extra/manpage output/freebsdtemp/usr/share/man/man1/sshyp-mfa.1
gzip output/freebsdtemp/usr/share/man/man1/sshyp-mfa.1
pkg create -m output/freebsdtemp/ -r output/freebsdtemp/ -p output/freebsdtemp/plist -o output/
rm -rf output/freebsdtemp
echo -e "\nFreeBSD packaging complete\n"
} &&
if [ "$distro" == "7" ] || [ "$distro" == "8" ]; then if [ "$1" == "generic" ]; then # build scripts
echo -e '\nGenerating PKGBUILD...' _create_generic
echo "# Maintainer: Randall Winkhart <idgr at tutanota dot com> elif [ "$1" == "pkgbuild" ]; then
_create_generic
pkgname=sshyp-mfa _create_pkgbuild
pkgver="$version" elif [ "$1" == "apkbuild" ]; then
pkgrel="$revision" _create_generic
pkgdesc='An MFA (TOTP/Steam) key generator for the sshyp password manager' _create_apkbuild
url='https://github.com/rwinkhart/sshyp-labs' elif [ "$1" == "haiku" ]; then # distribution packages
arch=('any') _create_hpkg
license=('GPL3') elif [ "$1" == "debian" ]; then
depends=(sshyp python) _create_deb
elif [ "$1" == "termux" ]; then
source=(\""$source"\") _create_termux
sha512sums=('"$sha512"') elif [ "$1" == "fedora" ]; then
_create_generic
package() { _create_rpm
elif [ "$1" == "freebsd" ]; then
tar xf sshyp-mfa-"\"\$pkgver\"".tar.xz -C "\"\${pkgdir}\"" _create_freebsd_pkg
elif [ "$1" == "buildable-arch" ]; then
} _create_generic
" > packages/PKGBUILD _create_pkgbuild
echo -e "\nPKGBUILD generated.\n" _create_apkbuild
if [[ $(pacman -Q dpkg) == "dpkg"* ]]; then
_create_deb
_create_termux
fi
if [[ "$(pacman -Q freebsd-pkg)" == "freebsd-pkg"* ]]; then
_create_freebsd_pkg
fi
else
echo -e '\nusage: package.sh [target] <revision>\n\ntargets:\n mainline: pkgbuild apkbuild haiku fedora debian\n experimental: freebsd termux\n other: buildable-arch\n'
fi fi
Executable → Regular
View File
+4 -5
View File
@@ -1,10 +1,9 @@
sshyp-mfa is a FOSS extension for the sshyp password manager. sshyp-mfa is a FOSS extension for the sshyp password manager.
Copyright (C) 2022 Randall Winkhart idgr@tutanota.com Copyright (C) 2022-2023 Randall Winkhart idgr@tutanota.com
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of version 3 (only) of the GNU General Public License
the Free Software Foundation, either version 3 of the License, or as published by the Free Software Foundation.
(at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -12,4 +11,4 @@
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
+1
View File
@@ -0,0 +1 @@
1.4.0.1