Merge sane branch with main branch, release 1.0

Version 1.0 (Sane coding, finalized release)
main
Kamal Curi 4 years ago committed by GitHub
commit ca5d4969c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -17,3 +17,9 @@
- 0.6: - 0.6:
· Added "random string for password" function · Added "random string for password" function
· Fixed a bug with the copy command when the database is empty · Fixed a bug with the copy command when the database is empty
- 1.0:
· Code cleanup
· Added 'help' command
· Minor bug fixes:
· ITEM_CURSOR and GLOBAL_CURSOR now behave properly under all(tested) circumstances
· Added random string to modify password

@ -12,12 +12,12 @@ Just run `install.sh` **WITHOUT SUDO**
If you're upgrading Steelbox, don't worry: `install.sh` will do it automatically without messing with your password file If you're upgrading Steelbox, don't worry: `install.sh` will do it automatically without messing with your password file
#### Dependencies: #### Dependencies:
As of V0.5, you need the [pyperclip](https://pypi.org/project/pyperclip/) module. You can install it with [pip](https://pypi.org/project/pip/): Clipboard support needs the [pyperclip](https://pypi.org/project/pyperclip/) module. You can install it with [pip](https://pypi.org/project/pip/):
`pip3 install pyperclip` `pip3 install pyperclip`
Also, for clipboard support to work, you need [xclip](https://github.com/astrand/xclip) or [xsel](https://github.com/kfish/xsel) on your machine. Also for clipboard support, you need [xclip](https://github.com/astrand/xclip) or [xsel](https://github.com/kfish/xsel) on your machine.
This program has no support for the wayland clipboard. This program has no support for the wayland clipboard... Unless pyperclip starts supporting it :P
The standard ( this program was made with 3.10 ) python installation comes with the `curses` and `csv` modules, just make sure you have [GnuPG](https://gnupg.org/) installed. The standard ( this program was made with v3.10 ) python installation comes with the `curses` and `csv` modules, just make sure you have [GnuPG](https://gnupg.org/) installed.

@ -0,0 +1,29 @@
Made by Kamal 'brejela' Curi, kamalcuri@outlook.com ││
For licensing information, read LICENSE ││
-------------------------------------------------------------------------------- ││
Directional keys:...........Move the cursor ││
PgDown/F1:..................Previous Page ││
PgUp/F2:....................Next Page ││
Enter/E:....................View password ││
R:..........................Opens a window with a random string ││
##### These commands work wether there's an open password or not ##### ││
C/F3:.......................Copy password to clipboard (Requires xclip or xsel) ││
N/F4:.......................New password ││
M/F5:.......................Modify password ││
D/Del:......................Delete password ││
###################################################################### ││
When creating a password, you can leave the PSWD field empty, a random password ││
will be generated in its place. ││
Leaving the PSWD field empty when modifying a password will also give it ││
a random string.
------------------------------------------------------------------------ ││
In case you're not running this software under st or alacritty, ││
cursor navigation can be a bit janky: ││
CTRL+A to go to the far left of the field ││
CTRL+E to go to the far right of the field ││
CTRL+B to move the cursor once to the left ││
CTRL+F to move the cursor once to the right ││
CTRL+H to remove one character (Backspace) ││
CTRL+D to remove highlghted character (Delete) ││
CTRL+O to clear the field
------------------------------------------------------------------------

@ -1,11 +1,11 @@
import csv import csv
import curses import curses
from curses import wrapper
from curses.textpad import Textbox from curses.textpad import Textbox
import sys import sys
import os import os
import pyperclip as pc import pyperclip as pc
import random import random
version = sys.argv[1] version = sys.argv[1]
## Initialization of bottomline dependencies ## Initialization of bottomline dependencies
@ -22,33 +22,57 @@ fields = ["service", "user", "pswd"]
HOMEDIR = os.environ['HOME'] HOMEDIR = os.environ['HOME']
PASFILE=HOMEDIR+"/.pasfile.csv" PASFILE=HOMEDIR+"/.pasfile.csv"
# Initializes Curses' screen
def main(stdscr): def reloadFiles():
# Opens password file files.clear()
with open(PASFILE, mode='r') as pasfile: with open(PASFILE, mode='r') as pasfile:
# Creates reader object # Creates reader object
csvreader=csv.DictReader(pasfile) csvreader=csv.DictReader(pasfile)
for ids in csvreader: for ids in csvreader:
files.append(ids) files.append(ids)
## Initializes color pairs
# Password pallete (Foreground = Background)
curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_BLACK) # Initializes the curses screen
pwd_pallete = curses.color_pair(1) stdscr = curses.initscr()
# Main window pallete curses.noecho()
curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_BLACK) curses.cbreak()
main_pallete = curses.color_pair(2) stdscr.keypad(True)
stdscr.clear()
# Clears screen
stdscr.clear() def steelbox():
reloadFiles()
# Initializes the main window
global mainwin
mainwin = curses.newwin(TERM_LINES -1, TERM_COLS, 0, 0)
mainwin.keypad(True)
mainwin.border()
# Initializes the bottom window
global statuswin
statuswin= curses.newwin(3, TERM_COLS, TERM_LINES, 0)
statuswin.keypad(True)
statuswin.border()
cleanWins()
while True:
reloadFiles()
displayItems()
stdscr.move(TERM_LINES, TERM_COLS)
command()
# Defines global variables
def globals():
## Global variables
# Determines terminal size # Determines terminal size
global TERM_LINES global TERM_LINES
TERM_LINES=curses.LINES - 1 TERM_LINES=curses.LINES - 1
if TERM_LINES <= 20: if TERM_LINES <= 20:
sys.exit("ERROR: Your terminal is too small!") close("ERROR: Your terminal is too small!")
global TERM_COLS global TERM_COLS
TERM_COLS=curses.COLS - 1 TERM_COLS=curses.COLS - 1
if TERM_COLS <=80: if TERM_COLS <=80:
sys.exit("ERROR: Your terminal is too small!") close("ERROR: Your terminal is too small!")
# Global (program-wide) variables for cursor position # Global (program-wide) variables for cursor position
global LINE global LINE
LINE = 0 LINE = 0
@ -89,7 +113,6 @@ def main(stdscr):
# What row the cursor is in # What row the cursor is in
global CUROW global CUROW
CUROW = 0 CUROW = 0
global PSERV global PSERV
PSERV = "" PSERV = ""
global PUSER global PUSER
@ -97,389 +120,317 @@ def main(stdscr):
global PPSWD global PPSWD
PPSWD = "" PPSWD = ""
# Gets user command
def command():
# Initializes the main window # The GLOBAL_CURSOR points to the main files object, so that it gets the right file.
mainwin = curses.newwin(TERM_LINES -1, TERM_COLS, 0, 0) global c
mainwin.keypad(True) global CUROW
mainwin.bkgd(' ', main_pallete) global ITEM_CURSOR
mainwin.border() global GLOBAL_CURSOR
global CURR_PAGE
# Initializes the bottom window c = mainwin.getch()
statusWin = curses.newwin(3, TERM_COLS, TERM_LINES, 0) if c == ord('q'):
statusWin.keypad(True) close()
statusWin.border() elif c == curses.KEY_DOWN:
statusWin.bkgd(' ', main_pallete) if GLOBAL_CURSOR < len(files) - 1:
statusWin.border() ITEM_CURSOR+=1
GLOBAL_CURSOR+=1
elif c == curses.KEY_UP:
while True: if GLOBAL_CURSOR > 0:
# Creates a name list ITEM_CURSOR-=1
displayList = [] GLOBAL_CURSOR-=1
elif c == curses.KEY_RIGHT:
# This makes sure the cursor stays on the screen TODO: delete this if CUROW < NROWS and (ITEM_CURSOR + MAX_LINES) < len(files) - 1:
if ITEM_CURSOR < 0: ITEM_CURSOR = 0 ITEM_CURSOR+=MAX_LINES - 1
if ITEM_CURSOR > MAX_ITEMS or ITEM_CURSOR > len(files)-1: ITEM_CURSOR = 0 GLOBAL_CURSOR+=MAX_LINES - 1
CUROW+=1
# Makes sure the windows are properly clean else:
mainwin.border() ITEM_CURSOR = len(files) - 1
statusWin.border() GLOBAL_CURSOR = len(files) - 1
mainwin.border()
mainwin.addstr(0, 1, "SteelBox V" + str(version))
mainwin.refresh()
statusWin.border()
statusWin.refresh()
# Reset global necessities
LINE = 0
COLUMN = 0
currItem = 0
highOpt = ()
# Defines what to display
startDisplay = (CURR_PAGE-1)*MAX_ITEMS
stopDisplay = CURR_PAGE*MAX_ITEMS
# Appends the names in the CSV to display on the main window
for ps_name in files:
displayList.append(ps_name['service'][:15])
for item in displayList[startDisplay:stopDisplay]:
# If the item is the one with the cursor, highlight it
if currItem == ITEM_CURSOR:
mode = curses.A_REVERSE
highOpt = mainwin.getyx()
else:
mode = curses.A_NORMAL
mainwin.addstr(1 + LINE, 1 + COLUMN, item, mode)
LINE+=1
currItem+=1
if LINE >= WINLIMIT:
LINE = 0
COLUMN+=16
NROWS+=1
mainwin.refresh()
STATUS_MESSAGE = "PrvPage(F1),NxtPage(F2),(d|el),(e)xamine,(n)ew,(c)opy,(m)odify,(r)andom,(q)uit"
statusWin.addstr(0,0, STATUS_MESSAGE)
statusWin.refresh()
## Command logic
# The GLOBAL_CURSOR points to the main files object, so that it gets the right file.
global c
c = mainwin.getch()
if c == ord('q'):
return(0)
elif c == curses.KEY_DOWN:
if GLOBAL_CURSOR < len(files) - 1:
ITEM_CURSOR+=1
GLOBAL_CURSOR+=1
elif c == curses.KEY_UP:
if GLOBAL_CURSOR > 0:
ITEM_CURSOR-=1
GLOBAL_CURSOR-=1
elif c == curses.KEY_RIGHT:
if CUROW < NROWS: if CUROW < NROWS:
ITEM_CURSOR+=MAX_LINES - 1
GLOBAL_CURSOR+=MAX_LINES - 1
CUROW+=1 CUROW+=1
elif c == curses.KEY_LEFT: else:
if CUROW > 0: CUROW = NROWS
ITEM_CURSOR-=MAX_LINES - 1 elif c == curses.KEY_LEFT:
GLOBAL_CURSOR-=MAX_LINES - 1 if CUROW > 0:
CUROW-=1 ITEM_CURSOR-=MAX_LINES - 1
elif c == curses.KEY_F1 or c == curses.KEY_PPAGE: GLOBAL_CURSOR-=MAX_LINES - 1
# The next two IF statements are here to avoid unintended GLOBAL_CURSOR changes CUROW-=1
if CURR_PAGE > 1: elif c == curses.KEY_F1 or c == curses.KEY_PPAGE:
CURR_PAGE-=1 # The next two IF statements are here to avoid unintended GLOBAL_CURSOR changes
GLOBAL_CURSOR-=MAX_ITEMS if CURR_PAGE > 1:
elif c == curses.KEY_F2 or c == curses.KEY_NPAGE: CURR_PAGE-=1
if CURR_PAGE < MAX_PAGES: GLOBAL_CURSOR-=MAX_ITEMS
CURR_PAGE+=1 elif c == curses.KEY_F2 or c == curses.KEY_NPAGE:
GLOBAL_CURSOR+=MAX_ITEMS if CURR_PAGE < MAX_PAGES:
CURR_PAGE+=1
elif c == ord('c') or c == curses.KEY_F3: GLOBAL_CURSOR+=MAX_ITEMS
if len(files) > 0: elif c == 10 or c == curses.KEY_ENTER or c == ord('e'):
pc.copy(files[GLOBAL_CURSOR]['pswd']) examine()
statusWin.border() elif c == ord('c') or c == curses.KEY_F3:
STATUS_MESSAGE = "Copied password for " + files[GLOBAL_CURSOR]['service'] copy()
statusWin.addstr(0,0, STATUS_MESSAGE) elif c == ord('n') or c == curses.KEY_F4:
statusWin.refresh() newFile()
mainwin.getch() elif c == ord('m') or c == curses.KEY_F5:
modFile()
elif c == ord('r'): elif c == ord('d') or c == curses.KEY_DC:
ranWin = curses.newwin(3, 49, int(TERM_LINES/2), int(TERM_COLS/2)) delFile()
ranWin.border() elif c == ord('r'):
ranWin.addstr(0, 1, "Random string") rwin()
ranWin.addstr(1, 1, randString()) elif c == ord('h'):
ranWin.refresh() sbhelp()
ranWin.getch()
elif c == ord('d') or c == curses.KEY_DC: def newFile():
dlWin = curses.newwin(3, 22, int(TERM_LINES/2), int(TERM_COLS/2)) # Initializes the 'new password' window
dlWin.border() npWin = curses.newwin(5, 60,int(TERM_LINES/2)-2, int(TERM_COLS/2)-18)
dlWin.refresh() nwCord = npWin.getbegyx()
statusWin.border() # Initializes the windows in which the textboxes will reside for input
STATUS_MESSAGE = "Delete " + displayList[GLOBAL_CURSOR] + "?" svWin = curses.newwin(1, 45, nwCord[0]+1, nwCord[1]+6)
statusWin.addstr(0,0, STATUS_MESSAGE) svBox = Textbox(svWin)
statusWin.refresh() usWin = curses.newwin(1, 45, nwCord[0]+2, nwCord[1]+6)
dlWin.addstr(1, 1, "Are you sure? (y/N)") usBox = Textbox(usWin)
c = dlWin.getch() psWin = curses.newwin(1, 45, nwCord[0]+3, nwCord[1]+6)
if c == ord('y'): psBox = Textbox(psWin)
files.pop(GLOBAL_CURSOR)
with open(PASFILE, mode='w') as pasfile: # Clears the 'new password' window
csvwriter = csv.DictWriter(pasfile, fields) npWin.border()
csvwriter.writeheader() npWin.border()
csvwriter.writerows(files) npWin.addstr(0, 1, "New password")
files.clear() npWin.addstr(1, 1, "SRVC:")
with open(PASFILE, mode='r') as pasfile: npWin.addstr(2, 1, "USER:")
# Creates reader object npWin.addstr(3, 1, "PSWD:")
csvreader=csv.DictReader(pasfile) STATUS_MESSAGE = "CTRL+G to enter, MAX 45 CHARS"
for ids in csvreader: displayStatus(STATUS_MESSAGE)
files.append(ids) npWin.refresh()
# For some reason, KEY_UP is 10, instead of the 343 the debbuger flags... Welp ¯\_(ツ)_/¯ # Takes data
elif c == 10 or c == curses.KEY_ENTER or c == ord('e'): svBox.edit()
# highOpt = Coordinates of the first option's character passService = svBox.gather()
LINE = highOpt[0] usBox.edit()
COLUMN = highOpt[1] passUser = usBox.gather()
# These if statements make it so files being shown will always do so inside the terminal screen psBox.edit()
if COLUMN+32 > TERM_COLS: passPswd = psBox.gather()
COLUMN-=int(TERM_COLS/MAX_ROWS) if passService != '' and passUser != '':
if LINE+10 > TERM_LINES: if passPswd == '':
LINE-=10 passPswd = randString()
# Initializes the file viewer window # wtf = write to file
fileWin = curses.newwin(5, 60, LINE+5, COLUMN) wtf = {'service' : passService, 'user' : passUser, 'pswd' : passPswd}
# Clears the window files.append(wtf)
fileWin.border() with open(PASFILE, mode='w') as pasfile:
fileWin.border() csvwriter = csv.DictWriter(pasfile, fields)
csvwriter.writeheader()
passService = files[GLOBAL_CURSOR]['service'][:45] csvwriter.writerows(files)
passUser = files[GLOBAL_CURSOR]['user'][:45] reloadFiles()
passPswd = files[GLOBAL_CURSOR]['pswd'][:45]
fileWin.addstr(0, 1, "View Password")
fileWin.addstr(1, 1, "SRVC: " + passService) def examine():
fileWin.addstr(2, 1, "NAME: " + passUser) # highOpt = Coordinates of the first option's character
fileWin.addstr(3, 1, "PSWD: " + passPswd) LINE = highOpt[0]
statusWin.border() COLUMN = highOpt[1]
STATUS_MESSAGE = "cmds:(d|DEL)ete,(m)odify, (c)opy " # These if statements make it so files being shown will always do so inside the terminal screen
statusWin.addstr(0,0, STATUS_MESSAGE) if COLUMN+32 > TERM_COLS:
statusWin.refresh() COLUMN-=int(TERM_COLS/MAX_ROWS)
fileWin.refresh() if LINE+10 > TERM_LINES:
# Gets command to act on the highlighted file LINE-=10
c = fileWin.getch() # Initializes the file viewer window
if c == ord('d') or c == curses.KEY_DC: fileWin = curses.newwin(5, 60, LINE+5, COLUMN)
dlWin = curses.newwin(3, 22, int(TERM_LINES/2), int(TERM_COLS/2)) # Clears the window
dlWin.border() fileWin.border()
dlWin.refresh() fileWin.border
statusWin.border() passService = files[GLOBAL_CURSOR]['service'][:45]
STATUS_MESSAGE = "Delete " + displayList[GLOBAL_CURSOR] + "?" passUser = files[GLOBAL_CURSOR]['user'][:45]
statusWin.addstr(0,0, STATUS_MESSAGE) passPswd = files[GLOBAL_CURSOR]['pswd'][:45]
statusWin.refresh() fileWin.addstr(0, 1, "View Password")
dlWin.addstr(1, 1, "Are you sure? (y/N)") fileWin.addstr(1, 1, "SRVC: " + passService)
c = dlWin.getch() fileWin.addstr(2, 1, "NAME: " + passUser)
if c == ord('y'): fileWin.addstr(3, 1, "PSWD: " + passPswd)
files.pop(GLOBAL_CURSOR) STATUS_MESSAGE = "cmds:(d|DEL)ete,(m)odify, (c)opy "
with open(PASFILE, mode='w') as pasfile: displayStatus(STATUS_MESSAGE)
csvwriter = csv.DictWriter(pasfile, fields) # Gets command to act on the highlighted file
csvwriter.writeheader() c = fileWin.getch()
csvwriter.writerows(files) if c == ord('d') or c == curses.KEY_DC:
files.clear() delFile()
with open(PASFILE, mode='r') as pasfile: elif c == ord('m'):
# Creates reader object modFile()
csvreader=csv.DictReader(pasfile) elif c == ord('c') or c == curses.KEY_F3:
for ids in csvreader: copy()
files.append(ids)
elif c == ord('m'): def modFile():
# Extracts the file to be modified # Extracts the file to be modified
modFile = files[GLOBAL_CURSOR] modFile = files[GLOBAL_CURSOR]
# Removes it from the main file # Removes it from the main file
files.pop(GLOBAL_CURSOR) files.pop(GLOBAL_CURSOR)
# Creates the 'modify password' window # Creates the 'modify password' window
modWin = curses.newwin(5, 60,int(TERM_LINES/2)-2, int(TERM_COLS/2)-18) modWin = curses.newwin(5, 60,int(TERM_LINES/2)-2, int(TERM_COLS/2)-18)
# Gets the coordinates for the top left corner of said window # Gets the coordinates for the top left corner of said window
nwCord = modWin.getbegyx() nwCord = modWin.getbegyx()
# Creates the fields in which the password will be edited # Creates the fields in which the password will be edited
svWin = curses.newwin(1, 45, nwCord[0]+1, nwCord[1]+6) svWin = curses.newwin(1, 45, nwCord[0]+1, nwCord[1]+6)
svWin.addstr(0, 0, modFile['service']) svWin.addstr(0, 0, modFile['service'])
svWin.move(0, 0) svWin.move(0, 0)
svBox = Textbox(svWin) svBox = Textbox(svWin)
usWin = curses.newwin(1, 45, nwCord[0]+2, nwCord[1]+6) usWin = curses.newwin(1, 45, nwCord[0]+2, nwCord[1]+6)
usWin.addstr(0, 0, modFile['user']) usWin.addstr(0, 0, modFile['user'])
usWin.move(0, 0) usWin.move(0, 0)
usBox = Textbox(usWin) usBox = Textbox(usWin)
psWin = curses.newwin(1, 45, nwCord[0]+3, nwCord[1]+6) psWin = curses.newwin(1, 45, nwCord[0]+3, nwCord[1]+6)
psWin.addstr(0, 0, modFile['pswd']) psWin.addstr(0, 0, modFile['pswd'])
psWin.move(0, 0) psWin.move(0, 0)
psBox = Textbox(psWin) psBox = Textbox(psWin)
# Clears the 'modify password' window # Clears the 'modify password' window
modWin.border() modWin.border()
modWin.border() modWin.border
modWin.addstr(0, 1, "Modify password")
modWin.addstr(0, 1, "Modify password") modWin.addstr(1, 1, "SRVC:")
modWin.addstr(1, 1, "SRVC:") modWin.addstr(2, 1, "USER:")
modWin.addstr(2, 1, "USER:") modWin.addstr(3, 1, "PSWD:")
modWin.addstr(3, 1, "PSWD:") modWin.refresh()
modWin.refresh() svWin.refresh()
svWin.refresh() usWin.refresh()
usWin.refresh() psWin.refresh()
psWin.refresh()
# Takes data
# Takes data STATUS_MESSAGE = "Edit SERVICE field - CTRL+G to enter, leave empty to cancel, MAX 45 CHARS"
STATUS_MESSAGE = "Edit SERVICE field - CTRL+G to enter, leave empty to cancel, MAX 45 CHARS" displayStatus(STATUS_MESSAGE)
statusWin.border() svBox.edit()
statusWin.addstr(0,0, STATUS_MESSAGE) passService = svBox.gather()
statusWin.refresh() STATUS_MESSAGE = "Edit USER field - CTRL+G to enter, leave empty to cancel, MAX 45 CHARS"
svBox.edit() displayStatus(STATUS_MESSAGE)
passService = svBox.gather() usBox.edit()
STATUS_MESSAGE = "Edit USER field - CTRL+G to enter, leave empty to cancel, MAX 45 CHARS" passUser = usBox.gather()
statusWin.border() STATUS_MESSAGE = "Edit PASSWORD field - CTRL+G to enter, leave empty for random string"
statusWin.addstr(0,0, STATUS_MESSAGE) displayStatus(STATUS_MESSAGE)
statusWin.refresh() psBox.edit()
usBox.edit() passPswd = psBox.gather()
passUser = usBox.gather() if passPswd == '':
STATUS_MESSAGE = "Edit PASSWORD field - CTRL+G to enter, leave empty for random string" passPswd = randString()
statusWin.border() modFile = {'service' : passService, 'user' : passUser, 'pswd' : passPswd}
statusWin.addstr(0,0, STATUS_MESSAGE) files.insert(GLOBAL_CURSOR, modFile)
statusWin.refresh() with open(PASFILE, mode='w') as pasfile:
psBox.edit() # Creates writer object and writes to the csv file
passPswd = psBox.gather() csvwriter = csv.DictWriter(pasfile, fields)
modFile = {'service' : passService, 'user' : passUser, 'pswd' : passPswd} csvwriter.writeheader()
files.insert(GLOBAL_CURSOR, modFile) csvwriter.writerows(files)
with open(PASFILE, mode='w') as pasfile: reloadFiles()
# Creates writer object and writes to the csv file
csvwriter = csv.DictWriter(pasfile, fields)
csvwriter.writeheader() def delFile():
csvwriter.writerows(files) dlWin = curses.newwin(3, 22, int(TERM_LINES/2), int(TERM_COLS/2))
files.clear() dlWin.border()
with open(PASFILE, mode='r') as pasfile: dlWin.refresh()
# Creates reader object STATUS_MESSAGE = "Delete " + displayList[GLOBAL_CURSOR] + "?"
csvreader=csv.DictReader(pasfile) displayStatus(STATUS_MESSAGE)
for ids in csvreader: dlWin.addstr(1, 1, "Are you sure? (y/N)")
files.append(ids) c = dlWin.getch()
if c == ord('y'):
elif c == ord('c') or c == curses.KEY_F3: files.pop(GLOBAL_CURSOR)
pc.copy(files[GLOBAL_CURSOR]['pswd']) with open(PASFILE, mode='w') as pasfile:
statusWin.border() csvwriter = csv.DictWriter(pasfile, fields)
STATUS_MESSAGE = "Copied password for " + files[GLOBAL_CURSOR]['service'] csvwriter.writeheader()
statusWin.addstr(0,0, STATUS_MESSAGE) csvwriter.writerows(files)
statusWin.refresh() reloadFiles()
mainwin.getch()
elif c == ord('n'): # Opens a new window with a random string of length 45
# Initializes the 'new password' window def rwin():
npWin = curses.newwin(5, 60,int(TERM_LINES/2)-2, int(TERM_COLS/2)-18) ranWin = curses.newwin(3, 49, int(TERM_LINES/2), int(TERM_COLS/2))
nwCord = npWin.getbegyx() ranWin.border()
# Initializes the windows in which the textboxes will reside for input ranWin.addstr(0, 1, "Random string")
svWin = curses.newwin(1, 45, nwCord[0]+1, nwCord[1]+6) ranWin.addstr(1, 1, randString())
svBox = Textbox(svWin) ranWin.refresh()
usWin = curses.newwin(1, 45, nwCord[0]+2, nwCord[1]+6) ranWin.getch()
usBox = Textbox(usWin)
psWin = curses.newwin(1, 45, nwCord[0]+3, nwCord[1]+6)
psBox = Textbox(psWin) # Copies password to clipboard
def copy():
# Clears the 'new password' window if len(files) > 0:
npWin.border() pc.copy(files[GLOBAL_CURSOR]['pswd'])
npWin.border() STATUS_MESSAGE = "Copied password for " + files[GLOBAL_CURSOR]['service']
displayStatus(STATUS_MESSAGE)
npWin.addstr(0, 1, "New password") mainwin.getch()
npWin.addstr(1, 1, "SRVC:")
npWin.addstr(2, 1, "USER:")
npWin.addstr(3, 1, "PSWD:")
STATUS_MESSAGE = "CTRL+G to enter, MAX 45 CHARS" # Cleans the windows
statusWin.addstr(0,0, STATUS_MESSAGE) def cleanWins():
statusWin.refresh() mainwin.clear()
npWin.refresh() statuswin.clear()
mainwin.border()
# Takes data statuswin.border()
svBox.edit() mainwin.addstr(0, 1, "SteelBox V" + str(version))
passService = svBox.gather() mainwin.refresh()
usBox.edit() statuswin.refresh()
passUser = usBox.gather()
psBox.edit()
passPswd = psBox.gather()
if passService != '' and passUser != '':
if passPswd == '':
passPswd = randString()
# wtf = write to file
wtf = {'service' : passService, 'user' : passUser, 'pswd' : passPswd}
files.append(wtf)
with open(PASFILE, mode='w') as pasfile:
csvwriter = csv.DictWriter(pasfile, fields)
csvwriter.writeheader()
csvwriter.writerows(files)
elif c == ord('m'):
# Extracts the file to be modified
modFile = files[GLOBAL_CURSOR]
# Removes it from the main file
files.pop(GLOBAL_CURSOR)
# Creates the 'modify password' window
modWin = curses.newwin(5, 60,int(TERM_LINES/2)-2, int(TERM_COLS/2)-18)
# Gets the coordinates for the top left corner of said window
nwCord = modWin.getbegyx()
# Creates the fields in which the password will be edited
svWin = curses.newwin(1, 45, nwCord[0]+1, nwCord[1]+6)
svWin.addstr(0, 0, modFile['service'])
svWin.move(0, 0)
svBox = Textbox(svWin)
usWin = curses.newwin(1, 45, nwCord[0]+2, nwCord[1]+6)
usWin.addstr(0, 0, modFile['user'])
usWin.move(0, 0)
usBox = Textbox(usWin)
psWin = curses.newwin(1, 45, nwCord[0]+3, nwCord[1]+6)
psWin.addstr(0, 0, modFile['pswd'])
psWin.move(0, 0)
psBox = Textbox(psWin)
# Clears the 'modify password' window
modWin.border()
modWin.border()
modWin.addstr(0, 1, "Modify password")
modWin.addstr(1, 1, "SRVC:")
modWin.addstr(2, 1, "USER:")
modWin.addstr(3, 1, "PSWD:")
STATUS_MESSAGE = "CTRL+G to enter, MAX 45 CHARS"
statusWin.addstr(0,0, STATUS_MESSAGE)
statusWin.refresh()
modWin.refresh()
svWin.refresh()
usWin.refresh()
psWin.refresh()
# Takes data
STATUS_MESSAGE = "Edit SERVICE field"
statusWin.addstr(0,0, STATUS_MESSAGE)
statusWin.refresh()
svBox.edit()
passService = svBox.gather()
STATUS_MESSAGE = "Edit USER field"
statusWin.addstr(0,0, STATUS_MESSAGE)
statusWin.refresh()
usBox.edit()
passUser = usBox.gather()
STATUS_MESSAGE = "Edit PASSWORD field"
statusWin.addstr(0,0, STATUS_MESSAGE)
statusWin.refresh()
psBox.edit()
passPswd = psBox.gather()
modFile = {'service' : passService, 'user' : passUser, 'pswd' : passPswd}
files.insert(GLOBAL_CURSOR, modFile)
with open(PASFILE, mode='w') as pasfile:
# Creates writer object and writes to the csv file
csvwriter = csv.DictWriter(pasfile, fields)
csvwriter.writeheader()
csvwriter.writerows(files)
files.clear()
with open(PASFILE, mode='r') as pasfile:
# Creates reader object
csvreader=csv.DictReader(pasfile)
for ids in csvreader:
files.append(ids)
# Displays the items on the screen properly
def displayItems():
cleanWins()
global NROWS
global ITEM_CURSOR
# Creates a name list
global displayList
displayList = []
# Appends the names in the CSV to display on the main window
for ps_name in files:
displayList.append(ps_name['service'][:15])
# Reset global necessities
LINE = 0
COLUMN = 0
currItem = 0
NROWS = 0
global highOpt
highOpt = ()
# Defines what to display
startDisplay = (CURR_PAGE-1)*MAX_ITEMS
stopDisplay = CURR_PAGE*MAX_ITEMS
for item in displayList[startDisplay:stopDisplay]:
# If the item is the one with the cursor, highlight it
if currItem == ITEM_CURSOR:
mode = curses.A_REVERSE
highOpt = mainwin.getyx()
else:
mode = curses.A_NORMAL
mainwin.addstr(1 + LINE, 1 + COLUMN, item, mode)
LINE+=1
currItem+=1
if LINE >= WINLIMIT:
LINE = 0
COLUMN+=16
NROWS+=1
STATUS_MESSAGE = "PrvPage(F1),NxtPage(F2),(d|el),(e)xamine,(n)ew,(c)opy,(m)odify,(r)andom,(q)uit"
displayStatus(STATUS_MESSAGE)
mainwin.refresh()
# Displays on the status window
def displayStatus(msg):
statuswin.border()
statuswin.addstr(0,0, msg)
statuswin.refresh()
def sbhelp():
helpwin = curses.newwin(TERM_LINES - 1, TERM_COLS - 1, 0, 0)
helpwin.border()
helpwin.addstr(1, 1, "Steelbox V." + version)
line = 2
with open("sbhelp", mode='r') as sbhfile:
sbh = sbhfile.readlines()
for lines in sbh:
helpwin.addstr(line, 1, lines)
line+=1
line+=1
helpwin.addstr(line, 1, "PRESS ANY KEY TO CONTINUE", curses.A_REVERSE)
helpwin.getch()
# Returns a random string of length 45
def randString(): def randString():
result = '' result = ''
for _ in range(45): for _ in range(45):
@ -489,4 +440,16 @@ def randString():
result += chr(ascNum) result += chr(ascNum)
return(result) return(result)
wrapper(main)
# Finishes the application
def close(error = ''):
curses.nocbreak()
stdscr.keypad(False)
curses.echo()
curses.endwin()
sys.exit(error)
globals()
steelbox()
close()

@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
version="0.6" version="1.0"
echo Steelbox V$version echo Steelbox V$version

Loading…
Cancel
Save