Browse Source

Initial commit

master
bakatrouble 6 years ago
commit
8c26558f2a
10 changed files with 4763 additions and 0 deletions
  1. +146
    -0
      .gitignore
  2. +113
    -0
      autoindex.py
  3. +4383
    -0
      bottle.py
  4. +27
    -0
      configs/nginx.conf
  5. +9
    -0
      configs/supervisor.conf
  6. +6
    -0
      configs/uwsgi.ini
  7. +79
    -0
      filelist.tpl
  8. +0
    -0
      files/.gitkeep
  9. +0
    -0
      logs/.gitkeep
  10. +0
    -0
      subdomain_files/.gitkeep

+ 146
- 0
.gitignore View File

@ -0,0 +1,146 @@
# Created by .ignore support plugin (hsz.mobi)
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/dictionaries
# Sensitive or high-churn files:
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
# Gradle:
.idea/**/gradle.xml
.idea/**/libraries
# Mongo Explorer plugin:
.idea/**/mongoSettings.xml
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# dotenv
.env
# virtualenv
.venv
venv/
ENV/
# Spyder project settings
.spyderproject
# Rope project settings
.ropeproject
# ====================
files/*
subdomain_files/*
!.gitkeep

+ 113
- 0
autoindex.py View File

@ -0,0 +1,113 @@
from bottle import route, request, run, redirect, template, default_app, abort
import os
from datetime import datetime
from mimetypes import guess_type
base_hosts = [
'127.0.0.1.xip.io:8080'
]
def format_size(size):
for unit in ['B', 'KiB', 'MiB', 'GiB', 'TiB']:
if size < 2048:
return f'{size} {unit}'
else:
size //= 1024
return f'{size} PiB'
def format_date(ts):
return datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
def get_sort_icon(test, sort):
if sort == test:
return '<i class="sort descending icon"></i>'
elif sort == f'-{test}':
return '<i class="sort ascending icon"></i>'
else:
return ''
def get_sort_link(current, sort, hidden):
return f'?sort={"-" if current == sort else ""}{sort}{"&hidden" if hidden else ""}'
def get_file_icon(name):
t = guess_type(name)[0].split('/')[0]
if t in ['text', 'image', 'audio', 'video']:
return t
return ''
class ListEntry:
def __init__(self, dir, name):
path = os.path.join(dir, name)
self.name = name
self.isdir = os.path.isdir(path)
self.size = os.path.getsize(path)
self.created = os.path.getctime(path)
def resolve_path(domain, path):
if domain in base_hosts:
return os.path.join(os.path.dirname(__file__), 'files', *path.split('/'))
else:
for host in base_hosts:
if host in domain:
return os.path.join(os.path.dirname(__file__), 'subdomain_files',
domain[:domain.index(host)-1], *path.split('/'))
raise ValueError
def list_dir(dir, sort=None, hidden=False):
lst = [ListEntry(dir, name) for name in os.listdir(dir) if hidden or not name.startswith('.')]
lst = sorted(lst, key={
'name': lambda item: (not item.isdir, item.name.lower()),
'-name': lambda item: (item.isdir, item.name.lower()),
'size': lambda item: (not item.isdir, item.size),
'-size': lambda item: (item.isdir, item.size),
'created': lambda item: (not item.isdir, item.created),
'-created': lambda item: (item.isdir, item.created)
}[sort], reverse=sort.startswith('-'))
return lst
@route('/')
@route('/<path:path>')
def index(path=''):
domain = request.urlparts.netloc
query = request.urlparts.query
try:
resolved_path = resolve_path(domain, path)
except ValueError:
return 'GTFO'
if os.path.isdir(resolved_path):
if path and path[-1] != '/':
return redirect(f'/{path}/')
hidden = 'hidden' in request.GET
sort = request.GET.get('sort', 'name')
if sort not in ['name', '-name', 'size', '-size', 'created', '-created']:
sort = 'name'
return template('filelist',
lst=list_dir(resolved_path, sort, hidden),
format_size=format_size,
format_date=format_date,
get_sort_icon=get_sort_icon,
get_sort_link=get_sort_link,
sort=sort,
hidden=hidden,
path=path,
query=query,
guess_type=guess_type,
get_file_icon=get_file_icon)
else:
return abort(404)
application = default_app()
if __name__ == '__main__':
run(host='localhost', port=8080, debug=True, reloader=True)

+ 4383
- 0
bottle.py
File diff suppressed because it is too large
View File


+ 27
- 0
configs/nginx.conf View File

@ -0,0 +1,27 @@
server {
listen 80;
server_name drop.217.182.90.36.xip.io;
location /_ {
alias /srv/apps/drop/files;
}
location / {
include uwsgi_params;
uwsgi_pass unix:///tmp/drop.sock;
}
}
server {
listen 80;
server_name ~^(?<dir>.*)\.drop\.217\.182\.90\.36\.xip\.io$;
location /_ {
alias /srv/apps/drop/subdomain_files/$dir;
}
location / {
include uwsgi_params;
uwsgi_pass unix:///tmp/drop.sock;
}
}

+ 9
- 0
configs/supervisor.conf View File

@ -0,0 +1,9 @@
[program:drop]
user = www-data
directory = /srv/apps/drop
command = /srv/apps/drop/venv/bin/uwsgi --ini /srv/apps/drop/configs/uwsgi.ini
autostart = true
autorestart = true
stderr_logfile = /srv/apps/drop/logs/uwsgi_err.log
stdout_logfile = /srv/apps/drop/logs/uwsgi_out.log
stopsignal = INT

+ 6
- 0
configs/uwsgi.ini View File

@ -0,0 +1,6 @@
[uwsgi]
socket = /tmp/drop.sock
module = autoindex:application
master = true
processes = 2
enable-threads = true

+ 79
- 0
filelist.tpl View File

@ -0,0 +1,79 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>File list</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.10/components/reset.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.10/components/site.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.10/components/icon.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.10/components/table.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.10/components/container.min.css" rel="stylesheet" />
<style>
table tbody tr {
position: relative;
}
table tbody tr a {
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
</style>
</head>
<body>
<div class="ui main container" style="padding: 15px 0">
<h2>Directory Index - /{{ path }}</h2>
<table class="ui selectable unstackable table">
<thead>
<tr>
<th><a href="{{ get_sort_link(sort, 'name', hidden) }}">
Name {{ !get_sort_icon('name', sort) }}
</a></th>
<th style="width: 100px;"><a href="{{ get_sort_link(sort, 'size', hidden) }}">
Size {{ !get_sort_icon('size', sort) }}
</a></th>
<th style="width: 170px;"><a href="{{ get_sort_link(sort, 'created', hidden) }}">
Created {{ !get_sort_icon('created', sort) }}
</a></th>
</tr>
</thead>
<tbody>
% if path:
<tr style="cursor: pointer">
<td>
<a href="../{{ f'?{query}' if query else '' }}"></a>
<i class="level up icon"></i>
../
</td>
<td></td>
<td></td>
</tr>
% end
% for item in lst:
<tr style="cursor: pointer">
% if item.isdir:
<td>
<a href="{{ item.name }}/{{ f'?{query}' if query else '' }}"></a>
<i class="folder outline icon"></i>
{{ item.name }}/
</td>
<td></td>
<td></td>
% else:
<td>
<a href="/_/{{ path }}{{ item.name }}" target="_blank"></a>
<i class="file {{ get_file_icon(item.name) }} outline icon"></i>
{{ item.name }} [{{ guess_type(item.name)[0] }}]
</td>
<td><span title="{{ item.size }} byte(s)">{{ format_size(item.size) }}</span></td>
<td>{{ format_date(item.created) }}</td>
% end
</tr>
% end
</tbody>
</table>
</div>
</body>
</html>

+ 0
- 0
files/.gitkeep View File


+ 0
- 0
logs/.gitkeep View File


+ 0
- 0
subdomain_files/.gitkeep View File


Loading…
Cancel
Save