mirror of
https://github.com/amigan/rustypaste-pretty.git
synced 2024-11-21 11:59:48 -05:00
Merge branch 'upreb'
This commit is contained in:
commit
e042821848
19 changed files with 2264 additions and 334 deletions
|
@ -1,8 +1,8 @@
|
||||||
# Directories
|
# Directories
|
||||||
/.git/
|
/.git/
|
||||||
/.github/
|
/.github/
|
||||||
/target/
|
|
||||||
/upload/
|
/upload/
|
||||||
|
/shuttle/
|
||||||
|
|
||||||
# Files
|
# Files
|
||||||
.gitignore
|
.gitignore
|
||||||
|
|
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
|
@ -1,2 +1,3 @@
|
||||||
github: orhun
|
github: orhun
|
||||||
patreon: orhunp
|
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:
|
jobs:
|
||||||
audit:
|
audit:
|
||||||
name: Audit
|
name: Audit
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@v3
|
||||||
- name: Install Rust
|
- name: Install Rust
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
|
|
8
.github/workflows/cd.yml
vendored
8
.github/workflows/cd.yml
vendored
|
@ -8,13 +8,13 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
publish-github:
|
publish-github:
|
||||||
name: Publish on GitHub
|
name: Publish on GitHub
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
TARGET: [x86_64-unknown-linux-gnu, x86_64-unknown-linux-musl]
|
TARGET: [x86_64-unknown-linux-gnu, x86_64-unknown-linux-musl]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@v3
|
||||||
- name: Set the release version
|
- name: Set the release version
|
||||||
run: echo "RELEASE_VERSION=${GITHUB_REF:11}" >> $GITHUB_ENV
|
run: echo "RELEASE_VERSION=${GITHUB_REF:11}" >> $GITHUB_ENV
|
||||||
- name: Install musl-tools
|
- name: Install musl-tools
|
||||||
|
@ -57,10 +57,10 @@ jobs:
|
||||||
publish-crates-io:
|
publish-crates-io:
|
||||||
name: Publish on crates.io
|
name: Publish on crates.io
|
||||||
needs: publish-github
|
needs: publish-github
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@v3
|
||||||
- name: Publish
|
- name: Publish
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
|
|
28
.github/workflows/ci.yml
vendored
28
.github/workflows/ci.yml
vendored
|
@ -8,12 +8,12 @@ on:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 0 * * 0'
|
- cron: "0 0 * * 0"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check:
|
check:
|
||||||
name: Check
|
name: Check
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Install Rust toolchain
|
- name: Install Rust toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
|
@ -22,7 +22,7 @@ jobs:
|
||||||
profile: minimal
|
profile: minimal
|
||||||
override: true
|
override: true
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@v3
|
||||||
- name: Check the project files
|
- name: Check the project files
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
|
@ -31,7 +31,7 @@ jobs:
|
||||||
|
|
||||||
test:
|
test:
|
||||||
name: Test suite
|
name: Test suite
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Install Rust toolchain
|
- name: Install Rust toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
|
@ -39,7 +39,7 @@ jobs:
|
||||||
toolchain: stable
|
toolchain: stable
|
||||||
override: true
|
override: true
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@v3
|
||||||
- name: Setup cargo-tarpaulin
|
- name: Setup cargo-tarpaulin
|
||||||
run: |
|
run: |
|
||||||
curl -s https://api.github.com/repos/xd009642/tarpaulin/releases/latest | \
|
curl -s https://api.github.com/repos/xd009642/tarpaulin/releases/latest | \
|
||||||
|
@ -49,7 +49,7 @@ jobs:
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo tarpaulin --out Xml --verbose -- --test-threads 1
|
run: cargo tarpaulin --out Xml --verbose -- --test-threads 1
|
||||||
- name: Upload reports to codecov
|
- name: Upload reports to codecov
|
||||||
uses: codecov/codecov-action@v1
|
uses: codecov/codecov-action@v3
|
||||||
with:
|
with:
|
||||||
name: code-coverage-report
|
name: code-coverage-report
|
||||||
file: cobertura.xml
|
file: cobertura.xml
|
||||||
|
@ -60,7 +60,7 @@ jobs:
|
||||||
|
|
||||||
fixtures:
|
fixtures:
|
||||||
name: Test fixtures
|
name: Test fixtures
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Install Rust toolchain
|
- name: Install Rust toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
|
@ -69,7 +69,7 @@ jobs:
|
||||||
profile: minimal
|
profile: minimal
|
||||||
override: true
|
override: true
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@v3
|
||||||
- name: Build the project
|
- name: Build the project
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
|
@ -84,7 +84,7 @@ jobs:
|
||||||
|
|
||||||
clippy:
|
clippy:
|
||||||
name: Lints
|
name: Lints
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Install Rust toolchain
|
- name: Install Rust toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
|
@ -94,7 +94,7 @@ jobs:
|
||||||
components: clippy
|
components: clippy
|
||||||
override: true
|
override: true
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@v3
|
||||||
- name: Check the lints
|
- name: Check the lints
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
|
@ -103,7 +103,7 @@ jobs:
|
||||||
|
|
||||||
rustfmt:
|
rustfmt:
|
||||||
name: Formatting
|
name: Formatting
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Install Rust toolchain
|
- name: Install Rust toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
|
@ -113,7 +113,7 @@ jobs:
|
||||||
components: rustfmt
|
components: rustfmt
|
||||||
override: true
|
override: true
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@v3
|
||||||
- name: Check the formatting
|
- name: Check the formatting
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
|
@ -122,10 +122,10 @@ jobs:
|
||||||
|
|
||||||
lychee:
|
lychee:
|
||||||
name: Links
|
name: Links
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@v3
|
||||||
- name: Check the links
|
- name: Check the links
|
||||||
uses: lycheeverse/lychee-action@v1
|
uses: lycheeverse/lychee-action@v1
|
||||||
with:
|
with:
|
||||||
|
|
24
.github/workflows/docker.yml
vendored
24
.github/workflows/docker.yml
vendored
|
@ -15,14 +15,14 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
docker:
|
docker:
|
||||||
name: Docker Build and Push
|
name: Docker Build and Push
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v3
|
uses: docker/metadata-action@v4
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
orhunp/rustypaste
|
orhunp/rustypaste
|
||||||
|
@ -37,10 +37,10 @@ jobs:
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: docker/setup-buildx-action@v1
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
- name: Cache Docker layers
|
- name: Cache Docker layers
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: /tmp/.buildx-cache
|
path: /tmp/.buildx-cache
|
||||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||||
|
@ -49,14 +49,14 @@ jobs:
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
username: orhunp
|
username: orhunp
|
||||||
password: ${{ secrets.DOCKER_TOKEN }}
|
password: ${{ secrets.DOCKER_TOKEN }}
|
||||||
|
|
||||||
- name: Login to GHCR
|
- name: Login to GHCR
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
|
@ -64,16 +64,24 @@ jobs:
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
id: docker_build
|
id: docker_build
|
||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v4
|
||||||
with:
|
with:
|
||||||
context: ./
|
context: ./
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
|
platforms: linux/amd64
|
||||||
builder: ${{ steps.buildx.outputs.name }}
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
sbom: true
|
||||||
|
provenance: true
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
cache-from: type=local,src=/tmp/.buildx-cache
|
cache-from: type=local,src=/tmp/.buildx-cache
|
||||||
cache-to: type=local,dest=/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
|
- name: Image digest
|
||||||
run: echo ${{ steps.docker_build.outputs.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
|
# Changelog
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
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/),
|
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).
|
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
|
## [0.8.4] - 2023-01-31
|
||||||
|
|
||||||
### Added
|
### 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.
|
- 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
|
## [0.8.3] - 2023-01-30
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- Bump dependencies
|
- Bump dependencies
|
||||||
- Switch to [Rust](https://hub.docker.com/_/rust) image for the Dockerfile
|
- Switch to [Rust](https://hub.docker.com/_/rust) image for the Dockerfile
|
||||||
- Remove unused `clap` dependency
|
- Remove unused `clap` dependency
|
||||||
|
|
||||||
## [0.8.2] - 2022-10-04
|
## [0.8.2] - 2022-10-04
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- Don't expose version endpoint in default config
|
- Don't expose version endpoint in default config
|
||||||
- Set `expose_version` to `false` in the configuration file
|
- Set `expose_version` to `false` in the configuration file
|
||||||
|
|
||||||
## [0.8.1] - 2022-10-04
|
## [0.8.1] - 2022-10-04
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Add `<server_address>/version` endpoint for retrieving the server version
|
- Add `<server_address>/version` endpoint for retrieving the server version
|
||||||
|
|
||||||
```toml
|
```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.
|
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
|
### Fixed
|
||||||
|
|
||||||
- Replace unmaintained `dotenv` crate with `dotenvy`
|
- Replace unmaintained `dotenv` crate with `dotenvy`
|
||||||
- Fixes [RUSTSEC-2021-0141](https://rustsec.org/advisories/RUSTSEC-2021-0141.html)
|
- Fixes [RUSTSEC-2021-0141](https://rustsec.org/advisories/RUSTSEC-2021-0141.html)
|
||||||
|
|
||||||
## [0.8.0] - 2022-10-03
|
## [0.8.0] - 2022-10-03
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Support adding a landing page
|
- Support adding a landing page
|
||||||
|
|
||||||
You can now specify a landing page text in the configuration file as follows:
|
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.
|
If the landing page entry is not present in the configuration file, visiting the index page will redirect to the repository.
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- Do not check for duplicate files by default
|
- Do not check for duplicate files by default
|
||||||
- Set `duplicate_files` to `true` in the configuration file
|
- 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
|
- 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 💖
|
- Consider supporting me for my open-source work 💖
|
||||||
|
|
||||||
## [0.7.1] - 2022-05-21
|
## [0.7.1] - 2022-05-21
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Aggressively test everything
|
- Aggressively test everything
|
||||||
- Add the missing unit tests for the server endpoints (code coverage is increased to 84%)
|
- 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)
|
- 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
|
## [0.7.0] - 2022-03-26
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Support auto-deletion of expired files
|
- 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:
|
`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).
|
- For the installation and usage, see the Arch Linux [PKGBUILD](https://github.com/archlinux/svntogit-community/blob/packages/rustypaste/trunk/PKGBUILD).
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- Upgrade Actix dependencies
|
- 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)
|
- `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
|
- Strip the binaries during automated builds
|
||||||
- Size of the Docker image is reduced by ~20%
|
- Size of the Docker image is reduced by ~20%
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Prevent invalid attempts of serving directories
|
- 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 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.
|
- This issue had no security impact (path traversal wasn't possible) since internal server error was returned.
|
||||||
|
|
||||||
## [0.6.5] - 2022-03-13
|
## [0.6.5] - 2022-03-13
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Add instructions for installing [rustypaste](https://archlinux.org/packages/community/x86_64/rustypaste/) on Arch Linux
|
- Add instructions for installing [rustypaste](https://archlinux.org/packages/community/x86_64/rustypaste/) on Arch Linux
|
||||||
- `pacman -S rustypaste` 🎉
|
- `pacman -S rustypaste` 🎉
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fix a bug where the use of `CONFIG` environment variable causes a conflict between the configuration file path and `[config]` section
|
- 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
|
## [0.6.4] - 2022-03-11
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Support setting the refresh rate for hot-reloading the configuration file.
|
- Support setting the refresh rate for hot-reloading the configuration file.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
@ -121,11 +191,14 @@ timeout="30s"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
- Bump [regex crate](https://github.com/rust-lang/regex) to **1.5.5**
|
- 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)
|
- Fixes [CVE-2022-24713](https://github.com/advisories/GHSA-m5pq-gvj9-9vr8)
|
||||||
|
|
||||||
## [0.6.3] - 2022-02-24
|
## [0.6.3] - 2022-02-24
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Support setting the authentication token in the configuration file.
|
- 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.
|
- 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
|
## [0.6.2] - 2021-12-05
|
||||||
|
|
||||||
### Updated
|
### Updated
|
||||||
|
|
||||||
- Improve the concurrency
|
- 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`.
|
- 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
|
- Reference: https://rust-lang.github.io/rfcs/3014-must-not-suspend-lint.html
|
||||||
|
|
||||||
## [0.6.1] - 2021-11-16
|
## [0.6.1] - 2021-11-16
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Gracefully handle the hot-reloading errors.
|
- 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).
|
- 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
|
## [0.6.0] - 2021-11-07
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Support pasting files from remote URLs (via `remote=` form field)
|
- Support pasting files from remote URLs (via `remote=` form field)
|
||||||
|
|
||||||
- `{server.max_content_length}` is used for download limit
|
- `{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)
|
- 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
|
- Hot reload configuration file to apply configuration changes instantly without restarting the server
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Library: Switch to Rust 2021 edition
|
- Library: Switch to Rust 2021 edition
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
- Prevent serving an already expired file
|
- 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.
|
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)
|
reference: [f078a9afa74f8608ee3f2a6e705159df15915c78](https://github.com/orhun/rustypaste/commit/f078a9afa74f8608ee3f2a6e705159df15915c78)
|
||||||
|
|
||||||
## [0.5.0] - 2021-10-12
|
## [0.5.0] - 2021-10-12
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Added an entry in the configuration file to disable "duplicate uploads":
|
- Added an entry in the configuration file to disable "duplicate uploads":
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
@ -176,13 +260,17 @@ duplicate_files = false
|
||||||
Under the hood, it checks the SHA256 digest of the uploaded files.
|
Under the hood, it checks the SHA256 digest of the uploaded files.
|
||||||
|
|
||||||
## [0.4.1] - 2021-09-19
|
## [0.4.1] - 2021-09-19
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Update README.md:
|
- Update README.md:
|
||||||
- Mention the new standalone tool: [rustypaste-cli](https://github.com/orhun/rustypaste-cli)
|
- Mention the new standalone tool: [rustypaste-cli](https://github.com/orhun/rustypaste-cli)
|
||||||
- Add [installation](https://github.com/orhun/rustypaste#installation) section.
|
- Add [installation](https://github.com/orhun/rustypaste#installation) section.
|
||||||
|
|
||||||
## [0.4.0] - 2021-08-27
|
## [0.4.0] - 2021-08-27
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Support [expiring links](README.md#expiration) (via `expire:` header)
|
- Support [expiring links](README.md#expiration) (via `expire:` header)
|
||||||
- Timestamps are used as extension for expiring files
|
- Timestamps are used as extension for expiring files
|
||||||
- Expired files can be cleaned up with [this command](README.md#cleaning-up-expired-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
|
- `{server.upload_path}/oneshot` is used for storage
|
||||||
|
|
||||||
## [0.3.1] - 2021-08-10
|
## [0.3.1] - 2021-08-10
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Switch to [upload-release-action](https://github.com/svenstaro/upload-release-action) for uploading releases
|
- Switch to [upload-release-action](https://github.com/svenstaro/upload-release-action) for uploading releases
|
||||||
|
|
||||||
## [0.3.0] - 2021-08-09
|
## [0.3.0] - 2021-08-09
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Support overriding MIME types (config: `mime_override`)
|
- Support overriding MIME types (config: `mime_override`)
|
||||||
- Support blacklisting MIME types (config: `mime_blacklist`)
|
- Support blacklisting MIME types (config: `mime_blacklist`)
|
||||||
|
|
||||||
## [0.2.0] - 2021-08-04
|
## [0.2.0] - 2021-08-04
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Support shortening URLs (via `url=` form field)
|
- Support shortening URLs (via `url=` form field)
|
||||||
- `{server.upload_path}/url` is used for storage
|
- `{server.upload_path}/url` is used for storage
|
||||||
|
|
||||||
## [0.1.3] - 2021-07-28
|
## [0.1.3] - 2021-07-28
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Prevent sending empty file name and zero bytes
|
- Prevent sending empty file name and zero bytes
|
||||||
- Prevent path traversal on upload directory ([#2](https://github.com/orhun/rustypaste/issues/2))
|
- 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))
|
- Check the content length while reading bytes for preventing OOM ([#1](https://github.com/orhun/rustypaste/issues/1))
|
||||||
|
|
||||||
## [0.1.2] - 2021-07-27
|
## [0.1.2] - 2021-07-27
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Update Continuous Deployment workflow to publish Docker images
|
- Update Continuous Deployment workflow to publish Docker images
|
||||||
|
|
||||||
## [0.1.1] - 2021-07-27
|
## [0.1.1] - 2021-07-27
|
||||||
|
|
||||||
Initial release.
|
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]
|
[package]
|
||||||
name = "rustypaste"
|
name = "rustypaste"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "A minimal file upload/pastebin service"
|
description = "A minimal file upload/pastebin service"
|
||||||
authors = ["Orhun Parmaksız <orhunparmaksiz@gmail.com>"]
|
authors = ["Orhun Parmaksız <orhunparmaksiz@gmail.com>"]
|
||||||
|
@ -12,28 +12,46 @@ keywords = ["paste", "pastebin", "upload"]
|
||||||
categories = ["web-programming::http-server"]
|
categories = ["web-programming::http-server"]
|
||||||
include = ["src/**/*", "Cargo.*", "LICENSE", "README.md", "CHANGELOG.md"]
|
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]
|
[dependencies]
|
||||||
actix-web = { version = "4.3.0", features = ["rustls"] }
|
actix-web = { version = "4.3.1" }
|
||||||
actix-multipart = "0.5.0"
|
actix-multipart = "0.6.0"
|
||||||
actix-files = "0.6.2"
|
actix-files = "0.6.2"
|
||||||
awc = { version = "3.1.0", features = ["rustls"] }
|
awc = { version = "3.1.1" }
|
||||||
env_logger = "0.10.0"
|
env_logger = "0.10.0"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
serde = "1.0.152"
|
serde = "1.0.163"
|
||||||
futures-util = "0.3.26"
|
futures-util = "0.3.28"
|
||||||
petname = { version = "1.1.3", default-features = false, features = ["std_rng", "default_dictionary"] }
|
petname = { version = "1.1.3", default-features = false, features = [
|
||||||
|
"std_rng",
|
||||||
|
"default_dictionary",
|
||||||
|
] }
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
dotenvy = "0.15.6"
|
dotenvy = "0.15.7"
|
||||||
url = "2.3.1"
|
url = "2.3.1"
|
||||||
mime = "0.3.16"
|
mime = "0.3.17"
|
||||||
regex = "1.6.0"
|
regex = "1.8.1"
|
||||||
serde_regex = "1.1.0"
|
serde_regex = "1.1.0"
|
||||||
lazy-regex = "2.4.1"
|
lazy-regex = "2.5.0"
|
||||||
humantime = "2.1.0"
|
humantime = "2.1.0"
|
||||||
humantime-serde = "1.1.1"
|
humantime-serde = "1.1.1"
|
||||||
glob = "0.3.1"
|
glob = "0.3.1"
|
||||||
ring = "0.16.20"
|
ring = "0.16.20"
|
||||||
hotwatch = "0.4.5"
|
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"
|
text-template = "0.1.0"
|
||||||
|
|
||||||
[dependencies.config]
|
[dependencies.config]
|
||||||
|
@ -42,11 +60,11 @@ default-features = false
|
||||||
features = ["toml", "yaml"]
|
features = ["toml", "yaml"]
|
||||||
|
|
||||||
[dependencies.byte-unit]
|
[dependencies.byte-unit]
|
||||||
version = "4.0.18"
|
version = "4.0.19"
|
||||||
features = ["serde"]
|
features = ["serde"]
|
||||||
|
|
||||||
[dependencies.infer]
|
[dependencies.infer]
|
||||||
version = "0.12.0"
|
version = "0.13.0"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -14,9 +14,7 @@ RUN cp target/release/rustypaste build-out/
|
||||||
|
|
||||||
FROM scratch
|
FROM scratch
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=builder \
|
COPY --from=builder /app/build-out/rustypaste .
|
||||||
/app/build-out/rustypaste \
|
|
||||||
/app/config.toml ./
|
|
||||||
ENV SERVER__ADDRESS=0.0.0.0:8000
|
ENV SERVER__ADDRESS=0.0.0.0:8000
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
USER 1000:1000
|
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>
|
<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.
|
**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!
|
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
|
some text
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The public instance is available at [https://rustypaste.shuttleapp.rs](https://rustypaste.shuttleapp.rs) 🚀
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- File upload & URL shortening & upload from URL
|
- File upload & URL shortening & upload from URL
|
||||||
|
@ -22,6 +32,7 @@ some text
|
||||||
- pet name (e.g. `capital-mosquito.txt`)
|
- pet name (e.g. `capital-mosquito.txt`)
|
||||||
- alphanumeric string (e.g. `yB84D2Dv.txt`)
|
- alphanumeric string (e.g. `yB84D2Dv.txt`)
|
||||||
- supports expiring links
|
- supports expiring links
|
||||||
|
- auto-expiration of files (optional)
|
||||||
- auto-deletion of expired files (optional)
|
- auto-deletion of expired files (optional)
|
||||||
- supports one shot links (can only be viewed once)
|
- supports one shot links (can only be viewed once)
|
||||||
- guesses MIME types
|
- guesses MIME types
|
||||||
|
@ -55,9 +66,17 @@ cargo install rustypaste
|
||||||
pacman -S 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
|
### 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
|
### Build from source
|
||||||
|
|
||||||
|
@ -67,13 +86,34 @@ cd rustypaste/
|
||||||
cargo build --release
|
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
|
```sh
|
||||||
# run unit tests
|
|
||||||
cargo test -- --test-threads 1
|
cargo test -- --test-threads 1
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### Test Fixtures
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./fixtures/test-fixtures.sh
|
||||||
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
The standalone command line tool (`rpaste`) is available [here](https://github.com/orhun/rustypaste-cli).
|
The standalone command line tool (`rpaste`) is available [here](https://github.com/orhun/rustypaste-cli).
|
||||||
|
|
36
config.toml
36
config.toml
|
@ -1,29 +1,20 @@
|
||||||
[config]
|
[config]
|
||||||
refresh_rate="1s"
|
refresh_rate = "1s"
|
||||||
|
|
||||||
[server]
|
[server]
|
||||||
address="127.0.0.1:8020"
|
address="127.0.0.1:8020"
|
||||||
|
#url = "https://rustypaste.shuttleapp.rs"
|
||||||
#workers=4
|
#workers=4
|
||||||
max_content_length="10MB"
|
max_content_length = "10MB"
|
||||||
upload_path="./upload"
|
upload_path = "./upload"
|
||||||
timeout="30s"
|
timeout = "30s"
|
||||||
expose_version=false
|
expose_version = false
|
||||||
style="monokai"
|
style="monokai"
|
||||||
landing_page="""Submit files via HTTP POST here:
|
landing_page = """
|
||||||
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."""
|
|
||||||
|
|
||||||
[paste]
|
[paste]
|
||||||
random_url = { enabled = true, type = "petname", words = 2, separator = "-" }
|
random_url = { enabled = true, type = "petname", words = 2, separator = "-" }
|
||||||
|
@ -36,15 +27,16 @@ mime_override = [
|
||||||
{ mime = "video/webm", regex = "^.*\\.webm$" },
|
{ mime = "video/webm", regex = "^.*\\.webm$" },
|
||||||
{ mime = "video/x-matroska", regex = "^.*\\.mkv$" },
|
{ mime = "video/x-matroska", regex = "^.*\\.mkv$" },
|
||||||
{ mime = "application/octet-stream", regex = "^.*\\.bin$" },
|
{ mime = "application/octet-stream", regex = "^.*\\.bin$" },
|
||||||
{ mime = "text/plain", regex = "^.*\\.(log|txt|diff)$" },
|
{ mime = "text/plain", regex = "^.*\\.(log|txt|diff|sh|rs|toml)$" },
|
||||||
]
|
]
|
||||||
mime_blacklist = [
|
mime_blacklist = [
|
||||||
"application/x-dosexec",
|
"application/x-dosexec",
|
||||||
"application/java-archive",
|
"application/java-archive",
|
||||||
"application/java-vm"
|
"application/java-vm",
|
||||||
]
|
]
|
||||||
|
|
||||||
duplicate_files = true
|
duplicate_files = true
|
||||||
|
# default_expiry = "1h"
|
||||||
delete_expired_files = { enabled = true, interval = "1h" }
|
delete_expired_files = { enabled = true, interval = "1h" }
|
||||||
|
|
||||||
[paste.highlight_override]
|
[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 {
|
pub struct ServerConfig {
|
||||||
/// The socket address to bind.
|
/// The socket address to bind.
|
||||||
pub address: String,
|
pub address: String,
|
||||||
|
/// URL that can be used to access the server externally.
|
||||||
|
pub url: Option<String>,
|
||||||
/// Number of workers to start.
|
/// Number of workers to start.
|
||||||
pub workers: Option<usize>,
|
pub workers: Option<usize>,
|
||||||
/// Maximum content length.
|
/// Maximum content length.
|
||||||
|
@ -63,8 +65,11 @@ pub struct PasteConfig {
|
||||||
/// Media type blacklist.
|
/// Media type blacklist.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub mime_blacklist: Vec<String>,
|
pub mime_blacklist: Vec<String>,
|
||||||
/// Allow duplicate uploads
|
/// Allow duplicate uploads.
|
||||||
pub duplicate_files: Option<bool>,
|
pub duplicate_files: Option<bool>,
|
||||||
|
/// Default expiry time.
|
||||||
|
#[serde(default, with = "humantime_serde")]
|
||||||
|
pub default_expiry: Option<Duration>,
|
||||||
/// Delete expired files.
|
/// Delete expired files.
|
||||||
pub delete_expired_files: Option<CleanupConfig>,
|
pub delete_expired_files: Option<CleanupConfig>,
|
||||||
/// Highlight override.
|
/// Highlight override.
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
use crate::util;
|
|
||||||
use actix_web::http::header::{
|
use actix_web::http::header::{
|
||||||
ContentDisposition as ActixContentDisposition, DispositionParam, DispositionType, HeaderMap,
|
ContentDisposition as ActixContentDisposition, DispositionParam, DispositionType, HeaderMap,
|
||||||
};
|
};
|
||||||
use actix_web::{error, Error as ActixError};
|
use actix_web::{error, Error as ActixError};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
/// Custom HTTP header for expiry dates.
|
/// Custom HTTP header for expiry dates.
|
||||||
pub const EXPIRE: &str = "expire";
|
pub const EXPIRE: &str = "expire";
|
||||||
|
|
||||||
/// Parses the expiry date from the [`custom HTTP header`](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()) {
|
if let Some(expire_time) = headers.get(EXPIRE).and_then(|v| v.to_str().ok()) {
|
||||||
let timestamp = util::get_system_time()?;
|
|
||||||
let expire_time =
|
let expire_time =
|
||||||
humantime::parse_duration(expire_time).map_err(error::ErrorInternalServerError)?;
|
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 {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
@ -62,9 +61,9 @@ impl ContentDisposition {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::util;
|
||||||
use actix_web::http::header::{HeaderName, HeaderValue};
|
use actix_web::http::header::{HeaderName, HeaderValue};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_content_disposition() -> Result<(), ActixError> {
|
fn test_content_disposition() -> Result<(), ActixError> {
|
||||||
|
@ -97,7 +96,8 @@ mod tests {
|
||||||
HeaderName::from_static(EXPIRE),
|
HeaderName::from_static(EXPIRE),
|
||||||
HeaderValue::from_static("5ms"),
|
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());
|
assert!(expiry_time > util::get_system_time()?.as_millis());
|
||||||
thread::sleep(Duration::from_millis(10));
|
thread::sleep(Duration::from_millis(10));
|
||||||
assert!(expiry_time < util::get_system_time()?.as_millis());
|
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::middleware::Logger;
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
|
#[cfg(not(feature = "shuttle"))]
|
||||||
use actix_web::{App, HttpServer};
|
use actix_web::{App, HttpServer};
|
||||||
use awc::ClientBuilder;
|
use awc::ClientBuilder;
|
||||||
use hotwatch::{Event, Hotwatch};
|
use hotwatch::{Event, Hotwatch};
|
||||||
use rustypaste::config::Config;
|
use rustypaste::config::{Config, ServerConfig};
|
||||||
use rustypaste::paste::PasteType;
|
use rustypaste::paste::PasteType;
|
||||||
use rustypaste::server;
|
use rustypaste::server;
|
||||||
use rustypaste::util;
|
use rustypaste::util;
|
||||||
|
@ -11,17 +12,28 @@ use rustypaste::CONFIG_ENV;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::Result as IoResult;
|
use std::io::Result as IoResult;
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::{mpsc, RwLock};
|
use std::sync::{mpsc, RwLock};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
#[cfg(feature = "shuttle")]
|
||||||
|
use {
|
||||||
|
actix_web::web::{self, ServiceConfig},
|
||||||
|
shuttle_actix_web::ShuttleActixWeb,
|
||||||
|
};
|
||||||
|
|
||||||
#[actix_web::main]
|
/// Sets up the application.
|
||||||
async fn main() -> IoResult<()> {
|
///
|
||||||
|
/// * 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.
|
// Load the .env file.
|
||||||
dotenvy::dotenv().ok();
|
dotenvy::dotenv().ok();
|
||||||
|
|
||||||
// Initialize logger.
|
// Initialize logger.
|
||||||
|
#[cfg(not(feature = "shuttle"))]
|
||||||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||||
|
|
||||||
// Parse configuration.
|
// Parse configuration.
|
||||||
|
@ -30,7 +42,7 @@ async fn main() -> IoResult<()> {
|
||||||
env::remove_var(CONFIG_ENV);
|
env::remove_var(CONFIG_ENV);
|
||||||
PathBuf::from(path)
|
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");
|
let config = Config::parse(&config_path).expect("failed to parse config");
|
||||||
log::trace!("{:#?}", config);
|
log::trace!("{:#?}", config);
|
||||||
|
@ -83,6 +95,7 @@ async fn main() -> IoResult<()> {
|
||||||
.unwrap_or_else(|_| panic!("failed to watch {config_path:?}"));
|
.unwrap_or_else(|_| panic!("failed to watch {config_path:?}"));
|
||||||
|
|
||||||
// Create a thread for cleaning up expired files.
|
// Create a thread for cleaning up expired files.
|
||||||
|
let upload_path = server_config.upload_path.clone();
|
||||||
thread::spawn(move || loop {
|
thread::spawn(move || loop {
|
||||||
let mut enabled = false;
|
let mut enabled = false;
|
||||||
if let Some(ref cleanup_config) = paste_config
|
if let Some(ref cleanup_config) = paste_config
|
||||||
|
@ -92,7 +105,7 @@ async fn main() -> IoResult<()> {
|
||||||
{
|
{
|
||||||
if cleanup_config.enabled {
|
if cleanup_config.enabled {
|
||||||
log::debug!("Running cleanup...");
|
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) {
|
match fs::remove_file(&file) {
|
||||||
Ok(()) => log::info!("Removed expired file: {:?}", file),
|
Ok(()) => log::info!("Removed expired file: {:?}", file),
|
||||||
Err(e) => log::error!("Cannot remove expired file: {}", e),
|
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.
|
// Create an HTTP server.
|
||||||
let mut http_server = HttpServer::new(move || {
|
let mut http_server = HttpServer::new(move || {
|
||||||
let http_client = ClientBuilder::new()
|
let http_client = ClientBuilder::new()
|
||||||
|
@ -144,3 +166,33 @@ async fn main() -> IoResult<()> {
|
||||||
// Run the server.
|
// Run the server.
|
||||||
http_server.run().await
|
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()
|
.read()
|
||||||
.map_err(|_| error::ErrorInternalServerError("cannot acquire config"))?;
|
.map_err(|_| error::ErrorInternalServerError("cannot acquire config"))?;
|
||||||
match &config.server.landing_page {
|
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()
|
None => Ok(HttpResponse::Found()
|
||||||
.append_header(("Location", env!("CARGO_PKG_HOMEPAGE")))
|
.append_header(("Location", env!("CARGO_PKG_HOMEPAGE")))
|
||||||
.finish()),
|
.finish()),
|
||||||
|
@ -158,6 +160,18 @@ async fn upload(
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, Error> {
|
||||||
let connection = request.connection_info().clone();
|
let connection = request.connection_info().clone();
|
||||||
let host = connection.peer_addr().unwrap_or("unknown host");
|
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(
|
auth::check(
|
||||||
host,
|
host,
|
||||||
request.headers(),
|
request.headers(),
|
||||||
|
@ -169,7 +183,16 @@ async fn upload(
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.cloned()),
|
.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();
|
let mut urls: Vec<String> = Vec::new();
|
||||||
while let Some(item) = payload.next().await {
|
while let Some(item) = payload.next().await {
|
||||||
let mut field = item?;
|
let mut field = item?;
|
||||||
|
@ -208,9 +231,8 @@ async fn upload(
|
||||||
.get_file(bytes_checksum)
|
.get_file(bytes_checksum)
|
||||||
{
|
{
|
||||||
urls.push(format!(
|
urls.push(format!(
|
||||||
"{}://{}/{}\n",
|
"{}/{}\n",
|
||||||
connection.scheme(),
|
server_url,
|
||||||
connection.host(),
|
|
||||||
file.path
|
file.path
|
||||||
.file_name()
|
.file_name()
|
||||||
.map(|v| v.to_string_lossy())
|
.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),
|
Byte::from_bytes(paste.data.len() as u128).get_appropriate_unit(false),
|
||||||
host
|
host
|
||||||
);
|
);
|
||||||
urls.push(format!(
|
urls.push(format!("{}/{}\n", server_url, file_name));
|
||||||
"{}://{}/{}\n",
|
|
||||||
connection.scheme(),
|
|
||||||
connection.host(),
|
|
||||||
file_name
|
|
||||||
));
|
|
||||||
} else {
|
} else {
|
||||||
log::warn!("{} sent an invalid form field", host);
|
log::warn!("{} sent an invalid form field", host);
|
||||||
return Err(error::ErrorBadRequest("invalid form field"));
|
return Err(error::ErrorBadRequest("invalid form field"));
|
||||||
|
|
Loading…
Reference in a new issue