├── README.md └── ssslide.py /README.md: -------------------------------------------------------------------------------- 1 | # ssslide 2 | View screenshots as a slideshow over http 3 | 4 | Run ssslide.py from inside the directory with screenshots and then view them over http with the given url. 5 | 6 | ``` 7 | $ ~/target/screenshots$ ssslide 8 | 9 | _ _ _ 10 | ___ ___ ___| (_) __| | ___ 11 | / __/ __/ __| | |/ _` |/ _ \ 12 | \__ \__ \__ \ | | (_| | __/ 13 | |___/___/___/_|_|\__,_|\___| 14 | tehryanx 15 | 16 | serving 53 images on http://1.2.3.4:8000 17 | ``` 18 | # Usage 19 | ``` 20 | $ ~/bounties/lyft/screenshots$ ssslide --help 21 | usage: ssslide [-h] [-p PORT] [-z] 22 | 23 | Serve images from the current directory as a slideshow over http. 24 | 25 | optional arguments: 26 | -h, --help show this help message and exit 27 | -p PORT, --port PORT The port to listen on. Defaults to 8000 28 | -z, --zip Zip all images and serve them at /zip 29 | 30 | Happy hacking! 31 | ``` 32 | 33 | ### use h and l or j and k to flip through the screenshots in your browser. 34 | 35 | (I do realize the code is a disaster, and I plan to refactor it :X) 36 | -------------------------------------------------------------------------------- /ssslide.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from http.server import HTTPServer, BaseHTTPRequestHandler 4 | import os, mimetypes, re, signal, argparse 5 | from zipfile import ZipFile 6 | from requests import get 7 | import uuid, base64 8 | 9 | parser = argparse.ArgumentParser(description='Serve images from the current directory as a slideshow over http.', epilog='Happy hacking!') 10 | parser.add_argument('-p', '--port', type=int, default="8000", help="The port to listen on. Defaults to 8000") 11 | parser.add_argument('-z', '--zip', action="store_true", default=False, help="Zip all images and serve them at /zip") 12 | args = parser.parse_args() 13 | 14 | port=args.port 15 | zipflag=args.zip 16 | key = str(uuid.uuid1()) 17 | 18 | js_array = "" 19 | 20 | def sigint_handler(signum, frame): 21 | print("Received sigint. Exiting.") 22 | exit() 23 | 24 | 25 | class StaticServer(BaseHTTPRequestHandler): 26 | 27 | 28 | def do_GET(self): 29 | 30 | if "?" in self.path: 31 | path = self.path.split("?")[0] 32 | param = self.path.split("?")[1] 33 | else: 34 | print("No param.") 35 | return 36 | 37 | if key not in param: 38 | self.send_response(403) 39 | self.send_header("Content-type", "text/html") 40 | self.end_headers() 41 | self.wfile.write(b"Bad key: Access denied.") 42 | return 43 | 44 | if len(re.findall("[^=?a-zA-Z0-9._-]", path[1:])): 45 | print("Bad chars detected in: {}".format(path)) 46 | return 47 | 48 | if 'zip' in path: 49 | print("FOUND ZIP.") 50 | if zipflag: 51 | collection = [] 52 | with os.scandir('.') as files: 53 | for f in files: 54 | if os.path.isfile(f.name): 55 | if 'image' in mimetypes.guess_type(f.name)[0]: 56 | collection.append(f.name) 57 | zipObj = ZipFile('collection.zip', 'w') 58 | 59 | for file in collection: 60 | zipObj.write(file) 61 | zipObj.close() 62 | 63 | self.send_response(200) 64 | self.send_header('Content-type', 'application/zip') 65 | self.send_header('Content-disposition', 'attachment; filename="collection.zip') 66 | self.end_headers() 67 | with open('collection.zip', 'rb') as fh: 68 | zip = fh.read() 69 | self.wfile.write(zip) 70 | else: 71 | print ("Attempted to access zip but -z not set.") 72 | self.send_response(403) 73 | self.send_header('Content-type', 'text/html') 74 | self.end_headers() 75 | self.wfile.write(b"Attempted to access zip but -z not set.") 76 | return 77 | 78 | if path == '/': 79 | # serve slideshow code. 80 | html = """ 81 | 82 | 83 | ssslide 84 | 112 | 113 | 114 |
115 | 116 | 117 | 118 | """ 119 | self.send_response(200) 120 | self.send_header('Content-type', 'text/html') 121 | self.end_headers() 122 | self.wfile.write(bytes(html, 'utf8')) 123 | else: 124 | filename = os.path.abspath('.') + path 125 | if os.path.isfile(filename): 126 | mimetype = mimetypes.guess_type(filename)[0] 127 | if 'image' not in mimetype: 128 | self.send_response(403) 129 | self.end_headers() 130 | self.wfile.write(b'403') 131 | else: 132 | self.send_response(200) 133 | self.send_header('Content-type', mimetype) 134 | self.end_headers() 135 | with open(filename, 'rb') as fh: 136 | html = fh.read() 137 | self.wfile.write(html) 138 | else: 139 | self.send_response(404) 140 | self.end_headers() 141 | self.wfile.write(b'404: Nothing here.') 142 | 143 | 144 | signal.signal(signal.SIGINT, sigint_handler) 145 | 146 | images = [] 147 | with os.scandir('.') as files: 148 | for f in files: 149 | if os.path.isfile(f.name): 150 | if 'image' in mimetypes.guess_type(f.name)[0]: 151 | images.append(f.name) 152 | 153 | delim="?key="+key+"','" 154 | js_array = "'" + delim.join(images) + "/?key="+key+"'" 155 | 156 | ip = get('https://icanhazip.com').text.strip() 157 | 158 | 159 | 160 | header=""" 161 | \033[92m _ _ _ 162 | ___ ___ ___| (_) __| | ___ 163 | / __/ __/ __| | |/ _` |/ _ \\ 164 | \__ \__ \__ \ | | (_| | __/ 165 | |___/___/___/_|_|\__,_|\___| 166 | \033[0m\033[94mtehryanx\033[0m 167 | """ 168 | print(header) 169 | print("serving \033[94m{}\033[0m images on \033[92mhttp://{}\033[0m:\033[92m{}\033[0m/?\033[92mkey\033[0m=\033[92m{}\033[0m".format(str(len(images)),ip,port,key)) 170 | if zipflag: 171 | print("zip archive available at \033[92mhttp://{}\033[0m:\033[92m{}/zip\033[0m?\033[92mkey\033[0m=\033[92m{}\033[0m".format(ip,port,key)) 172 | httpd = HTTPServer(('', port), StaticServer) 173 | httpd.serve_forever() 174 | --------------------------------------------------------------------------------