diff --git a/web/SimpleWebPage.py b/web/SimpleWebPage.py index 0610e56..1eb4733 100755 --- a/web/SimpleWebPage.py +++ b/web/SimpleWebPage.py @@ -1,13 +1,18 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # coding=utf-8 ''' A script that creates an index for a folder. ''' -import os,sys,time -import urllib +import os +import sys +import time +import string +import urllib.parse from glob import fnmatch +import base64 +import random -VERSION = "20200427" +VERSION = "20200619" IMAGE_EXTENSIONS = ['png', 'gif', 'jpg', 'jpeg', 'tif', 'tiff'] def setup(): @@ -26,6 +31,8 @@ def setup(): help="Output filename (Default: index.html)") parser.add_argument("-p",action="store_false",dest="parent",default=True, help="Do no print .. link for parent folder.") + parser.add_argument("--password",type=str,dest="password",default=None, + help="Set a password to view page. The file list will be written to a randomly generated filename. Note: this is not secure, as the target link will still be unprotected if known.") parser.add_argument("-r",action="store_true",dest="recursive",default=False, help="Include all files recursively in the list. Do not include any folders.") parser.add_argument("--images",action="store_true",dest="images",default=False, @@ -57,7 +64,7 @@ def setup2HTML(opts): return ''%";".join([ 'hidden=%s'%opts.hidden, 'parent=%s'%opts.parent, - 'title=%s'%urllib.quote(opts.title), + 'title=%s'%urllib.parse.quote(opts.title), 'images=%s'%opts.images ]) @@ -73,7 +80,7 @@ def HTML2setup(opts): (k,v) = s.split('=',1) if k == 'hidden': opts.hidden = v == "True" if k == 'parent': opts.parent = v == "True" - if k == 'title': opts.title = urllib.unquote(v) + if k == 'title': opts.title = urllib.parse.unquote(v) if k == 'images': opts.images = v == "True" read_config = True print("Reading options from existing " + opts.filename) @@ -109,7 +116,11 @@ def get_files_and_folders(opts): def generate_index(opts): + opts.password_filename = "" dirs, files, path = get_files_and_folders(opts) + if opts.password != None: + opts.password_filename = opts.filename + opts.filename = generate_password_page(path, opts.filename, opts.password) existing_config = False if opts.filename in files: opts, existing_config = HTML2setup(opts) @@ -117,6 +128,7 @@ def generate_index(opts): print(opts.filename + " exists, and not generated with SimpleWebPage. Exiting.") sys.exit(1) files = [ f for f in files if f != opts.filename] + files = [ f for f in files if f != opts.password_filename] files = match_files(files, opts.includes) dirs.sort() files.sort() @@ -135,6 +147,50 @@ def generate_index(opts): return +def generate_password_page(path, password_file, password): + def ha(p): + h = 0 + for c in p: + h = ((h<<5) - h) + ord(c) + h = h & 0xffffffff + if h > (1<<31) - 1: + h -= (1<<32) + return h + + + def scramble(p,t): + p = (p * (int(len(t)/len(p))+1))[:len(t)] + t = (t * (int(len(p)/len(t))+1))[:len(p)] + s = '' + for i in range(len(p)): + s += chr(ord(p[i]) + ord(t[i])) + return s + + + def enc(s): + return base64.b64encode(s.encode('latin1')).decode('ascii') + + + def random_string(stringLength=8): + letters = string.ascii_lowercase + string.digits + return ''.join(random.choice(letters) for i in range(stringLength)) + + + def get_target(filename): + return "{0}.{2}{1}".format( + *os.path.splitext(filename) + (random_string(),) + ) + + target_file = get_target(password_file) + secret = "{}:{}".format( + ha(password), + enc(scramble(password, target_file)) + ) + with open(os.path.join(path, password_file), 'wt') as f: + f.write(get_password_page(secret)) + return target_file + + def get_filelink(path,fname,images=False): if os.path.islink(os.path.join(path, fname)) and not os.path.exists(os.path.join(path, fname)): (fsize, fsstr, fsstrb, fdstr)=(0, "NA", "NA", "NA") @@ -149,7 +205,7 @@ def get_filelink(path,fname,images=False): else: fname_str = fname return '