Files
SocksBin/paster.py

291 lines
11 KiB
Python
Raw Normal View History

2020-04-11 19:13:03 +00:00
#!venv/bin/python
2020-06-04 13:24:17 +05:30
# replace the above line with the path to your virtual environment.
2020-04-11 18:42:11 +05:30
2020-04-11 21:09:58 +05:30
import os
import socket
import secrets
import sys
import getopt
import re
2020-04-11 23:54:57 +05:30
from time import gmtime, strftime
2020-04-11 19:32:52 +05:30
# Config
2020-04-11 23:54:57 +05:30
def main(theargs):
# where to serve this page.
# 127.0.0.1 / localhost => only accessible locally, on this machine
2020-04-11 21:09:58 +05:30
# 0.0.0.0 => accessible to the internet, by any host
hostname = "0.0.0.0"
# which port number to bind to
# choose a port number > 1000, to prevent interference with system processes
2020-04-11 22:15:44 +05:30
port = 8888
# maximum number of clients this can handle at any given time
queue_depth = 10
# directory path
2020-04-11 22:15:44 +05:30
# default is $HOME i.e. /home/username/socksbin
output_directory = os.path.join(os.path.expanduser("~"), "socksbin")
2020-04-11 21:09:58 +05:30
# specify the length of generated filename. multiples of 2 only
slug_size = 8
# amount of data transferred at a time, in bytes
2020-04-11 21:09:58 +05:30
# set between 4096 and 64000.
buffer_size = 32768
2020-04-11 22:15:44 +05:30
log = False
# path for log file
log_file = "/tmp/socklog.txt"
2020-04-11 22:15:44 +05:30
# base url where the file will be served to the user
2020-04-12 01:20:12 +05:30
base_url = "http://localhost/"
2020-04-11 22:15:44 +05:30
helpmessage = """
Welcome to SocksBin, the command line pastebin !
Released under GNU GPL.
2020-04-11 22:15:44 +05:30
-n --hostname\tSet the hostname to listen for. 0.0.0.0 by default.
2020-04-11 19:44:57 +00:00
-p --port\t\tExternel port number to listen on. 8888 by default
-q --queue_depth\tMax number of simultaneous connections to accept
2020-04-11 19:44:57 +00:00
-o --output_directory File storage location. $HOME/socksbin by default
-s --slug_size\tLength of url to generate.
2020-06-04 13:24:17 +05:30
-b --buffer_size\tPacket size in bytes.
2020-04-11 19:44:57 +00:00
-l --log_file\tPath to log file.
-h --help\t\tDisplay this message
-u --url\t\tSpecify the url to append to when giving the link to the user.
"""
try:
2020-04-11 22:15:44 +05:30
if theargs[0] == "-h" or theargs[0] == "--help":
print(helpmessage)
sys.exit()
except IndexError:
pass
try:
opts, args = getopt.getopt(theargs, "n:p:q:o:s:b:l:u:", [
"hostname=", "port=", "queue_depth=", "output_directory=", "slug_size=", "buffer_size=", "log_file=", "url="])
for opt, arg in opts:
if opt in ['-n', '--hostname']:
if arg.find('/') != -1:
print("Incorrect hostname. / not allowed. Run with -h for options")
sys.exit()
else:
hostname = arg
elif opt in ['-p', "--port"]:
if re.match("^ *\d[\d ]*$", arg) is None:
2020-04-11 21:09:58 +05:30
print(
"Incorrect port format. Choose a number between 0 and 64738. Warning: ports below 1000 could interfere with system processes.")
sys.exit()
elif int(arg) > 64738:
2020-04-11 21:09:58 +05:30
print(
"Incorrect port format. Choose a number between 0 and 64738. Warning: ports below 1000 could interfere with system processes.")
sys.exit()
elif int(arg) < 1000:
2020-04-11 21:09:58 +05:30
choice = input(
"Warning: ports below 1000 could interfere with system processes. Do you want to choose a different port ? (y/n): ")
if choice.lower() == "y":
arg = input("Please enter your new port number: ")
if re.match("^ *\d[\d ]*$", arg) is None:
2020-04-11 21:09:58 +05:30
print(
"Incorrect port format. Choose a number between 1000 and 64738")
sys.exit()
else:
2020-04-11 22:15:44 +05:30
port = int(arg)
elif choice.lower() == "n":
pass
2020-04-11 21:09:58 +05:30
port = int(arg)
elif opt in ['-q', "--queue_depth"]:
2020-04-11 21:09:58 +05:30
if not arg.isdigit():
print(
"Queue depth can only be an integer. Run with -h for more options")
sys.exit()
2020-04-11 22:15:44 +05:30
elif int(arg) > 1000 or int(arg) < 2:
print("Queue depth has to be between 2 and 1000")
sys.exit()
2020-04-11 21:09:58 +05:30
queue_depth = int(arg)
elif opt in ['-o', "--output_directory"]:
2020-04-11 21:09:58 +05:30
directory = arg
if os.path.isdir(directory):
permission = (isWritable(directory))
if not permission:
2020-04-11 22:15:44 +05:30
print(
f"You do not have permissions to write to {directory}")
2020-04-11 21:09:58 +05:30
sys.exit()
else:
output_directory = arg
else:
2020-04-11 22:15:44 +05:30
parent_dir = (os.path.abspath(
os.path.join(directory, os.pardir)))
2020-04-11 21:09:58 +05:30
if not os.path.isdir(parent_dir):
2020-04-11 22:15:44 +05:30
print(
f"The parent folder {parent_dir} does not exist. Please try again after creating it.")
2020-04-11 21:09:58 +05:30
sys.exit()
permission = (isWritable(parent_dir))
2020-04-11 22:15:44 +05:30
2020-04-11 21:09:58 +05:30
if not permission:
2020-04-11 22:15:44 +05:30
print(
f"You do not have permissions to write to {directory}, or the parent folder {parent_dir} does not exist")
2020-04-11 21:09:58 +05:30
sys.exit()
else:
try:
os.makedirs(directory)
print(f"> Directory {directory} created !")
output_directory = arg
except OSError:
2020-04-11 22:15:44 +05:30
print(
"unable to create directory. Please check your permissions.")
sys.exit()
elif opt in ['-s', "--slug_size"]:
2020-04-11 22:15:44 +05:30
if not arg.isdigit():
print("slug length can only be a integer, between 4 and 20")
sys.exit()
elif int(arg) > 20 or int(arg) < 2:
print("Slug length has to be between 4 and 20")
sys.exit()
else:
slug_size = int(arg)
elif opt in ['-b', "--buffer_size"]:
2020-04-11 22:15:44 +05:30
if not arg.isdigit():
print("buffer length can only be a integer, between 1024 and 60000")
sys.exit()
elif int(arg) > 60000 or int(arg) < 1024:
print("buffer length has to be between 1024 and 60000")
sys.exit()
else:
buffer_size = int(arg)
elif opt in ['-l', "--log_file"]:
2020-04-11 22:15:44 +05:30
try:
parent_dir = (os.path.abspath(
os.path.join(arg, os.pardir)))
except:
print("Error while creating log file. Incorrect format.")
sys.exit()
2020-04-11 21:09:58 +05:30
2020-04-11 22:15:44 +05:30
if not os.path.isdir(parent_dir):
print(
f"The parent folder {parent_dir} does not exist. Please try again after creating it.")
sys.exit()
permission = (isWritable(parent_dir))
if not permission:
print(
f"You do not have permissions to write to {arg}, or the parent folder {parent_dir} does not exist")
sys.exit()
log_file = arg
log = True
elif opt in ['-h', '--help']:
print(helpmessage)
sys.exit()
elif opt in ['-u', '--url']:
base_url = arg
constants = ({
2020-04-11 21:09:58 +05:30
"hostname": hostname,
"port": port,
2020-04-11 22:15:44 +05:30
"queue_depth": queue_depth,
"output_directory": output_directory,
"slug_size": slug_size,
"buffer_size": buffer_size,
"log": log,
"log_file": log_file,
"base_url": base_url
})
except getopt.GetoptError as err:
print(err)
print("Run with -h or --help to see the various options")
2020-04-11 19:32:52 +05:30
2020-04-11 22:15:44 +05:30
server(constants)
2020-04-11 19:32:52 +05:30
#######################################################################################
2020-04-11 22:15:44 +05:30
def server(config):
2020-04-11 19:32:52 +05:30
# create the socket
# AF_INET => IPv4
# SOCK_STREAM => TCP Connections
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2020-04-11 22:15:44 +05:30
s.bind((config['hostname'], config['port']))
2020-04-11 19:32:52 +05:30
2020-04-11 22:15:44 +05:30
s.listen(config['queue_depth'])
2020-04-11 19:32:52 +05:30
while True:
2020-04-11 23:54:57 +05:30
try:
clientSocket, address = s.accept()
print(f"Connection from {address} has been established")
filepath = secrets.token_hex(config['slug_size'])
filepath = filepath[:config['slug_size']]
clientSocket.sendall(
2020-04-11 19:13:03 +00:00
bytes(config['base_url']+filepath+"\n", "utf-8"))
2020-04-11 23:54:57 +05:30
clientSocket.shutdown(socket.SHUT_WR)
full_message = ""
while True:
data = clientSocket.recv(config['buffer_size'])
if len(data) <= 0:
break
full_message += data.decode('utf-8')
with open(os.path.join(config['output_directory'], filepath), 'w') as writer:
writer.write(full_message)
2020-04-11 19:13:03 +00:00
with open(os.path.join(config['output_directory'], filepath + "_color"), 'w') as writer:
2020-04-11 23:54:57 +05:30
received_code = full_message
try:
from pygments.formatters.html import HtmlFormatter
from pygments import highlight
from pygments.lexers import guess_lexer
lexer = guess_lexer(received_code)
fmter = HtmlFormatter(
noclasses=True, style="colorful", linenos=True)
result = highlight(received_code, lexer, fmter)
writer.write(result)
except Exception as e:
print("unable to format")
print(e)
if config['log']:
showtime = strftime("%Y-%m-%d %H:%M:%S", gmtime())
with open(config['log_file'], 'a') as logFile:
logFile.write(f"Time: {showtime}\t")
logFile.write(f"Address: {address} \t")
logFile.write(f"file: {filepath} \n")
except Exception as e:
2020-06-04 13:21:38 +05:30
print(e)
2020-04-11 23:54:57 +05:30
if config['log']:
with open(config['log_file']+"_e.txt", 'a') as logFile:
logFile.write(f"# Address: {address}\t")
logFile.write(f"message: {full_message}\t")
logFile.write(f"Error: {e}")
2020-04-11 19:32:52 +05:30
2020-04-11 21:09:58 +05:30
def isWritable(directory):
try:
2020-04-11 22:15:44 +05:30
tmp_prefix = "write_tester"
2020-04-11 21:09:58 +05:30
count = 0
filename = os.path.join(directory, tmp_prefix)
while(os.path.exists(filename)):
2020-04-11 22:15:44 +05:30
filename = "{}.{}".format(
os.path.join(directory, tmp_prefix), count)
2020-04-11 21:09:58 +05:30
count = count + 1
2020-04-11 22:15:44 +05:30
f = open(filename, "w")
2020-04-11 21:09:58 +05:30
f.close()
os.remove(filename)
return True
except Exception as e:
return False
2020-04-11 23:54:57 +05:30
2020-04-11 19:32:52 +05:30
if __name__ == "__main__":
2020-04-11 21:09:58 +05:30
main(sys.argv[1:])