'
' This is a remake of my Password Manager program. I am actually using this
' program to store all my passwords.
'
' Blowfish-cbc encyption with:
' openssl enc -e -a -salt -bf -in data.txt -out data.pwd -pass pass:test
'
' Simple frontend for SSL to keep passwords in a safe place.
'
' (c) Peter van Eerten, February 2010 - GPL. Use with HUG 0.16 or higher.
'
' Version 1.0: Initial release
' Version 1.1: Capture wrong file reading, show total entries
' Version 1.2: Adapted for Cancel-button in FILEDIALOG
' Version 1.3: Compliancy with BaCon 1.0 build 11
'-------------------------------------------------------------------
OPTION BASE 1
SETENVIRON "LANG", "C"
INCLUDE "hug.bac"
' For now, we can store a 100 passwords.
CONST Max_Entries = 100
GLOBAL instance$[Max_Entries]
GLOBAL Tot_Entries, Current_Action
'-------------------------------------------------------------------
SUB Toggle_Visible
LOCAL status
status = GET(chk)
IF status IS 1 THEN SET(pw, TRUE)
ELSE SET(pw, 0)
END SUB
'-------------------------------------------------------------------
SUB Show_File_Dlg
SHOW(file_dlg)
END SUB
'-------------------------------------------------------------------
SUB Show_Save_Dlg
IF Tot_Entries > 0 THEN SHOW(save_dlg)
END SUB
'-------------------------------------------------------------------
' Can close multiple DIALOG widgets
SUB Close_Dialog(NUMBER widget)
HIDE(widget)
FOCUS(pw)
END SUB
'-------------------------------------------------------------------
SUB Hide_File_Dlg(NUMBER dialog, int button)
LOCAL result$
LOCAL size, x, i
HIDE(dialog)
IF button ISNOT GTK_RESPONSE_CANCEL THEN
' Decrypt using unlock key and put into list
result$ = EXEC$(CONCAT$("openssl enc -d -a -salt -bf -in ", GRAB$(dialog), " -pass pass:", GRAB$(pw), " 2>&1"))
IF INSTR(result$, "bad decrypt") THEN
SHOW(errdlg1)
ELIF INSTR(result$, "error") THEN
SHOW(errdlg3)
ELIF FILETYPE(GRAB$(dialog)) IS 1 THEN
' Cleanup array
FOR i = 1 TO Max_Entries
instance$[i] = ""
NEXT
SPLIT result$ BY NL$ TO record$ SIZE Tot_Entries
' Last entry closes with NL$, therefore one less to split
DECR Tot_Entries
FOR x = 1 TO Tot_Entries
instance$[x] = record$[x]
NEXT
END IF
SORT instance$
' Put into list
TEXT(lst, "")
FOR x = 1 TO Tot_Entries
SPLIT instance$[Max_Entries - Tot_Entries + x] BY CHR$(9) TO field$ SIZE size
TEXT(lst, field$[1])
NEXT
TEXT(user_lbl_name, "")
TEXT(pass_lbl_name, "")
TEXT(mainwin, CONCAT$("Password Manager - ", STR$(Tot_Entries), " entries."))
END IF
END SUB
'-------------------------------------------------------------------
SUB Save_Data(NUMBER dialog, int button)
LOCAL x
LOCAL data$
HIDE(dialog)
IF button IS GTK_RESPONSE_YES THEN
SORT instance$
FOR x = 1 TO Tot_Entries
data$ = CONCAT$(data$, instance$[Max_Entries - Tot_Entries + x], NL$)
NEXT
' Encrypt using unlock key and store as file
SYSTEM CONCAT$("echo \"", CHOP$(data$), "\" | openssl enc -e -a -salt -bf -out \"", GRAB$(save_dlg), "\" -pass pass:", GRAB$(pw), " 2>&1")
SHOW(cfrmdlg3)
END IF
END SUB
'-------------------------------------------------------------------
SUB Hide_Save_Dlg(NUMBER dialog, int button)
HIDE(dialog)
IF button ISNOT GTK_RESPONSE_CANCEL THEN
IF FILEEXISTS(GRAB$(save_dlg)) > 4 THEN
SHOW(cfrmdlg2)
ELIF LEN(GRAB$(save_dlg)) > 0 THEN
Save_Data(cfrmdlg2, GTK_RESPONSE_YES)
END IF
END IF
END SUB
'-------------------------------------------------------------------
SUB Lookup_Data
LOCAL dim
SPLIT instance$[Max_Entries - Tot_Entries + GET(lst) + 1] BY CHR$(9) TO entry$ SIZE dim
' Check if there is data left
IF dim > 2 THEN
TEXT(user_lbl_name, entry$[2])
TEXT(pass_lbl_name, entry$[3])
END IF
END SUB
'-------------------------------------------------------------------
SUB Delete_Entry(NUMBER widget, int button)
LOCAL x, size
' Hide the confirmation dialog
HIDE(widget)
IF button IS GTK_RESPONSE_YES THEN
instance$[Max_Entries - Tot_Entries + GET(lst) + 1] = ""
DECR Tot_Entries
TEXT(lst, "")
' Only when there are entries fill the list
IF Tot_Entries > 0 THEN
SORT instance$
FOR x = 1 TO Tot_Entries
SPLIT instance$[Max_Entries - Tot_Entries + x] BY CHR$(9) TO field$ SIZE size
TEXT(lst, field$[1])
NEXT
END IF
TEXT(user_lbl_name, "")
TEXT(pass_lbl_name, "")
TEXT(mainwin, CONCAT$("Password Manager - ", STR$(Tot_Entries), " entries."))
END IF
END SUB
'-------------------------------------------------------------------
SUB Delete_Confirm
IF Tot_Entries > 0 AND GET(lst) >= 0 THEN SHOW(cfrmdlg1)
END SUB
'-------------------------------------------------------------------
SUB Process_Entry
LOCAL x
' Hide the dialog
HIDE(subwin)
' Are we editing or adding
IF Current_Action ISNOT 0 THEN
instance$[Max_Entries - Tot_Entries + GET(lst) + 1] = ""
Tot_Entries = Tot_Entries - 1
END IF
IF Tot_Entries < Max_Entries THEN
SORT instance$
instance$[1] = CONCAT$(GRAB$(entry1), CHR$(9), GRAB$(entry2), CHR$(9), GRAB$(entry3))
Tot_Entries = Tot_Entries + 1
TEXT(lst, "")
' Fill the list
SORT instance$
FOR x = 1 TO Tot_Entries
SPLIT instance$[Max_Entries - Tot_Entries + x] BY CHR$(9) TO field$ SIZE size
TEXT(lst, field$[1])
NEXT
TEXT(user_lbl_name, "")
TEXT(pass_lbl_name, "")
TEXT(mainwin, CONCAT$("Password Manager - ", STR$(Tot_Entries), " entries."))
ELSE
SHOW(errdlg2)
END IF
END SUB
'-------------------------------------------------------------------
SUB Add_Entry
' We are adding data
Current_Action = 0
' Cleanup
TEXT(entry1, "")
TEXT(entry2, "")
TEXT(entry3, "")
FOCUS(entry1)
SHOW(subwin)
END SUB
'-------------------------------------------------------------------
SUB Edit_Entry
LOCAL dim
IF GET(lst) >= 0 THEN
SPLIT instance$[Max_Entries - Tot_Entries + GET(lst) + 1] BY CHR$(9) TO entry$ SIZE dim
TEXT(entry1, entry$[1])
TEXT(entry2, entry$[2])
TEXT(entry3, entry$[3])
SHOW(subwin)
Current_Action = 1
END IF
END SUB
'-------------------------------------------------------------------
SUB Close_Subwin
HIDE(subwin)
END SUB
'-------------------------------------------------------------------
' Check for OpenSSL on the system
IF ISFALSE(LEN(EXEC$("which openssl 2>/dev/null"))) THEN
PRINT "No OpenSSL found on this system! Exiting..."
END
ENDIF
' Initialize array
FOR i = 1 TO Max_Entries
instance$[i] = ""
NEXT
' Create main window
mainwin = WINDOW("Password Manager", 400, 300)
' Top frame
frame1 = FRAME(390, 50)
ATTACH(mainwin, frame1, 5, 5)
label = MARK("Unlock key: ", 80, 30)
ATTACH(mainwin, label, 15, 15)
pw = PASSWORD(195, 30)
ATTACH(mainwin, pw, 100, 15)
chk = CHECK("Visible", 70, 30)
ATTACH(mainwin, chk, 315, 15)
' Body frame
frame2 = FRAME(300, 235)
ATTACH(mainwin, frame2, 5, 60)
lst = LIST(280, 150)
ATTACH(mainwin, lst, 15, 70)
user_label = MARK("Username: ", 80, 30)
ATTACH(mainwin, user_label, 15, 230)
user_lbl_name = MARK("|------------------------------------|", 190, 30)
SET(user_lbl_name, 1)
ATTACH(mainwin, user_lbl_name, 95, 230)
pass_label = MARK("Password: ", 80, 30)
ATTACH(mainwin, pass_label, 15, 260)
pass_lbl_name = MARK("|------------------------------------|", 190, 30)
SET(pass_lbl_name, 1)
ATTACH(mainwin, pass_lbl_name, 95, 260)
' Buttons
file_btn = STOCK("gtk-open", 85, 35)
ATTACH(mainwin, file_btn, 310, 60)
add_btn = STOCK("gtk-add", 85, 35)
ATTACH(mainwin, add_btn, 310, 100)
edit_btn = STOCK("gtk-edit", 85, 35)
ATTACH(mainwin, edit_btn, 310, 140)
del_btn = STOCK("gtk-delete", 85, 35)
ATTACH(mainwin, del_btn, 310, 180)
save_btn = STOCK("gtk-save", 85, 35)
ATTACH(mainwin, save_btn, 310, 220)
quit_btn = STOCK("gtk-quit", 85, 35)
ATTACH(mainwin, quit_btn, 310, 260)
' Define subwindow for adding/editing entries
subwin = WINDOW("Entry definition", 300, 175)
frame3 = FRAME(290, 165)
ATTACH(subwin, frame3, 5, 5)
label1 = MARK(" Instance: ", 90, 30)
ATTACH(subwin, label1, 15, 15)
entry1 = ENTRY("", 170, 30)
ATTACH(subwin, entry1, 115, 15)
label2 = MARK(" User name: ", 90, 30)
ATTACH(subwin, label2, 15, 50)
entry2 = ENTRY("", 170, 30)
ATTACH(subwin, entry2, 115, 50)
label3 = MARK(" Password: ", 90, 30)
ATTACH(subwin, label3, 15, 85)
entry3 = ENTRY("", 170, 30)
ATTACH(subwin, entry3, 115, 85)
ok_btn = STOCK("gtk-ok", 80, 35)
ATTACH(subwin, ok_btn, 205, 125)
can_btn = STOCK("gtk-cancel", 80, 35)
ATTACH(subwin, can_btn, 115, 125)
Close_Subwin
' Create filebrowser, save dialog
file_dlg = FILEDIALOG("Select file...", "gtk-open", 200, 80, 0)
save_dlg = FILEDIALOG("Save as file...", "gtk-save", 200, 80, 1)
' Some info messages
errdlg1 = MSGDIALOG("Wrong unlock key entered!", 250, 120, 3, 2)
errdlg2 = MSGDIALOG("No space left to store new entries!", 250, 120, 3, 2)
errdlg3 = MSGDIALOG("Could not read file!", 250, 120, 3, 2)
cfrmdlg1 = MSGDIALOG("Are you sure to delete this entry?", 250, 120, 2, 4)
cfrmdlg2 = MSGDIALOG("File exists! Overwrite?", 250, 120, 2, 4)
cfrmdlg3 = MSGDIALOG("File saved.", 250, 120, 0, 1)
' Define the callbacks
CALLBACK(quit_btn, QUIT)
CALLBACK(chk, Toggle_Visible)
CALLBACK(file_btn, Show_File_Dlg)
CALLBACK(file_dlg, Hide_File_Dlg)
CALLBACK(add_btn, Add_Entry)
CALLBACK(edit_btn, Edit_Entry)
CALLBACK(del_btn, Delete_Confirm)
CALLBACK(lst, Lookup_Data)
CALLBACK(save_btn, Show_Save_Dlg)
CALLBACK(save_dlg, Hide_Save_Dlg)
CALLBACK(can_btn, Close_Subwin)
CALLBACK(ok_btn, Process_Entry)
CALLBACK(errdlg1, Close_Dialog)
CALLBACK(errdlg2, Close_Dialog)
CALLBACK(errdlg3, Close_Dialog)
CALLBACK(cfrmdlg1, Delete_Entry)
CALLBACK(cfrmdlg2, Save_Data)
CALLBACK(cfrmdlg3, Close_Dialog)
FOCUS(pw)
' Endless GTK loop
DISPLAY