Compare commits

...

384 Commits

Author SHA1 Message Date
Orhun Parmaksız 81d25401ff
chore(deps): bump libc to 0.2.155 2024-05-28 23:02:10 +03:00
dependabot[bot] 2bdd62bf1d
chore(deps): bump serde from 1.0.197 to 1.0.203 (#291)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.197 to 1.0.203.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.197...v1.0.203)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-27 20:56:38 +03:00
dependabot[bot] 9ceb0d4c21
chore(deps): bump docker/setup-qemu-action from 2 to 3 (#283)
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 2 to 3.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-13 19:27:39 +03:00
Orhun Parmaksız 7afea1721d
chore(docker): enable arm64 builds (#280)
This reverts commit d57ed1125f.
2024-05-11 23:40:06 +03:00
Orhun Parmaksız c04c39b975
docs(readme): remove blog post link 2024-05-05 14:01:07 +03:00
Orhun Parmaksız 32f95ef938
docs(readme): remove public instance link 2024-05-05 13:59:03 +03:00
dependabot[bot] 15e3619479
chore(deps): bump tokio from 1.36.0 to 1.37.0 (#268)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2024-04-04 00:09:29 +03:00
Orhun Parmaksız 2037530078
refactor(ci): provide codecov token via env
https://github.com/codecov/codecov-action/issues/1292
2024-04-04 00:03:57 +03:00
Orhun Parmaksız 44c07a3eb6
chore(release): prepare for v0.15.0 2024-03-27 23:03:10 +03:00
Orhun Parmaksız 64d783bd0d
chore(deps): bump all dependencies 2024-03-27 22:49:10 +03:00
Orhun Parmaksız 1fd561f869
docs(readme): add packaging status badge 2024-03-27 17:39:35 +03:00
dependabot[bot] c6d6da6296
chore(deps): bump codecov/codecov-action from 3 to 4 (#237)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-27 17:35:54 +03:00
Orhun Parmaksız 54e2ddc91a
chore(deps): bump serde from 1.0.196 to 1.0.197 2024-03-27 17:35:12 +03:00
dependabot[bot] 8e505c0da8
chore(deps): bump regex from 1.10.3 to 1.10.4 (#267)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-27 17:34:04 +03:00
Orhun Parmaksız 0f0ba72305
chore(deps): bump shuttle dependencies 2024-03-27 17:33:23 +03:00
dependabot[bot] 77e97573ef
chore(deps): bump tokio from 1.35.1 to 1.36.0 (#242)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-27 17:27:22 +03:00
dependabot[bot] 40f5d909ca
chore(deps): bump config from 0.13.4 to 0.14.0 (#240)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-27 17:27:07 +03:00
dependabot[bot] 567480a21e
chore(deps): bump actix-files from 0.6.2 to 0.6.5 (#225)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-27 17:25:43 +03:00
dependabot[bot] e8c342af46
chore(deps): bump ring from 0.17.7 to 0.17.8 (#248)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-27 17:25:13 +03:00
dependabot[bot] 1442771a57
chore(deps): bump awc from 3.3.0 to 3.4.0 (#243)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-27 17:24:56 +03:00
Orhun Parmaksız dadd88c240
chore(license): update the copyright years 2024-03-24 23:45:04 +03:00
Orhun Parmaksız e3b00453d9
chore(github): update funding options 2024-03-24 23:44:34 +03:00
Helmut K. C. Tessarek b2acb71d0d
refactor(ci): replace unmaintained action (#266) 2024-03-23 11:47:23 +01:00
Orhun Parmaksız db24d911f6
chore(deps): set up mergify 2024-03-14 23:02:13 +03:00
Helmut K. C. Tessarek 4774de6652
refactor(server): use more specific HTTP status codes (#262)
* refactor(server): use more specific http status codes

* fix: clippy error - oops missed that one

* test(fixtures): add check for status code
2024-03-11 14:00:45 +01:00
Helmut K. C. Tessarek 4987cfe5e5
fix(upload): error on upload with the same filename (#258) 2024-03-08 14:47:13 +01:00
Orhun Parmaksız c60a614258
chore(ci): switch to cargo-llvm-cov for code coverage (#260) 2024-03-08 14:17:42 +01:00
Helmut K. C. Tessarek fa5105deab
test(upload): update the hash of the example file (#254)
changed at source
2024-03-06 05:57:59 +01:00
Jake Howard dae00c42b5
feat(server): do path joins more safely (#247)
* Do path joins more safely

* Improve path cleaning and tests

* Lower-case error message

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>

* Correct handle potential errors in `get_path`

* Use `expect` in tests, rather than `unwrap`

* Correctly handle invalid upload path without panic

* Correctly handle filesystem create errors

* Use result rather than option to allow easier error handling

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2024-03-06 05:55:59 +01:00
Orhun Parmaksız 12f0e8f3a7
chore(server): gracefully exit when there is no config file found 2024-03-01 22:17:17 +03:00
Helmut K. C. Tessarek db971e6434
feat(server): allow to override filename when using random_url (#233)
* feat(server): allow to override filename when using random_url

* docs(README): remove line from features

* refactor(header): make const private
2024-02-12 13:06:12 +01:00
Helmut K. C. Tessarek 8e6393c6f4
fix(server): return the correct file on multiple files with same name (#234)
* fix(server): file not found, even though on server and not expired

* test: rename test
2024-02-09 21:38:33 +01:00
Helmut K. C. Tessarek e06c18279e
ci(shuttle): fix deployment (#236)
* ci(shuttle): fix deployment

* chore: add dummy file to trigger pipeline

* chore: remove dummy file to trigger pipeline

* ci(shuttle): remove dorny/paths-filter
2024-02-06 18:31:46 +01:00
Helmut K. C. Tessarek 48a3626c7d
fix(server): improve logging for deleted file (#235) 2024-01-31 21:25:04 +01:00
dependabot[bot] 8de2450931
chore(deps): bump serde from 1.0.195 to 1.0.196 (#232)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.195 to 1.0.196.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.195...v1.0.196)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-29 15:04:10 +01:00
dependabot[bot] 2003abe8bd
chore(deps): bump dorny/paths-filter from 2 to 3 (#231)
Bumps [dorny/paths-filter](https://github.com/dorny/paths-filter) from 2 to 3.
- [Release notes](https://github.com/dorny/paths-filter/releases)
- [Changelog](https://github.com/dorny/paths-filter/blob/master/CHANGELOG.md)
- [Commits](https://github.com/dorny/paths-filter/compare/v2...v3)

---
updated-dependencies:
- dependency-name: dorny/paths-filter
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-25 16:57:35 +01:00
dependabot[bot] 4703b26194
chore(deps): bump byte-unit from 5.1.3 to 5.1.4 (#229)
Bumps [byte-unit](https://github.com/magiclen/byte-unit) from 5.1.3 to 5.1.4.
- [Commits](https://github.com/magiclen/byte-unit/compare/v5.1.3...v5.1.4)

---
updated-dependencies:
- dependency-name: byte-unit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-24 13:48:07 +01:00
dependabot[bot] e383b6f426
chore(deps): bump regex from 1.10.2 to 1.10.3 (#227)
Bumps [regex](https://github.com/rust-lang/regex) from 1.10.2 to 1.10.3.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.10.2...1.10.3)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-22 16:11:30 +01:00
dependabot[bot] fa7304a5d0
chore(deps): bump actions/cache from 3 to 4 (#226)
Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-18 16:59:37 +01:00
dependabot[bot] 90c0477edb
chore(deps): bump serde from 1.0.194 to 1.0.195 (#221)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.194 to 1.0.195.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.194...v1.0.195)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-08 12:35:54 +01:00
dependabot[bot] 7f8428c75d
chore(deps): bump byte-unit from 5.1.2 to 5.1.3 (#220)
Bumps [byte-unit](https://github.com/magiclen/byte-unit) from 5.1.2 to 5.1.3.
- [Commits](https://github.com/magiclen/byte-unit/compare/v5.1.2...v5.1.3)

---
updated-dependencies:
- dependency-name: byte-unit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-08 12:35:35 +01:00
dependabot[bot] 25a013266c
chore(deps): bump serde from 1.0.193 to 1.0.194 (#219)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.193 to 1.0.194.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.193...v1.0.194)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-02 12:41:04 +01:00
Orhun Parmaksız 274bbd3307
fix(lints): apply clippy suggestions 2023-12-31 14:06:46 +03:00
dependabot[bot] c9ba166865
chore(deps): bump awc from 3.2.0 to 3.3.0 (#215)
Bumps [awc](https://github.com/actix/actix-web) from 3.2.0 to 3.3.0.
- [Release notes](https://github.com/actix/actix-web/releases)
- [Changelog](https://github.com/actix/actix-web/blob/master/CHANGES.md)
- [Commits](https://github.com/actix/actix-web/compare/awc-v3.2.0...awc-v3.3.0)

---
updated-dependencies:
- dependency-name: awc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-25 15:23:17 +01:00
dependabot[bot] 4af7970f48
chore(deps): bump futures-util from 0.3.29 to 0.3.30 (#214)
Bumps [futures-util](https://github.com/rust-lang/futures-rs) from 0.3.29 to 0.3.30.
- [Release notes](https://github.com/rust-lang/futures-rs/releases)
- [Changelog](https://github.com/rust-lang/futures-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/futures-rs/compare/0.3.29...0.3.30)

---
updated-dependencies:
- dependency-name: futures-util
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-25 15:18:58 +01:00
dependabot[bot] 87a0ba21ed
chore(deps): bump actix-web from 4.4.0 to 4.4.1 (#213)
Bumps [actix-web](https://github.com/actix/actix-web) from 4.4.0 to 4.4.1.
- [Release notes](https://github.com/actix/actix-web/releases)
- [Changelog](https://github.com/actix/actix-web/blob/master/CHANGES.md)
- [Commits](https://github.com/actix/actix-web/compare/web-v4.4.0...web-v4.4.1)

---
updated-dependencies:
- dependency-name: actix-web
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-25 15:18:34 +01:00
Orhun Parmaksız c8dd41549d
chore(release): prepare for v0.14.4 2023-12-20 22:52:27 +03:00
Helmut K. C. Tessarek ec9b55f3e2
fix(auth): remove excessive warning and typo (#210) 2023-12-20 18:47:51 +01:00
dependabot[bot] f905648866
chore(deps): bump tokio from 1.35.0 to 1.35.1 (#208)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.35.0 to 1.35.1.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.35.0...tokio-1.35.1)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-20 12:57:53 +01:00
dependabot[bot] cf21df8a7c
chore(deps): bump byte-unit from 5.0.4 to 5.1.2 (#207)
Bumps [byte-unit](https://github.com/magiclen/byte-unit) from 5.0.4 to 5.1.2.
- [Commits](https://github.com/magiclen/byte-unit/compare/v5.0.4...v5.1.2)

---
updated-dependencies:
- dependency-name: byte-unit
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-18 13:46:56 +01:00
dependabot[bot] a806af9a41
chore(deps): bump byte-unit from 5.0.3 to 5.0.4 (#206)
Bumps [byte-unit](https://github.com/magiclen/byte-unit) from 5.0.3 to 5.0.4.
- [Commits](https://github.com/magiclen/byte-unit/compare/v5.0.3...v5.0.4)

---
updated-dependencies:
- dependency-name: byte-unit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-15 15:35:55 +01:00
Orhun Parmaksız f3962485df
chore(deps): bump shuttle dependencies 2023-12-13 20:40:50 +03:00
Orhun Parmaksız d6e1968191
chore(changelog): update entries for v0.14.3 2023-12-12 21:31:26 +03:00
Orhun Parmaksız e34f747761
chore(release): prepare for v0.14.3 2023-12-12 21:30:08 +03:00
Artem Medvedev e21f99ac4a
refactor(server)!: cleanup authorization boilerplate (#199)
* refactor!: use `actix-web-grants` to protect endpoints

* fix: filter out blank strings

* doc: add documentation for a function

* fix: don't return body for not exposed endpoints

* test: add fixtures

* test: fix naming

* test: remove extra step in teardown
2023-12-12 19:21:29 +01:00
Artem Medvedev b74e9ceeaf
docs(readme): explain behavior of unset `auth_tokens` and `delete_tokens` (#202)
* doc(readme): explain behavior of unset `auth_tokens` & `delete_tokens`

Just a clarification on how this works in the case of uninstalled tokens, for greater clarity and security

* docs(readme): update styling

* docs(readme): update grammar

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-12-11 19:19:18 +01:00
Artem Medvedev c5c9c6d233
chore(fixtures): run fixtures on `macos` & `ubuntu` (#201)
* ci(fixtures): run fixtures on `macos` & `ubuntu`

In order to check the fixtures works on both OS

* fix: install coreutils for macos

* doc: add mention coreutils on `macOS`

* ci: fix

* ci: fix

* refactor(fixture): rename matrix.os.version to matrix.os.runner

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-12-11 19:16:25 +01:00
dependabot[bot] d7c67e0350
chore(deps): bump tokio from 1.34.0 to 1.35.0 (#203)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.34.0 to 1.35.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.34.0...tokio-1.35.0)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-11 13:46:46 +01:00
Artem Medvedev adbd67a182
test(fixtures): support `fixtures` on `macOS` (#200)
* test: support fixtures for macOS

* chore: clarify the comment

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-12-10 16:04:28 +01:00
Orhun Parmaksız 3e34206884
chore(deps): bump shuttle dependencies to 0.35.0 2023-12-09 22:41:20 +03:00
dependabot[bot] 1e9a3b4a71
chore(deps): bump ring from 0.17.6 to 0.17.7 (#196)
Bumps [ring](https://github.com/briansmith/ring) from 0.17.6 to 0.17.7.
- [Commits](https://github.com/briansmith/ring/commits)

---
updated-dependencies:
- dependency-name: ring
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-06 19:07:16 +01:00
Orhun Parmaksız d4b02eca91
fix(shuttle): fix Shuttle entrypoint 2023-12-05 15:22:10 +03:00
Orhun Parmaksız 0f377fc44c
chore(release): prepare for v0.14.2 2023-12-05 15:21:06 +03:00
Orhun Parmaksız 62948abdc0
docs(release): add release instructions 2023-12-05 15:17:55 +03:00
Orhun Parmaksız bb33f437ba
chore(deps): upgrade transitive dependencies 2023-12-05 15:14:08 +03:00
Orhun Parmaksız ef08b9e838
refactor(tracing): use macros from tracing crate 2023-12-05 15:12:48 +03:00
dependabot[bot] a291307bec
chore(deps): bump byte-unit from 4.0.19 to 5.0.3 (#192)
* chore(deps): bump byte-unit from 4.0.19 to 5.0.3

Bumps [byte-unit](https://github.com/magiclen/byte-unit) from 4.0.19 to 5.0.3.
- [Commits](https://github.com/magiclen/byte-unit/compare/v4.0.19...v5.0.3)

---
updated-dependencies:
- dependency-name: byte-unit
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(deps): update codebase accordingly to the new version of byte-unit

* fix(fixtures): use more precise byte comparison

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-12-05 13:08:22 +01:00
Orhun Parmaksız 3c3a4b58ac
chore(example): add auth token handling to HTML form example (#183) 2023-12-03 21:37:00 +03:00
Orhun Parmaksız fd75750a43
chore(deps): bump shuttle dependencies to 0.34.1 2023-11-30 00:47:36 +03:00
Orhun Parmaksız 339963f2bd
refactor(ci): fix multiline if statement 2023-11-30 00:46:54 +03:00
Orhun Parmaksız ed9f6aa586
chore(shuttle): deploy when Shuttle dependency is updated 2023-11-30 00:44:47 +03:00
dependabot[bot] 7c9f443943
chore(deps): bump ring from 0.17.5 to 0.17.6 (#195)
Bumps [ring](https://github.com/briansmith/ring) from 0.17.5 to 0.17.6.
- [Commits](https://github.com/briansmith/ring/commits)

---
updated-dependencies:
- dependency-name: ring
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-29 22:36:59 +01:00
dependabot[bot] 50fad6e333
chore(deps): bump lazy-regex from 3.0.2 to 3.1.0 (#182)
Bumps [lazy-regex](https://github.com/Canop/lazy-regex) from 3.0.2 to 3.1.0.
- [Changelog](https://github.com/Canop/lazy-regex/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Canop/lazy-regex/commits)

---
updated-dependencies:
- dependency-name: lazy-regex
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-24 23:05:34 +01:00
dependabot[bot] cc6815d783
chore(deps): bump config from 0.13.3 to 0.13.4 (#188)
Bumps [config](https://github.com/mehcode/config-rs) from 0.13.3 to 0.13.4.
- [Changelog](https://github.com/mehcode/config-rs/blob/v0.13.4/CHANGELOG.md)
- [Commits](https://github.com/mehcode/config-rs/compare/0.13.3...v0.13.4)

---
updated-dependencies:
- dependency-name: config
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-24 23:05:17 +01:00
Orhun Parmaksız 92a4360752
chore(deps): bump shuttle dependencies to 0.34.0 2023-11-25 01:03:37 +03:00
dependabot[bot] 89459e6be7
chore(deps): bump url from 2.4.1 to 2.5.0 (#189)
Bumps [url](https://github.com/servo/rust-url) from 2.4.1 to 2.5.0.
- [Release notes](https://github.com/servo/rust-url/releases)
- [Commits](https://github.com/servo/rust-url/compare/v2.4.1...v2.5.0)

---
updated-dependencies:
- dependency-name: url
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-23 19:38:17 +01:00
dependabot[bot] 616e5846cc
chore(deps): bump serde from 1.0.192 to 1.0.193 (#187)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.192 to 1.0.193.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.192...v1.0.193)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-21 23:11:01 +01:00
Orhun Parmaksız 54a906ddf7
chore(deps): bump shuttle dependencies to 0.33.0 2023-11-18 13:02:01 +01:00
dependabot[bot] 4bd3082566
chore(deps): bump tokio from 1.33.0 to 1.34.0 (#181)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.33.0 to 1.34.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.33.0...tokio-1.34.0)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-15 18:20:18 +01:00
dependabot[bot] 0e7aafaf0f
chore(deps): bump tracing-subscriber from 0.3.17 to 0.3.18 (#184)
Bumps [tracing-subscriber](https://github.com/tokio-rs/tracing) from 0.3.17 to 0.3.18.
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](https://github.com/tokio-rs/tracing/compare/tracing-subscriber-0.3.17...tracing-subscriber-0.3.18)

---
updated-dependencies:
- dependency-name: tracing-subscriber
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-14 15:00:22 +01:00
Orhun Parmaksız b0c61cdb09
bump shuttle dependencies to 0.32.0 2023-11-09 15:35:13 +03:00
dependabot[bot] 12b1c713a6
chore(deps): bump serde from 1.0.190 to 1.0.192 (#178)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.190 to 1.0.192.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.190...v1.0.192)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-07 22:24:14 +01:00
Orhun Parmaksız c6d32d6df9
docs(readme): update table of contents 2023-11-03 10:32:32 +01:00
DtxdF 9a73b3e9c5
docs(readme): add instructions for FreeBSD (#177)
* docs(readme): add instructions for FreeBSD

* docs(readme): add appjail to features section
2023-11-03 10:32:09 +01:00
Orhun Parmaksız 79662d64ab
chore(release): prepare for v0.14.1 2023-11-03 00:05:00 +01:00
Orhun Parmaksız eee3355107
fix(lib): fix typos 2023-11-02 23:58:46 +01:00
Orhun Parmaksız 87c0b11c60
chore(deps): upgrade transitive dependencies 2023-11-02 23:58:02 +01:00
Orhun Parmaksız 25be13d9bf
bump shuttle dependencies to 0.31.0 2023-11-02 16:10:51 +01:00
dependabot[bot] d943ad5bc6
chore(deps): bump futures-util from 0.3.28 to 0.3.29 (#174)
Bumps [futures-util](https://github.com/rust-lang/futures-rs) from 0.3.28 to 0.3.29.
- [Release notes](https://github.com/rust-lang/futures-rs/releases)
- [Changelog](https://github.com/rust-lang/futures-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/futures-rs/compare/0.3.28...0.3.29)

---
updated-dependencies:
- dependency-name: futures-util
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-27 15:19:41 +02:00
dependabot[bot] f0e0b247eb
chore(deps): bump serde from 1.0.189 to 1.0.190 (#173)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.189 to 1.0.190.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.189...v1.0.190)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-26 14:18:07 +02:00
Orhun Parmaksız 30400cab0d
chore(deps): bump shuttle dependencies to 0.30.1 2023-10-25 16:36:42 +02:00
dependabot[bot] 2477b7428e
chore(deps): bump tracing from 0.1.39 to 0.1.40 (#168)
Bumps [tracing](https://github.com/tokio-rs/tracing) from 0.1.39 to 0.1.40.
- [Release notes](https://github.com/tokio-rs/tracing/releases)
- [Commits](https://github.com/tokio-rs/tracing/compare/tracing-0.1.39...tracing-0.1.40)

---
updated-dependencies:
- dependency-name: tracing
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-23 19:12:51 +02:00
Jean SIMARD 70541bb842
feat(log): switch to `tracing` for logging (#163)
* feat(log): use 'tracing-subscriber' instead of 'env_logger'

resolves #161

* feat: use 'tracing' instead of 'log'

* feat: make 'INFO' the default log level
2023-10-20 23:30:16 +02:00
dependabot[bot] cd9ace952c
chore(deps): bump ring from 0.17.4 to 0.17.5 (#167)
Bumps [ring](https://github.com/briansmith/ring) from 0.17.4 to 0.17.5.
- [Commits](https://github.com/briansmith/ring/commits)

---
updated-dependencies:
- dependency-name: ring
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-19 14:25:37 +02:00
Orhun Parmaksız 77bb4ca299
chore(deps): bump regex to 1.10.2 2023-10-18 22:18:31 +03:00
dependabot[bot] 5d0e38ad15
chore(deps): bump regex from 1.10.0 to 1.10.1 (#165)
Bumps [regex](https://github.com/rust-lang/regex) from 1.10.0 to 1.10.1.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.10.0...1.10.1)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-17 11:25:28 +02:00
dependabot[bot] 4cb6548851
chore(deps): bump ring from 0.17.3 to 0.17.4 (#164)
Bumps [ring](https://github.com/briansmith/ring) from 0.17.3 to 0.17.4.
- [Commits](https://github.com/briansmith/ring/commits)

---
updated-dependencies:
- dependency-name: ring
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-17 11:24:58 +02:00
dependabot[bot] db97b32955
chore(deps): bump serde from 1.0.188 to 1.0.189 (#162)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.188 to 1.0.189.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.188...v1.0.189)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-13 14:37:49 +02:00
dependabot[bot] 25171ad828
chore(deps): bump ring from 0.17.2 to 0.17.3 (#160)
Bumps [ring](https://github.com/briansmith/ring) from 0.17.2 to 0.17.3.
- [Commits](https://github.com/briansmith/ring/commits)

---
updated-dependencies:
- dependency-name: ring
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-10 16:30:26 +02:00
dependabot[bot] d3394d0d30
chore(deps): bump regex from 1.9.6 to 1.10.0 (#159)
Bumps [regex](https://github.com/rust-lang/regex) from 1.9.6 to 1.10.0.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.9.6...1.10.0)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-10 16:30:12 +02:00
Orhun Parmaksız 48cdd09298
chore(deps): bump shuttle dependencies to 0.29.0 2023-10-09 16:26:51 +03:00
dependabot[bot] b2cdc072ca
chore(deps): bump ring from 0.17.0 to 0.17.2 (#157)
Bumps [ring](https://github.com/briansmith/ring) from 0.17.0 to 0.17.2.
- [Commits](https://github.com/briansmith/ring/commits)

---
updated-dependencies:
- dependency-name: ring
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-09 15:24:10 +02:00
dependabot[bot] 6be7b850a1
chore(deps): bump tokio from 1.32.0 to 1.33.0 (#155)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.32.0 to 1.33.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.32.0...tokio-1.33.0)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-09 15:23:35 +02:00
Orhun Parmaksız c60b548cc7
fix(lints): apply clippy suggestions 2023-10-07 14:40:05 +03:00
dependabot[bot] 8d4063c051
chore(deps): bump ring from 0.16.20 to 0.17.0 (#151)
Bumps [ring](https://github.com/briansmith/ring) from 0.16.20 to 0.17.0.
- [Commits](https://github.com/briansmith/ring/commits)

---
updated-dependencies:
- dependency-name: ring
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-07 13:09:46 +02:00
Orhun Parmaksız 0eebb78694
chore(deps): bump shuttle dependencies to 0.28.0 2023-10-04 22:12:27 +03:00
dependabot[bot] 9e6dfeeaaa
chore(deps): bump regex from 1.9.5 to 1.9.6 (#152)
Bumps [regex](https://github.com/rust-lang/regex) from 1.9.5 to 1.9.6.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.9.5...1.9.6)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-02 14:29:50 +02:00
Orhun Parmaksız 86759450b9
chore(deps): bump shuttle dependencies to 0.27.0 2023-09-22 15:01:20 +03:00
Orhun Parmaksız 613f1cd73d
fix(ci): use the correct arguments for cargo-tarpaulin 2023-09-19 13:58:21 +03:00
dependabot[bot] ab3e4844a9
chore(deps): bump docker/build-push-action from 4 to 5 (#143)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 4 to 5.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v4...v5)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-19 12:57:16 +02:00
Orhun Parmaksız 3f13beccaf
chore(deps): bump shuttle dependencies to 0.26.0 2023-09-19 13:56:46 +03:00
dependabot[bot] 6a1b911652
chore(deps): bump docker/setup-buildx-action from 2 to 3 (#141)
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 2 to 3.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-12 21:23:45 +02:00
dependabot[bot] fb0c075fc2
chore(deps): bump docker/login-action from 2 to 3 (#140)
Bumps [docker/login-action](https://github.com/docker/login-action) from 2 to 3.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-12 21:23:10 +02:00
dependabot[bot] 1fb0858f01
chore(deps): bump lazy-regex from 3.0.1 to 3.0.2 (#144)
Bumps [lazy-regex](https://github.com/Canop/lazy-regex) from 3.0.1 to 3.0.2.
- [Changelog](https://github.com/Canop/lazy-regex/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Canop/lazy-regex/commits)

---
updated-dependencies:
- dependency-name: lazy-regex
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-12 21:21:32 +02:00
dependabot[bot] ca68abd2a6
chore(deps): bump docker/metadata-action from 4 to 5 (#142)
Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 4 to 5.
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Upgrade guide](https://github.com/docker/metadata-action/blob/master/UPGRADE.md)
- [Commits](https://github.com/docker/metadata-action/compare/v4...v5)

---
updated-dependencies:
- dependency-name: docker/metadata-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-12 21:20:56 +02:00
Orhun Parmaksız f46d2f5af5
chore(release): prepare for v0.14.0 2023-09-05 20:46:33 +03:00
dependabot[bot] cef84b482f
chore(deps): bump actions/checkout from 3 to 4 (#139)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-05 13:51:34 +02:00
dependabot[bot] a6c17f14e0
chore(deps): bump regex from 1.9.4 to 1.9.5 (#138)
Bumps [regex](https://github.com/rust-lang/regex) from 1.9.4 to 1.9.5.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.9.4...1.9.5)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-04 15:26:49 +02:00
Helmut K. C. Tessarek cc9633cc95
refactor(server): change response to 'file deleted' (#137) 2023-09-04 11:09:29 +02:00
Andy Baird 27e3be5a2d
feat(server): add delete endpoint (#136)
* Delete endpoint implementation with delete_tokens configuration

* style(server): remove empty line, add dot at end of doc comment

* test(fixtures): add fixture test for file delete

* refactor(config): add delete_tokens to config.toml

* docs(readme): add info on how to delete file from server

* Update README.md

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>

* Update README.md

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>

* refactor(server): use log::error! and return 500

Co-authored-by: Helmut K. C. Tessarek <tessarek@evermeet.cx>

* test(server): add test_delete_file_without_token_in_config

* refactor(server): use one function to retrieve auth/delete tokens

Co-authored-by: Helmut K. C. Tessarek <tessarek@evermeet.cx>

* test(config): add test_get_tokens

* test(config): improve test_get_tokens

* feat(config): disallow empty tokens

* feat(server): update the messages for delete endpoint

---------

Co-authored-by: Helmut K. C. Tessarek <tessarek@evermeet.cx>
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-09-03 17:47:52 +02:00
Helmut K. C. Tessarek 2292c24aaf
chore(project): update crates and rustls deps (#135)
* chore(project): update crates and rustls deps

* chore(docker): update Rust to 1.72.0

* Update Dockerfile

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-08-30 12:04:52 +02:00
Orhun Parmaksız 614b44884d
chore(deps): bump shuttle dependencies to 0.25.0 2023-08-28 19:44:13 +03:00
dependabot[bot] 15cea9a157
chore(deps): bump url from 2.4.0 to 2.4.1 (#130)
Bumps [url](https://github.com/servo/rust-url) from 2.4.0 to 2.4.1.
- [Release notes](https://github.com/servo/rust-url/releases)
- [Commits](https://github.com/servo/rust-url/compare/v2.4.0...v2.4.1)

---
updated-dependencies:
- dependency-name: url
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-28 18:25:16 +02:00
Orhun Parmaksız a44ae94132
chore(release): prepare for v0.13.0 2023-08-26 23:40:04 +03:00
Orhun Parmaksız ec7a81ee6d
chore(deps): upgrade dependencies 2023-08-26 23:15:24 +03:00
Ömer Üstün 95379c9f66
feat(server): support handling spaces in filenames (#107)
* feat(server): add url encoding

- Introduced an option to enable encoding for filenames in the returned URL.
- Modified the encoding approach to specifically target whitespaces, replacing them with `%20`.
- Included unit tests to validate this encoding approach.
- Added fixture tests for broader functional verification.
- Removed the `urlencoding` dependency from `Cargo.toml`.

* Refactor code and fixtures for better compliance and consistency

- Fixed errors in the fixture configuration to ensure tests run as expected.
- Reformatted line endings for consistency across the codebase.
- Made necessary adjustments to adhere to Clippy's recommendations.

* Enhance whitespace handling options for filenames

- Implemented a configuration choice for space handling in filenames: encode, replace with underscores or none.
- Added corresponding unit and fixture tests.

* Remove redundant function call

Fixed misplaced line as per @tessus's review feedback, preventing duplicate handling of spaces in filenames.

* Delete test file with spaces.txt

* Refactor filename space handling

- Introduced `SpaceHandling` enum to manage filename spaces.
- Updated server.rs and paste.rs to utilize the new method.
- Added unit tests for the new filename handling method.
- Adjusted fixture tests to reflect these changes.

* Move filename processing into `SpaceHandling` enum

- Relocated filename processing logic to reside within the `SpaceHandling` enum, enhancing encapsulation.
- Updated calls in `server.rs` and `paste.rs` to use the new method structure.
- Adjusted unit tests to align with the refactored function location and call pattern.

* Refactor based on review suggestions

- Incorporated the inline suggestions made by @tessus, removing the unnecessary one-line assignments.
- Ensured the code adheres to Rust guidelines by running clippy and fmt.

* chore(deps): revert changes in Cargo.lock

* chore(config): replace spaces as default

* refactor(config): move SpaceHandling to config module

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-08-26 14:35:13 +02:00
dependabot[bot] 38d76fcb0f
chore(deps): bump serde from 1.0.185 to 1.0.186 (#124)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.185 to 1.0.186.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.185...v1.0.186)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-24 18:09:04 +02:00
dependabot[bot] 31c6cbfcfb
chore(deps): bump serde from 1.0.183 to 1.0.185 (#123)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.183 to 1.0.185.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.183...v1.0.185)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-21 13:58:45 +02:00
Helmut K. C. Tessarek d2d07ad345
feat(server): improve random_url config handling (#122)
* feat(server): improve random_url config handling

* log deprecation warnings after hot reload of config

* refactor(config): adjust config files

* tests(config): add test for deprecation codepath

* remove unnecessary to_string()

* style: delete empty line

* refactor(server): clean up random_url config handling

* refactor(config): update configs accordingly to deprecated random_url.enabled

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-08-20 20:32:41 +02:00
dependabot[bot] 679a26475a
chore(deps): bump tokio from 1.31.0 to 1.32.0 (#119)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.31.0 to 1.32.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.31.0...tokio-1.32.0)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-17 15:40:45 +02:00
Orhun Parmaksız 852e409b22
chore(deps): bump shuttle dependencies to 0.24.0 2023-08-17 16:05:09 +03:00
Helmut K. C. Tessarek c9a3ba4b86
chore(ci): replace unmaintained actions (#116) 2023-08-16 10:56:36 +02:00
Helmut K. C. Tessarek 9145c46e18
fix(server): don't log invalid token in release builds (#112)
* fix(server): don't log invalid token in release builds

* refactor(auth): use inline formatting for auth logs

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-08-14 14:05:34 +02:00
dependabot[bot] 0b8f63de19
chore(deps): bump tokio from 1.30.0 to 1.31.0 (#113)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.30.0 to 1.31.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.30.0...tokio-1.31.0)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-14 13:37:51 +02:00
dependabot[bot] 58e5558a10
chore(deps): bump log from 0.4.19 to 0.4.20 (#114)
Bumps [log](https://github.com/rust-lang/log) from 0.4.19 to 0.4.20.
- [Release notes](https://github.com/rust-lang/log/releases)
- [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/log/compare/0.4.19...0.4.20)

---
updated-dependencies:
- dependency-name: log
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-14 13:37:01 +02:00
Orhun Parmaksız 77f0e429d1
chore(release): prepare for v0.12.1 2023-08-11 15:26:36 +03:00
Helmut K. C. Tessarek 17ed34fc12
fix(server): do not list expired files (#109)
* fix(server): do not list expired files

* refactor(server): simplify list files function

* add test case

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-08-11 14:23:07 +02:00
dependabot[bot] 0e9688e8a4
chore(deps): bump tokio from 1.29.1 to 1.30.0 (#110)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.29.1 to 1.30.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.29.1...tokio-1.30.0)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-10 18:15:09 +02:00
Orhun Parmaksız 61d4a9e3e6
chore(release): prepare for v0.12.0 2023-08-07 14:49:03 +03:00
Orhun Parmaksız f473966f9d
chore(deps): upgrade transitive dependencies 2023-08-07 14:02:35 +03:00
Orhun Parmaksız 2734f371c9
chore(deps): bump shuttle dependencies to 0.23.0 2023-08-07 14:01:46 +03:00
Orhun Parmaksız 97ec45ed0b
chore(deps): upgrade dependencies 2023-08-07 14:01:01 +03:00
Andy Baird d0a67751dc
feat(server): add an endpoint for retrieving a list of files (#94)
* Start

* Wip

* Implement path based JSON index

* Remove json_index_path

* Return datetime stamp instead of relative time

* Add file size to list item

* Add auth check when retrieving JSON index

* Make json index path hardcoded

* Test (currently failing)

* Fix test for test_json_list

* Clippy fix

* Revert cargo to original versions with only needed changes

* Add detail about auth guard affecting list route

* Change json_index_path to expose_list

* Remove unneeded linebreak

* Remove unnecessary import

* Remove unnecessary space at end of line

* Move config check after auth check

* Use new auth check syntax, add docs to struct, rename test_json_list to test_list

* Replace chrono usage with uts2ts

* Check list result in test

* Add example to README

* Upgrade serde_json to 1.0.103

* Add linebreak

* Remove unneeded clone

* Remove extra nl

* Update README.md

* Update README.md

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>

* Update README.md

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>

* Remove serde_json

* Set default config to false for expose_list

* Apply suggestions from code review

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>

* Check that option is value in test_list

* Update Cargo.toml

Co-authored-by: Helmut K. C. Tessarek <tessarek@evermeet.cx>

* Update cargo.lock

* Use expect() to check file name

* Remove underscore from list item struct

* Keep comma after last line

* refactor(server): rename ListItem fields

* test(fixtures): add fixture test for listing files

* test push

* remove file again

* chop off ts from filename and minor refactor

* update README

* docs(readme): fix capitalization

* refactor(server): clean up list implementation

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
Co-authored-by: Helmut K. C. Tessarek <tessarek@evermeet.cx>
2023-08-07 12:55:13 +02:00
dependabot[bot] ee8996193d
chore(deps): bump serde from 1.0.180 to 1.0.181 (#108)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.180 to 1.0.181.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.180...v1.0.181)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-04 18:57:27 +02:00
dependabot[bot] cee95d9f85
chore(deps): bump serde from 1.0.179 to 1.0.180 (#103)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.179 to 1.0.180.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.179...v1.0.180)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 14:55:51 +02:00
Orhun Parmaksız 4daf41e9be
chore(deps): bump shuttle dependencies to 0.22.0 2023-08-02 15:53:18 +03:00
dependabot[bot] 8a82513a7c
chore(deps): bump serde from 1.0.177 to 1.0.179 (#102)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.177 to 1.0.179.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.177...v1.0.179)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-31 13:40:50 +02:00
dependabot[bot] c2c93a45ef
chore(deps): bump serde from 1.0.176 to 1.0.177 (#101)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.176 to 1.0.177.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.176...v1.0.177)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-28 20:35:00 +02:00
dependabot[bot] 278a97cc2e
chore(deps): bump lazy-regex from 3.0.0 to 3.0.1 (#100)
Bumps [lazy-regex](https://github.com/Canop/lazy-regex) from 3.0.0 to 3.0.1.
- [Changelog](https://github.com/Canop/lazy-regex/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Canop/lazy-regex/commits)

---
updated-dependencies:
- dependency-name: lazy-regex
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-28 20:34:46 +02:00
dependabot[bot] 2580e5cb7d
chore(deps): bump serde from 1.0.175 to 1.0.176 (#99)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.175 to 1.0.176.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.175...v1.0.176)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-27 14:08:37 +02:00
dependabot[bot] 8172f1f316
chore(deps): bump serde from 1.0.174 to 1.0.175 (#98)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.174 to 1.0.175.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.174...v1.0.175)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-24 15:44:16 +02:00
Helmut K. C. Tessarek 33e038cd4b
style(server): add new line char to most prominent messages (#97) 2023-07-22 10:12:04 +02:00
dependabot[bot] 2e13d7a0a1
chore(deps): bump serde from 1.0.173 to 1.0.174 (#96)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.173 to 1.0.174.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.173...v1.0.174)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-21 14:50:37 +02:00
Helmut K. C. Tessarek 0d4808880f
feat(server): support multiple auth tokens (#84)
* feat(server): support multiple auth tokens

Example:

```toml
[server]
auth_tokens = [
  "super_secret_token1",
  "super_secret_token2",
]
```

The previously used `AUTH_TOKEN` environment variable can still be used
and will be evaluated as well.

* fixtures: add all tokens in array to the test

* add deprecation warning for auth_token

* also add deprecation warnings at server startup

* fix formatting

* fixed tests, so that we do not use deprecated config options

* use bash array

* refactor: use separate function

* refactor: check auth tokens

* Update fixtures/test-server-auth-multiple-tokens/test.sh

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>

* refactor: convert functions to methods

* refactor: check function

* refactor: get_tokens method

* style(format): add newline between functions

* refactor(server): print deprecation warnings once

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-07-21 12:28:17 +02:00
dependabot[bot] b1bdc45767
chore(deps): bump serde from 1.0.171 to 1.0.173 (#95)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.171 to 1.0.173.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.171...v1.0.173)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-20 18:25:37 +02:00
Orhun Parmaksız f09c467f6e
chore(deps): bump shuttle dependencies to 0.21.0 2023-07-11 15:24:15 +03:00
dependabot[bot] 12afa9e468
chore(deps): bump lazy-regex from 2.5.0 to 3.0.0 (#88)
Bumps [lazy-regex](https://github.com/Canop/lazy-regex) from 2.5.0 to 3.0.0.
- [Changelog](https://github.com/Canop/lazy-regex/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Canop/lazy-regex/commits)

---
updated-dependencies:
- dependency-name: lazy-regex
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-11 14:18:51 +02:00
dependabot[bot] c6863ab8bf
chore(deps): bump serde from 1.0.167 to 1.0.171 (#91)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.167 to 1.0.171.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.167...v1.0.171)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-11 14:13:16 +02:00
dependabot[bot] 43cbb56599
chore(deps): bump regex from 1.9.0 to 1.9.1 (#90)
Bumps [regex](https://github.com/rust-lang/regex) from 1.9.0 to 1.9.1.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.9.0...1.9.1)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-11 14:12:14 +02:00
Helmut K. C. Tessarek a868a5fdde
chore(github): update the PR template about code blocks (#85) 2023-07-08 20:56:07 +02:00
dependabot[bot] 8a0445727d
chore(deps): bump serde from 1.0.166 to 1.0.167 (#86)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.166 to 1.0.167.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.166...v1.0.167)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-07 22:11:30 +02:00
dependabot[bot] ced71c71f9
chore(deps): bump regex from 1.8.4 to 1.9.0 (#83)
Bumps [regex](https://github.com/rust-lang/regex) from 1.8.4 to 1.9.0.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.8.4...1.9.0)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-06 18:34:28 +02:00
dependabot[bot] 4071792555
chore(deps): bump infer from 0.14.0 to 0.15.0 (#82)
Bumps [infer](https://github.com/bojand/infer) from 0.14.0 to 0.15.0.
- [Release notes](https://github.com/bojand/infer/releases)
- [Commits](https://github.com/bojand/infer/compare/v0.14.0...v0.15.0)

---
updated-dependencies:
- dependency-name: infer
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-06 00:09:19 +02:00
dependabot[bot] 49e8763257
chore(deps): bump serde from 1.0.165 to 1.0.166 (#81)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.165 to 1.0.166.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.165...v1.0.166)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-04 19:06:17 +02:00
dependabot[bot] e18372bb4b
chore(deps): bump serde from 1.0.164 to 1.0.165 (#80)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.164 to 1.0.165.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.164...v1.0.165)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-03 19:58:26 +02:00
Orhun Parmaksız 39f9a62425
fix(shuttle): deploy when a new tag is created 2023-07-01 17:45:41 +03:00
Orhun Parmaksız a402776739
chore(release): prepare for v0.11.1 2023-07-01 17:31:39 +03:00
Orhun Parmaksız 936feaedd5
fix(server): allow using deprecated landing page fields
This is a hotfix commit which allows the use of [server.landing_page]
fields even when the [landing_page] section does not exist in the
configuration file.
2023-07-01 17:28:56 +03:00
Orhun Parmaksız 4ca95cb381
chore(release): prepare for v0.11.0 2023-07-01 12:30:16 +03:00
Orhun Parmaksız fe38ef8835
chore(deps): upgrade transitive dependencies 2023-07-01 11:43:12 +03:00
Orhun Parmaksız b23e9f64bf
chore(github): add pull request template 2023-07-01 01:25:26 +03:00
Orhun Parmaksız 074991810e
chore(style): add editorconfig 2023-07-01 01:21:02 +03:00
Helmut K. C. Tessarek 62bbfef6a3
feat(server): add random suffix mode (#69)
* add random suffix mode

* fix linter issues

* add test case

* fix linter issues

* add comments, remove empty lines and single line declarations

* more test cases

* refactor(config): rename suffix_mode to random_suffix

* refactor(paste): clean up the random suffix logic

* chore(config): add random suffix example to default config

* docs(readme): mention random suffix feature

* test(fixtures): add fixture test for random suffix mode

* random_suffix -> suffix_mode

* fix default extension for .dotfile w/o extension

* fix formatting

* style(format): fix the indentation for random suffix fixture

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-07-01 00:11:16 +02:00
dependabot[bot] d740ae7e89
chore(deps): bump tokio from 1.29.0 to 1.29.1 (#77)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.29.0 to 1.29.1.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.29.0...tokio-1.29.1)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-30 14:59:55 +02:00
Orhun Parmaksız b549e3df7b
chore(deps): bump shuttle dependencies to 0.20.0 2023-06-29 16:28:15 +03:00
dependabot[bot] 38fd3cf8df
chore(deps): bump tokio from 1.28.2 to 1.29.0 (#73)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.28.2 to 1.29.0.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.28.2...tokio-1.29.0)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-29 15:23:06 +02:00
Ömer Furkan Demircioğlu d51b68da10
style(server): add new line character to 404 message (#72) 2023-06-27 15:08:46 +02:00
Orhun Parmaksız 40a87c586b
fix(config): warn about the deprecated fields even though the section does not exist 2023-06-24 09:29:05 +03:00
Orhun Parmaksız 4df136870a
fix(deploy): use the static folder for config (#70) 2023-06-23 18:33:05 +03:00
Helmut K. C. Tessarek aa1734b3f8
refactor(config): use a separate section for the landing page (#65)
* add [landing_page] section to config

Migration path:

Old:

```
[server]
landing_page = "Landing page text."
landing_page_file = "index.html"
landing_page_content_type = "text/html; charset=utf-8"
```

New:

```
[landing_page]
text = "Landing page text."
file = "index.html"
content_type = "text/html; charset=utf-8"
```

* fix typo and remove comments

* make the section optional

* make the section optional

* test(server): fix landing page related test failures

* also change html_form.toml

* do not break current config

* refactor(config): deprecate server.landing_page config fields

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-06-23 17:20:24 +02:00
Orhun Parmaksız 62c461702a
feat(shuttle): allow manually running the deployment job 2023-06-23 17:24:51 +03:00
dependabot[bot] 8f8e0caab0
chore(deps): bump infer from 0.13.0 to 0.14.0 (#71)
Bumps [infer](https://github.com/bojand/infer) from 0.13.0 to 0.14.0.
- [Release notes](https://github.com/bojand/infer/releases)
- [Commits](https://github.com/bojand/infer/compare/v0.13.0...v0.14.0)

---
updated-dependencies:
- dependency-name: infer
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-23 16:07:08 +02:00
Orhun Parmaksız ff9fd68e89
chore(deps): bump shuttle dependencies to 0.19.0 2023-06-20 23:13:00 +03:00
Orhun Parmaksız 5b01c98243
docs(readme): note that the Alpine package is moved to the community 2023-06-16 17:41:59 +03:00
Orhun Parmaksız 1f041d3f74
refactor(example): use a file for HTML form landing page example 2023-06-16 17:38:12 +03:00
Helmut K. C. Tessarek e0d6712dd3
feat(server): support a file for the landing page (#64)
* implemented landing_page_file

* fixed issues found by linter

* fixed formatting

* refactor(config): refactor landing page file handling

* add tests

* fix unnecessary conversion

* fix formatting

* remove comment

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-06-16 16:21:44 +02:00
Helmut K. C. Tessarek f7beaef502
feat(server): honor X-Forward-* headers (#61)
* honor X-Forward-* headers

Behind a reverse proxy, the log entries always showed the IP address of the reverse proxy.
With this change the real IP address of the client is shown.
Since the IP address is only used for info in the log, there are no security implications.

* style(format): apply formatting

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-06-13 01:00:55 +02:00
Helmut K. C. Tessarek 917074158a
docs(readme): list all supported units for expiry (#63)
These suffixes are also supported in the `config.toml`.
2023-06-13 00:14:05 +02:00
dependabot[bot] 6d3d224307
chore(deps): bump log from 0.4.18 to 0.4.19 (#62)
Bumps [log](https://github.com/rust-lang/log) from 0.4.18 to 0.4.19.
- [Release notes](https://github.com/rust-lang/log/releases)
- [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/log/compare/0.4.18...0.4.19)

---
updated-dependencies:
- dependency-name: log
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-13 00:13:07 +02:00
dependabot[bot] b3fd28795d
chore(deps): bump serde from 1.0.163 to 1.0.164 (#60)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.163 to 1.0.164.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.163...v1.0.164)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-08 18:04:03 +02:00
Orhun Parmaksız a1bc77430e
chore(release): prepare for v0.10.1 2023-06-06 00:29:52 +03:00
dependabot[bot] 07ec392867
chore(deps): bump hotwatch from 0.4.6 to 0.5.0 (#55)
Bumps [hotwatch](https://github.com/francesca64/hotwatch) from 0.4.6 to 0.5.0.
- [Release notes](https://github.com/francesca64/hotwatch/releases)
- [Changelog](https://github.com/francesca64/hotwatch/blob/main/CHANGELOG.md)
- [Commits](https://github.com/francesca64/hotwatch/compare/v0.4.6...v0.5.0)

---
updated-dependencies:
- dependency-name: hotwatch
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-05 23:15:30 +02:00
dependabot[bot] b4d1178ca4
chore(deps): bump shuttle dependencies to 0.18.0
chore(deps): bump shuttle-actix-web from 0.17.0 to 0.18.0

Bumps shuttle-actix-web from 0.17.0 to 0.18.0.

---
updated-dependencies:
- dependency-name: shuttle-actix-web
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

chore(deps): bump shuttle-runtime from 0.17.0 to 0.18.0

Bumps shuttle-runtime from 0.17.0 to 0.18.0.

---
updated-dependencies:
- dependency-name: shuttle-runtime
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

chore(deps): bump shuttle-static-folder from 0.17.0 to 0.18.0

Bumps shuttle-static-folder from 0.17.0 to 0.18.0.

---
updated-dependencies:
- dependency-name: shuttle-static-folder
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-05 23:50:16 +03:00
Orhun Parmaksız c9bc01fe65
chore(shuttle): test the shuttle builds 2023-06-05 23:41:26 +03:00
dependabot[bot] 39c85977bf
chore(deps): bump url from 2.3.1 to 2.4.0 (#56)
Bumps [url](https://github.com/servo/rust-url) from 2.3.1 to 2.4.0.
- [Release notes](https://github.com/servo/rust-url/releases)
- [Commits](https://github.com/servo/rust-url/compare/v2.3.1...v2.4.0)

---
updated-dependencies:
- dependency-name: url
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-05 22:28:25 +02:00
Orhun Parmaksız 19cb7cccb7
refactor(middleware): polish the ContentLengthLimiter implementation 2023-06-05 23:02:10 +03:00
Orhun Parmaksız 1670a71cdd
feat(server): implement middleware for limiting the content length (#53) 2023-06-05 22:49:26 +03:00
Orhun Parmaksız a13c0f123a
fix(hotwatch): do not drop the config watcher 2023-06-04 14:43:08 +03:00
Orhun Parmaksız d4d8a28783
chore(release): prepare for v0.10.0 2023-05-31 02:16:47 +03:00
Orhun Parmaksız 4f539d2246
chore(deps): upgrade transitive dependencies 2023-05-31 02:15:16 +03:00
Orhun Parmaksız f165c29faf
docs(readme): add link to the blog post 2023-05-31 01:24:46 +03:00
Orhun Parmaksız ebe2087845
docs(readme): add table of contents 2023-05-31 01:22:57 +03:00
Chris Jones 1a89589669
docs(example): add information about using HTML form (#51)
* docs(readme): add information about using html form

* chore(example): improve HTML form example

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-05-31 00:21:15 +02:00
Orhun Parmaksız 1a9163639c
chore(log): add startup log for showing the server address 2023-05-31 00:53:59 +03:00
dependabot[bot] ea01ba5794
chore(deps): bump tokio from 1.28.1 to 1.28.2 (#49)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.28.1 to 1.28.2.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.28.1...tokio-1.28.2)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-29 18:34:00 +02:00
dependabot[bot] cc16878b00
chore(deps): bump log from 0.4.17 to 0.4.18 (#50)
Bumps [log](https://github.com/rust-lang/log) from 0.4.17 to 0.4.18.
- [Release notes](https://github.com/rust-lang/log/releases)
- [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/log/compare/0.4.17...0.4.18)

---
updated-dependencies:
- dependency-name: log
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-29 18:33:02 +02:00
Rahul Garg bd88146430
feat(server): support one shot URLs (#46)
* Add support for OneshotUrl

* Review cmt: Update README

* docs(oneshot): update documentation about oneshot URLs

* Review cmt: revert fmt

* test(fixtures): add fixture test for oneshot URLs

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-05-28 22:09:14 +02:00
Chris Jones 9d153ad907
feat(server): allow configuring the content type for landing page (#48)
* Allow user configuration of content type

* style(format): apply formatting

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-05-28 00:16:46 +02:00
dependabot[bot] 8e22d4b71a
chore(deps): bump regex from 1.8.2 to 1.8.3 (#47)
Bumps [regex](https://github.com/rust-lang/regex) from 1.8.2 to 1.8.3.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.8.2...1.8.3)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-27 16:32:33 +02:00
Orhun Parmaksız 6f2d27d589
chore(release): prepare for v0.9.1 2023-05-24 22:58:07 +03:00
Orhun Parmaksız 848e503870
chore(deps): upgrade transitive dependencies 2023-05-24 22:53:05 +03:00
Orhun Parmaksız 9738a750e3
chore(deps): bump shuttle dependencies 2023-05-24 15:28:32 +03:00
dependabot[bot] 30ba212465
chore(deps): bump regex from 1.8.1 to 1.8.2 (#42)
Bumps [regex](https://github.com/rust-lang/regex) from 1.8.1 to 1.8.2.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.8.1...1.8.2)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-24 14:22:26 +02:00
Orhun Parmaksız f20e2d8d12
chore(shuttle): increase the max content length 2023-05-17 17:21:49 +03:00
Orhun Parmaksız 1966982198
chore(shuttle): increase the default expiry time 2023-05-17 17:20:09 +03:00
Orhun Parmaksız 9ead53097e
docs(readme): fix the OpenSSL feature example 2023-05-17 14:27:04 +03:00
Orhun Parmaksız 8359aadec6
docs(readme): mention the available feature flags 2023-05-17 14:04:32 +03:00
Orhun Parmaksız bfe78c067e
chore(release): prepare for v0.9.0 2023-05-17 13:47:01 +03:00
Orhun Parmaksız f28fe68ba7
chore(deps): upgrade transitive dependencies 2023-05-17 12:32:48 +03:00
alice dca8041990
feat(deps): allow using openssl for tls (#37)
* feat(deps): allow using openssl for tls

this allows reusing the openssl present on a distro already,
and takes a release build with it from 5.5 to 4.7mb

* chore(shuttle): update the enabled features for deployment

---------

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2023-05-17 11:30:59 +02:00
Orhun Parmaksız 5b45b35a44
docs(readme): add information about how to run test fixtures 2023-05-17 12:29:40 +03:00
Orhun Parmaksız c1b47e28c9
docs(readme): add instructions for Alpine Linux 2023-05-17 12:28:39 +03:00
Orhun Parmaksız b092b0047d
style(changelog): format the changelog 2023-05-17 12:25:12 +03:00
Orhun Parmaksız 00d46b4b21
style(readme): add badges to README.md 2023-05-17 04:32:54 +03:00
Orhun Parmaksız e3a634b7af
chore(deploy): restart the project before deployment 2023-05-17 04:23:01 +03:00
Orhun Parmaksız 9e61cca98e
docs(readme): update features section about `default_expiry` 2023-05-14 23:55:47 +03:00
Orhun Parmaksız d57ed1125f
chore(docker): disable arm64 builds temporarily 2023-05-14 22:06:29 +03:00
Orhun Parmaksız a415ef60a0
chore(docker): enable dependency caching in Dockerfile
This reverts commit 82f1a3207f.
2023-05-14 21:57:27 +03:00
Orhun Parmaksız 82f1a3207f
chore(docker): remove dependency caching from Dockerfile 2023-05-14 21:44:22 +03:00
Orhun Parmaksız 29ddef8df0
feat(deploy): deploy on shuttle.rs (#36)
* feat(deploy): deploy on shuttle.rs

* chore(deploy): add automated shuttle deploy workflow

* style(readme): update the formatting in README.md

* chore(deploy): optimize shuttle workflow

* fix(deploy): start the project

* fix(deploy): remove start step

This reverts commit 4f25921aeb.

* chore(deploy): expose the version for the public instance

* docs(lib): update the comment for shuttle entry-point

* chore(deploy): run the shuttle deployment on new tag
2023-05-14 18:03:53 +02:00
Orhun Parmaksız 019d1556da
chore(ci): use the stable version for checkout action 2023-05-14 13:48:39 +03:00
Orhun Parmaksız ab5e153a4e
style(config): format the default config 2023-05-14 13:38:34 +03:00
Orhun Parmaksız 4a4301ee72
style(server): make the default landing page fancier 2023-05-14 01:56:57 +03:00
Orhun Parmaksız 607f07b6e1
feat(server): support server-side default expiry time 2023-05-14 01:30:35 +03:00
Orhun Parmaksız 9ea7d5de8a
feat(config): support overriding the server URL 2023-05-13 23:20:52 +03:00
Orhun Parmaksız 4e45b6a20d
style(config): format the config 2023-05-13 22:50:39 +03:00
dependabot[bot] 9fcbb1dfb0
chore(deps): bump serde from 1.0.162 to 1.0.163 (#35)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.162 to 1.0.163.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.162...v1.0.163)

---
updated-dependencies:
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-11 18:21:20 +02:00
Orhun Parmaksız 85e0c410d4
fix(docker): remove target directory from excluded files for proper caching 2023-05-11 00:45:23 +03:00
dependabot[bot] ad4c990b13
chore(deps): bump codecov/codecov-action from 1 to 3 (#34)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 1 to 3.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v1...v3)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-10 23:43:07 +02:00
Orhun Parmaksız 18ba29e04a
chore(github): update funding options 2023-05-11 00:41:41 +03:00
Orhun Parmaksız 5e8ea66256
chore(ci): integrate dependabot 2023-05-11 00:41:03 +03:00
Orhun Parmaksız 70085f3ad0
chore(ci): update runners to Ubuntu 22.04 2023-05-11 00:40:08 +03:00
Orhun Parmaksız d82e99c128
chore(deps): upgrade dependencies 2023-05-11 00:39:04 +03:00
Orhun Parmaksız dc499e402e
chore(docker): optimize docker build workflow 2023-05-11 00:29:11 +03:00
Orhun Parmaksız ce51c184a5
docs(changelog): update changelog entry for 0.8.4 2023-01-31 21:21:54 +03:00
Orhun Parmaksız a0ba66cac1
chore(release): prepare for v0.8.4 2023-01-31 21:20:06 +03:00
Orhun Parmaksız 29d5856566
chore(deps): upgrade transitive dependencies 2023-01-31 21:09:03 +03:00
Orhun Parmaksız 99ac6156a8
feat(server): allow downloading files via `?download=true` parameter (#24) 2023-01-31 21:03:00 +03:00
Orhun Parmaksız e459ba5f3c
chore(release): prepare for v0.8.3 2023-01-30 22:24:52 +03:00
Orhun Parmaksız e013ac26bd
chore(bin): strip the binary symbols with an option in Cargo.toml 2023-01-30 21:07:37 +03:00
Orhun Parmaksız c5389a1200
fix(docker): switch to Rust image as builder for Dockerfile 2023-01-30 21:03:42 +03:00
Orhun Parmaksız 240907c53a
chore(deps): upgrade dependencies 2023-01-30 20:41:19 +03:00
Orhun Parmaksız e82914f0f1
fix(ci): update cargo-tarpaulin installation command 2023-01-29 16:52:29 +03:00
Orhun Parmaksız 695bb738cd
docs(license): update copyright years 2023-01-01 20:38:12 +03:00
Marcin Puc 96b919e5ee
chore(deps): remove unused clap dependency (#32) 2023-01-01 18:36:37 +01:00
Orhun Parmaksız 8bac3cc91f
fix(lints): apply clippy suggestions for tests 2022-12-18 23:43:58 +03:00
Orhun Parmaksız e83b8e6f4a
fix(lints): apply clippy suggestions 2022-12-18 23:12:28 +03:00
Orhun Parmaksız a954676547
chore(release): prepare for v0.8.2 2022-10-04 19:37:09 +02:00
Leonidas Spyropoulos a324305a7d
fix(config): don't expose version endpoint in default config (#31)
Signed-off-by: Leonidas Spyropoulos <artafinde@archlinux.org>

Signed-off-by: Leonidas Spyropoulos <artafinde@archlinux.org>
2022-10-04 16:29:23 +00:00
Orhun Parmaksız df0d5391b4
docs(changelog): update CHANGELOG.md for v0.8.1 2022-10-04 13:55:05 +02:00
Orhun Parmaksız 8394aacb49
chore(deps): update time dependency 2022-10-04 13:04:21 +02:00
Leonidas Spyropoulos 1050448ebd
chore(deps): replace unmaintained dotenv with dotenvy (#30)
Fixes: #25

Signed-off-by: Leonidas Spyropoulos <artafinde@archlinux.org>3
2022-10-04 10:02:51 +00:00
Orhun Parmaksız 20a1482aa7
chore(release): prepare for v0.8.1 2022-10-04 12:49:58 +02:00
Leonidas Spyropoulos 5cdbc8da61
feat(server): expose version as endpoint (#29)
Fixes: #27

Signed-off-by: Leonidas Spyropoulos <artafinde@archlinux.org>
2022-10-04 09:38:37 +00:00
Orhun Parmaksız 00cee6d9ba
chore(release): prepare for v0.8.0 2022-10-04 01:29:35 +02:00
Orhun Parmaksız 6ffc5d6209
chore(deps): upgrade dependencies 2022-10-04 01:14:23 +02:00
TheTechRobo 37cb4d3fcb
feat(server): add landing page (#26)
* feat(server): add landing page

Fixes orhun/rustypaste#13

* feat(server): allow using {REPOSITORY} in landing page

* fix(server): Get rid of unused import, add line about expiration

* chore(fmt): cargo fmt

* fix(tests): inject app data for fixing index test

* feat(server): redirect to GitHub repository if landing page is not specified

* test(fixtures): add fixture test for landing page

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2022-10-03 21:27:35 +00:00
Orhun Parmaksız 1e1da30b83
fix(lints): apply clippy suggestions 2022-08-14 12:11:03 +02:00
Orhun Parmaksız a7dcc39f91
chore(funding): enable GitHub Sponsors for funding
https://github.com/sponsors/orhun
2022-07-31 15:05:03 +02:00
PLANTROON a0f076269e
chore(config): do not check for duplicate files by default (#23)
It is an expensive operation to do on slower hardware and can take unreasonable amount of time for bigger files
2022-06-25 02:57:03 +03:00
Orhun Parmaksız 59f9b46bb8
chore(release): prepare for v0.7.1 2022-05-21 20:02:05 +03:00
Orhun Parmaksız 16628e402a
chore(deps): upgrade dependencies 2022-05-21 19:54:05 +03:00
Orhun Parmaksız deec5d4c29
test(fixtures): add fixture test for random URL 2022-05-21 19:31:43 +03:00
Orhun Parmaksız a98f0ae22e
test(fixtures): add fixture test for default extension 2022-05-21 19:23:59 +03:00
Orhun Parmaksız 5cdca1d9aa
test(fixtures): add fixture test for MIME override 2022-05-21 19:12:09 +03:00
Orhun Parmaksız c06fff92ac
test(fixtures): add fixture test for MIME blacklist 2022-05-21 18:47:41 +03:00
Orhun Parmaksız d262a3d297
test(fixtures): add fixture test for auto deletion 2022-05-21 18:23:21 +03:00
Orhun Parmaksız a6a8261a73
refactor(fixtures): merge test steps in a single subshell 2022-05-21 17:52:47 +03:00
Orhun Parmaksız 00167db3d6
fix(fixtures): enable random URLs for duplicate file fixture 2022-05-21 17:52:14 +03:00
Orhun Parmaksız cccbf98acc
refactor(fixtures): use subshell for running fixture methods 2022-05-21 16:51:06 +03:00
Orhun Parmaksız c60090d461
fix(fixtures): exit the run_test function on error 2022-05-21 16:43:32 +03:00
Orhun Parmaksız 685d9607c8
chore(ci): run test fixtures 2022-05-21 15:46:37 +03:00
Orhun Parmaksız 4d16e65edb
test(fixtures): add a test framework along with test fixtures 2022-05-21 15:27:38 +03:00
Orhun Parmaksız 3467038353
feat(env): support configuring logger from .env file 2022-05-21 09:07:37 +03:00
Orhun Parmaksız 63c79b8297
feat(log): print the configuration as trace log at startup 2022-05-21 06:26:17 +03:00
Orhun Parmaksız 48063d736a
feat(config): allow omitting MIME settings from the config 2022-05-21 06:25:23 +03:00
Orhun Parmaksız 87d2423d1a
test(server): add test for duplicate uploads 2022-05-18 09:50:47 +03:00
Orhun Parmaksız 013c6ac810
test(server): add tests for server configuration 2022-05-17 22:38:57 +03:00
Orhun Parmaksız 1f8f462299
test(server): add tests for different paste types 2022-05-17 22:09:24 +03:00
Orhun Parmaksız a330b59dca
fix(lints): apply clippy suggestions for tests 2022-05-16 12:58:41 +03:00
Orhun Parmaksız 657ca8c1d4
fix(server): do not hold the RwLock guard before async calls 2022-05-16 12:34:57 +03:00
Orhun Parmaksız 59415cd31a
docs(readme): update contributing details 2022-05-16 10:28:57 +03:00
Orhun Parmaksız 1d44cbd9c8
test(server): add test for upload 2022-05-16 10:25:59 +03:00
Orhun Parmaksız 74237d56c5
chore(release): prepare for v0.7.0 2022-03-26 00:54:15 +03:00
Orhun Parmaksız 527fbc4f49
chore(deps): upgrade dependencies 2022-03-26 00:07:57 +03:00
frederik 8679ff91dc
chore(systemd): add systemd service files (#22)
Add systemd files to serve files from /var/lib/rustypaste, automatic
user creation via systemd-sysusers and AUTH_TOKEN configuration via
rustypaste.env in /etc/rustypaste/rustypaste.env.

implements #16
2022-03-25 23:51:20 +03:00
Orhun Parmaksız 8ed0b7bbf1
chore(build): strip the binary 2022-03-23 16:48:39 +03:00
Orhun Parmaksız 9136d1ce09
docs(readme): add testing instructions to README.md 2022-03-23 16:41:09 +03:00
Orhun Parmaksız dd91c50d50
feat(server): support auto-deletion of expired files (#17)
feat(server): support auto-deletion of expired files (#17)

chore(ci): set the number of test threads to 1

feat(config): allow the real-time update of cleanup routine

docs(readme): update README.md about deleting expired files
2022-03-23 16:13:46 +03:00
Orhun Parmaksız a3e266b8b4
refactor(server): define global constants for environment variables 2022-03-17 15:54:08 +03:00
Orhun Parmaksız c48e45d68c
chore(deps): upgrade actix dependencies
closes #18
2022-03-17 15:46:32 +03:00
Orhun Parmaksız 51d6fdd0d8
docs(readme): reorder sections in README.md 2022-03-17 11:53:16 +03:00
Orhun Parmaksız 2d5c14a6e0
docs(readme): apply shellcheck suggestions to cleanup script 2022-03-17 11:50:27 +03:00
sh 44ab1318ee
docs(readme): add shell script for cleaning files (#20) 2022-03-17 11:47:33 +03:00
Sven-Hendrik Haase d3a9e0c69d
chore(codecov): add codecov config (#21)
This is to ensure that trivial decreases in code coverage don't fail the pipeline.
2022-03-17 00:29:26 +03:00
Orhun Parmaksız 525129ddcb
fix(server): check if the path is a file while serving
closes #19
2022-03-16 16:37:54 +03:00
Orhun Parmaksız ffe067f9da
chore(release): prepare for v0.6.5 2022-03-13 21:33:32 +03:00
Orhun Parmaksız 08dc063a7a
docs(readme): add installation instructions for Arch Linux 2022-03-13 21:13:31 +03:00
Orhun Parmaksız 1dd5dcf167
fix(config): unset `CONFIG` environment variable to avoid conflicts 2022-03-13 21:12:10 +03:00
Orhun Parmaksız e3a97045f4
chore(release): prepare for v0.6.4 2022-03-12 02:04:18 +03:00
Orhun Parmaksız bdb8492a11
chore(deps): upgrade dependencies 2022-03-12 02:02:36 +03:00
Orhun Parmaksız 94516c95bb
feat(config): support setting the timeout for HTTP requests 2022-03-12 00:35:54 +03:00
Orhun Parmaksız fda6f91211
style(readme): update the formatting of example shell function 2022-03-12 00:03:37 +03:00
Orhun Parmaksız 9e5bd112e7
feat(config): support setting the refresh rate for hot-reloading 2022-03-12 00:02:25 +03:00
Orhun Parmaksız 0f893ba058
docs(changelog): update CHANGELOG.md about auth_token example 2022-02-25 00:32:19 +03:00
Orhun Parmaksız d4a12cdcee
chore(release): prepare for v0.6.3 2022-02-25 00:25:50 +03:00
Orhun Parmaksız 2ef453be28
chore(docker): remove Rust edition workaround from Dockerfile 2022-02-25 00:14:14 +03:00
Orhun Parmaksız d6ba6ac630
chore(deps): upgrade dependencies 2022-02-25 00:10:52 +03:00
Orhun Parmaksız 6f1dcab15a
fix(lints): apply clippy suggestions 2022-02-24 23:54:54 +03:00
Orhun Parmaksız 3cc40deca0
feat(config): support setting the auth token in config 2022-02-24 23:51:47 +03:00
Orhun Parmaksız 53686c6c93
docs(license): update copyright years 2022-01-09 15:05:41 +03:00
Orhun Parmaksız 4f6456a3c8
chore(release): prepare for v0.6.2 2021-12-05 16:16:10 +03:00
Orhun Parmaksız 17b8c1940c
chore(deps): upgrade dependencies 2021-12-05 16:09:53 +03:00
Orhun Parmaksız ebbe8dbfae
test(paste): update paste test about borrowing the config 2021-12-05 15:27:38 +03:00
Orhun Parmaksız 2b80c78a02
Merge branch 'master' of ssh://github.com/orhun/rustypaste 2021-12-05 15:04:21 +03:00
Orhun Parmaksız 8f3f89716f
fix(async): drop the RW guard of config before suspend points 2021-12-05 15:03:51 +03:00
Orhun Parmaksız 5cbb41c247
fix(async): clone Ref to avoid holding it across a suspend point 2021-12-05 14:13:25 +03:00
Sven Assmann 8a03fe3655
chore(deps): bump versions (#9) 2021-11-17 19:42:45 +03:00
Orhun Parmaksız dbda1bb94a
chore(release): prepare for v0.6.1 2021-11-16 19:48:38 +03:00
Orhun Parmaksız 8b17137c52
fix(server): gracefully handle the hot-reloading errors 2021-11-16 19:27:18 +03:00
Orhun Parmaksız 27cfa6aca3
chore(release): prepare for v0.6.0 2021-11-07 17:44:10 +03:00
Orhun Parmaksız f3859d2857
docs(readme): make the heading sizes consistent 2021-11-07 17:25:42 +03:00
Orhun Parmaksız 2b6b3caf2c
chore(deps): upgrade dependencies 2021-11-07 17:19:17 +03:00
Orhun Parmaksız 7797180937
fix(server): change the config data type for serve route 2021-11-07 17:03:00 +03:00
Orhun Parmaksız b12ff1f579
chore(docker): update Dockerfile about Rust edition 2021-11-07 16:52:08 +03:00
Orhun Parmaksız 6b3914a54e
chore(lib): import required traits for backwards edition compatibility 2021-11-07 16:25:08 +03:00
Orhun Parmaksız d927fb0b97
chore(security): optimize cargo-audit workflow 2021-11-07 16:16:46 +03:00
Orhun Parmaksız a2de1c3334
feat(config): hot-reload the configuration 2021-11-07 16:06:57 +03:00
Orhun Parmaksız f078a9afa7
fix(server): prevent serving an already expired file 2021-11-07 00:49:31 +03:00
Orhun Parmaksız 3eee294bd9
docs(lib): update the function comment for store_remote_file 2021-11-07 00:01:30 +03:00
Orhun Parmaksız 7a6842e181
feat(paste): support pasting files from remote URLs 2021-11-06 23:55:55 +03:00
Orhun Parmaksız bd86c27b08
chore(project): switch to Rust edition 2021 2021-11-05 23:33:42 +03:00
Orhun Parmaksız 0cbafd9538
chore(release): prepare for v0.5.0 2021-10-12 19:59:35 +03:00
Orhun Parmaksız 8eff8847ea
chore(docker): improve docker build workflow 2021-10-12 19:46:32 +03:00
Orhun Parmaksız dcaa5eccf9
chore(deps): upgrade dependencies 2021-10-12 19:42:25 +03:00
Orhun Parmaksız e29df82899
docs(readme): update the roadmap 2021-10-12 19:36:41 +03:00
Orhun Parmaksız c08fd29a45
feat(paste): make duplicate uploads optional (#7) 2021-10-12 19:35:06 +03:00
Orhun Parmaksız a5757d4892
chore(release): prepare for v0.4.1 2021-09-19 02:06:58 +03:00
Orhun Parmaksız 101e2ee79e
chore(deps): upgrade dependencies 2021-09-19 01:53:44 +03:00
Orhun Parmaksız 6f050e606c
docs(readme): add installation section 2021-09-19 01:49:59 +03:00
Orhun Parmaksız 43961d1633
docs(readme): mention the standalone CLI tool 2021-09-19 01:46:50 +03:00
Orhun Parmaksız 6c10d381b4
docs(readme): prefix commands with '$' 2021-09-19 01:27:14 +03:00
orhun faedf63ebf
fix(cd): checkout master branch for docker builds 2021-09-11 01:55:12 +03:00
orhun 14d278629f
chore(release): prepare for v0.4.0 2021-08-27 22:38:48 +03:00
orhun 45d97a9251
chore(deps): upgrade dependencies 2021-08-27 22:36:31 +03:00
orhun 929f664b09
docs(readme): add cleanup script to README.md 2021-08-27 22:19:40 +03:00
orhun 38a0144ad7
docs(readme): update README.md about expiring links 2021-08-27 21:12:18 +03:00
orhun 13126e79ce
refactor(paste): use timestamp for expiring one shot files 2021-08-27 16:05:40 +03:00
orhun 92c35fe6df
feat(paste): support setting an expiry date for uploads 2021-08-27 15:54:23 +03:00
orhun 33977de206
fix(ci): update lychee arguments to exclude example files 2021-08-26 23:15:47 +03:00
orhun 0138cff440
docs(readme): update README.md about one shot file uploads 2021-08-26 23:13:32 +03:00
orhun 7a510bc2ad
style(paste): use a custom 404 message while serving files 2021-08-26 23:06:05 +03:00
orhun 73359f3534
feat(paste): support disappearing (oneshot) files 2021-08-26 22:57:46 +03:00
orhun 3223c6379c
refactor(paste): associate directories with the paste types 2021-08-26 21:09:33 +03:00
orhun 47f6ff57bd
chore(release): prepare for v0.3.1 2021-08-10 00:02:04 +03:00
orhun 989693140b
fix(cd): switch to `upload-release-action` for uploading releases 2021-08-10 00:00:14 +03:00
orhun 6d29828a4b
chore(release): prepare for v0.3.0 2021-08-09 23:38:13 +03:00
orhun eaa8b09cd2
chore(docker): share the config file between host and container 2021-08-09 23:27:35 +03:00
orhun d0abe50679
docs(readme): mention MIME type overriding and blacklisting 2021-08-09 23:12:51 +03:00
orhun cc385d1aca
refactor(test): use `tests` module for tests 2021-08-09 22:50:01 +03:00
orhun e7ad855f4d
feat(paste): support blacklisting MIME types 2021-08-09 22:48:51 +03:00
orhun 03348cb38f
feat(paste): support overriding MIME types 2021-08-09 22:28:33 +03:00
orhun 0296bc0594
chore(release): prepare for v0.2.0 2021-08-04 18:04:29 +03:00
orhun 11482ff59f
docs(readme): mention URL shortening 2021-08-04 17:49:57 +03:00
orhun f3855be2c9
feat(paste): support shortening URLs 2021-08-04 17:35:54 +03:00
orhun e01911df4d
chore(release): prepare for v0.1.3 2021-07-28 00:33:58 +03:00
orhun 315a649777
fix(upload): prevent sending zero bytes 2021-07-28 00:25:18 +03:00
orhun f4a3c07def
fix(upload): prevent sending empty file name 2021-07-28 00:21:34 +03:00
orhun 315585db36
fix(upload): prevent path traversal on upload directory
closes #2
2021-07-28 00:14:27 +03:00
orhun 60c25e2fbc
fix(upload): check the content length while reading bytes
closes #1
2021-07-27 23:49:35 +03:00
orhun d02865b956
chore(release): prepare for v0.1.2 2021-07-27 17:27:22 +03:00
orhun 6019e77026
chore(cd): publish the tagged docker image 2021-07-27 17:08:51 +03:00
orhun 1c596ee760
chore(release): prepare for v0.1.1 2021-07-27 16:59:31 +03:00
orhun 27f2621cd2
fix(cd): install musl-tools for the musl target 2021-07-27 16:57:56 +03:00
104 changed files with 7947 additions and 1505 deletions

View File

@ -1,8 +1,9 @@
# Directories
/.git/
/.github/
/target/
/upload/
/shuttle/
/examples/
# Files
.gitignore

11
.editorconfig Normal file
View File

@ -0,0 +1,11 @@
# configuration for https://editorconfig.org
root = true
[*.rs]
indent_style = space
indent_size = 4
[*.sh]
indent_style = space
indent_size = 2

2
.github/FUNDING.yml vendored
View File

@ -1 +1,3 @@
github: orhun
patreon: orhunp
buy_me_a_coffee: orhun

52
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,52 @@
<!--- Thank you for contributing to rustypaste! -->
## Description
<!--- Describe your changes in detail -->
## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->
## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
## Changelog Entry
<!--- Please write the changelog entry for these changes. -->
<!--- Follow the <https://keepachangelog.com/en/1.0.0/> format. -->
<!--- Use one of the Added, Changed, Deprecated, Removed, Fixed, and Security headers accordingly. -->
<!-- For example:
````
### Added
- Add a middleware for checking the content length
- Before, the upload size was checked after full upload which was clearly wrong.
````
-->
## Types of Changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Documentation (no code change)
- [ ] Refactor (refactoring production code)
- [ ] Other <!--- (provide information) -->
## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
- [ ] My code follows the code style of this project.
- [ ] I have updated the documentation accordingly.
- [ ] I have formatted the code with [rustfmt](https://github.com/rust-lang/rustfmt).
- [ ] I checked the lints with [clippy](https://github.com/rust-lang/rust-clippy).
- [ ] I have added tests to cover my changes.
- [ ] All new and existing tests passed.

15
.github/dependabot.yml vendored Normal file
View 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

7
.github/mergify.yml vendored Normal file
View File

@ -0,0 +1,7 @@
pull_request_rules:
- name: Automatic merge for Dependabot pull requests
conditions:
- author=dependabot[bot]
actions:
merge:
method: squash

View File

@ -1,12 +1,17 @@
name: Security Audit
on:
schedule:
- cron: '0 0 * * 0'
- cron: "0 0 * * 0"
jobs:
audit:
name: Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions-rs/audit-check@v1
- name: Checkout the repository
uses: actions/checkout@v4
- name: Run cargo-audit
uses: rustsec/audit-check@v1.4.1
with:
token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -8,23 +8,29 @@ 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@v4
- name: Set the release version
run: echo "RELEASE_VERSION=${GITHUB_REF:11}" >> $GITHUB_ENV
- name: Install musl-tools
if: matrix.TARGET == 'x86_64-unknown-linux-musl'
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
--allow-unauthenticated musl-tools
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
target: ${{ matrix.TARGET }}
override: true
- name: Build
run: cargo build --release --locked --target ${{ matrix.TARGET }}
run: |
cargo build --release --locked --target ${{ matrix.TARGET }}
strip target/${{ matrix.TARGET }}/release/rustypaste
- name: Prepare release assets
run: |
mkdir release/
@ -38,23 +44,22 @@ jobs:
sha512sum rustypaste-${{ env.RELEASE_VERSION }}-${{ matrix.TARGET }}.tar.gz \
> rustypaste-${{ env.RELEASE_VERSION }}-${{ matrix.TARGET }}.tar.gz.sha512
- name: Upload the release
uses: softprops/action-gh-release@v1
uses: svenstaro/upload-release-action@v2
with:
files: |
rustypaste-${{ env.RELEASE_VERSION }}-${{ matrix.TARGET }}.tar.gz
rustypaste-${{ env.RELEASE_VERSION }}-${{ matrix.TARGET }}.tar.gz.sha512
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: rustypaste-${{ env.RELEASE_VERSION }}-${{ matrix.TARGET }}.tar.gz*
file_glob: true
overwrite: true
tag: ${{ github.ref }}
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@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Publish
uses: actions-rs/cargo@v1
with:
command: publish
args: --locked --token ${{ secrets.CARGO_TOKEN }}
run: cargo publish --locked --token ${{ secrets.CARGO_TOKEN }}

View File

@ -7,102 +7,109 @@ on:
pull_request:
branches:
- master
schedule:
- 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
with:
toolchain: stable
profile: minimal
override: true
- name: Checkout the repository
uses: actions/checkout@master
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Check the project files
uses: actions-rs/cargo@v1
with:
command: check
args: --locked --verbose
run: cargo check --locked --verbose
test:
name: Test suite
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Checkout the repository
uses: actions/checkout@master
- name: Setup cargo-tarpaulin
run: |
curl -s https://api.github.com/repos/xd009642/tarpaulin/releases/latest | \
grep "browser_download_url.*tar.gz" | cut -d : -f 2,3 | tr -d \" | wget -qi -
tar -xzf cargo-tarpaulin-*.tar.gz
mv cargo-tarpaulin ~/.cargo/bin/
- name: Run tests
run: cargo tarpaulin --out Xml --verbose
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Generate code coverage
run: cargo llvm-cov --lcov --output-path lcov.info -- --test-threads 1
env:
OUT_DIR: target
- name: Upload reports to codecov
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@v4
with:
name: code-coverage-report
file: cobertura.xml
file: lcov.info
flags: unit-tests
fail_ci_if_error: true
verbose: true
token: ${{ secrets.CODECOV_TOKEN }}
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
fixtures:
strategy:
fail-fast: false
matrix:
os:
- name: Linux
runner: ubuntu-22.04
- name: macOS
runner: macos-12
name: Test fixtures [${{ matrix.os.name }}]
runs-on: ${{ matrix.os.runner }}
steps:
- name: Checkout the repository
uses: actions/checkout@v4
- name: Install coreutils for MacOS
if: matrix.os.name == 'macOS'
run: brew install coreutils
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Build the project
run: cargo build --locked --verbose
- name: Run test fixtures
shell: bash
run: ./test-fixtures.sh
working-directory: fixtures
env:
DEBUG: true
clippy:
name: Lints
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
components: clippy
override: true
- name: Checkout the repository
uses: actions/checkout@master
- name: Check the lints
uses: actions-rs/cargo@v1
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
command: clippy
args: --verbose -- -D warnings
components: clippy
- name: Check the lints
run: cargo clippy --tests --verbose -- -D warnings
rustfmt:
name: Formatting
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
components: rustfmt
override: true
- name: Checkout the repository
uses: actions/checkout@master
- name: Check the formatting
uses: actions-rs/cargo@v1
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
command: fmt
args: -- --check --verbose
components: rustfmt
- name: Check the formatting
run: cargo fmt -- --check --verbose
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@v4
- name: Check the links
uses: lycheeverse/lychee-action@v1
with:
args: --exclude "example.com|site.com|localhost|awesome.txt" -v *.md
args: --exclude "example.com|site.com|localhost|awesome.txt|x.txt" -v *.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -4,27 +4,89 @@ on:
push:
branches:
- master
tags:
- "v*.*.*"
pull_request:
branches:
- master
schedule:
- cron: "0 0 * * 0"
jobs:
docker:
name: Docker
runs-on: ubuntu-20.04
name: Docker Build and Push
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@master
- name: Build
run: docker build -t rustypaste .
- name: Tag
run: |
docker tag rustypaste orhunp/rustypaste:latest
docker tag rustypaste docker.pkg.github.com/orhun/rustypaste/rustypaste:latest
- name: Login (Docker Hub)
run: echo ${{ secrets.DOCKER_TOKEN }} |
docker login -u orhunp --password-stdin
- name: Push (Docker Hub)
run: docker push orhunp/rustypaste:latest
- name: Login (Package Registry)
run: echo ${{ secrets.GITHUB_TOKEN }} |
docker login -u orhun docker.pkg.github.com --password-stdin
- name: Push (Package Registry)
run: docker push docker.pkg.github.com/orhun/rustypaste/rustypaste:latest
uses: actions/checkout@v4
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
orhunp/rustypaste
ghcr.io/${{ github.repository_owner }}/rustypaste/rustypaste
tags: |
type=schedule
type=ref,event=branch
type=ref,event=pr
type=sha
type=raw,value=latest
type=semver,pattern={{version}}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
- name: Cache Docker layers
uses: actions/cache@v4
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Login to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: orhunp
password: ${{ secrets.DOCKER_TOKEN }}
- name: Login to GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
id: docker_build
uses: docker/build-push-action@v5
with:
context: ./
file: ./Dockerfile
platforms: linux/amd64,linux/arm64
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 }}

38
.github/workflows/shuttle.yml vendored Normal file
View File

@ -0,0 +1,38 @@
name: Shuttle.rs
on:
push:
branches:
- master
tags:
- "v*.*.*"
workflow_dispatch:
jobs:
build:
name: Build / Deploy
runs-on: ubuntu-22.04
steps:
- name: Checkout the repository
uses: actions/checkout@v4
- 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: Build
run: cargo build --locked --verbose
- name: Deploy
if: ${{ startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' }}
run: |
cargo shuttle login --api-key ${{ secrets.SHUTTLE_TOKEN }}
cargo shuttle project restart
cargo shuttle deploy --allow-dirty --no-test

2
.gitignore vendored
View File

@ -5,4 +5,4 @@
**/*.rs.bk
# Default upload directory
/upload/
**/upload/

View File

@ -1,8 +1,723 @@
# 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).
## Unreleased
## [0.15.0] - 2024-03-27
### Added
- Allow to override filename when using `random_url` by @tessus in [#233](https://github.com/orhun/rustypaste/pull/233)
Now you can use the `filename` header to override the name of the uploaded file.
For example:
```sh
curl -F "file=@x.txt" -H "filename:override.txt" http://localhost:8000
```
Even if `random_url` is set, the filename will be override.txt
[`rustypaste-cli`](https://github.com/orhun/rustypaste-cli) also has a new argument for overriding the file name:
```sh
rpaste -n filename-on-server.txt awesome.txt
```
- Use more specific HTTP status codes by @tessus in [#262](https://github.com/orhun/rustypaste/pull/262)
`rustypaste` now returns more appropriate status codes in the following 2 cases (instead of a generic 500 code):
- If the mime type is on the blacklist: `UnsupportedMediaType` (415)
- If the file already exists: `Conflict` (409)
### Changed
- Do path joins more safely by @RealOrangeOne in [#247](https://github.com/orhun/rustypaste/pull/247)
- Gracefully exit when there is no config file found by @orhun
- Switch to cargo-llvm-cov for code coverage by @orhun in [#260](https://github.com/orhun/rustypaste/pull/260)
- Replace unmaintained action by @tessus in [#266](https://github.com/orhun/rustypaste/pull/266)
- Set up mergify by @orhun
- Apply clippy suggestions by @orhun
- Update funding options by @orhun
- Update the copyright years by @orhun
- Bump dependencies
### Fixed
- Improve logging for deleted file by @tessus in [#235](https://github.com/orhun/rustypaste/pull/235)
- Fix deployment by @tessus in [#236](https://github.com/orhun/rustypaste/pull/236)
- Return the correct file on multiple files with same name by @tessus in [#234](https://github.com/orhun/rustypaste/pull/234)
- Update the hash of the example file by @tessus in [#254](https://github.com/orhun/rustypaste/pull/254)
- Error on upload with the same filename by @tessus in [#258](https://github.com/orhun/rustypaste/pull/258)
### New Contributors
- @RealOrangeOne made their first contribution in [#247](https://github.com/orhun/rustypaste/pull/247)
## [0.14.4] - 2023-12-20
### Removed
- Remove excessive warning messages when auth tokens are not found (#210)
## [0.14.3] - 2023-12-12
### Changed
- Return `404` for not exposed endpoints instead of `403`
- Disallow blank `delete_tokens` and `auth_tokens`
- Bump dependencies
## [0.14.2] - 2023-12-05
### Added
- Add installation instructions for FreeBSD (#177)
- Add auth token handling to HTML form example (#183)
- Add release instructions
### Changed
- Bump Shuttle to `0.34.1`
- Bump dependencies
## [0.14.1] - 2023-11-02
### Changed
- Switch to `tracing` for logging (#163)
- Bump Shuttle to `0.31.0`
- Bump dependencies
## [0.14.0] - 2023-09-05
### Added
- Add delete endpoint (#136)
Now you can delete files from the server with sending a [`DELETE`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/DELETE) request. To enable this, set the `delete_tokens` array in the configuration file or use the `DELETE_TOKEN` environment variable.
```toml
[server]
delete_tokens = [ "may_the_force_be_with_you" ]
```
And then you can send a `DELETE` request as follows:
```sh
$ curl -H "Authorization: may_the_force_be_with_you" -X DELETE "<server_address>/file.txt"
file deleted
```
You can also use [`rpaste`](https://github.com/orhun/rustypaste-cli#delete-files-from-server) (the command line tool) to delete files:
```sh
$ rpaste -d awesome.UA86.txt
```
### Changed
- Update crates and rustls deps (#135)
- Bump Shuttle to `0.25.0`
## [0.13.0] - 2023-08-26
### Added
- Support handling spaces in filenames (#107)
Now you can replace the whitespaces with either underscore or encoded space (`%20`) character in the filenames.
For example:
```toml
[server]
handle_spaces = "replace"
```
```sh
$ curl -F "file=@test file.txt" <server_address>
<server_address>/test_file.txt
```
Or you can use encoded spaces:
```toml
[server]
handle_spaces = "encode"
```
```sh
$ curl -F "file=@test file.txt" <server_address>
<server_address>/test%20file.txt
```
Please note that `random_url` should not be configured to use the original file names.
### Changed
- Improve random_url config handling (#122)
`[paste].random_url.enabled` is deprecated. You can now disable random URLs by commenting out `[paste].random_url`.
```toml
# enabled
random_url = { type = "petname", words = 2, separator = "-" }
# disabled
# random_url = { type = "petname", words = 2, separator = "-" }
```
- Replace unmaintained actions (#116)
- Bump Shuttle to `0.24.0`
- Bump dependencies
### Fixed
- Don't log invalid token in release builds (#112)
Before, invalid tokens were logged as follows:
```
[2023-08-13T19:24:30Z WARN rustypaste::auth] authorization failure for a.b.c.d (header: invalid_token)
```
Now, we print the token only in debug mode. In release mode, the log entry will look like this:
```
[2023-08-13T19:24:30Z WARN rustypaste::auth] authorization failure for a.b.c.d
```
## [0.12.1] - 2023-08-11
### Fixed
- Do not list expired files (#109)
## [0.12.0] - 2023-08-07
### Added
- Add an endpoint for retrieving a list of files (#94)
Set the `expose_list` option to `true` in the configuration file for enabling this feature. It is disabled as default.
```toml
[server]
expose_list = true
```
Then you can receive the list of files as JSON via `/list` endpoint:
```sh
$ curl "http://<server_address>/list" | jq .
[
{
"file_name": "accepted-cicada.txt",
"file_size": 241,
"expires_at_utc": null
},
{
"file_name": "evolving-ferret.txt",
"file_size": 111,
"expires_at_utc": "2023-08-07 10:51:14"
}
]
```
- Support multiple auth tokens (#84)
`auth_token` option is now deprecated and replaced with `auth_tokens` which supports an array of authentication tokens. For example:
```toml
[server]
auth_tokens = [
"super_secret_token1",
"super_secret_token2",
]
```
- Add new line character to most prominent messages (#97)
This is a follow-up to #72 for making the terminal output better:
```sh
$ curl http://localhost:8000/sweeping-tahr
unauthorized
```
### Changed
- Bump Shuttle to `0.23.0`
- Bump dependencies
### Fixed
- Deploy the Shuttle service when a new tag is created
## [0.11.1] - 2023-07-01
This is a hotfix release for supporting the use of deprecated `[server].landing_page*` fields.
### Fixed
- Allow using deprecated landing page fields
## [0.11.0] - 2023-07-01
### Added
- Add a new section for the landing page
- Also, support a file for the landing page (#64)
Migration path:
Old:
```toml
[server]
landing_page = "Landing page text."
landing_page_file = "index.html"
landing_page_content_type = "text/html; charset=utf-8"
```
New:
```toml
[landing_page]
text = "Landing page text."
file = "index.html"
content_type = "text/html; charset=utf-8"
```
The configuration is backwards compatible but we recommend using the new `landing_page` section as shown above since the other fields are now deprecated.
- Add random suffix mode (#69)
- Support appending a random suffix to the filename before the extension. For example, `foo.tar.gz` will result in `foo.eu7f92x1.tar.gz`
To enable, set `suffix_mode` to `true`:
```toml
[paste]
random_url = { enabled = true, type = "alphanumeric", length = 6, suffix_mode = true }
```
- Honor X-Forward-\* headers (`X-Forwarded-For` / `X-Forwarded-Host` / `X-Forwarded-Proto`) (#61)
- This would be really useful to have for setups where the service is running behind a reverse-proxy or gateway and the possibility to adjust the logging output based on their availability, to have the real IP addresses of the clients available in the log.
- Add new line character to the 404 message (#72)
Terminal output will look better when the file is not found:
```sh
$ curl http://localhost:8000/sweeping-tahr
file is not found or expired :(
```
- Add editorconfig for correctly formatting the test fixture files
- Add pull request template
### Changed
- Bump Shuttle to `0.20.0`
- List all the supported units in the documentation (#63)
- Note that the Alpine Linux package is moved to the community
- <https://pkgs.alpinelinux.org/packages?name=rustypaste>
- Bump dependencies
### Fixed
- Use the static folder for the Shuttle config (#70)
- There was a regression in the previous release that has caused the static folder to be not present in Shuttle deployments. This shouldn't be an issue anymore and the deployment should be live.
- Also, it is now possible to trigger a deployment manually via GitHub Actions.
Thanks to [@tessus](https://github.com/tessus) for his contributions to this release!
## [0.10.1] - 2023-06-05
### Added
- Add a middleware for checking the content length
- Before, the upload size was checked after full upload which was clearly wrong.
- With this change, total amount of bytes to upload is checked via [`Content-Length`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length) header before the upload.
### Changed
- Bump Shuttle to `0.18.0`
- Bump hotwatch to 0.5.0
- Fixes [`RUSTSEC-2020-0016`](https://rustsec.org/advisories/RUSTSEC-2020-0016.html)
### Fixed
- Do not drop the config watcher
- Since `0.9.0`, the configuration watcher was dropped early which caused for it to not work and resulted in mysterious spikes in CPU usage.
- With this version, this issue is fixed.
## [0.10.0] - 2023-05-31
### Added
- Support one shot URLs
With using the `oneshot_url` multipart field, you can now shorten an URL and make it disappear after viewed once:
```sh
curl -F "oneshot_url=https://example.com" "<server_address>"
```
- Allow configuring the content type for the landing page
`landing_page_content_type` is added as a configuration option for setting the [`Content-Type`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) header:
```toml
[server]
landing_page = ""
landing_page_content_type = "text/plain; charset=utf-8"
```
- Add information/example about using HTML forms
With utilizing the newly added option for the content type, you can now use HTML forms for the landing page:
```toml
[server]
landing_page = "<html>"
landing_page_content_type = "text/html; charset=utf-8"
```
There is an example added to the repository: [html_form.toml](https://github.com/orhun/rustypaste/blob/1a8958966972f2afb04a12cb2f5537a1d971561c/examples/html_form.toml)
Also, there is an ongoing discussion about refactoring the usage of landing page fields in the configuration file. See [#52](https://github.com/orhun/rustypaste/issues/52)
- An informative log message is added for showing the server address at startup
## [0.9.1] - 2023-05-24
### Changed
- Bump Shuttle to `0.17.0`
- Tweak public instance settings
- Increase the default expiry time to 24 hours
- Increase the max content length to 20MB
- Bump dependencies
## [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
- Allow downloading files via `?download=true` parameter
- If you specify this for a file (e.g. `<server_address>/file?download=true`), `rustypaste` will override the MIME type to `application/octet-stream` and this will force your browser to download the file.
- 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
[server]
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:
```toml
[server]
landing_page = """
boo 👻
======
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
- Enable [GitHub Sponsors](https://github.com/sponsors/orhun) for funding
- 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:
```toml
# expired files will be cleaned up hourly
delete_expired_files = { enabled = true, interval = "1h" }
```
For users who want to have this feature disabled, there is an alternative [shell script](README.md#cleaning-up-expired-files) recommended in the documentation.
- Add systemd service files
- [systemd files](./extra/systemd/) have been added to serve files from `/var/lib/rustypaste`, create `rustypaste` user automatically via `systemd-sysusers` and configure `AUTH_TOKEN` via `rustypaste.env`.
- 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
[config]
refresh_rate="1s"
```
- Support setting the timeout for HTTP requests.
```toml
[server]
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.
```toml
[server]
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.
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
[paste]
# default: true
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)
- Support [one shot links](README.md#one-shot) (via `oneshot=` form field)
- `{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.

3482
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
[package]
name = "rustypaste"
version = "0.1.0"
edition = "2018"
version = "0.15.0"
edition = "2021"
description = "A minimal file upload/pastebin service"
authors = ["Orhun Parmaksız <orhunparmaksiz@gmail.com>"]
license = "MIT"
@ -12,38 +12,63 @@ 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-0_21", "awc/rustls-0_21"]
shuttle = ["dep:shuttle-actix-web", "dep:shuttle-runtime", "dep:tokio"]
[dependencies]
actix-web = "3.3.2"
actix-multipart = "0.3.0"
actix-files = "0.5.0"
env_logger = "0.9.0"
log = "0.4.14"
serde = "1.0.126"
futures-util = "0.3.15"
petname = "1.1.0"
rand = "0.8.4"
dotenv = "0.15.0"
actix-web = { version = "4.5.1" }
actix-web-grants = { version = "4.0.3" }
actix-multipart = "0.6.1"
actix-files = "0.6.5"
shuttle-actix-web = { version = "0.42.0", optional = true }
shuttle-runtime = { version = "0.42.0", optional = true }
awc = { version = "3.4.0" }
serde = "1.0.203"
futures-util = "0.3.30"
petname = { version = "1.1.3", default-features = false, features = [
"std_rng",
"default_dictionary",
] }
rand = "0.8.5"
dotenvy = "0.15.7"
url = "2.5.0"
mime = "0.3.17"
regex = "1.10.4"
serde_regex = "1.1.0"
lazy-regex = "3.1.0"
humantime = "2.1.0"
humantime-serde = "1.1.1"
glob = "0.3.1"
ring = "0.17.8"
hotwatch = "0.5.0"
tokio = { version = "1.37.0", optional = true }
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
uts2ts = "0.4.1"
path-clean = "1.0.1"
[dependencies.config]
version = "0.11.0"
version = "0.14.0"
default-features = false
features = ["toml", "yaml"]
[dependencies.byte-unit]
version = "4.0.12"
version = "5.1.4"
features = ["serde"]
[dependencies.infer]
version = "0.5.0"
version = "0.15.0"
default-features = false
[dev-dependencies]
actix-rt = "2.2.0"
actix-rt = "2.9.0"
[profile.dev]
opt-level = 0
debug = true
panic = "abort"
[profile.test]
opt-level = 0
@ -55,6 +80,7 @@ debug = false
panic = "unwind"
lto = true
codegen-units = 1
strip = true
[profile.bench]
opt-level = 3

View File

@ -1,5 +1,7 @@
FROM ekidd/rust-musl-builder:latest as builder
WORKDIR /home/rust/src
FROM rust:1.72.0-alpine3.18 as builder
WORKDIR /app
RUN apk update
RUN apk add --no-cache musl-dev
COPY Cargo.toml Cargo.toml
RUN mkdir -p src/
RUN echo "fn main() {println!(\"failed to build\")}" > src/main.rs
@ -8,13 +10,11 @@ RUN rm -f target/release/deps/rustypaste*
COPY . .
RUN cargo build --locked --release
RUN mkdir -p build-out/
RUN cp target/x86_64-unknown-linux-musl/release/rustypaste build-out/
RUN cp target/release/rustypaste build-out/
FROM scratch
WORKDIR /app
COPY --from=builder \
/home/rust/src/build-out/rustypaste \
/home/rust/src/config.toml ./
COPY --from=builder /app/build-out/rustypaste .
ENV SERVER__ADDRESS=0.0.0.0:8000
EXPOSE 8000
USER 1000:1000

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2021 Orhun Parmaksız
Copyright (c) 2021-2024 Orhun Parmaksız
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

259
README.md
View File

@ -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** is a minimal file upload/pastebin service.
```sh
@ -12,18 +20,72 @@ $ curl https://paste.site.com/safe-toad.txt
some text
```
</details>
<details>
<summary>Table of Contents</summary>
<!-- vim-markdown-toc GFM -->
- [Features](#features)
- [Installation](#installation)
- [From crates.io](#from-cratesio)
- [Arch Linux](#arch-linux)
- [Alpine Linux](#alpine-linux)
- [FreeBSD](#freebsd)
- [Binary releases](#binary-releases)
- [Build from source](#build-from-source)
- [Feature flags](#feature-flags)
- [Testing](#testing)
- [Unit tests](#unit-tests)
- [Test Fixtures](#test-fixtures)
- [Usage](#usage)
- [CLI](#cli)
- [Expiration](#expiration)
- [One shot files](#one-shot-files)
- [One shot URLs](#one-shot-urls)
- [URL shortening](#url-shortening)
- [Paste file from remote URL](#paste-file-from-remote-url)
- [Cleaning up expired files](#cleaning-up-expired-files)
- [Delete file from server](#delete-file-from-server)
- [Override the filename when using `random_url`](#override-the-filename-when-using-random_url)
- [Server](#server)
- [List endpoint](#list-endpoint)
- [HTML Form](#html-form)
- [Docker](#docker)
- [Nginx](#nginx)
- [Contributing](#contributing)
- [License](#license)
<!-- vim-markdown-toc -->
</details>
## Features
- File upload
- File upload & URL shortening & upload from URL
- supports basic HTTP authentication
- random file names (optional)
- pet name (e.g. `capital-mosquito.txt`)
- alphanumeric string (e.g. `yB84D2Dv.txt`)
- random suffix (e.g. `file.MRV5as.tar.gz`)
- supports expiring links
- auto-expiration of files (optional)
- auto-deletion of expired files (optional)
- supports one shot links/URLs (can only be viewed once)
- guesses MIME types
- supports overriding and blacklisting
- supports forcing to download via `?download=true`
- no duplicate uploads (optional)
- listing/deleting files
- custom landing page
- Single binary
- [binary releases](https://github.com/orhun/rustypaste/releases)
- Simple configuration
- supports hot reloading
- Easy to deploy
- [docker images](https://hub.docker.com/r/orhunp/rustypaste)
- [appjail images](https://github.com/AppJail-makejails/rustypaste)
- No database
- filesystem is used
- Self-hosted
@ -31,13 +93,90 @@ some text
- Written in Rust
- _blazingly fast!_
## Installation
<details>
<summary>Packaging status</summary>
[![Packaging status](https://repology.org/badge/vertical-allrepos/rustypaste.svg)](https://repology.org/project/rustypaste/versions)
</details>
### From crates.io
```sh
cargo install rustypaste
```
### Arch Linux
```sh
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 [community repository](https://wiki.alpinelinux.org/wiki/Repositories).
```sh
apk add rustypaste
```
### FreeBSD
```sh
pkg install rustypaste
```
### Binary releases
See the available binaries on the [releases](https://github.com/orhun/rustypaste/releases/) page.
### Build from source
```sh
git clone https://github.com/orhun/rustypaste.git
cd rustypaste/
cargo build --release
```
#### 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
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).
### CLI
```sh
function rpaste() {
curl -F "file=@$1" -H "Authorization: <auth_token>" "<server_address>"
curl -F "file=@$1" -H "Authorization: <auth_token>" "<server_address>"
}
```
@ -51,6 +190,82 @@ $ rpaste x.txt
$ rpaste -
```
#### Expiration
```sh
$ curl -F "file=@x.txt" -H "expire:10min" "<server_address>"
```
supported units:
- `nsec`, `ns`
- `usec`, `us`
- `msec`, `ms`
- `seconds`, `second`, `sec`, `s`
- `minutes`, `minute`, `min`, `m`
- `hours`, `hour`, `hr`, `h`
- `days`, `day`, `d`
- `weeks`, `week`, `w`
- `months`, `month`, `M`
- `years`, `year`, `y`
#### One shot files
```sh
$ curl -F "oneshot=@x.txt" "<server_address>"
```
#### One shot URLs
```sh
$ curl -F "oneshot_url=https://example.com" "<server_address>"
```
#### URL shortening
```sh
$ curl -F "url=https://example.com/some/long/url" "<server_address>"
```
#### Paste file from remote URL
```sh
$ curl -F "remote=https://example.com/file.png" "<server_address>"
```
#### Cleaning up expired files
Configure `[paste].delete_expired_files` to set an interval for deleting the expired files automatically.
On the other hand, following script can be used as [cron](https://en.wikipedia.org/wiki/Cron) for cleaning up the expired files manually:
```sh
#!/bin/env sh
now=$(date +%s)
find upload/ -maxdepth 2 -type f -iname "*.[0-9]*" |
while read -r filename; do
[ "$(( ${filename##*.} / 1000 - "${now}" ))" -lt 0 ] && rm -v "${filename}"
done
```
#### Delete file from server
Set `delete_tokens` array in [config.toml](./config.toml) to activate the [`DELETE`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/DELETE) endpoint and secure it with one (or more) auth token(s).
```sh
$ curl -H "Authorization: <auth_token>" -X DELETE "<server_address>/file.txt"
```
> The `DELETE` endpoint will not be exposed and will return `404` error if `delete_tokens` are not set.
#### Override the filename when using `random_url`
The generation of a random filename can be overridden by sending a header called `filename`:
```sh
curl -F "file=@x.txt" -H "filename: <file_name>" "<server_address>"
```
### Server
To start the server:
@ -72,8 +287,35 @@ $ echo "AUTH_TOKEN=$(openssl rand -base64 16)" > .env
$ rustypaste
```
You can also set multiple auth tokens via the array field `[server].auth_tokens` in your `config.toml`.
> If neither `AUTH_TOKEN` nor `[server].auth_tokens` are set, the server will not require any authentication.
>
> Exception is the `DELETE` endpoint, which requires at least one token to be set. See [deleting files from server](#delete-file-from-server) for more information.
See [config.toml](./config.toml) for configuration options.
#### List endpoint
Set `expose_list` to true in [config.toml](./config.toml) to be able to retrieve a JSON formatted list of files in your uploads directory. This will not include oneshot files, oneshot URLs, or URLs.
```sh
$ curl "http://<server_address>/list"
[{"file_name":"accepted-cicada.txt","file_size":241,"expires_at_utc":null}]
```
This route will require an `AUTH_TOKEN` if one is set.
#### HTML Form
It is possible to use an HTML form for uploading files. To do so, you need to update two fields in your `config.toml`:
- Set the `[landing_page].content_type` to `text/html; charset=utf-8`.
- Update the `[landing_page].text` field with your HTML form or point `[landing_page].file` to your html file.
For an example, see [examples/html_form.toml](./examples/html_form.toml)
#### Docker
Following command can be used to run a container which is built from the [Dockerfile](./Dockerfile) in this repository:
@ -81,6 +323,7 @@ Following command can be used to run a container which is built from the [Docker
```sh
$ docker run --rm -d \
-v "$(pwd)/upload/":/app/upload \
-v "$(pwd)/config.toml":/app/config.toml \
--env-file "$(pwd)/.env" \
-e "RUST_LOG=debug" \
-p 8000:8000 \
@ -123,21 +366,11 @@ http {
}
```
### Roadmap
- Support "disappearing" files
- Support setting an expiry date for uploads
- Write a CLI tool in Rust
### Contributing
Pull requests are welcome!
Consider submitting your ideas via issues first. Also, see the [roadmap](#roadmap) and/or run the following command to see what is needed to be done:
```sh
$ grep -nr "TODO:" src/
```
Consider submitting your ideas via [issues](https://github.com/orhun/rustypaste/issues/new) first and check out the [existing issues](https://github.com/orhun/rustypaste/issues).
#### License

7
RELEASE.md Normal file
View File

@ -0,0 +1,7 @@
# Creating a Release
1. Update the version in `Cargo.toml` accordingly to [Semantic Versioning](https://semver.org/).
2. Run `cargo build` to update the version in `Cargo.lock`.
3. Update [CHANGELOG.md](./CHANGELOG.md) accordingly.
4. Commit the changes. (see [this](https://github.com/orhun/rustypaste/commit/79662d64abfe497baa5e9690c0f56ca183391809) example commit)
5. Create a release [on GitHub](https://github.com/orhun/rustypaste/releases/new) with the same entries in `CHANGELOG.md`.

6
codecov.yml Normal file
View File

@ -0,0 +1,6 @@
codecov:
status:
project:
default:
target: auto
threshold: 2%

View File

@ -1,10 +1,70 @@
[config]
refresh_rate = "1s"
[server]
address="127.0.0.1:8000"
address = "127.0.0.1:8000"
#url = "https://rustypaste.shuttleapp.rs"
#workers=4
max_content_length="10MB"
upload_path="./upload"
max_content_length = "10MB"
upload_path = "./upload"
timeout = "30s"
expose_version = false
expose_list = false
#auth_tokens = [
# "super_secret_token1",
# "super_secret_token2",
#]
#delete_tokens = [
# "super_secret_token1",
# "super_secret_token3",
#]
handle_spaces = "replace" # or "encode"
[landing_page]
text = """
Submit files via HTTP POST here:
curl -F 'file=@example.txt' <server>
This will return the URL of the uploaded file.
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.
By default, pastes expire every hour. The server admin may or may not have
changed this.
Check out the GitHub repository at https://github.com/orhun/rustypaste
Command line tool is available at https://github.com/orhun/rustypaste-cli
"""
#file = "index.txt"
content_type = "text/plain; charset=utf-8"
[paste]
random_url = { enabled = true, type = "petname", words = 2, separator = "-" }
#random_url = { enabled = true, type = "alphanumeric", length = 8 }
random_url = { type = "petname", words = 2, separator = "-" }
#random_url = { type = "alphanumeric", length = 8 }
#random_url = { type = "alphanumeric", length = 6, suffix_mode = true }
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|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" }

View File

@ -13,3 +13,4 @@ services:
- "8000:8000"
volumes:
- ./upload/:/app/upload
- ./config.toml:/app/config.toml

37
examples/html_form.toml Normal file
View File

@ -0,0 +1,37 @@
[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 = false
[landing_page]
file = "landing_page.html"
content_type = "text/html; charset=utf-8"
[paste]
random_url = { type = "petname", words = 2, separator = "-" }
#random_url = { 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|sh|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" }

143
examples/landing_page.html Normal file
View File

@ -0,0 +1,143 @@
<html lang="en">
<head>
<title>rustypaste</title>
<meta charset="utf-8" />
<style>
body {
background-color: #f2f2f2;
font-family: arial, sans-serif;
margin: 0;
padding: 0;
}
pre {
background-color: #333;
color: #fff;
font-size: 18px;
margin: 0;
overflow: auto;
padding: 20px;
white-space: pre-wrap;
}
h2 {
color: #333;
font-size: 24px;
margin-top: 40px;
}
form {
margin: 20px 0;
}
input[type="text"],
input[type="file"] {
border: none;
border-radius: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
font-family: arial, sans-serif;
font-size: 18px;
margin-right: 10px;
padding: 10px;
width: 400px;
}
input[type="submit"] {
background-color: #333;
border: none;
border-radius: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
color: #fff;
cursor: pointer;
font-family: arial, sans-serif;
font-size: 18px;
padding: 10px 20px;
transition: background-color 0.2s ease-in-out;
}
input[type="submit"]:hover {
background-color: #444;
}
</style>
</head>
<body>
<pre>
┬─┐┬ ┬┌─┐┌┬┐┬ ┬┌─┐┌─┐┌─┐┌┬┐┌─┐
├┬┘│ │└─┐ │ └┬┘├─┘├─┤└─┐ │ ├┤
┴└─└─┘└─┘ ┴ ┴ ┴ ┴ ┴└─┘ ┴ └─┘
the server administrator might remove any pastes that they do not personally
want to host.
by default, pastes expire every hour.
</pre
>
<h2>share url</h2>
<form action="/" method="post" enctype="multipart/form-data">
<input type="text" name="url" />
<input type="submit" value="share" />
</form>
<h2>share file from url</h2>
<form action="/" method="post" enctype="multipart/form-data">
<input type="text" name="remote" />
<input type="submit" value="share" />
</form>
<h2>share file</h2>
<form action="/" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" value="share" />
</form>
<h2>share one-time file</h2>
<form action="/" method="post" enctype="multipart/form-data">
<input type="file" name="oneshot" />
<input type="submit" value="share" />
</form>
<h2>share file with auth token</h2>
<div id="shareForm">
<input type="file" id="file" name="file" /><br>
<input type="text" id="authToken" placeholder="Auth Token" />
<input type="submit" value="share" onclick="shareFileWithAuth()" />
</form>
</body>
<script>
function shareFileWithAuth() {
const fileInput = document.getElementById("file");
const file = fileInput.files[0];
if (!file) {
alert("Please select a file");
return;
}
const authTokenInput = document.getElementById("authToken");
const authToken = authTokenInput.value;
if (!authToken) {
alert("Please provide an Auth Token");
return;
}
const formData = new FormData();
formData.append("file", file);
fetch("/", {
method: "POST",
headers: {
Authorization: authToken,
},
body: formData,
})
.then((response) => {
if (!response.ok) {
alert("Failed to upload");
throw new Error("Network response was not ok");
}
return response.text();
})
.then((data) => {
window.open(data, "_blank");
})
.catch((error) => {
console.error("There was an error uploading the file:", error);
});
}
</script>
</html>

View File

@ -0,0 +1,2 @@
# To enable basic HTTP auth, set the AUTH_TOKEN
AUTH_TOKEN=""

View File

@ -0,0 +1,31 @@
[Unit]
Description=Rustypaste server
After=network-online.target
Wants=network-online.target systemd-networkd-wait-online.service
[Service]
User=rustypaste
Group=rustypaste
ExecStart=/usr/bin/rustypaste
ReadWritePaths=/var/lib/rustypaste
ReadOnlyPaths=/etc/rustypaste
WorkingDirectory=/var/lib/rustypaste
Environment="CONFIG=/etc/rustypaste/config.toml"
EnvironmentFile=/etc/rustypaste/rustypaste.env
# Hardening options
CapabilityBoundingSet=
AmbientCapabilities=
NoNewPrivileges=true
ProtectHome=true
ProtectSystem=strict
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
PrivateTmp=true
PrivateDevices=true
LockPersonality=true
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1 @@
u rustypaste - "Minimal file upload/pastebin service" /var/lib/rustypaste

View File

@ -0,0 +1 @@
d /var/lib/rustypaste 0750 rustypaste rustypaste

1
fixtures/.env Normal file
View File

@ -0,0 +1 @@
RUST_LOG=error

54
fixtures/README.md Normal file
View File

@ -0,0 +1,54 @@
## Fixtures
This directory contains the [test fixtures](https://en.wikipedia.org/wiki/Test_fixture) and a simple testing framework for `rustypaste`.
### Running fixtures
1. Build the project in debug mode: `cargo build`
2. Execute the runner script in this directory: `./test-fixtures.sh`
On `macOS` you need to have [coreutils](https://www.gnu.org/software/coreutils/) installed to run the script.
The simplest way is to install it via [Homebrew](https://brew.sh/): `brew install coreutils`
### Adding new fixtures
Create an appropriately named directory for the test fixture you want to add. e.g. `test-file-upload`
Each fixture directory should contain the following files:
```
test-file-upload/
├── config.toml
└── test.sh
```
- `config.toml`: Contains the `rustypaste` configuration. See [the default configuration](../config.toml).
- `test.sh`: Contains the helper functions for testing. The file format is the following:
```sh
#!/usr/bin/env bash
setup() {
# preparation
}
run_test() {
# assertions
}
teardown() {
# cleanup
}
```
These functions are executed in the order defined above.
See the [test-file-upload](./test-file-upload/test.sh) fixture for an example.
### Debugging
Set the `DEBUG` environment variable to `true` while executing the runner script:
```sh
$ DEBUG=true ./test-fixtures.sh
```

View File

@ -0,0 +1,9 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[paste]
random_url = { type = "petname", words = 2, separator = "-" }
default_extension = "txt"
duplicate_files = false

View File

@ -0,0 +1,30 @@
#!/usr/bin/env bash
duplicate_content="test data"
setup() {
echo "$duplicate_content" > file
date +%s > unique_file1
sleep 1
date +%s > unique_file2
}
run_test() {
first_file_url=$(curl -s -F "file=@file" localhost:8000)
test "$duplicate_content" = "$(cat upload/${first_file_url/http:\/\/localhost:8000\//})"
second_file_url=$(curl -s -F "file=@file" localhost:8000)
test "$first_file_url" = "$second_file_url"
for url in "$first_file_url" "$second_file_url"; do
test "$duplicate_content" = "$(curl -s $url)"
done
first_file_url=$(curl -s -F "file=@unique_file1" localhost:8000)
second_file_url=$(curl -s -F "file=@unique_file2" localhost:8000)
test "$first_file_url" != "$second_file_url"
}
teardown() {
rm file unique_file1 unique_file2
rm -r upload
}

View File

@ -0,0 +1,8 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[paste]
default_extension = "txt"
duplicate_files = false

View File

@ -0,0 +1,21 @@
#!/usr/bin/env bash
content="test data"
setup() {
echo "$content" > file
}
run_test() {
file_url=$(curl -s -F "file=@file" -H "expire:1s" localhost:8000)
test "$content" = "$(cat upload/file.txt.*)"
sleep 2
result="$(curl -s $file_url)"
test "file is not found or expired :(" = "$result"
}
teardown() {
rm file
rm -r upload
}

View File

@ -0,0 +1,9 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
delete_tokens = ["may_the_force_be_with_you"]
[paste]
default_extension = "txt"
duplicate_files = true

View File

@ -0,0 +1,19 @@
#!/usr/bin/env bash
content="test data"
setup() {
echo "$content" > file
}
run_test() {
file_url=$(curl -s -F "file=@file" localhost:8000)
test "$file_url" = "http://localhost:8000/file.txt"
test "file deleted" = "$(curl -s -H "Authorization: may_the_force_be_with_you" -X DELETE http://localhost:8000/file.txt)"
test "file is not found or expired :(" = "$(curl -s -H "Authorization: may_the_force_be_with_you" -X DELETE http://localhost:8000/file.txt)"
}
teardown() {
rm file
rm -r upload
}

View File

@ -0,0 +1,9 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[paste]
random_url = { type = "alphanumeric", length = "4", suffix_mode = true }
default_extension = "txt"
duplicate_files = true

View File

@ -0,0 +1,19 @@
#!/usr/bin/env bash
content="test data"
setup() {
echo "$content" > file
}
run_test() {
file_url=$(curl -s -F "file=@file" -H "filename:fn_from_header.txt" localhost:8000)
test "$file_url" = "http://localhost:8000/fn_from_header.txt"
test "$content" = "$(cat upload/fn_from_header.txt)"
test "$content" = "$(curl -s $file_url)"
}
teardown() {
rm file
rm -r upload
}

View File

@ -0,0 +1,9 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[paste]
random_url = { type = "alphanumeric", length = "4", suffix_mode = true }
default_extension = "txt"
duplicate_files = true

View File

@ -0,0 +1,23 @@
#!/usr/bin/env bash
content="test data"
setup() {
echo "$content" > file
}
run_test() {
file_url=$(curl -s -F "file=@file" -H "filename:fn_from_header.txt" localhost:8000)
test "$file_url" = "http://localhost:8000/fn_from_header.txt"
test "$content" = "$(cat upload/fn_from_header.txt)"
test "$content" = "$(curl -s $file_url)"
file_url=$(curl -s -F "file=@file" -H "filename:fn_from_header.txt" localhost:8000)
test "$file_url" = "file already exists"
status_code=$(curl -s -F "file=@file" -H "filename:fn_from_header.txt" -w "%{response_code}" -o /dev/null localhost:8000)
test "$status_code" = "409"
}
teardown() {
rm file
rm -r upload
}

View File

@ -0,0 +1,8 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[paste]
default_extension = "txt"
duplicate_files = true

View File

@ -0,0 +1,22 @@
#!/usr/bin/env bash
content="test data"
setup() {
echo "$content" > file
echo "$content" > .file
}
run_test() {
file_url=$(curl -s -F "file=@file" localhost:8000)
test "$file_url" = "http://localhost:8000/file.txt"
test "$content" = "$(cat upload/file.txt)"
test "$content" = "$(curl -s $file_url)"
file_url2=$(curl -s -F "file=@.file" localhost:8000)
test "$file_url2" = "http://localhost:8000/.file.txt"
}
teardown() {
rm file .file
rm -r upload
}

View File

@ -0,0 +1,10 @@
[server]
address="127.0.0.1:8000"
max_content_length="10MB"
upload_path="./upload"
handle_spaces = "replace"
[paste]
#random_url = { enabled = false, type = "alphanumeric", length = 6, suffix_mode = true }
default_extension = "txt"
duplicate_files = true

View File

@ -0,0 +1,21 @@
#!/usr/bin/env bash
content="test data for space replacement"
setup() {
echo "$content" > "test file with spaces.txt"
}
run_test() {
# Upload the file and get the URL.
replaced_url=$(curl -s -F "file=@test file with spaces.txt" localhost:8000)
# Ensure the URL contains underscores instead of spaces.
expected_url="http://localhost:8000/test_file_with_spaces.txt"
test "$replaced_url" = "$expected_url"
}
teardown() {
rm "test file with spaces.txt"
rm -r upload
}

39
fixtures/test-fixtures.sh Executable file
View File

@ -0,0 +1,39 @@
#!/usr/bin/env bash
FIXTURE_DIR=$(readlink -f "$(dirname "$0")")
PROJECT_DIR="$FIXTURE_DIR/.."
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m'
run_fixture() {
cd "$FIXTURE_DIR/$1" || exit 1
source "test.sh"
NO_COLOR=1 CONFIG=config.toml "$PROJECT_DIR/target/debug/rustypaste" &
SERVER_PID=$!
trap 'kill -9 "$SERVER_PID" && wait "$SERVER_PID" 2> /dev/null' RETURN
sleep 1
( set -e;
setup
run_test
teardown
)
result=$?
return "$result"
}
main() {
find * -maxdepth 0 -type d -print0 | while IFS= read -r -d '' fixture; do
run_fixture "$fixture"
exit_status=$?
if [ "$exit_status" -eq 0 ]; then
echo -e "[${GREEN}ok${NC}] $fixture"
else
echo -e "[${RED}fail${NC}] $fixture"
exit "$exit_status"
fi
done
}
[ "$DEBUG" == 'true' ] && set -x && export RUST_LOG=debug
main

View File

@ -0,0 +1,10 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
expose_list = false
[paste]
random_url = { type = "petname", words = 2, separator = "-" }
default_extension = "txt"
duplicate_files = true

View File

@ -0,0 +1,14 @@
#!/usr/bin/env bash
setup() {
:;
}
run_test() {
result=$(curl -s --write-out "%{http_code}" http://localhost:8000/list)
test "404" = "$result"
}
teardown() {
rm -r upload
}

View File

@ -0,0 +1,11 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
auth_token = "rustypasteisawesome"
expose_list = true
[paste]
random_url = { type = "petname", words = 2, separator = "-" }
default_extension = "txt"
duplicate_files = true

View File

@ -0,0 +1,20 @@
#!/usr/bin/env bash
auth_token="rustypasteisawesome"
content="test data"
file_count=3
setup() {
echo "$content" > file
}
run_test() {
seq $file_count | xargs -I -- curl -s -F "file=@file" -H "Authorization: $auth_token" localhost:8000 >/dev/null
test $file_count = $(curl -s -H "Authorization: $auth_token" localhost:8000/list | grep -o 'file_name' | wc -l)
test "unauthorized" = "$(curl -s localhost:8000/list)"
}
teardown() {
rm file
rm -r upload
}

View File

@ -0,0 +1,9 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[paste]
default_extension = "txt"
duplicate_files = true
delete_expired_files = { enabled = true, interval = "1h" }

View File

@ -0,0 +1,20 @@
#!/usr/bin/env bash
content="test data"
setup() {
echo "$content" > file
}
run_test() {
file_url=$(curl -s -F "file=@file" -H "expire:2s" localhost:8000)
file_url=$(curl -s -F "file=@file" -H "expire:1s" localhost:8000)
sleep 2
file_url=$(curl -s -F "file=@file" -H "expire:1m" localhost:8000)
test "$content" = "$(curl -s $file_url)"
}
teardown() {
rm file
rm -r upload
}

View File

@ -0,0 +1,8 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[paste]
default_extension = "txt"
duplicate_files = false

View File

@ -0,0 +1,21 @@
#!/usr/bin/env bash
content="0nesh0t"
setup() {
echo "$content" > file
}
run_test() {
file_url=$(curl -s -F "oneshot=@file" localhost:8000)
test "$content" = $(curl -s "$file_url")
test "$content" = "$(cat upload/oneshot/file.txt.*)"
result="$(curl -s $file_url)"
test "file is not found or expired :(" = "$result"
}
teardown() {
rm file
rm -r upload
}

View File

@ -0,0 +1,8 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[paste]
default_extension = "txt"
duplicate_files = false

View File

@ -0,0 +1,20 @@
#!/usr/bin/env bash
url="https://orhun.dev/"
setup() {
:;
}
run_test() {
file_url=$(curl -s -F "oneshot_url=$url" localhost:8000)
test "$url" = $(curl -Ls -w %{url_effective} -o /dev/null "$file_url")
test "$url" = "$(cat upload/oneshot_url/oneshot_url.*)"
result="$(curl -s $file_url)"
test "file is not found or expired :(" = "$result"
}
teardown() {
rm -r upload
}

View File

@ -0,0 +1,8 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10kb"
upload_path = "./upload"
[paste]
default_extension = "txt"
duplicate_files = false

View File

@ -0,0 +1,23 @@
#!/usr/bin/env bash
content="test"
setup() {
echo "$content" > file
}
run_test() {
result=$(curl -s --path-as-is localhost:8000/.)
test "file is not found or expired :(" = "$result"
result=$(curl -s --write-out "%{http_code}" --path-as-is localhost:8000/../test.sh)
test "404" = "$result"
result=$(curl -s -X POST -F "file=@file;filename=../." localhost:8000)
test "$content" = "$(cat upload/file.txt)"
}
teardown() {
rm file
rm -r upload
}

View File

@ -0,0 +1,9 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[paste]
random_url = { type = "alphanumeric", length = "6", suffix_mode = true }
default_extension = "txt"
duplicate_files = true

View File

@ -0,0 +1,29 @@
#!/usr/bin/env bash
content="test data"
setup() {
echo "$content" >file
}
run_test() {
first_file_url=$(curl -s -F "file=@file" localhost:8000)
test "$first_file_url" != "http://localhost:8000/file.txt"
test "$content" = "$(curl -s $first_file_url)"
second_file_url=$(curl -s -F "file=@file" localhost:8000)
test "$first_file_url" != "http://localhost:8000/file.txt"
test "$content" = "$(curl -s $first_file_url)"
test "$first_file_url" != "$second_file_url"
test "$(cat upload/${first_file_url/http:\/\/localhost:8000\//})" \
= "$(cat upload/${second_file_url/http:\/\/localhost:8000\//})"
[[ $(find upload/ -name "file.*.txt" -print -quit 2>/dev/null) ]] || exit 1
}
teardown() {
rm file
rm -r upload
}

View File

@ -0,0 +1,9 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[paste]
random_url = { type = "alphanumeric", length = "8" }
default_extension = "txt"
duplicate_files = true

View File

@ -0,0 +1,27 @@
#!/usr/bin/env bash
content="test data"
setup() {
echo "$content" > file
}
run_test() {
first_file_url=$(curl -s -F "file=@file" localhost:8000)
test "$first_file_url" != "http://localhost:8000/file.txt"
test "$content" = "$(curl -s $first_file_url)"
second_file_url=$(curl -s -F "file=@file" localhost:8000)
test "$first_file_url" != "http://localhost:8000/file.txt"
test "$content" = "$(curl -s $first_file_url)"
test "$first_file_url" != "$second_file_url"
test "$(cat upload/${first_file_url/http:\/\/localhost:8000\//})" \
= "$(cat upload/${second_file_url/http:\/\/localhost:8000\//})"
}
teardown() {
rm file
rm -r upload
}

View File

@ -0,0 +1,9 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
timeout = "60s"
[paste]
default_extension = "txt"
duplicate_files = false

View File

@ -0,0 +1,19 @@
#!/usr/bin/env bash
url="https://raw.githubusercontent.com/orhun/rustypaste/master/img/rustypaste_logo.png"
setup() {
:;
}
run_test() {
file_url=$(curl -s -F "remote=$url" localhost:8000)
curl -s "$file_url" -o uploaded_file > /dev/null
curl -s "$url" -o remote_file > /dev/null
test "$(sha256sum uploaded_file | awk '{print $1}')" = "$(sha256sum remote_file | awk '{print $1}')"
}
teardown() {
rm uploaded_file remote_file
rm -r upload
}

View File

@ -0,0 +1,9 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
auth_tokens = ["token1", "token2", "rustypasteisawesome", "token4"]
[paste]
default_extension = "txt"
duplicate_files = false

View File

@ -0,0 +1,27 @@
#!/usr/bin/env bash
auth_tokens=("rustypasteisawesome" "token1" "token2" "token4")
content="topsecret"
setup() {
echo "$content" > file
}
run_test() {
result=$(curl -s -F "file=@file" localhost:8000)
test "unauthorized" = "$result"
for auth_token in ${auth_tokens[@]}
do
result=$(curl -s -F "file=@file" -H "Authorization: $auth_token" localhost:8000)
test "unauthorized" != "$result"
test "$content" = "$(cat upload/file.txt)"
test "$content" = "$(curl -s $result)"
done
}
teardown() {
rm file
rm -r upload
}

View File

@ -0,0 +1,8 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[paste]
default_extension = "txt"
duplicate_files = false

View File

@ -0,0 +1,19 @@
#!/usr/bin/env bash
content="topsecret"
setup() {
echo "$content" > file
}
run_test() {
result=$(curl -s -F "file=@file" localhost:8000)
test "unauthorized" != "$result"
test "$content" = "$(cat upload/file.txt)"
test "$content" = "$(curl -s $result)"
}
teardown() {
rm file
rm -r upload
}

View File

@ -0,0 +1,9 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
auth_token = "rustypasteisawesome"
[paste]
default_extension = "txt"
duplicate_files = false

View File

@ -0,0 +1,23 @@
#!/usr/bin/env bash
auth_token="rustypasteisawesome"
content="topsecret"
setup() {
echo "$content" > file
}
run_test() {
result=$(curl -s -F "file=@file" localhost:8000)
test "unauthorized" = "$result"
result=$(curl -s -F "file=@file" -H "Authorization: $auth_token" localhost:8000)
test "unauthorized" != "$result"
test "$content" = "$(cat upload/file.txt)"
test "$content" = "$(curl -s $result)"
}
teardown() {
rm file
rm -r upload
}

View File

@ -0,0 +1,10 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[paste]
random_url = { type = "petname", words = 2, separator = "-" }
default_extension = "txt"
duplicate_files = true
delete_expired_files = { enabled = true, interval = "2s" }

View File

@ -0,0 +1,24 @@
#!/usr/bin/env bash
content="test content"
setup() {
echo "$content" > file
}
run_test() {
first_file_url=$(curl -s -F "file=@file" -H "expire:1s" localhost:8000)
second_file_url=$(curl -s -F "file=@file" -H "expire:4s" localhost:8000)
test "$content" = "$(curl -s $first_file_url)"
test "$content" = "$(curl -s $second_file_url)"
sleep 3
test "file is not found or expired :(" = "$(curl -s $first_file_url)"
test "$content" = "$(curl -s $second_file_url)"
sleep 1
test "file is not found or expired :(" = "$(curl -s $second_file_url)"
}
teardown() {
rm file
rm -r upload
}

View File

@ -0,0 +1,8 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[paste]
default_extension = "bin"
duplicate_files = false

View File

@ -0,0 +1,22 @@
#!/usr/bin/env bash
content="test data"
setup() {
echo "$content" > file
echo "<html></html>" > file.html
}
run_test() {
file_url=$(curl -s -F "file=@file" localhost:8000)
test "$file_url" = "http://localhost:8000/file.bin"
test "$content" = "$(cat upload/file.bin)"
test "$content" = "$(curl -s $file_url)"
test "http://localhost:8000/file.html" = "$(curl -s -F file=@file.html localhost:8000)"
}
teardown() {
rm file*
rm -r upload
}

View File

@ -0,0 +1,8 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[paste]
default_extension = "txt"
duplicate_files = false

View File

@ -0,0 +1,20 @@
#!/usr/bin/env bash
content="test data"
setup() {
echo "$content" > file
}
run_test() {
file_url=$(curl -s -F "file=@file" localhost:8000)
test "$file_url" = "http://localhost:8000/file.txt"
result=$(curl -s --write-out "%{http_code}" -X DELETE http://localhost:8000/file.txt)
test "404" = "$result"
}
teardown() {
rm file
rm -r upload
}

View File

@ -0,0 +1,13 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[landing_page]
text = "awesome_landing"
file = "page.txt"
content_type = "text/plain; charset=utf-8"
[paste]
default_extension = "txt"
duplicate_files = false

View File

@ -0,0 +1,16 @@
#!/usr/bin/env bash
landing_page="awesome_landing_from_file"
setup() {
echo $landing_page >page.txt
}
run_test() {
result=$(curl -s localhost:8000)
test "$landing_page" = "$result"
}
teardown() {
rm page.txt
}

View File

@ -0,0 +1,12 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[landing_page]
text = "awesome_landing"
content_type = "text/plain; charset=utf-8"
[paste]
default_extension = "txt"
duplicate_files = false

View File

@ -0,0 +1,16 @@
#!/usr/bin/env bash
landing_page="awesome_landing"
setup() {
:;
}
run_test() {
result=$(curl -s localhost:8000)
test "$landing_page" = "$result"
}
teardown() {
:;
}

View File

@ -0,0 +1,10 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[paste]
random_url = { type = "petname", words = 2, separator = "-" }
default_extension = "txt"
duplicate_files = true
mime_blacklist = ["text/html", "text/xml"]

View File

@ -0,0 +1,22 @@
#!/usr/bin/env bash
content="test data"
setup() {
echo "<html></html>" > file.html
echo '<?xml version="1.0" encoding="UTF-8" standalone="no" ?>' > file.xml
echo "$content" > file.txt
}
run_test() {
test "this file type is not permitted" = "$(curl -s -F "file=@file.html" localhost:8000)"
test "this file type is not permitted" = "$(curl -s -F "file=@file.xml" localhost:8000)"
test "415" = "$(curl -s -F "file=@file.xml" -w "%{response_code}" -o /dev/null localhost:8000)"
file_url=$(curl -s -F "file=@file.txt" localhost:8000)
test "$content" = "$(curl -s $file_url)"
}
teardown() {
rm file.*
rm -r upload
}

View File

@ -0,0 +1,13 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[paste]
random_url = { type = "petname", words = 2, separator = "-" }
default_extension = "txt"
duplicate_files = true
mime_override = [
{ mime = "application/x-shockwave-flash", regex = "^.*\\.txt$" },
{ mime = "image/gif", regex = "^.*\\.tar$" },
]

View File

@ -0,0 +1,26 @@
#!/usr/bin/env bash
content="test"
setup() {
for ext in "txt" "tar" "png"; do
echo "$content" > "file.$ext"
done
}
run_test() {
file_url=$(curl -s -F "file=@file.txt" localhost:8000)
test "application/x-shockwave-flash" = "$(curl -s --write-out %{content_type} $file_url | tail -n 1)"
file_url=$(curl -s -F "file=@file.tar" localhost:8000)
test "image/gif" = "$(curl -s --write-out %{content_type} $file_url | tail -n 1)"
file_url=$(curl -s -F "file=@file.png" localhost:8000)
test "image/png" = "$(curl -s --write-out %{content_type} $file_url | tail -n 1)"
test "$content" = "$(curl -s $file_url)"
}
teardown() {
rm file.*
rm -r upload
}

View File

@ -0,0 +1,8 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10KB"
upload_path = "./upload"
[paste]
default_extension = "txt"
duplicate_files = false

View File

@ -0,0 +1,28 @@
#!/usr/bin/env bash
setup() {
touch emptyfile
truncate -s 9KB smallfile
# On Linux, `fallocate -l 10000 normalfile` can be used for a better precision.
dd if=/dev/random of=normalfile count=10000 bs=1024 status=none
truncate -s 11KB bigfile
}
run_test() {
result=$(curl -s -F "file=@emptyfile" localhost:8000)
test "invalid file size" = "$result"
result=$(curl -s -F "file=@bigfile" localhost:8000)
test "upload limit exceeded" = "$result"
result=$(curl -s -F "file=@normalfile" localhost:8000)
test "upload limit exceeded" = "$result"
result=$(curl -s -F "file=@smallfile" localhost:8000)
test "upload limit exceeded" != "$result"
}
teardown() {
rm emptyfile smallfile normalfile bigfile
rm -r upload
}

View File

@ -0,0 +1,10 @@
[server]
address="127.0.0.1:8000"
max_content_length="10MB"
upload_path="./upload"
handle_spaces = "encode"
[paste]
#random_url = { enabled = false, type = "alphanumeric", length = 6, suffix_mode = true }
default_extension = "txt"
duplicate_files = true

View File

@ -0,0 +1,21 @@
#!/usr/bin/env bash
content="test data for URL encoding"
setup() {
echo "$content" > "test file with spaces.txt"
}
run_test() {
# Upload the file and get the URL.
encoded_url=$(curl -s -F "file=@test file with spaces.txt" localhost:8000)
# Ensure the URL is encoded correctly.
expected_url="http://localhost:8000/test%20file%20with%20spaces.txt"
test "$encoded_url" = "$expected_url"
}
teardown() {
rm "test file with spaces.txt"
rm -r upload
}

View File

@ -0,0 +1,8 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
[paste]
default_extension = "txt"
duplicate_files = false

View File

@ -0,0 +1,19 @@
#!/usr/bin/env bash
url="https://orhun.dev/"
setup() {
:;
}
run_test() {
curl -s -F "url=$url" localhost:8000 > /dev/null
test "$url" = "$(cat upload/url/url)"
result=$(curl -s -F "url=invalidurl" localhost:8000)
test "relative URL without a base" = "$result"
}
teardown() {
rm -r upload
}

View File

@ -0,0 +1,10 @@
[server]
address = "127.0.0.1:8000"
max_content_length = "10MB"
upload_path = "./upload"
expose_version = false
[paste]
random_url = { type = "petname", words = 2, separator = "-" }
default_extension = "txt"
duplicate_files = true

View File

@ -0,0 +1,15 @@
#!/usr/bin/env bash
setup() {
echo "$content" > file
}
run_test() {
result=$(curl -s --write-out "%{http_code}" http://localhost:8000/version)
test "404" = "$result"
}
teardown() {
rm file
rm -r upload
}

54
shuttle/config.toml Normal file
View File

@ -0,0 +1,54 @@
[config]
refresh_rate = "1s"
[server]
address = "127.0.0.1:8000"
url = "https://rustypaste.shuttleapp.rs"
#workers=4
max_content_length = "20MB"
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 24 hours. 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
🦀
"""
landing_page_content_type = "text/plain; charset=utf-8"
[paste]
# random_url = { type = "petname", words = 2, separator = "-" }
random_url = { 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 = "24h"
delete_expired_files = { enabled = true, interval = "1h" }

View File

@ -1,44 +1,162 @@
use crate::config::{Config, TokenType};
use actix_web::dev::{ServiceRequest, ServiceResponse};
use actix_web::http::header::AUTHORIZATION;
use actix_web::http::HeaderMap;
use actix_web::{error, Error};
use actix_web::http::Method;
use actix_web::middleware::ErrorHandlerResponse;
use actix_web::{error, web, Error};
use std::collections::HashSet;
use std::sync::RwLock;
/// Checks the authorization header for the specified token.
/// Extracts the tokens from the authorization header by token type.
///
/// `Authorization: (type) <token>`
pub fn check(host: &str, headers: &HeaderMap, token: Option<String>) -> Result<(), Error> {
if let Some(token) = token {
if !token.is_empty() {
let auth_header = headers
.get(AUTHORIZATION)
.map(|v| v.to_str().unwrap_or_default())
.map(|v| v.split_whitespace().last().unwrap_or_default());
if auth_header.unwrap_or_default() != token {
log::warn!(
"authorization failure for {} (header: {})",
host,
auth_header.unwrap_or("none"),
);
return Err(error::ErrorUnauthorized("unauthorized"));
pub(crate) async fn extract_tokens(req: &ServiceRequest) -> Result<HashSet<TokenType>, Error> {
let config = req
.app_data::<web::Data<RwLock<Config>>>()
.map(|cfg| cfg.read())
.and_then(Result::ok)
.ok_or_else(|| error::ErrorInternalServerError("cannot acquire config"))?;
let mut user_tokens = HashSet::with_capacity(2);
let auth_header = req
.headers()
.get(AUTHORIZATION)
.map(|v| v.to_str().unwrap_or_default())
.map(|v| v.split_whitespace().last().unwrap_or_default());
for token_type in [TokenType::Auth, TokenType::Delete] {
let maybe_tokens = config.get_tokens(token_type);
if let Some(configured_tokens) = maybe_tokens {
if configured_tokens.contains(auth_header.unwrap_or_default()) {
user_tokens.insert(token_type);
}
} else if token_type == TokenType::Auth {
// not configured `auth_tokens` means that the user is allowed to access the endpoints
user_tokens.insert(token_type);
} else if token_type == TokenType::Delete && req.method() == Method::DELETE {
// explicitly disable `DELETE` methods if no `delete_tokens` are set
warn!("delete endpoint is not served because there are no delete_tokens set");
Err(error::ErrorNotFound(""))?;
}
}
Ok(())
Ok(user_tokens)
}
/// Returns `HttpResponse` with unauthorized (`401`) error and `unauthorized\n` as body.
pub(crate) fn unauthorized_error() -> actix_web::HttpResponse {
error::ErrorUnauthorized("unauthorized\n").into()
}
/// Log all unauthorized requests.
pub(crate) fn handle_unauthorized_error<B>(
res: ServiceResponse<B>,
) -> actix_web::Result<ErrorHandlerResponse<B>> {
let connection = res.request().connection_info().clone();
let host = connection.realip_remote_addr().unwrap_or("unknown host");
#[cfg(debug_assertions)]
{
let auth_header = res
.request()
.headers()
.get(AUTHORIZATION)
.and_then(|v| v.to_str().ok())
.unwrap_or("none");
warn!("authorization failure for {host} (token: {auth_header})",);
}
#[cfg(not(debug_assertions))]
warn!("authorization failure for {host}");
Ok(ErrorHandlerResponse::Response(res.map_into_left_body()))
}
#[cfg(test)]
mod test {
mod tests {
use super::*;
use actix_web::http::HeaderValue;
use actix_web::http::header::HeaderValue;
use actix_web::test::TestRequest;
use actix_web::web::Data;
use actix_web::HttpResponse;
use awc::http::StatusCode;
#[actix_web::test]
async fn test_extract_tokens() -> Result<(), Error> {
let mut config = Config::default();
// request without configured auth-tokens
let request = TestRequest::default()
.app_data(Data::new(RwLock::new(config.clone())))
.insert_header((AUTHORIZATION, HeaderValue::from_static("basic test_token")))
.to_srv_request();
let tokens = extract_tokens(&request).await?;
assert_eq!(HashSet::from([TokenType::Auth]), tokens);
// request with configured auth-tokens
config.server.auth_tokens = Some(["test_token".to_string()].into());
let request = TestRequest::default()
.app_data(Data::new(RwLock::new(config.clone())))
.insert_header((AUTHORIZATION, HeaderValue::from_static("basic test_token")))
.to_srv_request();
let tokens = extract_tokens(&request).await?;
assert_eq!(HashSet::from([TokenType::Auth]), tokens);
// request with configured auth-tokens but wrong token in request
config.server.auth_tokens = Some(["test_token".to_string()].into());
let request = TestRequest::default()
.app_data(Data::new(RwLock::new(config.clone())))
.insert_header((
AUTHORIZATION,
HeaderValue::from_static("basic invalid_token"),
))
.to_srv_request();
let tokens = extract_tokens(&request).await?;
assert_eq!(HashSet::new(), tokens);
// DELETE request without configured delete-tokens
let request = TestRequest::default()
.method(Method::DELETE)
.app_data(Data::new(RwLock::new(config.clone())))
.insert_header((AUTHORIZATION, HeaderValue::from_static("basic test_token")))
.to_srv_request();
let res = extract_tokens(&request).await;
assert!(res.is_err());
assert_eq!(
Some(StatusCode::NOT_FOUND),
res.err()
.as_ref()
.map(Error::error_response)
.as_ref()
.map(HttpResponse::status)
);
// DELETE request with configured delete-tokens
config.server.delete_tokens = Some(["delete_token".to_string()].into());
let request = TestRequest::default()
.method(Method::DELETE)
.app_data(Data::new(RwLock::new(config.clone())))
.insert_header((
AUTHORIZATION,
HeaderValue::from_static("basic delete_token"),
))
.to_srv_request();
let tokens = extract_tokens(&request).await?;
assert_eq!(HashSet::from([TokenType::Delete]), tokens);
// DELETE request with configured delete-tokens but wrong token in request
let request = TestRequest::default()
.method(Method::DELETE)
.app_data(Data::new(RwLock::new(config.clone())))
.insert_header((
AUTHORIZATION,
HeaderValue::from_static("basic invalid_token"),
))
.to_srv_request();
let tokens = extract_tokens(&request).await?;
assert_eq!(HashSet::new(), tokens);
#[test]
fn test_check_auth() -> Result<(), Error> {
let mut headers = HeaderMap::new();
headers.insert(AUTHORIZATION, HeaderValue::from_static("basic test_token"));
assert!(check("", &headers, Some(String::from("test_token"))).is_ok());
assert!(check("", &headers, Some(String::from("invalid_token"))).is_err());
assert!(check("", &headers, None).is_ok());
assert!(check("", &HeaderMap::new(), None).is_ok());
assert!(check("", &HeaderMap::new(), Some(String::from("token"))).is_err());
Ok(())
}
}

View File

@ -1,15 +1,33 @@
use crate::mime::MimeMatcher;
use crate::random::RandomURLConfig;
use crate::{AUTH_TOKEN_ENV, DELETE_TOKEN_ENV};
use byte_unit::Byte;
use config::{self, ConfigError};
use std::path::PathBuf;
use std::collections::HashSet;
use std::env;
use std::path::{Path, PathBuf};
use std::time::Duration;
/// Configuration values.
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
pub struct Config {
/// Configuration settings.
#[serde(rename = "config")]
pub settings: Option<Settings>,
/// Server configuration.
pub server: ServerConfig,
/// Paste configuration.
pub paste: PasteConfig,
/// Landing page configuration.
pub landing_page: Option<LandingPageConfig>,
}
/// General settings for configuration.
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
pub struct Settings {
/// Refresh rate of the configuration file.
#[serde(with = "humantime_serde")]
pub refresh_rate: Duration,
}
/// Server configuration.
@ -17,49 +35,245 @@ pub struct Config {
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.
pub max_content_length: Byte,
/// Storage path.
pub upload_path: PathBuf,
/// Request timeout.
#[serde(default, with = "humantime_serde")]
pub timeout: Option<Duration>,
/// Authentication token.
#[deprecated(note = "use [server].auth_tokens instead")]
pub auth_token: Option<String>,
/// Authentication tokens.
pub auth_tokens: Option<HashSet<String>>,
/// Expose version.
pub expose_version: Option<bool>,
/// Landing page text.
#[deprecated(note = "use the [landing_page] table")]
pub landing_page: Option<String>,
/// Landing page content-type.
#[deprecated(note = "use the [landing_page] table")]
pub landing_page_content_type: Option<String>,
/// Handle spaces either via encoding or replacing.
pub handle_spaces: Option<SpaceHandlingConfig>,
/// Path of the JSON index.
pub expose_list: Option<bool>,
/// Authentication tokens for deleting.
pub delete_tokens: Option<HashSet<String>>,
}
/// Enum representing different strategies for handling spaces in filenames.
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum SpaceHandlingConfig {
/// Represents encoding spaces (e.g., using "%20").
Encode,
/// Represents replacing spaces with underscores.
Replace,
}
impl SpaceHandlingConfig {
/// Processes the given filename based on the specified space handling strategy.
pub fn process_filename(&self, file_name: &str) -> String {
match self {
Self::Encode => file_name.replace(' ', "%20"),
Self::Replace => file_name.replace(' ', "_"),
}
}
}
/// Landing page configuration.
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
pub struct LandingPageConfig {
/// Landing page text.
pub text: Option<String>,
/// Landing page file.
pub file: Option<String>,
/// Landing page content-type
pub content_type: Option<String>,
}
/// Paste configuration.
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
pub struct PasteConfig {
/// Random URL configuration.
pub random_url: RandomURLConfig,
pub random_url: Option<RandomURLConfig>,
/// Default file extension.
pub default_extension: String,
/// Media type override options.
#[serde(default)]
pub mime_override: Vec<MimeMatcher>,
/// Media type blacklist.
#[serde(default)]
pub mime_blacklist: Vec<String>,
/// 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>,
}
/// Cleanup configuration.
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
pub struct CleanupConfig {
/// Enable cleaning up.
pub enabled: bool,
/// Interval between clean-ups.
#[serde(default, with = "humantime_serde")]
pub interval: Duration,
}
/// Type of access token.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum TokenType {
/// Token for authentication.
Auth,
/// Token for DELETE endpoint.
Delete,
}
impl Config {
/// Parses the config file and returns the values.
pub fn parse(file_name: &str) -> Result<Config, ConfigError> {
let mut config = config::Config::default();
config
.merge(config::File::with_name(file_name))?
.merge(config::Environment::new().separator("__"))?;
config.try_into()
pub fn parse(path: &Path) -> Result<Config, ConfigError> {
config::Config::builder()
.add_source(config::File::from(path))
.add_source(config::Environment::default().separator("__"))
.build()?
.try_deserialize()
}
/// Retrieves all configured auth/delete tokens.
pub fn get_tokens(&self, token_type: TokenType) -> Option<HashSet<String>> {
let mut tokens = match token_type {
TokenType::Auth => {
let mut tokens: HashSet<_> = self.server.auth_tokens.clone().unwrap_or_default();
#[allow(deprecated)]
if let Some(token) = &self.server.auth_token {
tokens.insert(token.to_string());
}
if let Ok(env_token) = env::var(AUTH_TOKEN_ENV) {
tokens.insert(env_token);
}
tokens
}
TokenType::Delete => {
let mut tokens: HashSet<_> = self.server.delete_tokens.clone().unwrap_or_default();
if let Ok(env_token) = env::var(DELETE_TOKEN_ENV) {
tokens.insert(env_token);
}
tokens
}
};
// filter out blank tokens
tokens.retain(|v| !v.trim().is_empty());
Some(tokens).filter(|v| !v.is_empty())
}
/// Print deprecation warnings.
#[allow(deprecated)]
pub fn warn_deprecation(&self) {
if self.server.auth_token.is_some() {
warn!("[server].auth_token is deprecated, please use [server].auth_tokens");
}
if self.server.landing_page.is_some() {
warn!("[server].landing_page is deprecated, please use [landing_page].text");
}
if self.server.landing_page_content_type.is_some() {
warn!(
"[server].landing_page_content_type is deprecated, please use [landing_page].content_type"
);
}
if let Some(random_url) = &self.paste.random_url {
if random_url.enabled.is_some() {
warn!(
"[paste].random_url.enabled is deprecated, disable it by commenting out [paste].random_url"
);
}
}
}
}
#[cfg(test)]
mod test {
mod tests {
use super::*;
use std::env;
#[test]
fn test_parse_config() -> Result<(), ConfigError> {
let file_name = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("config.toml")
.to_str()
.unwrap()
.to_string();
let config_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("config.toml");
env::set_var("SERVER__ADDRESS", "0.0.1.1");
let config = Config::parse(&file_name)?;
let config = Config::parse(&config_path)?;
assert_eq!("0.0.1.1", config.server.address);
Ok(())
}
#[test]
#[allow(deprecated)]
fn test_parse_deprecated_config() -> Result<(), ConfigError> {
let config_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("config.toml");
env::set_var("SERVER__ADDRESS", "0.0.1.1");
let mut config = Config::parse(&config_path)?;
config.paste.random_url = Some(RandomURLConfig {
enabled: Some(true),
..RandomURLConfig::default()
});
assert_eq!("0.0.1.1", config.server.address);
config.warn_deprecation();
Ok(())
}
#[test]
fn test_space_handling() {
let processed_filename =
SpaceHandlingConfig::Replace.process_filename("file with spaces.txt");
assert_eq!("file_with_spaces.txt", processed_filename);
let encoded_filename = SpaceHandlingConfig::Encode.process_filename("file with spaces.txt");
assert_eq!("file%20with%20spaces.txt", encoded_filename);
}
#[test]
fn test_get_tokens() -> Result<(), ConfigError> {
let config_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("config.toml");
env::set_var("AUTH_TOKEN", "env_auth");
env::set_var("DELETE_TOKEN", "env_delete");
let mut config = Config::parse(&config_path)?;
// empty tokens will be filtered
config.server.auth_tokens =
Some(["may_the_force_be_with_you".to_string(), "".to_string()].into());
config.server.delete_tokens = Some(["i_am_your_father".to_string(), "".to_string()].into());
assert_eq!(
Some(HashSet::from([
"env_auth".to_string(),
"may_the_force_be_with_you".to_string()
])),
config.get_tokens(TokenType::Auth)
);
assert_eq!(
Some(HashSet::from([
"env_delete".to_string(),
"i_am_your_father".to_string()
])),
config.get_tokens(TokenType::Delete)
);
env::remove_var("AUTH_TOKEN");
env::remove_var("DELETE_TOKEN");
// `get_tokens` returns `None` if no tokens are configured
config.server.auth_tokens = Some([" ".to_string()].into());
config.server.delete_tokens = Some(HashSet::new());
assert_eq!(None, config.get_tokens(TokenType::Auth));
assert_eq!(None, config.get_tokens(TokenType::Delete));
Ok(())
}
}

View File

@ -1,102 +1,76 @@
use crate::config::Config;
use std::fs::File;
use std::io::{Result as IoResult, Write};
use crate::util;
use actix_web::{error, Error as ActixError};
use glob::glob;
use std::convert::TryFrom;
use std::fs::File as OsFile;
use std::path::{Path, PathBuf};
/// Writes the bytes to a file in upload directory.
///
/// - If `file_name` does not have an extension, it is replaced with [`default_extension`].
/// - If `file_name` is "-", it is replaced with "stdin".
/// - If [`random_url.enabled`] is `true`, `file_name` is replaced with a pet name or random string.
///
/// [`default_extension`]: crate::config::PasteConfig::default_extension
/// [`random_url.enabled`]: crate::random::RandomURLConfig::enabled
pub fn save(mut file_name: &str, bytes: &[u8], config: &Config) -> IoResult<String> {
if file_name == "-" {
file_name = "stdin";
/// [`PathBuf`] wrapper for storing checksums.
#[derive(Debug)]
pub struct File {
/// Path of the file.
pub path: PathBuf,
/// SHA256 checksum.
pub sha256sum: String,
}
/// Directory that contains [`File`]s.
pub struct Directory {
/// Files in the directory.
pub files: Vec<File>,
}
impl<'a> TryFrom<&'a Path> for Directory {
type Error = ActixError;
fn try_from(directory: &'a Path) -> Result<Self, Self::Error> {
let files = glob(directory.join("**").join("*").to_str().ok_or_else(|| {
error::ErrorInternalServerError("directory contains invalid characters")
})?)
.map_err(error::ErrorInternalServerError)?
.filter_map(Result::ok)
.filter(|path| !path.is_dir())
.filter_map(|path| match OsFile::open(&path) {
Ok(file) => Some((path, file)),
_ => None,
})
.filter_map(|(path, file)| match util::sha256_digest(file) {
Ok(sha256sum) => Some(File { path, sha256sum }),
_ => None,
})
.collect();
Ok(Self { files })
}
let mut path = config.server.upload_path.join(file_name);
match path.clone().extension() {
Some(extension) => {
if let Some(url) = config.paste.random_url.generate() {
path.set_file_name(url);
path.set_extension(extension);
}
}
None => {
if let Some(url) = config.paste.random_url.generate() {
path.set_file_name(url);
}
path.set_extension(
infer::get(bytes)
.map(|t| t.extension())
.unwrap_or(&config.paste.default_extension),
);
}
}
impl Directory {
/// Returns the file that matches the given checksum.
pub fn get_file<S: AsRef<str>>(self, sha256sum: S) -> Option<File> {
self.files.into_iter().find(|file| {
file.sha256sum == sha256sum.as_ref()
&& !util::TIMESTAMP_EXTENSION_REGEX.is_match(&file.path.to_string_lossy())
})
}
let mut buffer = File::create(&path)?;
buffer.write_all(bytes)?;
Ok(path
.file_name()
.map(|v| v.to_string_lossy())
.unwrap_or_default()
.to_string())
}
#[cfg(test)]
mod test {
mod tests {
use super::*;
use crate::random::{RandomURLConfig, RandomURLType};
use std::env;
use std::fs;
use std::path::PathBuf;
use std::ffi::OsString;
#[test]
fn test_save_file() -> IoResult<()> {
let mut config = Config::default();
config.server.upload_path = env::current_dir()?;
config.paste.random_url = RandomURLConfig {
enabled: true,
words: Some(3),
separator: Some(String::from("_")),
type_: RandomURLType::PetName,
..RandomURLConfig::default()
};
let file_name = save("test.txt", &[65, 66, 67], &config)?;
assert_eq!("ABC", fs::read_to_string(&file_name)?);
fn test_file_checksum() -> Result<(), ActixError> {
assert_eq!(
Some("txt"),
PathBuf::from(&file_name)
.extension()
.map(|v| v.to_str())
.flatten()
Some(OsString::from("rustypaste_logo.png").as_ref()),
Directory::try_from(
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("img")
.as_path()
)?
.get_file("2073f6f567dcba3b468c568d29cf8ed2e9d3f0f7305b9ab1b5a22861f5922e61")
.expect("cannot get file with checksum")
.path
.file_name()
);
fs::remove_file(file_name)?;
config.paste.default_extension = String::from("bin");
config.paste.random_url.enabled = false;
config.paste.random_url = RandomURLConfig {
enabled: true,
length: Some(10),
type_: RandomURLType::Alphanumeric,
..RandomURLConfig::default()
};
let file_name = save("random", &[120, 121, 122], &config)?;
assert_eq!("xyz", fs::read_to_string(&file_name)?);
assert_eq!(
Some("bin"),
PathBuf::from(&file_name)
.extension()
.map(|v| v.to_str())
.flatten()
);
fs::remove_file(file_name)?;
config.paste.random_url.enabled = false;
let file_name = save("test.file", &[116, 101, 115, 116], &config)?;
assert_eq!("test.file", &file_name);
assert_eq!("test", fs::read_to_string(&file_name)?);
fs::remove_file(file_name)?;
Ok(())
}
}

View File

@ -1,8 +1,34 @@
use actix_web::http::header::{
ContentDisposition as ActixContentDisposition, DispositionParam, DispositionType,
ContentDisposition as ActixContentDisposition, DispositionParam, DispositionType, HeaderMap,
};
use actix_web::{error, Error as ActixError};
use std::convert::TryFrom;
use std::time::Duration;
/// Custom HTTP header for expiry dates.
pub const EXPIRE: &str = "expire";
/// Custom HTTP header to override filename.
const FILENAME: &str = "filename";
/// Parses the expiry date from the [`custom HTTP header`](EXPIRE).
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 expire_time =
humantime::parse_duration(expire_time).map_err(error::ErrorInternalServerError)?;
Ok(time.checked_add(expire_time).map(|t| t.as_millis()))
} else {
Ok(None)
}
}
/// Parses the filename from the header.
pub fn parse_header_filename(headers: &HeaderMap) -> Result<Option<String>, ActixError> {
if let Some(file_name) = headers.get(FILENAME).and_then(|v| v.to_str().ok()) {
Ok(Some(file_name.to_string()))
} else {
Ok(None)
}
}
/// Wrapper for Actix content disposition header.
///
@ -13,12 +39,10 @@ pub struct ContentDisposition {
inner: ActixContentDisposition,
}
impl TryFrom<Option<ActixContentDisposition>> for ContentDisposition {
type Error = ActixError;
fn try_from(content_disposition: Option<ActixContentDisposition>) -> Result<Self, Self::Error> {
match content_disposition {
Some(inner) => Ok(Self { inner }),
None => Err(error::ErrorBadRequest("content disposition does not exist")),
impl From<ActixContentDisposition> for ContentDisposition {
fn from(content_disposition: ActixContentDisposition) -> Self {
Self {
inner: content_disposition,
}
}
}
@ -40,39 +64,55 @@ impl ContentDisposition {
.parameters
.iter()
.find(|param| param.is_filename())
.map(|param| param.as_filename())
.flatten()
.and_then(|param| param.as_filename())
.filter(|file_name| !file_name.is_empty())
.ok_or_else(|| error::ErrorBadRequest("file data not present"))
}
}
#[cfg(test)]
mod test {
mod tests {
use super::*;
use crate::util;
use actix_web::http::header::{HeaderName, HeaderValue};
use std::thread;
#[test]
fn test_content_disposition() -> Result<(), ActixError> {
assert!(ContentDisposition::try_from(None).is_err());
let actix_content_disposition = Some(ActixContentDisposition {
let actix_content_disposition = ActixContentDisposition {
disposition: DispositionType::FormData,
parameters: vec![
DispositionParam::Name(String::from("file")),
DispositionParam::Filename(String::from("x.txt")),
],
});
let content_disposition = ContentDisposition::try_from(actix_content_disposition)?;
};
let content_disposition = ContentDisposition::from(actix_content_disposition);
assert!(content_disposition.has_form_field("file"));
assert!(!content_disposition.has_form_field("test"));
assert_eq!("x.txt", content_disposition.get_file_name()?);
let actix_content_disposition = Some(ActixContentDisposition {
let actix_content_disposition = ActixContentDisposition {
disposition: DispositionType::Attachment,
parameters: vec![DispositionParam::Name(String::from("file"))],
});
let content_disposition = ContentDisposition::try_from(actix_content_disposition)?;
};
let content_disposition = ContentDisposition::from(actix_content_disposition);
assert!(!content_disposition.has_form_field("file"));
assert!(content_disposition.get_file_name().is_err());
Ok(())
}
#[test]
fn test_expiry_date() -> Result<(), ActixError> {
let mut headers = HeaderMap::new();
headers.insert(
HeaderName::from_static(EXPIRE),
HeaderValue::from_static("5ms"),
);
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());
Ok(())
}
}

View File

@ -13,8 +13,33 @@ pub mod server;
/// HTTP headers.
pub mod header;
/// File handler.
pub mod file;
/// Auth handler.
pub mod auth;
/// Storage handler.
pub mod paste;
/// File metadata handler.
pub mod file;
/// Media type handler.
pub mod mime;
/// Helper functions.
pub mod util;
/// Custom middleware implementation.
pub mod middleware;
// Use macros from tracing crate.
#[macro_use]
extern crate tracing;
/// Environment variable for setting the configuration file path.
pub const CONFIG_ENV: &str = "CONFIG";
/// Environment variable for setting the authentication token.
pub const AUTH_TOKEN_ENV: &str = "AUTH_TOKEN";
/// Environment variable for setting the deletion token.
pub const DELETE_TOKEN_ENV: &str = "DELETE_TOKEN";

View File

@ -1,28 +1,231 @@
use actix_web::middleware::Logger;
use actix_web::web::Data;
#[cfg(not(feature = "shuttle"))]
use actix_web::{App, HttpServer};
use rustypaste::config::Config;
use awc::ClientBuilder;
use hotwatch::notify::event::ModifyKind;
use hotwatch::{Event, EventKind, Hotwatch};
use rustypaste::config::{Config, ServerConfig};
use rustypaste::middleware::ContentLengthLimiter;
use rustypaste::paste::PasteType;
use rustypaste::server;
use rustypaste::util;
use rustypaste::CONFIG_ENV;
use std::env;
use std::fs;
use std::io::Result as IoResult;
use std::path::{Path, PathBuf};
use std::sync::{mpsc, RwLock};
use std::thread;
use std::time::Duration;
#[cfg(not(feature = "shuttle"))]
use tracing_subscriber::{
filter::LevelFilter, layer::SubscriberExt as _, util::SubscriberInitExt as _, EnvFilter,
};
#[cfg(feature = "shuttle")]
use {
actix_web::web::{self, ServiceConfig},
shuttle_actix_web::ShuttleActixWeb,
};
// Use macros from tracing crate.
#[macro_use]
extern crate tracing;
/// 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"))]
tracing_subscriber::registry()
.with(
EnvFilter::builder()
.with_default_directive(LevelFilter::INFO.into())
.from_env_lossy(),
)
.with(tracing_subscriber::fmt::layer())
.init();
// Parse configuration.
let config_path = match env::var(CONFIG_ENV).ok() {
Some(path) => {
env::remove_var(CONFIG_ENV);
PathBuf::from(path)
}
None => config_folder.join("config.toml"),
};
if !config_path.exists() {
error!(
"{} is not found, please provide a configuration file.",
config_path.display()
);
std::process::exit(1);
}
let config = Config::parse(&config_path).expect("failed to parse config");
trace!("{:#?}", config);
config.warn_deprecation();
let server_config = config.server.clone();
let paste_config = RwLock::new(config.paste.clone());
let (config_sender, config_receiver) = mpsc::channel::<Config>();
// Create necessary directories.
fs::create_dir_all(&server_config.upload_path)?;
for paste_type in &[PasteType::Url, PasteType::Oneshot, PasteType::OneshotUrl] {
fs::create_dir_all(paste_type.get_path(&server_config.upload_path)?)?;
}
// Set up a watcher for the configuration file changes.
let mut hotwatch = Hotwatch::new_with_custom_delay(
config
.settings
.as_ref()
.map(|v| v.refresh_rate)
.unwrap_or_else(|| Duration::from_secs(1)),
)
.expect("failed to initialize configuration file watcher");
// Hot-reload the configuration file.
let config = Data::new(RwLock::new(config));
let cloned_config = Data::clone(&config);
let config_watcher = move |event: Event| {
if let (EventKind::Modify(ModifyKind::Data(_)), Some(path)) =
(event.kind, event.paths.first())
{
match Config::parse(path) {
Ok(config) => match cloned_config.write() {
Ok(mut cloned_config) => {
*cloned_config = config.clone();
info!("Configuration has been updated.");
if let Err(e) = config_sender.send(config) {
error!("Failed to send config for the cleanup routine: {}", e)
}
cloned_config.warn_deprecation();
}
Err(e) => {
error!("Failed to acquire config: {}", e);
}
},
Err(e) => {
error!("Failed to update config: {}", e);
}
}
}
};
hotwatch
.watch(&config_path, config_watcher)
.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
.read()
.ok()
.and_then(|v| v.delete_expired_files.clone())
{
if cleanup_config.enabled {
debug!("Running cleanup...");
for file in util::get_expired_files(&upload_path) {
match fs::remove_file(&file) {
Ok(()) => info!("Removed expired file: {:?}", file),
Err(e) => error!("Cannot remove expired file: {}", e),
}
}
thread::sleep(cleanup_config.interval);
}
enabled = cleanup_config.enabled;
}
if let Some(new_config) = if enabled {
config_receiver.try_recv().ok()
} else {
config_receiver.recv().ok()
} {
match paste_config.write() {
Ok(mut paste_config) => {
*paste_config = new_config.paste;
}
Err(e) => {
error!("Failed to update config for the cleanup routine: {}", e);
}
}
}
});
Ok((config, server_config, hotwatch))
}
#[cfg(not(feature = "shuttle"))]
#[actix_web::main]
async fn main() -> IoResult<()> {
dotenv::dotenv().ok();
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
let config = Config::parse(env::var("CONFIG").as_deref().unwrap_or("config"))
.expect("failed to parse config");
let server_config = config.server.clone();
fs::create_dir_all(server_config.upload_path)?;
// Set up the application.
let (config, server_config, _hotwatch) = setup(&PathBuf::new())?;
// Create an HTTP server.
let mut http_server = HttpServer::new(move || {
let http_client = ClientBuilder::new()
.timeout(
server_config
.timeout
.unwrap_or_else(|| Duration::from_secs(30)),
)
.disable_redirects()
.finish();
App::new()
.data(config.clone())
.wrap(Logger::default())
.app_data(Data::clone(&config))
.app_data(Data::new(http_client))
.wrap(Logger::new(
"%{r}a \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\" %T",
))
.wrap(ContentLengthLimiter::new(server_config.max_content_length))
.configure(server::configure_routes)
})
.bind(server_config.address)?;
.bind(&server_config.address)?;
// Set worker count for the server.
if let Some(workers) = server_config.workers {
http_server = http_server.workers(workers);
}
// Run the server.
info!("Server is running at {}", server_config.address);
http_server.run().await
}
#[cfg(feature = "shuttle")]
#[shuttle_runtime::main]
async fn actix_web() -> ShuttleActixWeb<impl FnOnce(&mut ServiceConfig) + Send + Clone + 'static> {
// Set up the application.
let (config, server_config, _hotwatch) = setup(Path::new("shuttle"))?;
// 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::new(
"%{r}a \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\" %T",
))
.wrap(ContentLengthLimiter::new(server_config.max_content_length))
.configure(server::configure_routes),
);
};
Ok(service_config.into())
}

96
src/middleware.rs Normal file
View File

@ -0,0 +1,96 @@
use actix_web::dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform};
use actix_web::http::header::CONTENT_LENGTH;
use actix_web::http::StatusCode;
use actix_web::{body::EitherBody, Error};
use actix_web::{HttpMessage, HttpResponseBuilder};
use byte_unit::Byte;
use futures_util::{Future, TryStreamExt};
use std::{
future::{ready, Ready},
pin::Pin,
rc::Rc,
};
/// Content length limiter middleware.
#[derive(Debug)]
pub struct ContentLengthLimiter {
// Maximum amount of bytes to allow.
max_bytes: Byte,
}
impl ContentLengthLimiter {
/// Constructs a new instance.
pub fn new(max_bytes: Byte) -> Self {
Self { max_bytes }
}
}
impl<S, B> Transform<S, ServiceRequest> for ContentLengthLimiter
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<EitherBody<B>>;
type Error = Error;
type Transform = ContentLengthLimiterMiddleware<S>;
type InitError = ();
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ready(Ok(ContentLengthLimiterMiddleware {
service: Rc::new(service),
max_bytes: self.max_bytes,
}))
}
}
/// Content length limiter middleware implementation.
#[derive(Debug)]
pub struct ContentLengthLimiterMiddleware<S> {
service: Rc<S>,
max_bytes: Byte,
}
impl<S, B> Service<ServiceRequest> for ContentLengthLimiterMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<EitherBody<B>>;
type Error = Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
forward_ready!(service);
fn call(&self, mut request: ServiceRequest) -> Self::Future {
let service = Rc::clone(&self.service);
if let Some(content_length) = request
.headers()
.get(CONTENT_LENGTH)
.and_then(|v| v.to_str().ok())
.and_then(|v| v.parse::<Byte>().ok())
{
if content_length > self.max_bytes {
warn!(
"Upload rejected due to exceeded limit. ({:-#} > {:-#})",
content_length, self.max_bytes
);
return Box::pin(async move {
// drain the body due to https://github.com/actix/actix-web/issues/2695
let mut payload = request.take_payload();
while let Ok(Some(_)) = payload.try_next().await {}
Ok(request.into_response(
HttpResponseBuilder::new(StatusCode::PAYLOAD_TOO_LARGE)
.body("upload limit exceeded")
.map_into_right_body(),
))
});
}
}
Box::pin(async move {
service
.call(request)
.await
.map(ServiceResponse::map_into_left_body)
})
}
}

81
src/mime.rs Normal file
View File

@ -0,0 +1,81 @@
use actix_files::file_extension_to_mime;
use mime::{FromStrError, Mime};
use regex::Regex;
use std::path::PathBuf;
use std::str::FromStr;
/// Matcher for MIME types.
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
pub struct MimeMatcher {
/// MIME type to set for the matched file name.
pub mime: String,
/// Regex for matching the file name.
#[serde(with = "serde_regex")]
pub regex: Option<Regex>,
}
/// Returns the appropriate media type using an array of
/// [`MIME matcher`]s and the file name.
///
/// [`MIME matcher`]: MimeMatcher
pub fn get_mime_type(
mime_matchers: &[MimeMatcher],
file_name: String,
) -> Result<Mime, FromStrError> {
let path = PathBuf::from(&file_name);
let mut mime_type = file_extension_to_mime(
path.extension()
.and_then(|v| v.to_str())
.unwrap_or_default(),
);
for matcher in mime_matchers {
if matcher
.regex
.as_ref()
.map(|r| r.is_match(&file_name))
.unwrap_or(false)
{
mime_type = Mime::from_str(&matcher.mime)?;
break;
}
}
Ok(mime_type)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_match_mime_type() -> Result<(), FromStrError> {
assert_eq!(
mime::TEXT_PLAIN,
get_mime_type(
&[MimeMatcher {
mime: String::from("text/plain"),
regex: Regex::new("^.*\\.test$").ok(),
}],
String::from("mime.test")
)?
);
assert_eq!(
mime::IMAGE_PNG,
get_mime_type(
&[MimeMatcher {
mime: String::from("image/png"),
regex: Regex::new("^.*\\.PNG$").ok(),
}],
String::from("image.PNG")
)?
);
assert_eq!(
mime::APPLICATION_PDF,
get_mime_type(&[], String::from("book.pdf"))?
);
assert_eq!(
mime::APPLICATION_OCTET_STREAM,
get_mime_type(&[], String::from("x.unknown"))?
);
Ok(())
}
}

Some files were not shown because too many files have changed in this diff Show More