Compare commits
No commits in common. "master" and "v1.0.2-alpha" have entirely different histories.
master
...
v1.0.2-alp
15 changed files with 60 additions and 127 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -10,5 +10,3 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.coverage
|
.coverage
|
||||||
/*.md
|
/*.md
|
||||||
/.eggs/
|
|
||||||
/devel/
|
|
||||||
46
README.md
46
README.md
|
|
@ -2,40 +2,28 @@
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
**NOTE**: httpaste is publicly hosted at [httpaste.it](http://httpaste.it) and as a hidden Tor service ([https://paste77ubkwxy4fqezffsmthxdh3xerwi72tlsw2mch7ecjhw2xn7iyd.onion](https://paste77ubkwxy4fqezffsmthxdh3xerwi72tlsw2mch7ecjhw2xn7iyd.onion)).
|
httpaste is a pastebin application for easily pasting and retrieving data over
|
||||||
Both services are to be considered evaluatory, as long as the source code
|
HTTP from shell environments and web browsers. It is inspired by [sprunge.us](http://sprunge.us)
|
||||||
is in pre-release. Regarding voidance of pre-release status, see [Open Issues](https://victorykit.atlassian.net/issues/?jql=project%20%3D%20HTTPASTE%20AND%20fixVersion%20in%20(1.1.0-beta%2C%201.2.0-beta%2C%201.3.0)), for more information.
|
and [ix.io](http://ix.io/), but focuses on extendability, advanced security, with little to
|
||||||
|
no trade-off to simplicity. It can be hosted through WSGI, CGI, Fast CGI, or
|
||||||
|
as a standalone evaluation server. It offers multiple storage backends, such as
|
||||||
|
a filesystem backend, SQLite backend, MySQL backend, or MongoDB backend.
|
||||||
|
|
||||||
This program offers an HTTP interface for storing public and private data
|
All pastes are being encrypted on the fly and can only be retrieved by an
|
||||||
(a.k.a. pastes), commonly referred to as a pastebin application. It is inspired by [sprunge.us](http://sprunge.us) and [ix.io](http://ix.io/). It can be hosted through WSGI, CGI, Fast
|
authorized user, either through knowing the paste id of a public paste, or
|
||||||
CGI, or as a standalone evaluation server. It offers multiple storage backends,
|
having authentication credentials, as well as the paste id of a private paste.
|
||||||
such as a filesystem backend, SQLite backend, or MySQL backend.
|
This makes httpaste ideal as a pastebin for sensitive environments such as the
|
||||||
|
Tor network. Authentication credentials are created on-the-fly and don’t require a sign-up process.
|
||||||
|
|
||||||
Public data can be accessed through an URL, where as private pastes
|
httpaste supports output formatting for syntax highlighting (powered by
|
||||||
additionally require HTTP basic authentication. Creation of authentication
|
|
||||||
credentials happens on the fly, there is no sign-up process. Public pastes can
|
|
||||||
only be accessed by knowing their paste ids, they are not listed on any index,
|
|
||||||
since it isn’t technically possible (by design).
|
|
||||||
|
|
||||||
All pastes are symetrically encrypted server-side with an HMAC derived key and
|
|
||||||
SHA-256 hashing, a server-side salt and a randomly generated password. Public
|
|
||||||
paste’s passwords are derived from their ids. Private paste’s passwords are
|
|
||||||
randomly generated and stored inside a symetrically encrypted personal
|
|
||||||
database, with the encryption key also being derived through the same HMAC
|
|
||||||
mechanism, where the HTTP basic authentication credentials act as the master
|
|
||||||
password.
|
|
||||||
|
|
||||||
Paste ids, usernames, and any other identifiable attributes are only stored
|
|
||||||
inside storage backends as keyed and salted BLAKE2 hashes.
|
|
||||||
|
|
||||||
The program supports output formatting for syntax highlighting (powered by
|
|
||||||
[pygments](https://pygments.org/)), as well as MIME type output manipulation, and input encoding.
|
[pygments](https://pygments.org/)), as well as MIME type output manipulation, and input encoding.
|
||||||
The program can therefore serve as a minimalist, anonymous object storage for
|
Therefore httpaste can server as an anonymous object storage for small data.
|
||||||
small data.
|
|
||||||
|
|
||||||
Minute-based and ‘burn-after-read’ paste expiration are also supported.
|
Minute-based and ‘burn-after-read’ paste expiration are supported.
|
||||||
|
|
||||||
# Getting Started
|
httpaste focuses on security through cryptography, making it a computationally intensive application.
|
||||||
|
|
||||||
|
# Get Started
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,41 +9,28 @@ httpaste - versatile HTTP pastebin
|
||||||
|
|
||||||
.. image:: _assets/images/favpng_parrot-royalty-free-cartoon.png
|
.. image:: _assets/images/favpng_parrot-royalty-free-cartoon.png
|
||||||
|
|
||||||
.. note::
|
httpaste is a pastebin application for easily pasting and retrieving data over
|
||||||
httpaste is publicly hosted at `httpaste.it`_ and as a hidden Tor service (`<https://paste77ubkwxy4fqezffsmthxdh3xerwi72tlsw2mch7ecjhw2xn7iyd.onion>`_).
|
HTTP from shell environments and web browsers. It is inspired by `sprunge.us`_
|
||||||
Both services are to be considered evaluatory, as long as the source code
|
and `ix.io`_, but focuses on extendability, advanced security, with little to
|
||||||
is in pre-release. Regarding voidance of pre-release status, see `Open Issues`_, for more information.
|
no trade-off to simplicity. It can be hosted through WSGI, CGI, Fast CGI, or
|
||||||
|
as a standalone evaluation server. It offers multiple storage backends, such as
|
||||||
|
a filesystem backend, SQLite backend, MySQL backend, or MongoDB backend.
|
||||||
|
|
||||||
This program offers an HTTP interface for storing public and private data
|
All pastes are being encrypted on the fly and can only be retrieved by an
|
||||||
(a.k.a. pastes), commonly referred to as a pastebin application. It is inspired by `sprunge.us`_ and `ix.io`_. It can be hosted through WSGI, CGI, Fast
|
authorized user, either through knowing the paste id of a public paste, or
|
||||||
CGI, or as a standalone evaluation server. It offers multiple storage backends,
|
having authentication credentials, as well as the paste id of a private paste.
|
||||||
such as a filesystem backend, SQLite backend, or MySQL backend.
|
This makes httpaste ideal as a pastebin for sensitive environments such as the
|
||||||
|
Tor network. Authentication credentials are created on-the-fly and don't require a sign-up process.
|
||||||
|
|
||||||
Public data can be accessed through an URL, where as private pastes
|
httpaste supports output formatting for syntax highlighting (powered by
|
||||||
additionally require HTTP basic authentication. Creation of authentication
|
|
||||||
credentials happens on the fly, there is no sign-up process. Public pastes can
|
|
||||||
only be accessed by knowing their paste ids, they are not listed on any index,
|
|
||||||
since it isn't technically possible (by design).
|
|
||||||
|
|
||||||
All pastes are symetrically encrypted server-side with an HMAC derived key and
|
|
||||||
SHA-256 hashing, a server-side salt and a randomly generated password. Public
|
|
||||||
paste's passwords are derived from their ids. Private paste's passwords are
|
|
||||||
randomly generated and stored inside a symetrically encrypted personal
|
|
||||||
database, with the encryption key also being derived through the same HMAC
|
|
||||||
mechanism, where the HTTP basic authentication credentials act as the master
|
|
||||||
password.
|
|
||||||
|
|
||||||
Paste ids, usernames, and any other identifiable attributes are only stored
|
|
||||||
inside storage backends as keyed and salted BLAKE2 hashes.
|
|
||||||
|
|
||||||
The program supports output formatting for syntax highlighting (powered by
|
|
||||||
`pygments`_), as well as MIME type output manipulation, and input encoding.
|
`pygments`_), as well as MIME type output manipulation, and input encoding.
|
||||||
The program can therefore serve as a minimalist, anonymous object storage for
|
Therefore httpaste can server as an anonymous object storage for small data.
|
||||||
small data.
|
|
||||||
|
|
||||||
Minute-based and 'burn-after-read' paste expiration are also supported.
|
Minute-based and 'burn-after-read' paste expiration are supported.
|
||||||
|
|
||||||
.. include:: guide/getting-started.rst
|
httpaste focuses on security through cryptography, making it a computationally intensive application.
|
||||||
|
|
||||||
|
.. include:: guide/get-started.rst
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -83,7 +70,3 @@ This program uses licensed third-party software.
|
||||||
.. _sprunge.us: http://sprunge.us
|
.. _sprunge.us: http://sprunge.us
|
||||||
.. _pygments: https://pygments.org/
|
.. _pygments: https://pygments.org/
|
||||||
.. _icon: https://favpng.com/png_view/parrot-parrot-royalty-free-cartoon-png/gps7HM42
|
.. _icon: https://favpng.com/png_view/parrot-parrot-royalty-free-cartoon-png/gps7HM42
|
||||||
|
|
||||||
.. _Open Issues: https://victorykit.atlassian.net/issues/?jql=project%20%3D%20HTTPASTE%20AND%20fixVersion%20in%20(1.1.0-beta%2C%201.2.0-beta%2C%201.3.0)
|
|
||||||
|
|
||||||
.. _httpaste.it: http://httpaste.it
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
Getting Started
|
Get Started
|
||||||
===============
|
===========
|
||||||
|
|
||||||
Install
|
Install
|
||||||
"""""""
|
"""""""
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
:caption: Guides
|
:caption: Guides
|
||||||
|
|
||||||
guide/getting-started
|
guide/get-started
|
||||||
guide/advanced-usage
|
guide/advanced-usage
|
||||||
guide/backend
|
guide/backend
|
||||||
guide/cli
|
guide/cli
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = [
|
requires = [
|
||||||
"setuptools",
|
"setuptools",
|
||||||
"wheel",
|
"wheel"
|
||||||
"setuptools-scm[toml]"
|
|
||||||
]
|
]
|
||||||
build-backend = "setuptools.build_meta"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
|
@ -11,5 +10,3 @@ max_line_length = 80
|
||||||
aggressive = 3
|
aggressive = 3
|
||||||
recursive = true
|
recursive = true
|
||||||
in-place = true
|
in-place = true
|
||||||
|
|
||||||
[tool.setuptools_scm]
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
[metadata]
|
[metadata]
|
||||||
name = httpaste-victorykit
|
name = httpaste-victorykit
|
||||||
|
version = 1.0.1-alpha
|
||||||
author = Tiara Rodney
|
author = Tiara Rodney
|
||||||
author_email = t.rodney@victoryk.it
|
author_email = t.rodney@victoryk.it
|
||||||
description = a versatile HTTP pastebin
|
description = a versatile HTTP pastebin
|
||||||
|
|
@ -36,8 +37,3 @@ console_scripts =
|
||||||
|
|
||||||
[options.packages.find]
|
[options.packages.find]
|
||||||
where = src
|
where = src
|
||||||
|
|
||||||
[options.package_data]
|
|
||||||
* =
|
|
||||||
*.json
|
|
||||||
*.sql
|
|
||||||
|
|
@ -143,8 +143,6 @@ from inspect import isclass
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
from ast import literal_eval
|
from ast import literal_eval
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from os import environ
|
|
||||||
from importlib.resources import path as resource_path
|
|
||||||
|
|
||||||
from connexion import FlaskApp
|
from connexion import FlaskApp
|
||||||
from connexion.resolver import RestyResolver
|
from connexion.resolver import RestyResolver
|
||||||
|
|
@ -160,7 +158,7 @@ from httpaste.helper.http import (
|
||||||
UnauthorizedError)
|
UnauthorizedError)
|
||||||
|
|
||||||
|
|
||||||
CONFIGPATH_ENVIRON = 'HTTPASTE_CONFIGPATH'
|
CONFIGPATH_ENVIRON = 'HTTPASTE_CONFIG'
|
||||||
|
|
||||||
|
|
||||||
def get_sanitized_config_charset(charset: str):
|
def get_sanitized_config_charset(charset: str):
|
||||||
|
|
@ -200,17 +198,17 @@ class ServerConfig:
|
||||||
bind_address = None
|
bind_address = None
|
||||||
|
|
||||||
|
|
||||||
def get_config_path(var_name: str = CONFIGPATH_ENVIRON):
|
def get_config_path(environ: str = CONFIGPATH_ENVIRON):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
return environ[var_name]
|
return os.environ[environ]
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
|
|
||||||
raise ConfigError(
|
raise ConfigError(
|
||||||
f'environment variable \'{var_name}\' not set.') from e
|
'environment variable \'{environ}\' not set.') from e
|
||||||
|
|
||||||
|
|
||||||
def load_config(path: str) -> Tuple[Config, ServerConfig]:
|
def load_config(path: str) -> Tuple[Config, ServerConfig]:
|
||||||
|
|
@ -302,16 +300,13 @@ def get_flask_app(
|
||||||
|
|
||||||
options = {"swagger_ui": server_config.swagger_ui}
|
options = {"swagger_ui": server_config.swagger_ui}
|
||||||
|
|
||||||
#context manager returns a pathlib.Path object
|
application = FlaskApp(__name__, specification_dir='schema/')
|
||||||
with resource_path('httpaste.schema', 'httpaste.openapi.json') as path:
|
|
||||||
|
|
||||||
application = FlaskApp(__name__, specification_dir=path.parent)
|
application.add_api(
|
||||||
|
'httpaste.openapi.json',
|
||||||
application.add_api(
|
options=options,
|
||||||
path.name,
|
resolver=RestyResolver('httpaste.controller')
|
||||||
options=options,
|
)
|
||||||
resolver=RestyResolver('httpaste.controller')
|
|
||||||
)
|
|
||||||
|
|
||||||
for err_cls in [
|
for err_cls in [
|
||||||
BadRequestError,
|
BadRequestError,
|
||||||
|
|
@ -327,14 +322,6 @@ def get_flask_app(
|
||||||
with application.app.app_context():
|
with application.app.app_context():
|
||||||
application.app.httpaste = config
|
application.app.httpaste = config
|
||||||
|
|
||||||
#add header for browsers to present a sign-in prompt
|
|
||||||
@application.app.after_request
|
|
||||||
def rewrite_forbidden_request(response):
|
|
||||||
|
|
||||||
if response.status_code in [401]:
|
|
||||||
response.headers['WWW-Authenticate'] = 'Basic realm="private"'
|
|
||||||
return response
|
|
||||||
|
|
||||||
return application
|
return application
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
"""
|
"""
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
from importlib.resources import open_text
|
|
||||||
|
|
||||||
|
|
||||||
def _this_dir(basename: str) -> str:
|
def _this_dir(basename: str) -> str:
|
||||||
|
|
@ -21,7 +20,7 @@ def _path_output(path, echo: bool = False) -> str:
|
||||||
return path
|
return path
|
||||||
else:
|
else:
|
||||||
|
|
||||||
with open_text('httpaste', path) as fh:
|
with open(path, 'r') as fh:
|
||||||
|
|
||||||
return fh.read()
|
return fh.read()
|
||||||
|
|
||||||
|
|
@ -52,21 +51,21 @@ def command_wsgi(**kwargs):
|
||||||
"""get WSGI script
|
"""get WSGI script
|
||||||
"""
|
"""
|
||||||
|
|
||||||
print(_path_output('wsgi.py', kwargs.get('echo')))
|
print(_path_output(_this_dir('wsgi.py'), kwargs.get('echo')))
|
||||||
|
|
||||||
|
|
||||||
def command_cgi(**kwargs):
|
def command_cgi(**kwargs):
|
||||||
"""get CGI script
|
"""get CGI script
|
||||||
"""
|
"""
|
||||||
|
|
||||||
print(_path_output('cgi.py', kwargs.get('echo')))
|
print(_path_output(_this_dir('cgi.py'), kwargs.get('echo')))
|
||||||
|
|
||||||
|
|
||||||
def command_fcgi(**kwargs):
|
def command_fcgi(**kwargs):
|
||||||
"""get FastCGI script
|
"""get FastCGI script
|
||||||
"""
|
"""
|
||||||
|
|
||||||
print(_path_output('fcgi.py', kwargs.get('echo')))
|
print(_path_output(_this_dir('fcgi.py'), kwargs.get('echo')))
|
||||||
|
|
||||||
|
|
||||||
def command_default_config(**kwargs):
|
def command_default_config(**kwargs):
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
from os import path
|
from os import path
|
||||||
from sqlite3 import Connection
|
from sqlite3 import Connection
|
||||||
from time import time
|
from time import time
|
||||||
from importlib.resources import open_text
|
|
||||||
|
|
||||||
|
|
||||||
def load(proto: object, connection: Connection, model_class: type):
|
def load(proto: object, connection: Connection, model_class: type):
|
||||||
|
|
@ -64,7 +63,7 @@ def init(connection: Connection):
|
||||||
|
|
||||||
cur = connection.cursor()
|
cur = connection.cursor()
|
||||||
|
|
||||||
with open_text('httpaste.backend.sqlite', 'paste.sql') as fh:
|
with open(path.join(path.dirname(__file__), 'paste.sql'), 'r') as fh:
|
||||||
|
|
||||||
cur.execute(fh.read())
|
cur.execute(fh.read())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
from os import path
|
from os import path
|
||||||
from sqlite3 import Connection
|
from sqlite3 import Connection
|
||||||
from httpaste.model import User
|
from httpaste.model import User
|
||||||
from importlib.resources import open_text
|
|
||||||
|
|
||||||
|
|
||||||
def load(proto: User, connection: Connection):
|
def load(proto: User, connection: Connection):
|
||||||
|
|
@ -49,7 +48,7 @@ def init(connection: Connection):
|
||||||
|
|
||||||
cur = connection.cursor()
|
cur = connection.cursor()
|
||||||
|
|
||||||
with open_text('httpaste.backend.sqlite', 'user.sql') as fh:
|
with open(path.join(path.dirname(__file__), 'user.sql'), 'r') as fh:
|
||||||
|
|
||||||
cur.execute(fh.read())
|
cur.execute(fh.read())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,6 @@
|
||||||
from random import choice
|
from random import choice
|
||||||
from base64 import b64decode
|
from base64 import b64decode
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
from tempfile import mkdtemp
|
|
||||||
from pathlib import Path
|
|
||||||
from contextlib import contextmanager
|
|
||||||
|
|
||||||
|
|
||||||
class DecodeError(Exception):
|
class DecodeError(Exception):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -161,15 +161,6 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$ref": "#/components/parameters/syntax"
|
"$ref": "#/components/parameters/syntax"
|
||||||
},
|
|
||||||
{
|
|
||||||
"$ref": "#/components/parameters/format"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$ref": "#/components/parameters/linenos"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$ref": "#/components/parameters/mime"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,6 @@
|
||||||
"""
|
"""
|
||||||
from httpaste import load_config, get_flask_app, get_config_path
|
from httpaste import load_config, get_flask_app, get_config_path
|
||||||
|
|
||||||
config, server_config = load_config(get_config_path())
|
config, server_config = load_config(get_config_path)
|
||||||
|
|
||||||
application = get_flask_app(config, server_config)
|
application = get_flask_app(config, server_config)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue