Working PoC
This commit is contained in:
parent
1ae44a1f46
commit
feeeb7c421
|
@ -0,0 +1,133 @@
|
|||
import os
|
||||
import json
|
||||
|
||||
import uuid
|
||||
|
||||
|
||||
class BaseTextHandler(object):
|
||||
mimetype = 'text/mime'
|
||||
|
||||
@staticmethod
|
||||
def handle(httpd):
|
||||
raise Exception(f'Not implemented: Unable to handle {httpd} '
|
||||
'({BaseTextHandler.mimetype}')
|
||||
|
||||
|
||||
class OctetStreamHandler(object):
|
||||
mimetype = 'application/octet-stream'
|
||||
|
||||
def handle(httpd):
|
||||
raise Exception(f'Not implemented: Unable to handle {httpd} '
|
||||
'({StreamHandler.mimetype}')
|
||||
|
||||
|
||||
class ChunkTemplateHandler(BaseTextHandler):
|
||||
pass
|
||||
|
||||
|
||||
class ThumbHandler(object):
|
||||
mimetype = 'image/png'
|
||||
|
||||
def handle(httpd):
|
||||
raise Exception(f'Not implemented: Unable to handle {httpd} '
|
||||
'({ThumbHandler.mimetype}')
|
||||
|
||||
|
||||
class LegacyListHandler(BaseTextHandler):
|
||||
|
||||
def handle(httpd):
|
||||
# files = filess['files']
|
||||
raise Exception(f'Not implemented: Unable to handle {httpd} '
|
||||
'({LegacyListHandler.mimetype}')
|
||||
|
||||
|
||||
class JsonListHandler(object):
|
||||
mimetype = 'application/json'
|
||||
|
||||
def _make_jsonlist(files):
|
||||
filestats = []
|
||||
totalsize = 0
|
||||
for file_ in files:
|
||||
statinfo = os.stat(file_)
|
||||
filename = os.path.basename(file_)
|
||||
filepath = os.path.dirname(file_)
|
||||
filestats.append({
|
||||
'created': str(int(statinfo.st_ctime) * 1000),
|
||||
'modified': str(int(statinfo.st_mtime) * 1000),
|
||||
'name': filename,
|
||||
'path': filepath,
|
||||
'size': str(statinfo.st_size),
|
||||
'type': "Image" # TODO dynamic
|
||||
})
|
||||
totalsize += statinfo.st_size
|
||||
jsonlist = {
|
||||
'device': 'ANYONMOUS',
|
||||
'empty_dirs': [],
|
||||
'files': filestats,
|
||||
'uuid': str(uuid.uuid4()),
|
||||
'version': 4130
|
||||
}
|
||||
return json.dumps(jsonlist), totalsize
|
||||
|
||||
def handle(httpd):
|
||||
jsonlist, totalsize = JsonListHandler._make_jsonlist(httpd.files)
|
||||
httpd.send_response(200)
|
||||
httpd.send_header('Content-Type', 'application/json')
|
||||
httpd.end_headers()
|
||||
|
||||
response = bytes(jsonlist, 'utf-8')
|
||||
httpd.wfile.write(response)
|
||||
httpd.total_file_size = totalsize
|
||||
|
||||
|
||||
class SingleFileHandler(OctetStreamHandler):
|
||||
pass
|
||||
|
||||
|
||||
class ZipFileHandler(object):
|
||||
mimetype = 'application/zip'
|
||||
|
||||
def handle(httpd):
|
||||
raise Exception('ZipFileHandler not implemeted.')
|
||||
|
||||
|
||||
class SuperStreamHandler(OctetStreamHandler):
|
||||
|
||||
@staticmethod
|
||||
def _get_streamsize(files):
|
||||
totalsize = 0
|
||||
for file_ in files:
|
||||
statinfo = os.stat(file_)
|
||||
totalsize += statinfo.st_size
|
||||
return totalsize
|
||||
|
||||
@staticmethod
|
||||
def _stream_file_content(files):
|
||||
for file_ in files:
|
||||
with open(file_, 'rb') as f_handle:
|
||||
yield f_handle.read()
|
||||
|
||||
@staticmethod
|
||||
def handle(httpd):
|
||||
httpd.send_response(200)
|
||||
httpd.send_header('ylfrettub', '1')
|
||||
httpd.send_header('Content-Type', 'application/octet-stream')
|
||||
httpd.send_header('Content-Length',
|
||||
str(SuperStreamHandler._get_streamsize(httpd.files)))
|
||||
httpd.send_header('Content-Disposition', 'attachment; '
|
||||
'filename="RedHotChillyStream"')
|
||||
httpd.end_headers()
|
||||
for chunk in SuperStreamHandler._stream_file_content(httpd.files):
|
||||
httpd.wfile.write(chunk)
|
||||
|
||||
|
||||
class AssetHandler(OctetStreamHandler):
|
||||
pass
|
||||
|
||||
|
||||
class ApkRequestHandler(object):
|
||||
mimetype = 'application/vnd.android.package-archive'
|
||||
|
||||
def handle(httpd):
|
||||
raise Exception(f'Not implemented: Unable to handle {httpd} '
|
||||
'({ApkRequestHandler.mimetype}')
|
|
@ -0,0 +1,110 @@
|
|||
import os
|
||||
|
||||
from http.server import BaseHTTPRequestHandler
|
||||
import socketserver
|
||||
import threading
|
||||
import pyqrcode
|
||||
import socket
|
||||
import struct
|
||||
import base64
|
||||
|
||||
|
||||
from SuperBeam.RequestHandlers import (
|
||||
ChunkTemplateHandler, ThumbHandler, ApkRequestHandler, LegacyListHandler,
|
||||
SingleFileHandler, ZipFileHandler, SuperStreamHandler, AssetHandler,
|
||||
JsonListHandler
|
||||
)
|
||||
|
||||
|
||||
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
||||
pass
|
||||
|
||||
|
||||
class SuperBeamServer(BaseHTTPRequestHandler):
|
||||
|
||||
def do_GET(self):
|
||||
# TODO Add globbing
|
||||
print(threading.current_thread())
|
||||
paths = {
|
||||
'index': ChunkTemplateHandler,
|
||||
'/': ChunkTemplateHandler,
|
||||
'/index.htm': ChunkTemplateHandler, # TODO handler2
|
||||
'/getthumb': ThumbHandler,
|
||||
'/light': ChunkTemplateHandler, # TODO handler2
|
||||
'/superlist': LegacyListHandler,
|
||||
'/jsonlist': JsonListHandler,
|
||||
'/get/': SingleFileHandler,
|
||||
'/getapk': ApkRequestHandler,
|
||||
'/getzip': ZipFileHandler,
|
||||
'/getstream': SuperStreamHandler,
|
||||
'*': AssetHandler,
|
||||
}
|
||||
|
||||
if self.path in paths: # TODO startswith key check
|
||||
self.respond(paths[self.path])
|
||||
|
||||
def respond(self, handler):
|
||||
print('='*30 + ' DEBUG ' + '='*30)
|
||||
print('CONNECTION:', self.connection)
|
||||
print('HEADERS :', self.headers)
|
||||
print('REQUEST :', self.request)
|
||||
print('REQUEST* :', self.requestline)
|
||||
print('PATH :', self.path)
|
||||
print('COMMAND :', self.command)
|
||||
print('HANDLER :', handler)
|
||||
print('='*30 + ' DEBUG ' + '='*30)
|
||||
handler.handle(self)
|
||||
|
||||
|
||||
def get_primary_ip():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
try:
|
||||
# doesn't even have to be reachable
|
||||
s.connect(('10.255.255.255', 1))
|
||||
IP = s.getsockname()[0]
|
||||
except Exception as exc:
|
||||
print(exc)
|
||||
IP = '127.0.0.1'
|
||||
finally:
|
||||
s.close()
|
||||
return IP
|
||||
|
||||
|
||||
def show_qrcode():
|
||||
primary_ip = get_primary_ip()
|
||||
octets = [1]
|
||||
octets.extend([int(_) for _ in primary_ip.split('.')[::-1]])
|
||||
url = 'http://superbe.am/q?' + base64.b64encode(
|
||||
struct.pack('BBBBB', *octets)
|
||||
).decode('utf-8')
|
||||
qrcode = pyqrcode.create(url)
|
||||
print('\033[1;37;37m████████' + '██'*(len(qrcode.code[0])))
|
||||
for row in qrcode.code:
|
||||
print('\033[1;37;37m████', end='')
|
||||
for block in row:
|
||||
if block == 1:
|
||||
print('\033[1;30;30m ', end='')
|
||||
else:
|
||||
print('\033[1;37;37m██', end='')
|
||||
print('\033[1;37;37m████')
|
||||
print('\033[1;37;37m████████' + '██'*(len(qrcode.code[0])))
|
||||
|
||||
|
||||
def build_filelist(paths, recursive=True):
|
||||
filelist = []
|
||||
for path in paths:
|
||||
if os.path.isdir(path) and recursive:
|
||||
for root, dirs, files in os.walk(path):
|
||||
for file_ in files:
|
||||
filelist.append(os.path.join(root, file_))
|
||||
else:
|
||||
filelist.append(path)
|
||||
return filelist
|
||||
|
||||
|
||||
def serve_forever(files):
|
||||
Handler = SuperBeamServer
|
||||
Handler.files = files
|
||||
with socketserver.ThreadingTCPServer(('', 8080), Handler) as httpd:
|
||||
show_qrcode()
|
||||
httpd.serve_forever()
|
|
@ -7,82 +7,70 @@
|
|||
# Distributed under terms of the MIT license.
|
||||
|
||||
"""
|
||||
> GET /getstream HTTP/1.1
|
||||
> Host: 192.168.178.50:8080
|
||||
> User-Agent: sbeam
|
||||
> Accept: */*
|
||||
>
|
||||
* Mark bundle as not supporting multiuse
|
||||
< HTTP/1.1 200 OK
|
||||
< ylfrettub: 1
|
||||
< Content-Disposition: attachment; filename="RedHotChillyStream"
|
||||
< Date: Fri, 09 Aug 2019 12:57:20 GMT
|
||||
< Content-Length: 8137967
|
||||
< Content-Type: application/octet-stream
|
||||
|
||||
Server QR Code = http://superbe.am/q?ATKyqMA=
|
||||
Base64 = 01 32 b2 a8 c0 = 01 50 178 168 192
|
||||
"""
|
||||
|
||||
import os
|
||||
import click
|
||||
import requests
|
||||
import pyqrcode
|
||||
|
||||
import socket
|
||||
import struct
|
||||
import base64
|
||||
|
||||
# from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
import http.server
|
||||
import socketserver
|
||||
import SuperBeam
|
||||
|
||||
|
||||
def get_primary_ip():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
try:
|
||||
# doesn't even have to be reachable
|
||||
s.connect(('10.255.255.255', 1))
|
||||
IP = s.getsockname()[0]
|
||||
except Exception as exc:
|
||||
print(exc)
|
||||
IP = '127.0.0.1'
|
||||
finally:
|
||||
s.close()
|
||||
return IP
|
||||
@click.group()
|
||||
def cli():
|
||||
pass
|
||||
|
||||
|
||||
def show_qrcode():
|
||||
primary_ip = get_primary_ip()
|
||||
octets = [1]
|
||||
octets.extend([int(_) for _ in primary_ip.split('.')[::-1]])
|
||||
url = 'http://superbe.am/q?' + base64.b64encode(
|
||||
struct.pack('BBBBB', *octets)
|
||||
).decode('utf-8')
|
||||
qrcode = pyqrcode.create(url)
|
||||
print('\033[1;37;37m████████' + '██'*(len(qrcode.code[0])))
|
||||
for row in qrcode.code:
|
||||
print('\033[1;37;37m████', end='')
|
||||
for block in row:
|
||||
if block == 1:
|
||||
print('\033[1;30;30m ', end='')
|
||||
else:
|
||||
print('\033[1;37;37m██', end='')
|
||||
print('\033[1;37;37m████')
|
||||
print('\033[1;37;37m████████' + '██'*(len(qrcode.code[0])))
|
||||
@cli.command()
|
||||
@click.option('--recursive', default=True, is_flag=True,
|
||||
help='Recurse into sub directories')
|
||||
@click.argument('filename', nargs=-1, type=click.Path(exists=True))
|
||||
def serve(recursive, filename):
|
||||
filelist = SuperBeam.build_filelist(filename, recursive)
|
||||
SuperBeam.serve_forever(filelist)
|
||||
|
||||
|
||||
def serve_files():
|
||||
show_qrcode()
|
||||
Handler = http.server.SimpleHTTPRequestHandler
|
||||
with socketserver.TCPServer(('', 8081), Handler) as httpd:
|
||||
httpd.serve_forever()
|
||||
|
||||
|
||||
def get_superlist():
|
||||
with requests.get('http://192.168.178.50:8080/superlist',
|
||||
@cli.command()
|
||||
@click.argument('host', default='127.0.0.1')
|
||||
def superlist(host):
|
||||
with requests.get(f'http://{host}:8080/superlist',
|
||||
headers={'User-Agent': 'sbeam'}) as response:
|
||||
assert response.status_code == 200
|
||||
return response.text.split('\n')
|
||||
|
||||
|
||||
def save_stream(filename):
|
||||
with requests.get('http://192.168.178.50:8080/getstream', stream=True,
|
||||
@cli.command()
|
||||
@click.argument('host', default='127.0.0.1')
|
||||
@click.argument('filename', default='received.bin', type=click.File('w'))
|
||||
def receive(host, filename):
|
||||
with requests.get(f'http://{host}:8080/getstream', stream=True,
|
||||
headers={'User-Agent': 'sbeam'}) as response:
|
||||
assert response.status_code == 200
|
||||
with open(filename, 'wb') as handle:
|
||||
# length = response.headers.get('Content-length')
|
||||
# print(length)
|
||||
for chunk in response.iter_content(chunk_size=8196):
|
||||
handle.write(chunk)
|
||||
|
||||
|
||||
def split_stream(data, directory, superlist):
|
||||
@cli.command()
|
||||
@click.argument('filename', default='received.bin', type=click.File('r'))
|
||||
@click.argument('superlist', default='superlist', type=click.File('r'))
|
||||
@click.argument('directory', default='received', type=click.File('w'))
|
||||
def split_stream(data, superlist, directory):
|
||||
with open(data, 'rb') as blob:
|
||||
for item in superlist:
|
||||
if not item:
|
||||
|
@ -96,7 +84,7 @@ def split_stream(data, directory, superlist):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
serve_files()
|
||||
cli()
|
||||
# to_download = 0
|
||||
# superlist = get_superlist()
|
||||
# try:
|
||||
|
|
Loading…
Reference in New Issue