I'm new to programming. I wrote this following code in Python. It's a simple script that locks and unlocks a folder (basic functionality of a folder-lock) with a password.
I hope someone could suggest me to improve the code and make it shorter. Currently, it can lock single folder; however, I wanna make it multi-threading so that it can work on more than one directory. Any suggestion or advice in this regard will be highly appreciated.
r""" FolderLockV1.py: A simple python script to lock a folder with a password """
import os
import sys
import stat
import shutil
import ctypes
import hashlib
__author__ = 'AJ'
__version__ = '1.0.0'
TEMP_LOCATION = os.path.join(os.path.expanduser('~'), 'Desktop', 'TEMP_FOLDER') # dir path where target will be hidden
PASS_FILE = os.path.join(os.path.expanduser('~'), 'Desktop/TEMP_FOLDER', 'password.txt') # password file
FILE_PATH_CURRENT_FOLDER_TEXT_FILE = os.path.join(os.path.expanduser('~'), 'Desktop/TEMP_FOLDER', 'current_folder.txt')
def hash_data(data):
""" A function that returns hashed data, here sha512 hashing has been implemented """
encrypt_data = data.encode('utf-8')
hashed = hashlib.sha512(encrypt_data).hexdigest()
return hashed
def current_fold_path_fetcher():
""" Returns folder_path input from the user """
while True:
x = input('Path to the folder you wish to lock\n>>> ')
if os.path.exists(x):
return x
print('Not a valid folder path')
def store_retrieve_info(file_path, **kwargs):
""" A modified function for writing and reading texts to/from text files """
if len(kwargs) < 1:
print('Need to provide kwarg(s)')
if 'text' in kwargs:
with open(file_path, 'w') as f:
f.write(kwargs['text'])
if 'read' in kwargs:
if kwargs['read'] is True:
with open(file_path, 'r') as f:
x = f.read()
return x
def folder_lock():
""" One of the core functions, it basically locks(rather moves) the folder to a secret path """
fold_path = current_fold_path_fetcher()
global FILE_PATH_CURRENT_FOLDER_TEXT_FILE
store_retrieve_info(FILE_PATH_CURRENT_FOLDER_TEXT_FILE, text=fold_path) # writes current dir path to txt file
pass_word = input('password\n>>> ')
pass_word_hashed = hash_data(pass_word) # inputted password is being hashed
global PASS_FILE
store_retrieve_info(PASS_FILE, text=pass_word_hashed) # writes hashed password in a text file
global TEMP_LOCATION
shutil.move(fold_path, TEMP_LOCATION) # moves current dir to the temp dir to make it visualize as locked
print('Folder Locked')
def folder_unlock():
""" The other core function that unlocks the target dir """
global PASS_FILE
global TEMP_LOCATION
global FILE_PATH_CURRENT_FOLDER_TEXT_FILE
current_folder_path_from_file = str(store_retrieve_info(FILE_PATH_CURRENT_FOLDER_TEXT_FILE, read=True)) # reads
# current folder path from stored txt file
current_folder_in_temp = TEMP_LOCATION + '\\' + current_folder_path_from_file.rsplit('\\', 1)[-1] # recreates the
# old dir path where the hidden dir was initially located
in_pass = input('Password\n>>> ')
in_pass_hashed = hash_data(in_pass) # inputted password by the user is being hashed for verification
read_password = str(store_retrieve_info(PASS_FILE, read=True)) # loads the saved password in the memory
if in_pass_hashed == read_password: # matches inputted password with stored one
shutil.move(current_folder_in_temp, current_folder_path_from_file) # moves target dir to it's original path
print('fokder unlocked')
remove_file() # removes the temp folder and it's contents
else:
print('incorrect pass')
def initial_checkups():
""" An initial checkup function that makes sure that a temp dir exists """
global TEMP_LOCATION
if os.path.exists(TEMP_LOCATION):
pass
else:
os.makedirs(TEMP_LOCATION)
ctypes.windll.kernel32.SetFileAttributesW(TEMP_LOCATION, 0x02) # changes file-mode to hidden, 0x01 value to
# make it visible
def remove_file():
""" A supporting function that removes temp dir and it's contents """
# There are three options to make it happen, only option 2 has been chosen
# global PASS_FILE
# global FILE_PATH_CURRENT_FOLDER_TEXT_FILE
global TEMP_LOCATION
# option 1: remove each file then changing file-mode of the folder, then remove dir
# os.remove(PASS_FILE)
# os.remove(FILE_PATH_CURRENT_FOLDER_TEXT_FILE)
# os.chmod(TEMP_LOCATION, stat.S_IWRITE)
# os.rmdir(TEMP_LOCATION)
# option 2: change file-mode and then remove dir
os.chmod(TEMP_LOCATION, stat.S_IWRITE) # changes file attribute to writable i.e., make it not readonly dir
shutil.rmtree(TEMP_LOCATION) # removes temp dir
# option 3: remove dir and it's contents without changing any file-mode, more direct approach
# os.system('rmdir /S /Q "{}"'.format(TEMP_LOCATION))
def get_choice():
""" A function that return user choices """
while True:
choice_input = input('Press "L" to lock folder\nPress "U" to unlock folder\n'
'Press "Q" to quit application').lower()
if choice_input in {'l', 'u', 'q'}:
return choice_input
print('Wrong option selected')
def main():
print('Welcome to FolderLocker V0.1 by AJ\n')
initial_checkups() # creates temp dir
choice_made = get_choice()
if choice_made == 'l':
folder_lock()
if choice_made == 'u':
try:
folder_unlock()
except FileNotFoundError:
print('You NEED TO LOCK a folder before you try unlocking it!!!')
os.system('pause') # allows user to read console message
else:
sys.exit(0)
if __name__ == '__main__':
main()
-
\$\begingroup\$ I have upgraded your beautiful program locker with the possibility to add more than one folder and I will add more option, if possible i would you like to collaborate with you for this project, what do you think about it? Please contact me. \$\endgroup\$Mike Testo– Mike Testo2019年04月26日 18:07:58 +00:00Commented Apr 26, 2019 at 18:07
1 Answer 1
Currently, it can lock single folder; however, I wanna make it multi-threading so that it can work on more than one directory.
The most straight forward approach would be removing your dependence on global
. The (over)use of global
is frowned upon either way. Not just in Python either, proper scoping makes your code more robust. It decreases the risk of side effects, especially when the size of the code starts growing.
You'll also need to move TEMP_LOCATION
, PASS_FILE
and FILE_PATH_CURRENT_FOLDER_TEXT_FILE
into something that keeps track of the single folder they're associated with. After all, they will likely vary between targets. Could make a class and instantiate it once per folder. The start and end of your program would then look somewhat like this:
class FolderLocker:
def __init__(self):
self.temp_location = os.path.join(os.path.expanduser('~'), 'Desktop', 'TEMP_FOLDER')
self.pass_file = os.path.join(self.temp_location, 'password.txt')
self.current_folder_file = os.path.join(self.temp_location, 'current_folder.txt')
...
def run(self):
"""Runs the main menu of the folder locker application"""
print('Welcome to FolderLocker V0.1\n')
self.initial_checkups()
choice = self.get_choice()
if choice == 'l':
self.lock_folder()
elif choice == 'u':
self.unlock_folder()
else:
sys.exit(0)
if __name__ == '__main__':
folder_locker = FolderLocker()
folder_locker.run()
Next step would be using arguments to set your various folders to lock etc., but reorganization of the code is required before you make that step.