コミットを比較
10 コミット
647e3a54f1
...
363d4f49a7
作成者 | SHA1 | 日付 |
---|---|---|
Izuru Yakumo | 363d4f49a7 | |
Izuru Yakumo | 66db42e7b3 | |
Izuru Yakumo | d230f9461b | |
Izuru Yakumo | b5079c5d82 | |
Mia Herkt | c2b5e95903 | |
Mia Herkt | c189c47306 | |
Mia Herkt | 3d1facaec3 | |
Mia Herkt | e00866f5e4 | |
jonas-w | 3950f6e8eb | |
Mia Herkt | e1e99957b6 |
|
@ -1,22 +0,0 @@
|
|||
[Unit]
|
||||
Description=Prune 0x0 files
|
||||
After=remote-fs.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
User=nullptr
|
||||
WorkingDirectory=/path/to/0x0
|
||||
BindPaths=/path/to/0x0
|
||||
|
||||
Environment=FLASK_APP=fhost
|
||||
ExecStart=/usr/bin/flask prune
|
||||
ProtectProc=noaccess
|
||||
ProtectSystem=strict
|
||||
ProtectHome=tmpfs
|
||||
PrivateTmp=true
|
||||
PrivateUsers=true
|
||||
ProtectKernelLogs=true
|
||||
LockPersonality=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -1,9 +0,0 @@
|
|||
[Unit]
|
||||
Description=Prune 0x0 files
|
||||
|
||||
[Timer]
|
||||
OnCalendar=hourly
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
|
@ -1,22 +0,0 @@
|
|||
[Unit]
|
||||
Description=Scan 0x0 files with ClamAV
|
||||
After=remote-fs.target clamd.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
User=nullptr
|
||||
WorkingDirectory=/path/to/0x0
|
||||
BindPaths=/path/to/0x0
|
||||
|
||||
Environment=FLASK_APP=fhost
|
||||
ExecStart=/usr/bin/flask vscan
|
||||
ProtectProc=noaccess
|
||||
ProtectSystem=strict
|
||||
ProtectHome=tmpfs
|
||||
PrivateTmp=true
|
||||
PrivateUsers=true
|
||||
ProtectKernelLogs=true
|
||||
LockPersonality=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -1,9 +0,0 @@
|
|||
[Unit]
|
||||
Description=Scan 0x0 files with ClamAV
|
||||
|
||||
[Timer]
|
||||
OnCalendar=hourly
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
|
@ -0,0 +1,2 @@
|
|||
FLASK_APP=fhost
|
||||
* * 15 * * flask prune
|
|
@ -0,0 +1,2 @@
|
|||
FLASK_APP=fhost
|
||||
@hourly flask vscan
|
|
@ -0,0 +1,125 @@
|
|||
# 「null:ポインタ」
|
||||
|
||||
This is a no-bullshit file hosting and URL shortening service.
|
||||
Use with uWSGI.
|
||||
|
||||
# Configuration
|
||||
|
||||
To configure 0x0a, copy `instance/config.example.py` to
|
||||
`instance/config.py`, then edit it. Resonable defaults are set, but
|
||||
there\'s a couple options you\'ll need to change before running 0x0 for
|
||||
the first time.
|
||||
|
||||
By default, the configuration is stored in the Flask instance directory.
|
||||
Normally, this is in [./instance]{.title-ref}, but it might be different
|
||||
for your system. For details, see [the Flask
|
||||
documentation](https://flask.palletsprojects.com/en/2.0.x/config/#instance-folders).
|
||||
|
||||
To customize the home and error pages, simply create a `templates`
|
||||
directory in your instance directory and copy any templates you want to
|
||||
modify there.
|
||||
|
||||
If you are running nginx, you should use the `X-Accel-Redirect` header.
|
||||
To make it work, include this in your nginx config's `server` block:
|
||||
|
||||
location /up {
|
||||
internal;
|
||||
}
|
||||
|
||||
where `/up` is whatever you've configured as `FHOST_STORAGE_PATH`.
|
||||
|
||||
For all other servers, set `FHOST_USE_X_ACCEL_REDIRECT` to `False` and
|
||||
`USE_X_SENDFILE` to `True`, assuming your server supports this.
|
||||
Otherwise, Flask will serve the file with chunked encoding, which has
|
||||
several downsides, one of them being that range requests will not work.
|
||||
This is a problem for example when streaming media files: It won't be
|
||||
possible to seek, and some ISOBMFF (MP4) files will not play at all.
|
||||
|
||||
To make files expire, simply run `FLASK_APP=fhost flask prune` every now
|
||||
and then. You can use the provided crontab files for this.
|
||||
|
||||
Make sure to edit them to match your system configuration, assuming
|
||||
you have read `crontab(5)` on a sane OS.
|
||||
|
||||
Before running the service for the first time and every time you update
|
||||
it from this git repository, run `FLASK_APP=fhost flask db upgrade`.
|
||||
|
||||
# Moderation UI
|
||||
|
||||
![image](modui.webp){height="300px"}
|
||||
|
||||
0x0a features a TUI program for file moderation. With it, you can view a
|
||||
list of uploaded files, as well as extended information on them. It
|
||||
allows you to take actions like removing files temporarily or
|
||||
permanently, as well as blocking IP addresses and associated files.
|
||||
|
||||
If a sufficiently recent version of python-mpv with libmpv is present
|
||||
and your terminal supports it, you also get graphical file previews,
|
||||
including video playback. Upstream mpv currently supports sixels and the
|
||||
[kitty graphics protocol](https://sw.kovidgoyal.net/kitty/graphics-protocol/). For this
|
||||
to work, set the `MOD_PREVIEW_PROTO` option in `instance/config.py`.
|
||||
|
||||
Requirements:
|
||||
|
||||
* [Textual](https://textual.textualize.io/)
|
||||
|
||||
Optional:
|
||||
|
||||
* [python-mpv](https://github.com/jaseg/python-mpv) (graphical
|
||||
previews)
|
||||
* [PyAV](https://github.com/PyAV-Org/PyAV) (information on multimedia
|
||||
files)
|
||||
* [PyMuPDF](https://github.com/pymupdf/PyMuPDF) (previews and file
|
||||
information for PDF, XPS, EPUB, MOBI and FB2)
|
||||
* [libarchive-c](https://github.com/Changaco/python-libarchive-c)
|
||||
(archive content listing)
|
||||
|
||||
** Note: [Mosh](https://mosh.org/) currently does not support sixels or kitty
|
||||
graphics.
|
||||
|
||||
** Hint
|
||||
You may need to set the `COLORTERM` environment variable to `truecolor`.
|
||||
|
||||
** Tip
|
||||
Using compression with SSH (`-C` option) can significantly reduce the
|
||||
bandwidth requirements for graphics.
|
||||
|
||||
# NSFW Detection
|
||||
|
||||
0x0a supports classification of NSFW content via Yahoo's open\_nsfw Caffe
|
||||
neural network model. This works for images and video files and requires
|
||||
the following:
|
||||
|
||||
- Caffe Python module (built for Python 3)
|
||||
- [PyAV](https://github.com/PyAV-Org/PyAV)
|
||||
|
||||
# Virus Scanning
|
||||
|
||||
0x0 can scan its files with ClamAV's daemon. As this can take a long
|
||||
time for larger files, this does not happen immediately but instead
|
||||
every time you run the `vscan` command. It is recommended to configure a
|
||||
systemd timer or cronjob to do this periodically. Examples are included:
|
||||
|
||||
0x0a-vscan.crontab
|
||||
|
||||
Remember to adjust your size limits in clamd.conf, including
|
||||
`StreamMaxLength`!
|
||||
|
||||
This feature requires the [clamd
|
||||
module](https://pypi.org/project/clamd/).
|
||||
|
||||
# Network Security Considerations
|
||||
|
||||
Keep in mind that 0x0a can fetch files from URLs. This includes your
|
||||
local network! You should take precautions so that this feature cannot
|
||||
be abused. 0x0a does not (yet) have a way to filter remote URLs, but on
|
||||
Linux, you can use firewall rules and/or namespaces. This is less
|
||||
error-prone anyway.
|
||||
|
||||
For instance, if you are using the excellent
|
||||
[FireHOL](https://firehol.org/), it's very easy to create a group on
|
||||
your system and use it as a condition in your firewall rules. You would
|
||||
then run the application server under that group.
|
||||
|
||||
# Credits
|
||||
* All the ASCII art used on the templates was taken from https://www.asciiart.eu/
|
134
README.rst
134
README.rst
|
@ -1,134 +0,0 @@
|
|||
The Null Pointer
|
||||
================
|
||||
|
||||
This is a no-bullshit file hosting and URL shortening service that also runs
|
||||
`0x0.st <https://0x0.st>`_. Use with uWSGI.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
To configure 0x0, copy ``instance/config.example.py`` to ``instance/config.py``, then edit
|
||||
it. Resonable defaults are set, but there's a couple options you'll need to change
|
||||
before running 0x0 for the first time.
|
||||
|
||||
By default, the configuration is stored in the Flask instance directory.
|
||||
Normally, this is in `./instance`, but it might be different for your system.
|
||||
For details, see
|
||||
`the Flask documentation <https://flask.palletsprojects.com/en/2.0.x/config/#instance-folders>`_.
|
||||
|
||||
To customize the home and error pages, simply create a ``templates`` directory
|
||||
in your instance directory and copy any templates you want to modify there.
|
||||
|
||||
If you are running nginx, you should use the ``X-Accel-Redirect`` header.
|
||||
To make it work, include this in your nginx config’s ``server`` block::
|
||||
|
||||
location /up {
|
||||
internal;
|
||||
}
|
||||
|
||||
where ``/up`` is whatever you’ve configured as ``FHOST_STORAGE_PATH``.
|
||||
|
||||
For all other servers, set ``FHOST_USE_X_ACCEL_REDIRECT`` to ``False`` and
|
||||
``USE_X_SENDFILE`` to ``True``, assuming your server supports this.
|
||||
Otherwise, Flask will serve the file with chunked encoding, which has several
|
||||
downsides, one of them being that range requests will not work. This is a
|
||||
problem for example when streaming media files: It won’t be possible to seek,
|
||||
and some ISOBMFF (MP4) files will not play at all.
|
||||
|
||||
To make files expire, simply run ``FLASK_APP=fhost flask prune`` every
|
||||
now and then. You can use the provided systemd unit files for this::
|
||||
|
||||
0x0-prune.service
|
||||
0x0-prune.timer
|
||||
|
||||
Make sure to edit them to match your system configuration. In particular,
|
||||
set the user and paths in ``0x0-prune.service``.
|
||||
|
||||
Before running the service for the first time and every time you update it
|
||||
from this git repository, run ``FLASK_APP=fhost flask db upgrade``.
|
||||
|
||||
|
||||
Moderation UI
|
||||
-------------
|
||||
|
||||
.. image:: modui.webp
|
||||
:height: 300
|
||||
|
||||
0x0 features a TUI program for file moderation. With it, you can view a list
|
||||
of uploaded files, as well as extended information on them. It allows you to
|
||||
take actions like removing files temporarily or permanently, as well as
|
||||
blocking IP addresses and associated files.
|
||||
|
||||
If a sufficiently recent version of python-mpv with libmpv is present and
|
||||
your terminal supports it, you also get graphical file previews, including
|
||||
video playback. Upstream mpv currently supports sixels and the
|
||||
`kitty graphics protocol <https://sw.kovidgoyal.net/kitty/graphics-protocol/>`_.
|
||||
For this to work, set the ``MOD_PREVIEW_PROTO`` option in ``instance/config.py``.
|
||||
|
||||
Requirements:
|
||||
|
||||
* `Textual <https://textual.textualize.io/>`_
|
||||
|
||||
Optional:
|
||||
|
||||
* `python-mpv <https://github.com/jaseg/python-mpv>`_
|
||||
(graphical previews)
|
||||
* `PyAV <https://github.com/PyAV-Org/PyAV>`_
|
||||
(information on multimedia files)
|
||||
* `PyMuPDF <https://github.com/pymupdf/PyMuPDF>`_
|
||||
(previews and file information for PDF, XPS, EPUB, MOBI and FB2)
|
||||
* `libarchive-c <https://github.com/Changaco/python-libarchive-c>`_
|
||||
(archive content listing)
|
||||
|
||||
.. note::
|
||||
`Mosh <https://mosh.org/>`_ currently does not support sixels or kitty graphics.
|
||||
|
||||
.. hint::
|
||||
You may need to set the ``COLORTERM`` environment variable to
|
||||
``truecolor``.
|
||||
|
||||
.. tip::
|
||||
Using compression with SSH (``-C`` option) can significantly
|
||||
reduce the bandwidth requirements for graphics.
|
||||
|
||||
|
||||
NSFW Detection
|
||||
--------------
|
||||
|
||||
0x0 supports classification of NSFW content via Yahoo’s open_nsfw Caffe
|
||||
neural network model. This works for images and video files and requires
|
||||
the following:
|
||||
|
||||
* Caffe Python module (built for Python 3)
|
||||
* `PyAV <https://github.com/PyAV-Org/PyAV>`_
|
||||
|
||||
|
||||
Virus Scanning
|
||||
--------------
|
||||
|
||||
0x0 can scan its files with ClamAV’s daemon. As this can take a long time
|
||||
for larger files, this does not happen immediately but instead every time
|
||||
you run the ``vscan`` command. It is recommended to configure a systemd
|
||||
timer or cronjob to do this periodically. Examples are included::
|
||||
|
||||
0x0-vscan.service
|
||||
0x0-vscan.timer
|
||||
|
||||
Remember to adjust your size limits in clamd.conf, including
|
||||
``StreamMaxLength``!
|
||||
|
||||
This feature requires the `clamd module <https://pypi.org/project/clamd/>`_.
|
||||
|
||||
|
||||
Network Security Considerations
|
||||
-------------------------------
|
||||
|
||||
Keep in mind that 0x0 can fetch files from URLs. This includes your local
|
||||
network! You should take precautions so that this feature cannot be abused.
|
||||
0x0 does not (yet) have a way to filter remote URLs, but on Linux, you can
|
||||
use firewall rules and/or namespaces. This is less error-prone anyway.
|
||||
|
||||
For instance, if you are using the excellent `FireHOL <https://firehol.org/>`_,
|
||||
it’s very easy to create a group on your system and use it as a condition
|
||||
in your firewall rules. You would then run the application server under that
|
||||
group.
|
|
@ -0,0 +1,13 @@
|
|||
[uwsgi]
|
||||
uid = nullptr
|
||||
master = true
|
||||
processes = 10
|
||||
socket = socket
|
||||
chmod-socket = 664
|
||||
vacuum = true
|
||||
file = fhost.py
|
||||
plugins = python
|
||||
chdir = /path/to/0x0
|
||||
callable = app
|
||||
[nullptr]
|
||||
timeshift = 0
|
25
fhost.py
25
fhost.py
|
@ -106,6 +106,7 @@ db = SQLAlchemy(app)
|
|||
migrate = Migrate(app, db)
|
||||
|
||||
class URL(db.Model):
|
||||
__tablename__ = "URL"
|
||||
id = db.Column(db.Integer, primary_key = True)
|
||||
url = db.Column(db.UnicodeText, unique = True)
|
||||
|
||||
|
@ -134,6 +135,7 @@ class File(db.Model):
|
|||
ext = db.Column(db.UnicodeText)
|
||||
mime = db.Column(db.UnicodeText)
|
||||
addr = db.Column(db.UnicodeText)
|
||||
ua = db.Column(db.UnicodeText)
|
||||
removed = db.Column(db.Boolean, default=False)
|
||||
nsfw_score = db.Column(db.Float)
|
||||
expiration = db.Column(db.BigInteger)
|
||||
|
@ -142,11 +144,12 @@ class File(db.Model):
|
|||
last_vscan = db.Column(db.DateTime)
|
||||
size = db.Column(db.BigInteger)
|
||||
|
||||
def __init__(self, sha256, ext, mime, addr, expiration, mgmt_token):
|
||||
def __init__(self, sha256, ext, mime, addr, ua, expiration, mgmt_token):
|
||||
self.sha256 = sha256
|
||||
self.ext = ext
|
||||
self.mime = mime
|
||||
self.addr = addr
|
||||
self.ua = ua
|
||||
self.expiration = expiration
|
||||
self.mgmt_token = mgmt_token
|
||||
|
||||
|
@ -211,7 +214,7 @@ class File(db.Model):
|
|||
Any value greater that the longest allowed file lifespan will be rounded down to that
|
||||
value.
|
||||
"""
|
||||
def store(file_, requested_expiration: typing.Optional[int], addr, secret: bool):
|
||||
def store(file_, requested_expiration: typing.Optional[int], addr, ua, secret: bool):
|
||||
data = file_.read()
|
||||
digest = sha256(data).hexdigest()
|
||||
|
||||
|
@ -247,8 +250,10 @@ class File(db.Model):
|
|||
if not ext:
|
||||
if gmime in app.config["FHOST_EXT_OVERRIDE"]:
|
||||
ext = app.config["FHOST_EXT_OVERRIDE"][gmime]
|
||||
elif guess:
|
||||
ext = guess
|
||||
else:
|
||||
ext = guess_extension(gmime)
|
||||
ext = ""
|
||||
|
||||
return ext[:app.config["FHOST_MAX_EXT_LENGTH"]] or ".bin"
|
||||
|
||||
|
@ -275,9 +280,10 @@ class File(db.Model):
|
|||
mime = get_mime()
|
||||
ext = get_ext(mime)
|
||||
mgmt_token = secrets.token_urlsafe()
|
||||
f = File(digest, ext, mime, addr, expiration, mgmt_token)
|
||||
f = File(digest, ext, mime, addr, ua, expiration, mgmt_token)
|
||||
|
||||
f.addr = addr
|
||||
f.ua = ua
|
||||
|
||||
if isnew:
|
||||
f.secret = None
|
||||
|
@ -365,11 +371,11 @@ requested_expiration can be:
|
|||
Any value greater that the longest allowed file lifespan will be rounded down to that
|
||||
value.
|
||||
"""
|
||||
def store_file(f, requested_expiration: typing.Optional[int], addr, secret: bool):
|
||||
def store_file(f, requested_expiration: typing.Optional[int], addr, ua, secret: bool):
|
||||
if in_upload_bl(addr):
|
||||
return "Your host is blocked from uploading files.\n", 451
|
||||
|
||||
sf, isnew = File.store(f, requested_expiration, addr, secret)
|
||||
sf, isnew = File.store(f, requested_expiration, addr, ua, secret)
|
||||
|
||||
response = make_response(sf.geturl())
|
||||
response.headers["X-Expires"] = sf.expiration
|
||||
|
@ -379,7 +385,7 @@ def store_file(f, requested_expiration: typing.Optional[int], addr, secret: boo
|
|||
|
||||
return response
|
||||
|
||||
def store_url(url, addr, secret: bool):
|
||||
def store_url(url, addr, ua, secret: bool):
|
||||
if is_fhost_url(url):
|
||||
abort(400)
|
||||
|
||||
|
@ -400,7 +406,7 @@ def store_url(url, addr, secret: bool):
|
|||
|
||||
f = urlfile(read=r.raw.read, content_type=r.headers["content-type"], filename="")
|
||||
|
||||
return store_file(f, None, addr, secret)
|
||||
return store_file(f, None, addr, ua, secret)
|
||||
else:
|
||||
abort(413)
|
||||
else:
|
||||
|
@ -495,6 +501,7 @@ def fhost():
|
|||
request.files["file"],
|
||||
int(request.form["expires"]),
|
||||
request.remote_addr,
|
||||
request.user_agent.string,
|
||||
secret
|
||||
)
|
||||
except ValueError:
|
||||
|
@ -506,12 +513,14 @@ def fhost():
|
|||
request.files["file"],
|
||||
None,
|
||||
request.remote_addr,
|
||||
request.user_agent.string,
|
||||
secret
|
||||
)
|
||||
elif "url" in request.form:
|
||||
return store_url(
|
||||
request.form["url"],
|
||||
request.remote_addr,
|
||||
request.user_agent.string,
|
||||
secret
|
||||
)
|
||||
elif "shorten" in request.form:
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
"""Store user agent string with files
|
||||
|
||||
Revision ID: dd0766afb7d2
|
||||
Revises: 30bfe33aa328
|
||||
Create Date: 2023-03-29 07:18:49.113200
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'dd0766afb7d2'
|
||||
down_revision = '30bfe33aa328'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('file', schema=None) as batch_op:
|
||||
batch_op.add_column(sa.Column('ua', sa.UnicodeText(), nullable=True))
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('file', schema=None) as batch_op:
|
||||
batch_op.drop_column('ua')
|
||||
|
||||
# ### end Alembic commands ###
|
8
mod.py
8
mod.py
|
@ -26,6 +26,7 @@ class NullptrMod(Screen):
|
|||
("f4", "filter(4, 'Filter extension:')", "Filter Ext."),
|
||||
("f5", "refresh", "Refresh"),
|
||||
("f6", "filter_clear", "Clear filter"),
|
||||
("f7", "filter(5, 'Filter user agent:')", "Filter UA"),
|
||||
("r", "remove_file(False)", "Remove file"),
|
||||
("ctrl+r", "remove_file(True)", "Ban file"),
|
||||
("p", "ban_ip(False)", "Ban IP"),
|
||||
|
@ -60,6 +61,7 @@ class NullptrMod(Screen):
|
|||
case 2: finput.value = self.current_file.addr
|
||||
case 3: finput.value = self.current_file.mime
|
||||
case 4: finput.value = self.current_file.ext
|
||||
case 5: finput.value = self.current_file.ua or ""
|
||||
|
||||
def on_input_submitted(self, message: Input.Submitted) -> None:
|
||||
self.query_one("#filter_container").display = False
|
||||
|
@ -71,9 +73,10 @@ class NullptrMod(Screen):
|
|||
case 1:
|
||||
try: ftable.query = ftable.base_query.filter(File.id == su.debase(message.value))
|
||||
except ValueError: pass
|
||||
case 2: ftable.query = ftable.base_query.filter(File.addr == message.value)
|
||||
case 2: ftable.query = ftable.base_query.filter(File.addr.like(message.value))
|
||||
case 3: ftable.query = ftable.base_query.filter(File.mime.like(message.value))
|
||||
case 4: ftable.query = ftable.base_query.filter(File.ext.like(message.value))
|
||||
case 5: ftable.query = ftable.base_query.filter(File.ua.like(message.value))
|
||||
else:
|
||||
ftable.query = ftable.base_query
|
||||
|
||||
|
@ -249,9 +252,10 @@ class NullptrMod(Screen):
|
|||
("MIME type:", f.mime),
|
||||
("SHA256 checksum:", f.sha256),
|
||||
("Uploaded by:", Text(f.addr)),
|
||||
("User agent:", Text(f.ua or "")),
|
||||
("Management token:", f.mgmt_token),
|
||||
("Secret:", f.secret),
|
||||
("Is NSFW:", ("Yes" if f.is_nsfw else "No") + f" (Score: {f.nsfw_score:0.4f})"),
|
||||
("Is NSFW:", ("Yes" if f.is_nsfw else "No") + (f" (Score: {f.nsfw_score:0.4f})" if f.nsfw_score else " (Not scanned)")),
|
||||
("Is banned:", "Yes" if f.removed else "No"),
|
||||
("Expires:", time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(File.get_expiration(f.expiration, f.size)/1000)))
|
||||
])
|
||||
|
|
|
@ -1,2 +1,21 @@
|
|||
<!DOCTYPE HTML "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
<title>Unauthorized (401)</title>
|
||||
</head>
|
||||
<body>
|
||||
<pre>
|
||||
/\_/\
|
||||
/\ / o o \
|
||||
//\\ \~(*)~/
|
||||
` \/ ^ /
|
||||
| \|| ||
|
||||
\ '|| ||
|
||||
\)()-())
|
||||
</pre>
|
||||
<p>
|
||||
rm: cannot remove '{{ request.path.split("/")[1] }}': Permission denied
|
||||
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
{% set pid = range(20,100)|random %}
|
||||
<pre>Process {{ pid }} stopped
|
||||
* thread #1: tid = {{ pid }}, {{ "{:#018x}".format(id(g)) }}, name = 'fhost'
|
||||
frame #0:
|
||||
Process {{ pid }} stopped
|
||||
* thread #8: tid = {{ pid }}, {{ "{:#018x}".format(id(request)) }} fhost`get(path='{{ request.path }}') + 27 at fhost.c:139, name = 'fhost/responder', stop reason = invalid address (fault address: 0x30)
|
||||
frame #0: {3:#018x} fhost`get(path='{{ request.path }}') + 27 at fhost.c:139
|
||||
136 get(SrvContext *ctx, const char *path)
|
||||
137 {
|
||||
138 StoredObj *obj = ctx->store->query(shurl_debase(path));
|
||||
-> 139 switch (obj->type) {
|
||||
140 case ObjTypeFile:
|
||||
141 ctx->serve_file_id(obj->id);
|
||||
142 break;
|
||||
(lldb) q</pre>
|
||||
<!DOCTYPE HTML "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>The page you were looking for doesn't exist (404)</title>
|
||||
</head>
|
||||
<body bgcolor="#000000" text="#ffffff" link="#ffffff">
|
||||
<pre>
|
||||
/\_____/\
|
||||
/ o o \ ???
|
||||
( == ^ == )
|
||||
) (
|
||||
( )
|
||||
( ( ) ( ) )
|
||||
(__(__)___(__)__)
|
||||
</pre>
|
||||
<p>
|
||||
These are not the kittens you're looking for. <br>
|
||||
Move along.
|
||||
</p>
|
||||
<a href="/">Go Back?</a>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1 +1,26 @@
|
|||
<!DOCTYPE HTML "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
<title>Length Required (411)</title>
|
||||
</head>
|
||||
<body bgcolor="#000000" text="#ffffff">
|
||||
<pre>
|
||||
,-. _,---._ __ / \
|
||||
/ ) .-' `./ / \
|
||||
( ( ,' `/ /|
|
||||
\ `-" \'\ / |
|
||||
`. , \ \ / |
|
||||
/`. ,'-`----Y |
|
||||
( ; | '
|
||||
| ,-. ,-' | /
|
||||
| | ( | hjw | /
|
||||
) | \ `.___________|/
|
||||
`--' `--'
|
||||
</pre>
|
||||
<p>
|
||||
Could not determine remote file size (no Content-Length in response header; shoot admin).
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
|
@ -1 +1,20 @@
|
|||
<!DOCTYPE HTML "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
<title>Payload too large (413)</title>
|
||||
</head>
|
||||
<body bgcolor="#000000" text="#ffffff">
|
||||
<pre>
|
||||
(:`--..___...-''``-._ |`._
|
||||
```--...--. . `-..__ .`/ _\
|
||||
`\ ' ```--`. />
|
||||
: : : `:`-'
|
||||
`.:. `.._--...___ ``--...__
|
||||
``--..,) ```----....__,) fl (tweeked)
|
||||
</pre>
|
||||
<p>
|
||||
Remote file too large ({{ request.headers["content-length"]|filesizeformat(True) }} > {{ config["MAX_CONTENT_LENGTH"]|filesizeformat(True) }}).
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1 +1,33 @@
|
|||
451 Unavailable For Legal Reasons
|
||||
<!DOCTYPE HTML "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
<title>Unavailable for legal reasons (451)</title>
|
||||
</head>
|
||||
<body>
|
||||
<pre>
|
||||
.___________________________________________________________________________.
|
||||
| |
|
||||
|___________________________________________________________________________|
|
||||
| ! | | | | | |
|
||||
|_____|__,________|___________|______.____}__,________}___________|_____|
|
||||
| | \ \ \ \ \ | | / / / / / | |
|
||||
|_________|___\_,_\___\___\.__|___|___|___|___/___/___/___/___|_________|
|
||||
| | | | \/ ,".). ', \/. ', | | | |
|
||||
|_____|___| |. ' ,'|// / (/ ,. ' ,\( / , | |___|_____|
|
||||
| | ,| '|\/ \| \\,' ,'.' || \\,' .' ,| ' | |
|
||||
|_._______| " ,|' .| \_ |\/ |#\_/#| /_|\_ |#\_/,) ',.|,' |_________|
|
||||
| | | #|(,' ) \\\#\ \##/ ||/ \#\ \###/\ \/ \/.', | | |
|
||||
|_____|__,| || ) | \ |/ /#/ |#( \|\\| |#/ /##( )| \\'/ |___|_____|
|
||||
| | \ |.\\ |\_/#| /#)|##\ \\_/#| |######\ \\/#| | |
|
||||
|_________| /\\_/# |#\##/# boba@gagme.wwa.com #@#\ /#/\ |_____.___|
|
||||
| | | / ##/# ##\/#@####@@###V###\/#@####@@#Y### \ | | |
|
||||
|___._|___| / :Y##@@##@##@@###@@@###@##@@###@@@###@####: \ |___|_____|
|
||||
| | / :;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;: \ | |
|
||||
|_________|/ :::::::::::::::::::::::::::::::::::::::: \|_________|
|
||||
</pre>
|
||||
<p>
|
||||
That's too bad.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,69 +1,38 @@
|
|||
<pre>
|
||||
THE NULL POINTER
|
||||
================
|
||||
<!DOCTYPE HTML "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>0x0a 「null:ポインタ」</title>
|
||||
</head>
|
||||
<body bgcolor="#000000">
|
||||
<br><br><table border="2" cellpadding="12" cellspacing="0" bgcolor="#ffffff" align="center">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<h1>「null:ポインタ」</h1>
|
||||
</td>
|
||||
<td>
|
||||
<h2>File upload</h2>
|
||||
<center>
|
||||
<p>
|
||||
{% set fhost_url = url_for("fhost", _external=True).rstrip("/") %}
|
||||
HTTP POST files here:
|
||||
curl -F'file=@yourfile.png' {{ fhost_url }}
|
||||
You can also POST remote URLs:
|
||||
curl -F'url=http://example.com/image.jpg' {{ fhost_url }}
|
||||
If you don't want the resulting URL to be easy to guess:
|
||||
curl -F'file=@yourfile.png' -Fsecret= {{ fhost_url }}
|
||||
curl -F'url=http://example.com/image.jpg' -Fsecret= {{ fhost_url }}
|
||||
Or you can shorten URLs:
|
||||
curl -F'shorten=http://example.com/some/long/url' {{ fhost_url }}
|
||||
|
||||
It is possible to append your own file name to the URL:
|
||||
{{ fhost_url }}/aaa.jpg/image.jpeg
|
||||
|
||||
File URLs are valid for at least 30 days and up to a year (see below).
|
||||
Shortened URLs do not expire.
|
||||
|
||||
Files can be set to expire sooner by adding an "expires" parameter (in hours)
|
||||
curl -F'file=@yourfile.png' -Fexpires=24 {{ fhost_url }}
|
||||
OR by setting "expires" to a timestamp in epoch milliseconds
|
||||
curl -F'file=@yourfile.png' -Fexpires=1681996320000 {{ fhost_url }}
|
||||
|
||||
Expired files won't be removed immediately, but will be removed as part of
|
||||
the next purge.
|
||||
|
||||
Whenever a file that does not already exist or has expired is uploaded,
|
||||
the HTTP response header includes an X-Token field. You can use this
|
||||
to perform management operations on the file.
|
||||
|
||||
To delete the file immediately:
|
||||
curl -Ftoken=token_here -Fdelete= {{ fhost_url }}/abc.txt
|
||||
To change the expiration date (see above):
|
||||
curl -Ftoken=token_here -Fexpires=3 {{ fhost_url }}/abc.txt
|
||||
|
||||
{% set max_size = config["MAX_CONTENT_LENGTH"]|filesizeformat(True) %}
|
||||
Maximum file size: {{ max_size }}
|
||||
Not allowed: {{ config["FHOST_MIME_BLACKLIST"]|join(", ") }}
|
||||
|
||||
|
||||
FILE RETENTION PERIOD
|
||||
---------------------
|
||||
|
||||
retention = min_age + (-max_age + min_age) * pow((file_size / max_size - 1), 3)
|
||||
|
||||
days
|
||||
{{'{: 6}'.format(config.get("FHOST_MAX_EXPIRATION", 31536000000)//86400000)}} | \
|
||||
| \
|
||||
| \
|
||||
| \
|
||||
| \
|
||||
| \
|
||||
| ..
|
||||
| \
|
||||
{{'{: 6.1f}'.format((config.get("FHOST_MIN_EXPIRATION", 2592000000)/2 + config.get("FHOST_MAX_EXPIRATION", 31536000000)/2)/86400000)}} | ----------..-------------------------------------------
|
||||
| ..
|
||||
| \
|
||||
| ..
|
||||
| ...
|
||||
| ..
|
||||
| ...
|
||||
| ....
|
||||
| ......
|
||||
{{'{: 6}'.format(config.get("FHOST_MIN_EXPIRATION", 2592000000)//86400000)}} | ....................
|
||||
0{{ ((config["MAX_CONTENT_LENGTH"]/2)|filesizeformat(True)).split(" ")[0].rjust(27) }}{{ max_size.split(" ")[0].rjust(27) }}
|
||||
{{ max_size.split(" ")[1].rjust(54) }}
|
||||
</pre>
|
||||
<br>
|
||||
<form action="{{ fhost_url }}" method="POST" enctype="multipart/form-data">
|
||||
<input type="file" name="file">
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
Maximum file size: {{ max_size }} <br>
|
||||
Not allowed: {{ config["FHOST_MIME_BLACKLIST"] }} <br>
|
||||
<hr>
|
||||
<h2>URL shortening</h2>
|
||||
<form action="{{ fhost_url}}" method="POST">
|
||||
<input type="text" name="shorten">
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
</p>
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
|
読み込み中…
新しいイシューから参照