first commit
This commit is contained in:
commit
6df398966e
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
__pycache__/
|
||||
*.swp
|
||||
*.swo
|
||||
config.py
|
15
LICENSE
Normal file
15
LICENSE
Normal file
|
@ -0,0 +1,15 @@
|
|||
ISC License
|
||||
|
||||
Copyright (c) 2019, iou1name <iou1name@steelbea.me>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
24
README.md
Normal file
24
README.md
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Saddle
|
||||
A file hosting service similar to Pomf and Uguu but without the public nature.
|
||||
|
||||
## Requirements
|
||||
Python 3.7+
|
||||
PostgreSQL 11.5+
|
||||
Python packages: `wheel gunicorn aiohttp aiohttp_jinja2 asyncpg uvloop`
|
||||
|
||||
## Install
|
||||
```
|
||||
$ psql
|
||||
postgres=# CREATE DATABASE "saddle";
|
||||
postgres=# CREATE USER "saddle" WITH PASSWORD 'password';
|
||||
postgres=# ALTER ROLE "saddle" SET client_encoding TO 'utf8';
|
||||
postgres=# ALTER ROLE "saddle" SET default_transaction_isolation TO 'read committed';
|
||||
postgres=# ALTER ROLE "saddle" SET timezone TO 'UTC';
|
||||
postgres=# GRANT ALL PRIVILEGES ON DATABASE "saddle" TO "saddle";
|
||||
postgres=# \q
|
||||
```
|
||||
1. Get on the floor
|
||||
2. Walk the dinosaur
|
||||
|
||||
## Usage
|
||||
`gunicorn saddle:init_app --bind localhost:5000 --worker-class aiohttp.GunicornWebWorker`
|
61
buckler_aiohttp.py
Normal file
61
buckler_aiohttp.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Session interface middlewares to integrate the aiohttp app with Buckler.
|
||||
"""
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
import aiohttp
|
||||
from aiohttp import web
|
||||
|
||||
import config
|
||||
|
||||
@web.middleware
|
||||
async def buckler_session(request, handler):
|
||||
"""
|
||||
Verifies the user with the configured Buckler app and retrieves any
|
||||
session data they may have. Redirects them to the login page otherwise.
|
||||
"""
|
||||
user_id = request.cookies.get('userid')
|
||||
user_sid = request.cookies.get('session')
|
||||
|
||||
url = config.buckler['url'] + '/get_session'
|
||||
params = {
|
||||
'app_id': config.buckler['app_id'],
|
||||
'app_key': config.buckler['app_key'],
|
||||
'userid': user_id,
|
||||
'session': user_sid
|
||||
}
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url, params=params) as resp:
|
||||
data = await resp.json()
|
||||
if data.get('error'):
|
||||
raise web.HTTPFound(location=config.buckler['login_url'])
|
||||
request['session'] = data['session_data']
|
||||
request['meta'] = data['meta']
|
||||
|
||||
resp = await handler(request)
|
||||
|
||||
if request['session'] != data['session_data']: # session data modified
|
||||
url = config.buckler['url'] + '/set_session'
|
||||
data = json.dumps(request['session'])
|
||||
session.post(url, params=params, data=data) # TODO: error handle?
|
||||
|
||||
last_used = datetime.fromisoformat(request['meta']['last_used'])
|
||||
now = datetime.now(last_used.tzinfo)
|
||||
delta = now - last_used
|
||||
if delta.seconds > 600:
|
||||
resp.set_cookie(
|
||||
'userid',
|
||||
user_id,
|
||||
max_age=30*24*60*60,
|
||||
secure=True,
|
||||
httponly=True)
|
||||
resp.set_cookie(
|
||||
'session',
|
||||
user_sid,
|
||||
max_age=30*24*60*60,
|
||||
secure=True,
|
||||
httponly=True)
|
||||
|
||||
return resp
|
25
config.py.template
Executable file
25
config.py.template
Executable file
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Configuration settings for Saddle.
|
||||
`url_prefix` is the root path you wish app to reside at
|
||||
eg. https://example.com/saddle
|
||||
`upload_dir` is the system directory in which to store uploaded files.
|
||||
`db` specifies parameters for connecting to the PostgreSQL database.
|
||||
`buckler` specifies settings pertaining to the Buckler server.
|
||||
"""
|
||||
url_prefix = '/saddle'
|
||||
upload_dir = '/var/www/html/up'
|
||||
db = {
|
||||
'database': 'saddle',
|
||||
'user': 'saddle',
|
||||
'password': """password""",
|
||||
'host': 'localhost',
|
||||
'port': 5432,
|
||||
}
|
||||
|
||||
buckler = {
|
||||
'url': "http://127.0.0.1:5400/buckler",
|
||||
'app_id': 1,
|
||||
'app_key': """password""",
|
||||
'login_url': "/buckler/login",
|
||||
}
|
45
saddle.py
Normal file
45
saddle.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
A file hosting service similar to Pomf and Uguu but without the public nature.
|
||||
"""
|
||||
from aiohttp import web
|
||||
import jinja2
|
||||
import aiohttp_jinja2
|
||||
from aiohttp_jinja2 import render_template
|
||||
import asyncpg
|
||||
import uvloop
|
||||
|
||||
import config
|
||||
import buckler_aiohttp
|
||||
|
||||
uvloop.install()
|
||||
routes = web.RouteTableDef()
|
||||
|
||||
|
||||
@routes.get('/', name='index')
|
||||
async def index(request):
|
||||
"""The index page."""
|
||||
return render_template("index.html", request, locals())
|
||||
|
||||
|
||||
async def init_app():
|
||||
"""Initializes the application."""
|
||||
#app = web.Application(middlewares=[buckler_aiohttp.buckler_session])
|
||||
app = web.Application()
|
||||
aiohttp_jinja2.setup(app, loader=jinja2.FileSystemLoader('templates'))
|
||||
app['pool'] = await asyncpg.create_pool(**config.db)
|
||||
|
||||
async with app['pool'].acquire() as conn:
|
||||
with open('saddle.sql', 'r') as file:
|
||||
await conn.execute(file.read())
|
||||
|
||||
app.router.add_routes(routes)
|
||||
|
||||
app_wrap = web.Application()
|
||||
app_wrap.add_subapp(config.url_prefix, app)
|
||||
return app_wrap
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = init_app()
|
||||
web.run_app(app, host='0.0.0.0', port=5000)
|
7
saddle.sql
Normal file
7
saddle.sql
Normal file
|
@ -0,0 +1,7 @@
|
|||
CREATE TABLE IF NOT EXISTS upload (
|
||||
user_id INTEGER NOT NULL,
|
||||
id TEXT PRIMARY KEY,
|
||||
filename TEXT NOT NULL,
|
||||
upload_date TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
expiration_date TIMESTAMP
|
||||
)
|
7
static/saddle.css
Normal file
7
static/saddle.css
Normal file
|
@ -0,0 +1,7 @@
|
|||
body {
|
||||
margin-left: 10%;
|
||||
margin-right: 10%;
|
||||
background-color: lightcoral;
|
||||
font-family: Helvetica,sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
16
templates/index.html
Normal file
16
templates/index.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Saddle</title>
|
||||
<link rel="stylesheet" type="text/css" href="/static/saddle.css">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=0.8">
|
||||
<meta name="description" content="A file upload service.">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Saddle</h1>
|
||||
</header>
|
||||
<main>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user