mirror of
https://github.com/amigan/rustypaste-pretty.git
synced 2024-11-21 20:09:48 -05:00
Compare commits
31 commits
773932dd85
...
e042821848
Author | SHA1 | Date | |
---|---|---|---|
e042821848 | |||
3789caf68f | |||
|
9ead53097e | ||
|
8359aadec6 | ||
|
bfe78c067e | ||
|
f28fe68ba7 | ||
|
dca8041990 | ||
|
5b45b35a44 | ||
|
c1b47e28c9 | ||
|
b092b0047d | ||
|
00d46b4b21 | ||
|
e3a634b7af | ||
|
9e61cca98e | ||
|
d57ed1125f | ||
|
a415ef60a0 | ||
|
82f1a3207f | ||
|
29ddef8df0 | ||
|
019d1556da | ||
|
ab5e153a4e | ||
|
4a4301ee72 | ||
|
607f07b6e1 | ||
|
9ea7d5de8a | ||
|
4e45b6a20d | ||
|
9fcbb1dfb0 | ||
|
85e0c410d4 | ||
|
ad4c990b13 | ||
|
18ba29e04a | ||
|
5e8ea66256 | ||
|
70085f3ad0 | ||
|
d82e99c128 | ||
|
dc499e402e |
19 changed files with 2264 additions and 334 deletions
|
@ -1,8 +1,8 @@
|
|||
# Directories
|
||||
/.git/
|
||||
/.github/
|
||||
/target/
|
||||
/upload/
|
||||
/shuttle/
|
||||
|
||||
# Files
|
||||
.gitignore
|
||||
|
|
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
|
@ -1,2 +1,3 @@
|
|||
github: orhun
|
||||
patreon: orhunp
|
||||
custom: ["https://www.buymeacoffee.com/orhun"]
|
||||
|
|
15
.github/dependabot.yml
vendored
Normal file
15
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
version: 2
|
||||
updates:
|
||||
# Maintain dependencies for Cargo
|
||||
- package-ecosystem: cargo
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
||||
|
||||
# Maintain dependencies for GitHub Actions
|
||||
- package-ecosystem: github-actions
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
4
.github/workflows/audit.yml
vendored
4
.github/workflows/audit.yml
vendored
|
@ -7,10 +7,10 @@ on:
|
|||
jobs:
|
||||
audit:
|
||||
name: Audit
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v3
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
|
|
8
.github/workflows/cd.yml
vendored
8
.github/workflows/cd.yml
vendored
|
@ -8,13 +8,13 @@ on:
|
|||
jobs:
|
||||
publish-github:
|
||||
name: Publish on GitHub
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
TARGET: [x86_64-unknown-linux-gnu, x86_64-unknown-linux-musl]
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v3
|
||||
- name: Set the release version
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF:11}" >> $GITHUB_ENV
|
||||
- name: Install musl-tools
|
||||
|
@ -57,10 +57,10 @@ jobs:
|
|||
publish-crates-io:
|
||||
name: Publish on crates.io
|
||||
needs: publish-github
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v3
|
||||
- name: Publish
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
|
|
28
.github/workflows/ci.yml
vendored
28
.github/workflows/ci.yml
vendored
|
@ -8,12 +8,12 @@ on:
|
|||
branches:
|
||||
- master
|
||||
schedule:
|
||||
- cron: '0 0 * * 0'
|
||||
- cron: "0 0 * * 0"
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Check
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
|
@ -22,7 +22,7 @@ jobs:
|
|||
profile: minimal
|
||||
override: true
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v3
|
||||
- name: Check the project files
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
|
@ -31,7 +31,7 @@ jobs:
|
|||
|
||||
test:
|
||||
name: Test suite
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
|
@ -39,7 +39,7 @@ jobs:
|
|||
toolchain: stable
|
||||
override: true
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup cargo-tarpaulin
|
||||
run: |
|
||||
curl -s https://api.github.com/repos/xd009642/tarpaulin/releases/latest | \
|
||||
|
@ -49,7 +49,7 @@ jobs:
|
|||
- name: Run tests
|
||||
run: cargo tarpaulin --out Xml --verbose -- --test-threads 1
|
||||
- name: Upload reports to codecov
|
||||
uses: codecov/codecov-action@v1
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
name: code-coverage-report
|
||||
file: cobertura.xml
|
||||
|
@ -60,7 +60,7 @@ jobs:
|
|||
|
||||
fixtures:
|
||||
name: Test fixtures
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
|
@ -69,7 +69,7 @@ jobs:
|
|||
profile: minimal
|
||||
override: true
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v3
|
||||
- name: Build the project
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
|
@ -84,7 +84,7 @@ jobs:
|
|||
|
||||
clippy:
|
||||
name: Lints
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
|
@ -94,7 +94,7 @@ jobs:
|
|||
components: clippy
|
||||
override: true
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v3
|
||||
- name: Check the lints
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
|
@ -103,7 +103,7 @@ jobs:
|
|||
|
||||
rustfmt:
|
||||
name: Formatting
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
|
@ -113,7 +113,7 @@ jobs:
|
|||
components: rustfmt
|
||||
override: true
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v3
|
||||
- name: Check the formatting
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
|
@ -122,10 +122,10 @@ jobs:
|
|||
|
||||
lychee:
|
||||
name: Links
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v3
|
||||
- name: Check the links
|
||||
uses: lycheeverse/lychee-action@v1
|
||||
with:
|
||||
|
|
24
.github/workflows/docker.yml
vendored
24
.github/workflows/docker.yml
vendored
|
@ -15,14 +15,14 @@ on:
|
|||
jobs:
|
||||
docker:
|
||||
name: Docker Build and Push
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
orhunp/rustypaste
|
||||
|
@ -37,10 +37,10 @@ jobs:
|
|||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
|
@ -49,14 +49,14 @@ jobs:
|
|||
|
||||
- name: Login to Docker Hub
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: orhunp
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Login to GHCR
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
|
@ -64,16 +64,24 @@ jobs:
|
|||
|
||||
- name: Build and push
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: ./
|
||||
file: ./Dockerfile
|
||||
platforms: linux/amd64
|
||||
builder: ${{ steps.buildx.outputs.name }}
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
sbom: true
|
||||
provenance: true
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=local,src=/tmp/.buildx-cache
|
||||
cache-to: type=local,dest=/tmp/.buildx-cache
|
||||
|
||||
- name: Scan the image
|
||||
uses: anchore/sbom-action@v0
|
||||
with:
|
||||
image: ghcr.io/${{ github.repository_owner }}/rustypaste/rustypaste
|
||||
|
||||
- name: Image digest
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
|
|
33
.github/workflows/shuttle.yml
vendored
Normal file
33
.github/workflows/shuttle.yml
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
name: Deploy on Shuttle
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
name: Deploy
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
profile: minimal
|
||||
override: true
|
||||
- name: Install cargo-binstall
|
||||
uses: taiki-e/install-action@cargo-binstall
|
||||
- name: Install cargo-shuttle
|
||||
run: cargo binstall -y cargo-shuttle
|
||||
- name: Prepare for deployment
|
||||
shell: bash
|
||||
run: sed -i 's|default = \["rustls"\]|default = \["rustls", "shuttle"\]|g' Cargo.toml
|
||||
- name: Login
|
||||
run: cargo shuttle login --api-key ${{ secrets.SHUTTLE_TOKEN }}
|
||||
- name: Restart
|
||||
run: cargo shuttle project restart
|
||||
- name: Deploy
|
||||
run: cargo shuttle deploy --allow-dirty --no-test
|
99
CHANGELOG.md
99
CHANGELOG.md
|
@ -1,9 +1,58 @@
|
|||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.9.0] - 2023-05-17
|
||||
|
||||
The public instance is now available at [https://rustypaste.shuttleapp.rs](https://rustypaste.shuttleapp.rs) 🚀
|
||||
|
||||
Read the blog post about `rustypaste` and Shuttle deployments: [https://blog.orhun.dev/blazingly-fast-file-sharing](https://blog.orhun.dev/blazingly-fast-file-sharing)
|
||||
|
||||
### Added
|
||||
|
||||
- Deploy on Shuttle.rs
|
||||
- Support setting a default expiry time
|
||||
|
||||
You can now specify a expiry time for uploaded files. For example, if you want all the files to expire after one hour:
|
||||
|
||||
```toml
|
||||
[paste]
|
||||
default_expiry = "1h"
|
||||
```
|
||||
|
||||
- Support overriding the server URL
|
||||
|
||||
If you are using `rustypaste` with a redirect or reverse proxy, it is now possible to set a different URL for the returned results:
|
||||
|
||||
```toml
|
||||
[server]
|
||||
url = "https://rustypaste.shuttleapp.rs"
|
||||
```
|
||||
|
||||
- Add instructions for installing on Alpine Linux
|
||||
|
||||
`rustypaste` is now available in [testing](https://pkgs.alpinelinux.org/packages?name=rustypaste&branch=edge) repositories.
|
||||
|
||||
- Add new crate features
|
||||
|
||||
- `shuttle`: enable an entry point for deploying on Shuttle
|
||||
- `openssl`: use distro OpenSSL (binary size is reduced ~20% in release mode)
|
||||
- `rustls`: use [rustls](https://github.com/rustls/rustls) (enabled as default)
|
||||
|
||||
### Changed
|
||||
|
||||
- Make the default landing page fancier
|
||||
- Generate SBOM attestation for the Docker image
|
||||
|
||||
### Updated
|
||||
|
||||
- Bump dependencies
|
||||
- Update the funding options
|
||||
- Consider donating if you liked `rustypaste`: [https://donate.orhun.dev](https://donate.orhun.dev) 💖
|
||||
|
||||
## [0.8.4] - 2023-01-31
|
||||
|
||||
### Added
|
||||
|
@ -13,18 +62,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- This is useful when e.g. you want to be able to share the link to a file that would play in the browser (like `.mp4`) but also share a link that will auto-download as well.
|
||||
|
||||
## [0.8.3] - 2023-01-30
|
||||
|
||||
### Updated
|
||||
|
||||
- Bump dependencies
|
||||
- Switch to [Rust](https://hub.docker.com/_/rust) image for the Dockerfile
|
||||
- Remove unused `clap` dependency
|
||||
|
||||
## [0.8.2] - 2022-10-04
|
||||
|
||||
### Updated
|
||||
|
||||
- Don't expose version endpoint in default config
|
||||
- Set `expose_version` to `false` in the configuration file
|
||||
|
||||
## [0.8.1] - 2022-10-04
|
||||
|
||||
### Added
|
||||
|
||||
- Add `<server_address>/version` endpoint for retrieving the server version
|
||||
|
||||
```toml
|
||||
|
@ -35,11 +90,14 @@ expose_version=true
|
|||
If `expose_version` entry is not present in the configuration file, `/version` is not exposed. It is recommended to use this feature with authorization enabled.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Replace unmaintained `dotenv` crate with `dotenvy`
|
||||
- Fixes [RUSTSEC-2021-0141](https://rustsec.org/advisories/RUSTSEC-2021-0141.html)
|
||||
|
||||
## [0.8.0] - 2022-10-03
|
||||
|
||||
### Added
|
||||
|
||||
- Support adding a landing page
|
||||
|
||||
You can now specify a landing page text in the configuration file as follows:
|
||||
|
@ -56,6 +114,7 @@ welcome!
|
|||
If the landing page entry is not present in the configuration file, visiting the index page will redirect to the repository.
|
||||
|
||||
### Updated
|
||||
|
||||
- Do not check for duplicate files by default
|
||||
- Set `duplicate_files` to `true` in the configuration file
|
||||
- It is an expensive operation to do on slower hardware and can take an unreasonable amount of time for bigger files
|
||||
|
@ -63,13 +122,17 @@ If the landing page entry is not present in the configuration file, visiting the
|
|||
- Consider supporting me for my open-source work 💖
|
||||
|
||||
## [0.7.1] - 2022-05-21
|
||||
|
||||
### Added
|
||||
|
||||
- Aggressively test everything
|
||||
- Add the missing unit tests for the server endpoints (code coverage is increased to 84%)
|
||||
- Create a custom testing framework (written in Bash) for adding [test fixtures](https://github.com/orhun/rustypaste/tree/master/fixtures)
|
||||
|
||||
## [0.7.0] - 2022-03-26
|
||||
|
||||
### Added
|
||||
|
||||
- Support auto-deletion of expired files
|
||||
|
||||
`rustypaste` can now delete the expired files by itself. To enable this feature, add the following line to the `[paste]` section in the configuration file:
|
||||
|
@ -86,26 +149,33 @@ For users who want to have this feature disabled, there is an alternative [shell
|
|||
- For the installation and usage, see the Arch Linux [PKGBUILD](https://github.com/archlinux/svntogit-community/blob/packages/rustypaste/trunk/PKGBUILD).
|
||||
|
||||
### Updated
|
||||
|
||||
- Upgrade Actix dependencies
|
||||
- `actix-web` is updated to [`4.0.*`](https://github.com/actix/actix-web/blob/master/actix-web/CHANGES.md#401---2022-02-25)
|
||||
- Strip the binaries during automated builds
|
||||
- Size of the Docker image is reduced by ~20%
|
||||
|
||||
### Fixed
|
||||
|
||||
- Prevent invalid attempts of serving directories
|
||||
- This fixes an issue where requesting a directory was possible via e.g. `curl --path-as-is 0.0.0.0:8080/.`
|
||||
- This issue had no security impact (path traversal wasn't possible) since internal server error was returned.
|
||||
|
||||
## [0.6.5] - 2022-03-13
|
||||
|
||||
### Added
|
||||
|
||||
- Add instructions for installing [rustypaste](https://archlinux.org/packages/community/x86_64/rustypaste/) on Arch Linux
|
||||
- `pacman -S rustypaste` 🎉
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix a bug where the use of `CONFIG` environment variable causes a conflict between the configuration file path and `[config]` section
|
||||
|
||||
## [0.6.4] - 2022-03-11
|
||||
|
||||
### Added
|
||||
|
||||
- Support setting the refresh rate for hot-reloading the configuration file.
|
||||
|
||||
```toml
|
||||
|
@ -121,11 +191,14 @@ timeout="30s"
|
|||
```
|
||||
|
||||
### Security
|
||||
|
||||
- Bump [regex crate](https://github.com/rust-lang/regex) to **1.5.5**
|
||||
- Fixes [CVE-2022-24713](https://github.com/advisories/GHSA-m5pq-gvj9-9vr8)
|
||||
|
||||
## [0.6.3] - 2022-02-24
|
||||
|
||||
### Added
|
||||
|
||||
- Support setting the authentication token in the configuration file.
|
||||
- This is an alternative (but not recommended) way of setting up authentication when the use of `AUTH_TOKEN` environment variable is not applicable.
|
||||
|
||||
|
@ -135,28 +208,37 @@ auth_token="hunter2"
|
|||
```
|
||||
|
||||
## [0.6.2] - 2021-12-05
|
||||
|
||||
### Updated
|
||||
|
||||
- Improve the concurrency
|
||||
- Shrink the scope of non-suspendable types (`#[must_not_suspend]`) for dropping them before reaching a suspend point (`.await` call). This avoids possible deadlocks, delays, and situations where `Future`s not implementing `Send`.
|
||||
- Reference: https://rust-lang.github.io/rfcs/3014-must-not-suspend-lint.html
|
||||
|
||||
## [0.6.1] - 2021-11-16
|
||||
|
||||
### Fixed
|
||||
|
||||
- Gracefully handle the hot-reloading errors.
|
||||
- Errors that may occur while locking the [Mutex](https://doc.rust-lang.org/std/sync/struct.Mutex.html) are handled properly hence a single configuration change cannot take down the whole service due to [poisoning](https://doc.rust-lang.org/std/sync/struct.Mutex.html#poisoning).
|
||||
|
||||
## [0.6.0] - 2021-11-07
|
||||
|
||||
### Added
|
||||
|
||||
- Support pasting files from remote URLs (via `remote=` form field)
|
||||
|
||||
- `{server.max_content_length}` is used for download limit
|
||||
- See [README.md#paste-file-from-remote-url](https://github.com/orhun/rustypaste#paste-file-from-remote-url)
|
||||
|
||||
- Hot reload configuration file to apply configuration changes instantly without restarting the server
|
||||
|
||||
### Changed
|
||||
|
||||
- Library: Switch to Rust 2021 edition
|
||||
|
||||
### Security
|
||||
|
||||
- Prevent serving an already expired file
|
||||
|
||||
In the previous versions, it was possible to view an expired file by using the correct extension (timestamp). e.g. `paste.com/expired_file.txt.1630094518049` will serve the file normally although `paste.com/expired_file.txt` says that it is expired. This version fixes this vulnerability by regex-checking the requested file's extension.
|
||||
|
@ -164,7 +246,9 @@ In the previous versions, it was possible to view an expired file by using the c
|
|||
reference: [f078a9afa74f8608ee3f2a6e705159df15915c78](https://github.com/orhun/rustypaste/commit/f078a9afa74f8608ee3f2a6e705159df15915c78)
|
||||
|
||||
## [0.5.0] - 2021-10-12
|
||||
|
||||
### Added
|
||||
|
||||
- Added an entry in the configuration file to disable "duplicate uploads":
|
||||
|
||||
```toml
|
||||
|
@ -176,13 +260,17 @@ duplicate_files = false
|
|||
Under the hood, it checks the SHA256 digest of the uploaded files.
|
||||
|
||||
## [0.4.1] - 2021-09-19
|
||||
|
||||
### Changed
|
||||
|
||||
- Update README.md:
|
||||
- Mention the new standalone tool: [rustypaste-cli](https://github.com/orhun/rustypaste-cli)
|
||||
- Add [installation](https://github.com/orhun/rustypaste#installation) section.
|
||||
|
||||
## [0.4.0] - 2021-08-27
|
||||
|
||||
### Added
|
||||
|
||||
- Support [expiring links](README.md#expiration) (via `expire:` header)
|
||||
- Timestamps are used as extension for expiring files
|
||||
- Expired files can be cleaned up with [this command](README.md#cleaning-up-expired-files)
|
||||
|
@ -190,28 +278,39 @@ Under the hood, it checks the SHA256 digest of the uploaded files.
|
|||
- `{server.upload_path}/oneshot` is used for storage
|
||||
|
||||
## [0.3.1] - 2021-08-10
|
||||
|
||||
### Fixed
|
||||
|
||||
- Switch to [upload-release-action](https://github.com/svenstaro/upload-release-action) for uploading releases
|
||||
|
||||
## [0.3.0] - 2021-08-09
|
||||
|
||||
### Added
|
||||
|
||||
- Support overriding MIME types (config: `mime_override`)
|
||||
- Support blacklisting MIME types (config: `mime_blacklist`)
|
||||
|
||||
## [0.2.0] - 2021-08-04
|
||||
|
||||
### Added
|
||||
|
||||
- Support shortening URLs (via `url=` form field)
|
||||
- `{server.upload_path}/url` is used for storage
|
||||
|
||||
## [0.1.3] - 2021-07-28
|
||||
|
||||
### Fixed
|
||||
|
||||
- Prevent sending empty file name and zero bytes
|
||||
- Prevent path traversal on upload directory ([#2](https://github.com/orhun/rustypaste/issues/2))
|
||||
- Check the content length while reading bytes for preventing OOM ([#1](https://github.com/orhun/rustypaste/issues/1))
|
||||
|
||||
## [0.1.2] - 2021-07-27
|
||||
|
||||
### Changed
|
||||
|
||||
- Update Continuous Deployment workflow to publish Docker images
|
||||
|
||||
## [0.1.1] - 2021-07-27
|
||||
|
||||
Initial release.
|
||||
|
|
2063
Cargo.lock
generated
2063
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
44
Cargo.toml
44
Cargo.toml
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "rustypaste"
|
||||
version = "0.8.4"
|
||||
version = "0.9.0"
|
||||
edition = "2021"
|
||||
description = "A minimal file upload/pastebin service"
|
||||
authors = ["Orhun Parmaksız <orhunparmaksiz@gmail.com>"]
|
||||
|
@ -12,28 +12,46 @@ keywords = ["paste", "pastebin", "upload"]
|
|||
categories = ["web-programming::http-server"]
|
||||
include = ["src/**/*", "Cargo.*", "LICENSE", "README.md", "CHANGELOG.md"]
|
||||
|
||||
[features]
|
||||
default = ["rustls"]
|
||||
openssl = ["actix-web/openssl", "awc/openssl"]
|
||||
rustls = ["actix-web/rustls", "awc/rustls"]
|
||||
shuttle = [
|
||||
"dep:shuttle-actix-web",
|
||||
"dep:shuttle-runtime",
|
||||
"dep:shuttle-static-folder",
|
||||
"dep:tokio",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
actix-web = { version = "4.3.0", features = ["rustls"] }
|
||||
actix-multipart = "0.5.0"
|
||||
actix-web = { version = "4.3.1" }
|
||||
actix-multipart = "0.6.0"
|
||||
actix-files = "0.6.2"
|
||||
awc = { version = "3.1.0", features = ["rustls"] }
|
||||
awc = { version = "3.1.1" }
|
||||
env_logger = "0.10.0"
|
||||
log = "0.4.17"
|
||||
serde = "1.0.152"
|
||||
futures-util = "0.3.26"
|
||||
petname = { version = "1.1.3", default-features = false, features = ["std_rng", "default_dictionary"] }
|
||||
serde = "1.0.163"
|
||||
futures-util = "0.3.28"
|
||||
petname = { version = "1.1.3", default-features = false, features = [
|
||||
"std_rng",
|
||||
"default_dictionary",
|
||||
] }
|
||||
rand = "0.8.5"
|
||||
dotenvy = "0.15.6"
|
||||
dotenvy = "0.15.7"
|
||||
url = "2.3.1"
|
||||
mime = "0.3.16"
|
||||
regex = "1.6.0"
|
||||
mime = "0.3.17"
|
||||
regex = "1.8.1"
|
||||
serde_regex = "1.1.0"
|
||||
lazy-regex = "2.4.1"
|
||||
lazy-regex = "2.5.0"
|
||||
humantime = "2.1.0"
|
||||
humantime-serde = "1.1.1"
|
||||
glob = "0.3.1"
|
||||
ring = "0.16.20"
|
||||
hotwatch = "0.4.5"
|
||||
shuttle-actix-web = { version = "0.16.0", optional = true }
|
||||
shuttle-runtime = { version = "0.16.0", optional = true }
|
||||
shuttle-static-folder = { version = "0.16.0", optional = true }
|
||||
tokio = { version = "1.28.1", optional = true }
|
||||
text-template = "0.1.0"
|
||||
|
||||
[dependencies.config]
|
||||
|
@ -42,11 +60,11 @@ default-features = false
|
|||
features = ["toml", "yaml"]
|
||||
|
||||
[dependencies.byte-unit]
|
||||
version = "4.0.18"
|
||||
version = "4.0.19"
|
||||
features = ["serde"]
|
||||
|
||||
[dependencies.infer]
|
||||
version = "0.12.0"
|
||||
version = "0.13.0"
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -14,9 +14,7 @@ RUN cp target/release/rustypaste build-out/
|
|||
|
||||
FROM scratch
|
||||
WORKDIR /app
|
||||
COPY --from=builder \
|
||||
/app/build-out/rustypaste \
|
||||
/app/config.toml ./
|
||||
COPY --from=builder /app/build-out/rustypaste .
|
||||
ENV SERVER__ADDRESS=0.0.0.0:8000
|
||||
EXPOSE 8000
|
||||
USER 1000:1000
|
||||
|
|
46
README.md
46
README.md
|
@ -1,5 +1,13 @@
|
|||
<a href="https://github.com/orhun/rustypaste"><img src="img/rustypaste_logo.png" width="500"></a>
|
||||
|
||||
[![GitHub Release](https://img.shields.io/github/v/release/orhun/rustypaste?style=flat&labelColor=823213&color=2c2c2c&logo=GitHub&logoColor=white)](https://github.com/orhun/rustypaste/releases)
|
||||
[![Crate Release](https://img.shields.io/crates/v/rustypaste?style=flat&labelColor=823213&color=2c2c2c&logo=Rust&logoColor=white)](https://crates.io/crates/rustypaste/)
|
||||
[![Coverage](https://img.shields.io/codecov/c/gh/orhun/rustypaste?style=flat&labelColor=823213&color=2c2c2c&logo=Codecov&logoColor=white)](https://codecov.io/gh/orhun/rustypaste)
|
||||
[![Continuous Integration](https://img.shields.io/github/actions/workflow/status/orhun/rustypaste/ci.yml?branch=master&style=flat&labelColor=823213&color=2c2c2c&logo=GitHub%20Actions&logoColor=white)](https://github.com/orhun/rustypaste/actions?query=workflow%3A%22Continuous+Integration%22)
|
||||
[![Continuous Deployment](https://img.shields.io/github/actions/workflow/status/orhun/rustypaste/cd.yml?style=flat&labelColor=823213&color=2c2c2c&logo=GitHub%20Actions&logoColor=white&label=deploy)](https://github.com/orhun/rustypaste/actions?query=workflow%3A%22Continuous+Deployment%22)
|
||||
[![Docker Builds](https://img.shields.io/github/actions/workflow/status/orhun/rustypaste/docker.yml?style=flat&labelColor=823213&color=2c2c2c&label=docker&logo=Docker&logoColor=white)](https://hub.docker.com/r/orhunp/rustypaste)
|
||||
[![Documentation](https://img.shields.io/docsrs/rustypaste?style=flat&labelColor=823213&color=2c2c2c&logo=Rust&logoColor=white)](https://docs.rs/rustypaste/)
|
||||
|
||||
**Rustypaste-pretty** is a minimal file upload/pastebin service with client side highlighting provided by highlight.js.
|
||||
|
||||
Just add `?pretty` to the end of a link to highlight!
|
||||
|
@ -14,6 +22,8 @@ $ curl https://paste.site.com/safe-toad.txt
|
|||
some text
|
||||
```
|
||||
|
||||
The public instance is available at [https://rustypaste.shuttleapp.rs](https://rustypaste.shuttleapp.rs) 🚀
|
||||
|
||||
## Features
|
||||
|
||||
- File upload & URL shortening & upload from URL
|
||||
|
@ -22,6 +32,7 @@ some text
|
|||
- pet name (e.g. `capital-mosquito.txt`)
|
||||
- alphanumeric string (e.g. `yB84D2Dv.txt`)
|
||||
- supports expiring links
|
||||
- auto-expiration of files (optional)
|
||||
- auto-deletion of expired files (optional)
|
||||
- supports one shot links (can only be viewed once)
|
||||
- guesses MIME types
|
||||
|
@ -55,9 +66,17 @@ cargo install rustypaste
|
|||
pacman -S rustypaste
|
||||
```
|
||||
|
||||
### Alpine Linux
|
||||
|
||||
`rustypaste` is available for [Alpine Edge](https://pkgs.alpinelinux.org/packages?name=rustypaste&branch=edge). It can be installed via [apk](https://wiki.alpinelinux.org/wiki/Alpine_Package_Keeper) after enabling the [testing repository](https://wiki.alpinelinux.org/wiki/Repositories).
|
||||
|
||||
```sh
|
||||
apk add rustypaste
|
||||
```
|
||||
|
||||
### Binary releases
|
||||
|
||||
See the available binaries on [releases](https://github.com/orhun/rustypaste/releases/) page.
|
||||
See the available binaries on the [releases](https://github.com/orhun/rustypaste/releases/) page.
|
||||
|
||||
### Build from source
|
||||
|
||||
|
@ -67,13 +86,34 @@ cd rustypaste/
|
|||
cargo build --release
|
||||
```
|
||||
|
||||
#### Testing
|
||||
#### Feature flags
|
||||
|
||||
- `shuttle`: enable an entry point for deploying on Shuttle
|
||||
- `openssl`: use distro OpenSSL (binary size is reduced ~20% in release mode)
|
||||
- `rustls`: use [rustls](https://github.com/rustls/rustls) (enabled as default)
|
||||
|
||||
To enable a feature for build, pass `--features` flag to `cargo build` command.
|
||||
|
||||
For example, to reuse the OpenSSL present on a distro already:
|
||||
|
||||
```sh
|
||||
cargo build --release --no-default-features --features openssl
|
||||
```
|
||||
|
||||
#### Testing
|
||||
|
||||
##### Unit tests
|
||||
|
||||
```sh
|
||||
# run unit tests
|
||||
cargo test -- --test-threads 1
|
||||
```
|
||||
|
||||
##### Test Fixtures
|
||||
|
||||
```sh
|
||||
./fixtures/test-fixtures.sh
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
The standalone command line tool (`rpaste`) is available [here](https://github.com/orhun/rustypaste-cli).
|
||||
|
|
52
config.toml
52
config.toml
|
@ -1,50 +1,42 @@
|
|||
[config]
|
||||
refresh_rate="1s"
|
||||
refresh_rate = "1s"
|
||||
|
||||
[server]
|
||||
address="127.0.0.1:8020"
|
||||
#url = "https://rustypaste.shuttleapp.rs"
|
||||
#workers=4
|
||||
max_content_length="10MB"
|
||||
upload_path="./upload"
|
||||
timeout="30s"
|
||||
expose_version=false
|
||||
max_content_length = "10MB"
|
||||
upload_path = "./upload"
|
||||
timeout = "30s"
|
||||
expose_version = false
|
||||
style="monokai"
|
||||
landing_page="""Submit files via HTTP POST here:
|
||||
curl -F 'file=@example.txt' <server>"
|
||||
This will return the finished URL.
|
||||
|
||||
The server administrator might remove any pastes that they do not personally
|
||||
want to host.
|
||||
|
||||
If you are the server administrator and want to change this page, just go
|
||||
into your config file and change it! If you change the expiry time, it is
|
||||
recommended that you do.
|
||||
|
||||
Check out the GitHub repository at https://github.com/orhun/rustypaste
|
||||
|
||||
By default, pastes expire every hour. The server admin may or may not have
|
||||
changed this."""
|
||||
landing_page = """
|
||||
┬─┐┬ ┬┌─┐┌┬┐┬ ┬┌─┐┌─┐┌─┐┌┬┐┌─┐
|
||||
├┬┘│ │└─┐ │ └┬┘├─┘├─┤└─┐ │ ├┤
|
||||
┴└─└─┘└─┘ ┴ ┴ ┴ ┴ ┴└─┘ ┴ └─┘
|
||||
"""
|
||||
|
||||
[paste]
|
||||
random_url = { enabled = true, type = "petname", words = 2, separator = "-" }
|
||||
#random_url = { enabled = true, type = "alphanumeric", length = 8 }
|
||||
default_extension = "txt"
|
||||
mime_override = [
|
||||
{ mime = "image/jpeg", regex = "^.*\\.jpg$" },
|
||||
{ mime = "image/png", regex = "^.*\\.png$" },
|
||||
{ mime = "image/svg+xml", regex = "^.*\\.svg$" },
|
||||
{ mime = "video/webm", regex = "^.*\\.webm$" },
|
||||
{ mime = "video/x-matroska", regex = "^.*\\.mkv$" },
|
||||
{ mime = "application/octet-stream", regex = "^.*\\.bin$" },
|
||||
{ mime = "text/plain", regex = "^.*\\.(log|txt|diff)$" },
|
||||
{ mime = "image/jpeg", regex = "^.*\\.jpg$" },
|
||||
{ mime = "image/png", regex = "^.*\\.png$" },
|
||||
{ mime = "image/svg+xml", regex = "^.*\\.svg$" },
|
||||
{ mime = "video/webm", regex = "^.*\\.webm$" },
|
||||
{ mime = "video/x-matroska", regex = "^.*\\.mkv$" },
|
||||
{ mime = "application/octet-stream", regex = "^.*\\.bin$" },
|
||||
{ mime = "text/plain", regex = "^.*\\.(log|txt|diff|sh|rs|toml)$" },
|
||||
]
|
||||
mime_blacklist = [
|
||||
"application/x-dosexec",
|
||||
"application/java-archive",
|
||||
"application/java-vm"
|
||||
"application/x-dosexec",
|
||||
"application/java-archive",
|
||||
"application/java-vm",
|
||||
]
|
||||
|
||||
duplicate_files = true
|
||||
# default_expiry = "1h"
|
||||
delete_expired_files = { enabled = true, interval = "1h" }
|
||||
|
||||
[paste.highlight_override]
|
||||
|
|
53
shuttle/config.toml
Normal file
53
shuttle/config.toml
Normal file
|
@ -0,0 +1,53 @@
|
|||
[config]
|
||||
refresh_rate = "1s"
|
||||
|
||||
[server]
|
||||
address = "127.0.0.1:8000"
|
||||
url = "https://rustypaste.shuttleapp.rs"
|
||||
#workers=4
|
||||
max_content_length = "10MB"
|
||||
upload_path = "./upload"
|
||||
timeout = "30s"
|
||||
expose_version = true
|
||||
landing_page = """
|
||||
┬─┐┬ ┬┌─┐┌┬┐┬ ┬┌─┐┌─┐┌─┐┌┬┐┌─┐
|
||||
├┬┘│ │└─┐ │ └┬┘├─┘├─┤└─┐ │ ├┤
|
||||
┴└─└─┘└─┘ ┴ ┴ ┴ ┴ ┴└─┘ ┴ └─┘
|
||||
|
||||
Submit files via HTTP POST here:
|
||||
|
||||
curl -F 'file=@example.txt' https://rustypaste.shuttleapp.rs
|
||||
|
||||
This will return the URL of the uploaded file.
|
||||
|
||||
Pastes expire every hour. Uploaded files might not be persistent.
|
||||
|
||||
Check out the GitHub repository: https://github.com/orhun/rustypaste
|
||||
Command line tool is available : https://github.com/orhun/rustypaste-cli
|
||||
|
||||
If you liked this, consider supporting me: https://donate.orhun.dev <3
|
||||
|
||||
🦀
|
||||
"""
|
||||
|
||||
[paste]
|
||||
# random_url = { enabled = true, type = "petname", words = 2, separator = "-" }
|
||||
random_url = { enabled = true, type = "alphanumeric", length = 6 }
|
||||
default_extension = "txt"
|
||||
mime_override = [
|
||||
{ mime = "image/jpeg", regex = "^.*\\.jpg$" },
|
||||
{ mime = "image/png", regex = "^.*\\.png$" },
|
||||
{ mime = "image/svg+xml", regex = "^.*\\.svg$" },
|
||||
{ mime = "video/webm", regex = "^.*\\.webm$" },
|
||||
{ mime = "video/x-matroska", regex = "^.*\\.mkv$" },
|
||||
{ mime = "application/octet-stream", regex = "^.*\\.bin$" },
|
||||
{ mime = "text/plain", regex = "^.*\\.(log|txt|diff|sh|kt|rs|toml)$" },
|
||||
]
|
||||
mime_blacklist = [
|
||||
"application/x-dosexec",
|
||||
"application/java-archive",
|
||||
"application/java-vm",
|
||||
]
|
||||
duplicate_files = true
|
||||
default_expiry = "1h"
|
||||
delete_expired_files = { enabled = true, interval = "1h" }
|
|
@ -31,6 +31,8 @@ pub struct Settings {
|
|||
pub struct ServerConfig {
|
||||
/// The socket address to bind.
|
||||
pub address: String,
|
||||
/// URL that can be used to access the server externally.
|
||||
pub url: Option<String>,
|
||||
/// Number of workers to start.
|
||||
pub workers: Option<usize>,
|
||||
/// Maximum content length.
|
||||
|
@ -63,8 +65,11 @@ pub struct PasteConfig {
|
|||
/// Media type blacklist.
|
||||
#[serde(default)]
|
||||
pub mime_blacklist: Vec<String>,
|
||||
/// Allow duplicate uploads
|
||||
/// Allow duplicate uploads.
|
||||
pub duplicate_files: Option<bool>,
|
||||
/// Default expiry time.
|
||||
#[serde(default, with = "humantime_serde")]
|
||||
pub default_expiry: Option<Duration>,
|
||||
/// Delete expired files.
|
||||
pub delete_expired_files: Option<CleanupConfig>,
|
||||
/// Highlight override.
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
use crate::util;
|
||||
use actix_web::http::header::{
|
||||
ContentDisposition as ActixContentDisposition, DispositionParam, DispositionType, HeaderMap,
|
||||
};
|
||||
use actix_web::{error, Error as ActixError};
|
||||
use std::time::Duration;
|
||||
|
||||
/// Custom HTTP header for expiry dates.
|
||||
pub const EXPIRE: &str = "expire";
|
||||
|
||||
/// Parses the expiry date from the [`custom HTTP header`](EXPIRE).
|
||||
pub fn parse_expiry_date(headers: &HeaderMap) -> Result<Option<u128>, ActixError> {
|
||||
pub fn parse_expiry_date(headers: &HeaderMap, time: Duration) -> Result<Option<u128>, ActixError> {
|
||||
if let Some(expire_time) = headers.get(EXPIRE).and_then(|v| v.to_str().ok()) {
|
||||
let timestamp = util::get_system_time()?;
|
||||
let expire_time =
|
||||
humantime::parse_duration(expire_time).map_err(error::ErrorInternalServerError)?;
|
||||
Ok(timestamp.checked_add(expire_time).map(|t| t.as_millis()))
|
||||
Ok(time.checked_add(expire_time).map(|t| t.as_millis()))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
|
@ -62,9 +61,9 @@ impl ContentDisposition {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::util;
|
||||
use actix_web::http::header::{HeaderName, HeaderValue};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
fn test_content_disposition() -> Result<(), ActixError> {
|
||||
|
@ -97,7 +96,8 @@ mod tests {
|
|||
HeaderName::from_static(EXPIRE),
|
||||
HeaderValue::from_static("5ms"),
|
||||
);
|
||||
let expiry_time = parse_expiry_date(&headers)?.unwrap_or_default();
|
||||
let time = util::get_system_time()?;
|
||||
let expiry_time = parse_expiry_date(&headers, time)?.unwrap_or_default();
|
||||
assert!(expiry_time > util::get_system_time()?.as_millis());
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
assert!(expiry_time < util::get_system_time()?.as_millis());
|
||||
|
|
64
src/main.rs
64
src/main.rs
|
@ -1,9 +1,10 @@
|
|||
use actix_web::middleware::Logger;
|
||||
use actix_web::web::Data;
|
||||
#[cfg(not(feature = "shuttle"))]
|
||||
use actix_web::{App, HttpServer};
|
||||
use awc::ClientBuilder;
|
||||
use hotwatch::{Event, Hotwatch};
|
||||
use rustypaste::config::Config;
|
||||
use rustypaste::config::{Config, ServerConfig};
|
||||
use rustypaste::paste::PasteType;
|
||||
use rustypaste::server;
|
||||
use rustypaste::util;
|
||||
|
@ -11,17 +12,28 @@ use rustypaste::CONFIG_ENV;
|
|||
use std::env;
|
||||
use std::fs;
|
||||
use std::io::Result as IoResult;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{mpsc, RwLock};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
#[cfg(feature = "shuttle")]
|
||||
use {
|
||||
actix_web::web::{self, ServiceConfig},
|
||||
shuttle_actix_web::ShuttleActixWeb,
|
||||
};
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> IoResult<()> {
|
||||
/// Sets up the application.
|
||||
///
|
||||
/// * loads the configuration
|
||||
/// * initializes the logger
|
||||
/// * creates the necessary directories
|
||||
/// * spawns the threads
|
||||
fn setup(config_folder: &Path) -> IoResult<(Data<RwLock<Config>>, ServerConfig, Hotwatch)> {
|
||||
// Load the .env file.
|
||||
dotenvy::dotenv().ok();
|
||||
|
||||
// Initialize logger.
|
||||
#[cfg(not(feature = "shuttle"))]
|
||||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||
|
||||
// Parse configuration.
|
||||
|
@ -30,7 +42,7 @@ async fn main() -> IoResult<()> {
|
|||
env::remove_var(CONFIG_ENV);
|
||||
PathBuf::from(path)
|
||||
}
|
||||
None => PathBuf::from("config.toml"),
|
||||
None => config_folder.join("config.toml"),
|
||||
};
|
||||
let config = Config::parse(&config_path).expect("failed to parse config");
|
||||
log::trace!("{:#?}", config);
|
||||
|
@ -83,6 +95,7 @@ async fn main() -> IoResult<()> {
|
|||
.unwrap_or_else(|_| panic!("failed to watch {config_path:?}"));
|
||||
|
||||
// Create a thread for cleaning up expired files.
|
||||
let upload_path = server_config.upload_path.clone();
|
||||
thread::spawn(move || loop {
|
||||
let mut enabled = false;
|
||||
if let Some(ref cleanup_config) = paste_config
|
||||
|
@ -92,7 +105,7 @@ async fn main() -> IoResult<()> {
|
|||
{
|
||||
if cleanup_config.enabled {
|
||||
log::debug!("Running cleanup...");
|
||||
for file in util::get_expired_files(&server_config.upload_path) {
|
||||
for file in util::get_expired_files(&upload_path) {
|
||||
match fs::remove_file(&file) {
|
||||
Ok(()) => log::info!("Removed expired file: {:?}", file),
|
||||
Err(e) => log::error!("Cannot remove expired file: {}", e),
|
||||
|
@ -118,6 +131,15 @@ async fn main() -> IoResult<()> {
|
|||
}
|
||||
});
|
||||
|
||||
Ok((config, server_config, hotwatch))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "shuttle"))]
|
||||
#[actix_web::main]
|
||||
async fn main() -> IoResult<()> {
|
||||
// Set up the application.
|
||||
let (config, server_config, _) = setup(&PathBuf::new())?;
|
||||
|
||||
// Create an HTTP server.
|
||||
let mut http_server = HttpServer::new(move || {
|
||||
let http_client = ClientBuilder::new()
|
||||
|
@ -144,3 +166,33 @@ async fn main() -> IoResult<()> {
|
|||
// Run the server.
|
||||
http_server.run().await
|
||||
}
|
||||
|
||||
#[cfg(feature = "shuttle")]
|
||||
#[shuttle_runtime::main]
|
||||
async fn actix_web(
|
||||
#[shuttle_static_folder::StaticFolder(folder = "shuttle")] static_folder: PathBuf,
|
||||
) -> ShuttleActixWeb<impl FnOnce(&mut ServiceConfig) + Send + Clone + 'static> {
|
||||
// Set up the application.
|
||||
let (config, server_config, _) = setup(&static_folder)?;
|
||||
|
||||
// Create the service.
|
||||
let service_config = move |cfg: &mut ServiceConfig| {
|
||||
let http_client = ClientBuilder::new()
|
||||
.timeout(
|
||||
server_config
|
||||
.timeout
|
||||
.unwrap_or_else(|| Duration::from_secs(30)),
|
||||
)
|
||||
.disable_redirects()
|
||||
.finish();
|
||||
cfg.service(
|
||||
web::scope("")
|
||||
.app_data(Data::clone(&config))
|
||||
.app_data(Data::new(http_client))
|
||||
.wrap(Logger::default())
|
||||
.configure(server::configure_routes),
|
||||
);
|
||||
};
|
||||
|
||||
Ok(service_config.into())
|
||||
}
|
||||
|
|
|
@ -28,7 +28,9 @@ async fn index(config: web::Data<RwLock<Config>>) -> Result<HttpResponse, Error>
|
|||
.read()
|
||||
.map_err(|_| error::ErrorInternalServerError("cannot acquire config"))?;
|
||||
match &config.server.landing_page {
|
||||
Some(page) => Ok(HttpResponse::Ok().body(page.clone())),
|
||||
Some(page) => Ok(HttpResponse::Ok()
|
||||
.content_type("text/plain; charset=\"UTF-8\"")
|
||||
.body(page.clone())),
|
||||
None => Ok(HttpResponse::Found()
|
||||
.append_header(("Location", env!("CARGO_PKG_HOMEPAGE")))
|
||||
.finish()),
|
||||
|
@ -158,6 +160,18 @@ async fn upload(
|
|||
) -> Result<HttpResponse, Error> {
|
||||
let connection = request.connection_info().clone();
|
||||
let host = connection.peer_addr().unwrap_or("unknown host");
|
||||
let server_url = match config
|
||||
.read()
|
||||
.map_err(|_| error::ErrorInternalServerError("cannot acquire config"))?
|
||||
.server
|
||||
.url
|
||||
.clone()
|
||||
{
|
||||
Some(v) => v,
|
||||
None => {
|
||||
format!("{}://{}", connection.scheme(), connection.host(),)
|
||||
}
|
||||
};
|
||||
auth::check(
|
||||
host,
|
||||
request.headers(),
|
||||
|
@ -169,7 +183,16 @@ async fn upload(
|
|||
.as_ref()
|
||||
.cloned()),
|
||||
)?;
|
||||
let expiry_date = header::parse_expiry_date(request.headers())?;
|
||||
let time = util::get_system_time()?;
|
||||
let mut expiry_date = header::parse_expiry_date(request.headers(), time)?;
|
||||
if expiry_date.is_none() {
|
||||
expiry_date = config
|
||||
.read()
|
||||
.map_err(|_| error::ErrorInternalServerError("cannot acquire config"))?
|
||||
.paste
|
||||
.default_expiry
|
||||
.and_then(|v| time.checked_add(v).map(|t| t.as_millis()));
|
||||
}
|
||||
let mut urls: Vec<String> = Vec::new();
|
||||
while let Some(item) = payload.next().await {
|
||||
let mut field = item?;
|
||||
|
@ -208,9 +231,8 @@ async fn upload(
|
|||
.get_file(bytes_checksum)
|
||||
{
|
||||
urls.push(format!(
|
||||
"{}://{}/{}\n",
|
||||
connection.scheme(),
|
||||
connection.host(),
|
||||
"{}/{}\n",
|
||||
server_url,
|
||||
file.path
|
||||
.file_name()
|
||||
.map(|v| v.to_string_lossy())
|
||||
|
@ -248,12 +270,7 @@ async fn upload(
|
|||
Byte::from_bytes(paste.data.len() as u128).get_appropriate_unit(false),
|
||||
host
|
||||
);
|
||||
urls.push(format!(
|
||||
"{}://{}/{}\n",
|
||||
connection.scheme(),
|
||||
connection.host(),
|
||||
file_name
|
||||
));
|
||||
urls.push(format!("{}/{}\n", server_url, file_name));
|
||||
} else {
|
||||
log::warn!("{} sent an invalid form field", host);
|
||||
return Err(error::ErrorBadRequest("invalid form field"));
|
||||
|
|
Loading…
Reference in a new issue