mirror of https://github.com/zer0bin-dev/zer0bin
Merge pull request #42 from zer0bin-dev/main
This commit is contained in:
commit
c49cc4191a
|
@ -5,6 +5,6 @@
|
|||
- Your code must be formatted with the formatters we use
|
||||
- The frontend must use our `prettier` config
|
||||
- The backend must use `rustfmt`
|
||||
- The frontend must be installed and compiled with `yarn` and `parcel`
|
||||
- The frontend must be installed with `yarn` and compiled with `parcel`
|
||||
- Additional frontend packages must not be considered bloated
|
||||
- All commits must follow [Conventional Commits](https://marketplace.visualstudio.com/items?itemName=vivaxy.vscode-conventional-commits)
|
||||
|
|
121
README.md
121
README.md
|
@ -10,127 +10,64 @@
|
|||
<br>
|
||||
<p align="center">
|
||||
<a href="https://github.com/zer0bin-dev/zer0bin/stargazers">
|
||||
<img alt="Stargazers" src="https://custom-icon-badges.herokuapp.com/github/stars/zer0bin-dev/zer0bin?style=for-the-badge&logo=star&color=f6c177&logoColor=ebbcba&labelColor=191724"></a>
|
||||
<img alt="Stargazers" src="https://custom-icon-badges.herokuapp.com/github/stars/zer0bin-dev/zer0bin?style=for-the-badge&logo=star&color=f6c177&logoColor=eb6f92&labelColor=191724"></a>
|
||||
<a href="https://github.com/zer0bin-dev/zer0bin/wiki">
|
||||
<img alt="Wiki" src="https://custom-icon-badges.herokuapp.com/badge/read_the-wiki-ebbcba?style=for-the-badge&logo=repo&logoColor=eb6f92&labelColor=191724"></a>
|
||||
<a href="https://github.com/zer0bin-dev/zer0bin/releases/latest">
|
||||
<img alt="Releases" src="https://img.shields.io/github/release/zer0bin-dev/zer0bin?style=for-the-badge&logo=github&color=31748f&logoColor=ebbcba&labelColor=191724"/></a>
|
||||
<img alt="Releases" src="https://img.shields.io/github/release/zer0bin-dev/zer0bin?style=for-the-badge&logo=github&color=31748f&logoColor=eb6f92&labelColor=191724"/></a>
|
||||
<a href="https://github.com/zer0bin-dev/zer0bin/blob/main/LICENSE">
|
||||
<img alt="License" src="https://custom-icon-badges.herokuapp.com/github/license/zer0bin-dev/zer0bin?style=for-the-badge&logo=law&color=c4a7e7&logoColor=ebbcba&labelColor=191724"></a>
|
||||
<img alt="License" src="https://custom-icon-badges.herokuapp.com/github/license/zer0bin-dev/zer0bin?style=for-the-badge&logo=law&color=c4a7e7&logoColor=eb6f92&labelColor=191724"></a>
|
||||
<a href="https://github.com/zer0bin-dev/zer0bin/issues">
|
||||
<img alt="Issues" src="https://custom-icon-badges.herokuapp.com/github/issues/zer0bin-dev/zer0bin?style=for-the-badge&logo=issue-opened&color=9ccfd8&logoColor=eb6f92&labelColor=191724"></a>
|
||||
</p>
|
||||
<br>
|
||||
</div>
|
||||
|
||||
# Features
|
||||
|
||||
- ✨ Code highlighting and line numbers (default)
|
||||
- 📖 Markdown rendering (add `---` or `md` to the start of your paste)
|
||||
- 🧑💻 [CLI Client](https://github.com/zer0bin-dev/zer0)
|
||||
- 🚀 Easily selfhostable
|
||||
- 👀 View counter
|
||||
- ⌨️ Keybinds (<kbd>Ctrl</kbd> + <kbd>S</kbd>: save paste, <kbd>Ctrl</kbd> + <kbd>N</kbd>: new paste, <kbd>Ctrl</kbd> + <kbd>D</kbd>: duplicate paste)
|
||||
- 📱 Mobile-friendly UI
|
||||
- 🧈 Super smooth scrolling
|
||||
- 🖼️ Badge generation for stats (seen below)
|
||||
|
||||
# Public instances
|
||||
|
||||
Submit your public instance [here](https://github.com/Domterion/zer0bin/issues/new?assignees=&labels=&template=03_public_instance.md&title=%F0%9F%9A%80+)!
|
||||
|
||||
| Website | Expiration | Max paste size | Version | Country |
|
||||
| ---------------------------------------------- | ---------- | -------------- | ------- | ------- |
|
||||
| [zer0b.in](https://zer0b.in) | 90 days | 50,000 chars | v0.7.1 | 🇺🇸 USA |
|
||||
| [stepbro.voring.me](https://stepbro.voring.me) | 365 days | 69,000 chars | v0.7.1 | 🇺🇸 USA |
|
||||
| [tinker.nz](https://tinker.nz/) | 28 days | 69,420 chars | v0.7.1 | 🇳🇿 NZ |
|
||||
| URL | Expiration | Max paste size | Total Pastes | Version | Country |
|
||||
| ---------------------------------------------- | ---------- | -------------- | -------------------------------------------- | --------------------------------------------- | ------- |
|
||||
| [zer0b.in](https://zer0b.in) | 90 days | 50,000 chars | ![pastes](https://zer0b.in/api/b/t) | ![version](https://zer0b.in/api/b/v) | 🇺🇸 USA |
|
||||
| [stepbro.voring.me](https://stepbro.voring.me) | 365 days | 69,000 chars | ![pastes](https://stepbro.voring.me/api/b/t) | ![version](https://stepbro.voring.me/api/b/v) | 🇺🇸 USA |
|
||||
| [tinker.nz](https://tinker.nz/) | 28 days | 69,420 chars | ![pastes](https://tinker.nz/api/b/t) | ![version](https://tinker.nz/api/b/v) | 🇳🇿 NZ |
|
||||
|
||||
# Technologies used
|
||||
|
||||
### Frontend:
|
||||
|
||||
<a href="https://www.typescriptlang.org/"><img src="https://github.com/tandpfun/skill-icons/raw/main/icons/TypeScript.svg" height=40/></a> <a href="https://sass-lang.com/"><img src="https://github.com/tandpfun/skill-icons/raw/main/icons/Sass.svg" height=40/></a> <a href="https://pugjs.org/"><img src="https://github.com/tandpfun/skill-icons/raw/main/icons/Pug-Dark.svg" height=40/></a> <a href="https://rosepinetheme.com/"><img src="https://cdn.discordapp.com/attachments/810799100940255260/953176309444542464/RosePine.svg" height=40/></a> <a href="https://highlightjs.org/"><img src="https://cdn.discordapp.com/attachments/810799100940255260/953177926688464936/HLJS.svg" height=40/></a> <a href="https://github.com/ant-design/ant-design-icons"><img src="https://cdn.discordapp.com/attachments/810799100940255260/953181625259266059/AntIcons-Dark.svg" height=40/></a> <a href="https://github.com/idiotWu/smooth-scrollbar"><img src="https://cdn.discordapp.com/attachments/810799100940255260/953564432628322364/SmoothScrollJS.svg" height=40/></a><br><a href="https://atomiks.github.io/tippyjs/"><img src="https://cdn.discordapp.com/attachments/872332549777666078/955624715521769522/Tippy.svg" height=40/></a> <a href="https://github.com/loonywizard/js-confetti"><img src="https://cdn.discordapp.com/attachments/810799100940255260/955609316042362930/JSConfetti.svg" height=40/></a> <a href="https://github.com/hadialqattan/no-darkreader"><img src="https://cdn.discordapp.com/attachments/810799100940255260/955869669535907870/NoDarkReader.svg" height=40/></a> <a href="https://parceljs.org/"><img src="https://user-images.githubusercontent.com/44733677/158683062-17ac3b62-cacd-4add-babb-1f74f36020d8.svg" height=40/></a> <a href="https://prettier.io/"><img src="https://cdn.discordapp.com/attachments/810799100940255260/953339670538887318/Prettier.svg" height=40/></a> <a href="https://yarnpkg.org"><img src="https://cdn.discordapp.com/attachments/810799100940255260/954823377493852170/Yarn.svg" height=40/></a> <a href="https://transfonter.org"><img src="https://user-images.githubusercontent.com/44733677/159066877-234f68ba-e95c-439d-b5fe-74def49dc762.svg" height=40></a>
|
||||
<a href="https://www.typescriptlang.org/"><img src="https://github.com/tandpfun/skill-icons/raw/main/icons/TypeScript.svg" height=40/></a> <a href="https://definitelytyped.org/"><img src="https://cdn.discordapp.com/attachments/810799100940255260/953567495321710602/DefinitelyTyped.svg" height=40/></a> <a href="https://sass-lang.com/"><img src="https://github.com/tandpfun/skill-icons/raw/main/icons/Sass.svg" height=40/></a> <a href="https://pugjs.org/"><img src="https://github.com/tandpfun/skill-icons/raw/main/icons/Pug-Dark.svg" height=40/></a> <a href="https://rosepinetheme.com/"><img src="https://cdn.discordapp.com/attachments/810799100940255260/953176309444542464/RosePine.svg" height=40/></a> <a href="https://highlightjs.org/"><img src="https://cdn.discordapp.com/attachments/810799100940255260/956227499229061140/hljs.svg" height=40/></a> <a href="https://marked.js.org/"><img src="https://cdn.discordapp.com/attachments/810799100940255260/956263178961047612/MarkedJS.svg" height=40/></a> <a href="https://github.com/ant-design/ant-design-icons"><img src="https://cdn.discordapp.com/attachments/810799100940255260/956227498985799690/anticons.svg" height=40/></a><br><a href="https://github.com/idiotWu/smooth-scrollbar"><img src="https://cdn.discordapp.com/attachments/810799100940255260/953564432628322364/SmoothScrollJS.svg" height=40/></a> <a href="https://atomiks.github.io/tippyjs/"><img src="https://cdn.discordapp.com/attachments/872332549777666078/955624715521769522/Tippy.svg" height=40/></a> <a href="https://github.com/loonywizard/js-confetti"><img src="https://cdn.discordapp.com/attachments/810799100940255260/955609316042362930/JSConfetti.svg" height=40/></a> <a href="https://github.com/hadialqattan/no-darkreader"><img src="https://cdn.discordapp.com/attachments/810799100940255260/955869669535907870/NoDarkReader.svg" height=40/></a> <a href="https://parceljs.org/"><img src="https://user-images.githubusercontent.com/44733677/158683062-17ac3b62-cacd-4add-babb-1f74f36020d8.svg" height=40/></a> <a href="https://prettier.io/"><img src="https://cdn.discordapp.com/attachments/810799100940255260/953339670538887318/Prettier.svg" height=40/></a> <a href="https://yarnpkg.org"><img src="https://cdn.discordapp.com/attachments/810799100940255260/954823377493852170/Yarn.svg" height=40/></a> <a href="https://transfonter.org"><img src="https://user-images.githubusercontent.com/44733677/159066877-234f68ba-e95c-439d-b5fe-74def49dc762.svg" height=40></a>
|
||||
|
||||
### Backend:
|
||||
|
||||
<a href="https://www.rust-lang.org/"><img src="https://github.com/tandpfun/skill-icons/raw/main/icons/Rust.svg" height=40/></a> <a href="https://actix.rs/"><img src="https://user-images.githubusercontent.com/44733677/158648238-0586f185-4e0c-43bc-b6a9-effd18b3b1ac.svg" height=40/></a> <a href="https://github.com/serde-rs/serde"><img src="https://cdn.discordapp.com/attachments/810799100940255260/953176309964627978/Serde-Dark.svg" height=40/></a> <a href="https://github.com/launchbadge/sqlx"><img src="https://cdn.discordapp.com/attachments/810799100940255260/953176310354673704/SQLX-Dark.svg" height=40/></a> <a href="https://github.com/chronotope/chrono"><img src="https://cdn.discordapp.com/attachments/810799100940255260/953178919169835018/NPM-svg.png" height=40/></a> <a href="https://www.postgresql.org/"><img src="https://github.com/tandpfun/skill-icons/raw/main/icons/PostgreSQL-Dark.svg" height=40/></a> <a href="https://github.com/nikolay-govorov/nanoid"><img src="https://cdn.discordapp.com/attachments/810799100940255260/953176309629067354/NanoID-Dark.svg" height=40/></a>
|
||||
<a href="https://www.rust-lang.org/"><img src="https://github.com/tandpfun/skill-icons/raw/main/icons/Rust.svg" height=40/></a> <a href="https://actix.rs/"><img src="https://user-images.githubusercontent.com/44733677/158648238-0586f185-4e0c-43bc-b6a9-effd18b3b1ac.svg" height=40/></a> <a href="https://github.com/serde-rs/serde"><img src="https://cdn.discordapp.com/attachments/810799100940255260/956227498792849418/serde.svg" height=40/></a> <a href="https://github.com/launchbadge/sqlx"><img src="https://cdn.discordapp.com/attachments/810799100940255260/956227498608320562/sqlx.svg" height=40/></a> <a href="https://github.com/chronotope/chrono"><img src="https://cdn.discordapp.com/attachments/810799100940255260/953178919169835018/NPM-svg.png" height=40/></a> <a href="https://www.postgresql.org/"><img src="https://github.com/tandpfun/skill-icons/raw/main/icons/PostgreSQL-Dark.svg" height=40/></a> <a href="https://github.com/nikolay-govorov/nanoid"><img src="https://cdn.discordapp.com/attachments/810799100940255260/953176309629067354/NanoID-Dark.svg" height=40/></a> <a href="https://github.com/cgburgess/badge-maker"><img src="https://cdn.discordapp.com/attachments/810799100940255260/956244924930617385/RustBadgeMaker.svg" height=40/></a>
|
||||
|
||||
### Misc:
|
||||
|
||||
<a href="https://nginx.com/"><img src="https://github.com/tandpfun/skill-icons/raw/main/icons/Nginx.svg" height=40/></a> <!-- <a href="https://docker.com/"><img src="https://github.com/tandpfun/skill-icons/raw/main/icons/Docker.svg" height=40/></a> --> <a href="https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax"><img src="https://github.com/tandpfun/skill-icons/raw/main/icons/Markdown-Dark.svg" height=40/></a> <a href="https://git-scm.com/"><img src="https://github.com/tandpfun/skill-icons/raw/main/icons/Git.svg" height=40/></a> <a href="https://www.conventionalcommits.org/"><img src="https://cdn.discordapp.com/attachments/810799100940255260/954930714007191582/ConventionalCommits.svg" height=40/></a>
|
||||
<a href="https://nginx.com/"><img src="https://github.com/tandpfun/skill-icons/raw/main/icons/Nginx.svg" height=40/></a> <!-- <a href="https://docker.com/"><img src="https://github.com/tandpfun/skill-icons/raw/main/icons/Docker.svg" height=40/></a> --> <a href="https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax"><img src="https://github.com/tandpfun/skill-icons/raw/main/icons/Markdown-Dark.svg" height=40/></a> <a href="https://git-scm.com/"><img src="https://github.com/tandpfun/skill-icons/raw/main/icons/Git.svg" height=40/></a> <a href="https://www.conventionalcommits.org/"><img src="https://cdn.discordapp.com/attachments/810799100940255260/955896756095320074/ConventionalCommits.svg" height=40/></a>
|
||||
|
||||
###### (Sorta) made with [Skill Icons](https://skillicons.dev/)
|
||||
|
||||
# API
|
||||
# More info
|
||||
|
||||
- **GET** `/api/p/:id` - Get a paste by ID
|
||||
- **POST** `/api/p/n` - Post a new paste
|
||||
- **GET** `/api/s` - Get stats about the instance
|
||||
### Looking for API reference, self-hosting instructions, and/or benchmarks?
|
||||
|
||||
# Self-host instructions
|
||||
<a href="https://github.com/zer0bin-dev/zer0bin/wiki">
|
||||
<img alt="Stargazers" src="https://custom-icon-badges.herokuapp.com/badge/read_the-wiki-ebbcba?style=for-the-badge&logo=repo&logoColor=eb6f92&labelColor=191724" height=50></a>
|
||||
|
||||
### Requirements
|
||||
|
||||
- 🦀 [Rust](https://www.rust-lang.org/) ≥ 1.58.0
|
||||
- 🐈 [Yarn](https://yarnpkg.com/) ≥ 1.0.0
|
||||
- 🐘 [PostgreSQL](https://www.postgresql.org/) ≥ 9.6
|
||||
- 🦝 [Nginx](https://www.nginx.com/) ≥ 1.18.0
|
||||
- 🌾 [Brotli plugin](https://github.com/google/ngx_brotli) recommended
|
||||
- 🐧 [Linux](https://kernel.org/) or 😈 [FreeBSD](https://freebsd.org/)
|
||||
- 🌄 Domain with [SSL](https://letsencrypt.org/)
|
||||
|
||||
<details>
|
||||
<summary><h3>Steps</h3></summary>
|
||||
|
||||
Please run each command one at a time!
|
||||
|
||||
```bash
|
||||
# export EDITOR=nano
|
||||
git clone https://github.com/zer0bin-dev/zer0bin && cd zer0bin
|
||||
$EDITOR example.nginx # Edit as appropriate
|
||||
mv example.nginx yourdomain.tld
|
||||
sudo cp ./yourdomain.tld /etc/nginx/sites-available
|
||||
sudo cp ./yourdomain.tld /etc/nginx/sites-enabled
|
||||
systemctl nginx restart # Or whichever process manager you use
|
||||
cd frontend
|
||||
cp config.example.json config.json
|
||||
$EDITOR config.json # Edit as appropriate
|
||||
yarn && yarn build
|
||||
cd ../backend
|
||||
psql -f schema.sql -U postgres zer0bin
|
||||
cp config.example.json config.json
|
||||
$EDITOR config.json # Edit as appropriate
|
||||
cargo build --release
|
||||
./target/release/zer0bin-bin # Preferably in a tmux session or as a service
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>Configuration</h3></summary>
|
||||
|
||||
| Key | Values | Description |
|
||||
| ------------------------------------------ | ------------------------ | ------------------------------------------------------------------------------ |
|
||||
| server.backend_host | 127.0.0.1 or 0.0.0.0 | The host to run the backend on |
|
||||
| server.backend_port | Any open port | The port to run the backend on |
|
||||
| pastes.character_limit | Number up to 2^64 - 1 | The amount of characters allowed in a single paste |
|
||||
| pastes.days_til_expiration | Number up to 2^63 or -1 | The days till a paste is to expire. If set to -1 then pastes will never expire |
|
||||
| pastes.id_length | Number up to 2^64 - 1 | The length of the ID for each paste |
|
||||
| databases.postgres_uri | PostreSQL Connection URI | The URI to use when connecting to a PostgreSQL database |
|
||||
| ratelimits.seconds_in_between_pastes | Number up to 2^64 - 1 | The seconds between paste uploads |
|
||||
| ratelimits.allowed_pastes_before_ratelimit | Number up to 2^32 - 1 | Amount of requests that can be made before they are blocked and have to wait |
|
||||
| logging.on_post_paste | true or false | Log on new paste is made |
|
||||
| logging.on_get_paste | true or false | Log on paste get |
|
||||
|
||||
</details>
|
||||
|
||||
# Benchmarks
|
||||
|
||||
###### Measured with Lighthouse and Firefox Network Performance Analysis
|
||||
|
||||
<details>
|
||||
<summary><h3>Results</h3></summary>
|
||||
|
||||
### Homepage
|
||||
|
||||
![image](https://user-images.githubusercontent.com/44733677/159143364-a6e06aee-256e-4998-83f2-541c77e85184.png)
|
||||
![image](https://user-images.githubusercontent.com/44733677/159143316-c8e95ed6-ec32-44b3-abcc-18bd204a004d.png)
|
||||
![image](https://user-images.githubusercontent.com/44733677/159143321-aa8a5f6f-53d2-40d1-bff9-71d72347e7ea.png)
|
||||
|
||||
### 20 line paste
|
||||
|
||||
![image](https://user-images.githubusercontent.com/44733677/159143373-6e8787d8-61ef-44dc-9d66-52cd74e2a495.png)
|
||||
![image](https://user-images.githubusercontent.com/44733677/159143298-f8c7420d-ff76-4db7-a98e-03ff3615315e.png)
|
||||
![image](https://user-images.githubusercontent.com/44733677/159143303-efb71e15-623a-42cc-abf6-7e602843d801.png)
|
||||
|
||||
</details>
|
||||
|
||||
# Contributing
|
||||
|
||||
See [CONTRIBUTING.md](./CONTRIBUTING.md)
|
||||
|
|
|
@ -71,7 +71,7 @@ dependencies = [
|
|||
"http",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"itoa 1.0.1",
|
||||
"language-tags",
|
||||
"local-channel",
|
||||
"log",
|
||||
|
@ -182,7 +182,7 @@ dependencies = [
|
|||
"encoding_rs",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"itoa",
|
||||
"itoa 1.0.1",
|
||||
"language-tags",
|
||||
"log",
|
||||
"mime",
|
||||
|
@ -268,12 +268,13 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
|||
|
||||
[[package]]
|
||||
name = "backend"
|
||||
version = "0.7.1"
|
||||
version = "1.0.1"
|
||||
dependencies = [
|
||||
"actix-cors",
|
||||
"actix-governor",
|
||||
"actix-rt",
|
||||
"actix-web",
|
||||
"badge-maker",
|
||||
"chrono",
|
||||
"nanoid",
|
||||
"serde",
|
||||
|
@ -281,12 +282,37 @@ dependencies = [
|
|||
"sqlx",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "badge-maker"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "383647c1ae7388c2801ef995f6de2f9551a361ad637f2a0e4fea41c51dd37b81"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"bincode",
|
||||
"itoa 0.4.8",
|
||||
"lazy_static",
|
||||
"regex",
|
||||
"seahash",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
@ -819,7 +845,7 @@ checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03"
|
|||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
"itoa 1.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -873,6 +899,12 @@ dependencies = [
|
|||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.1"
|
||||
|
@ -1364,6 +1396,12 @@ dependencies = [
|
|||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "seahash"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.6"
|
||||
|
@ -1396,7 +1434,7 @@ version = "1.0.79"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"itoa 1.0.1",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
@ -1408,7 +1446,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"itoa",
|
||||
"itoa 1.0.1",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
@ -1533,7 +1571,7 @@ dependencies = [
|
|||
"hex",
|
||||
"hmac",
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"itoa 1.0.1",
|
||||
"libc",
|
||||
"log",
|
||||
"md-5",
|
||||
|
@ -1652,7 +1690,7 @@ version = "0.3.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "004cbc98f30fa233c61a38bc77e96a9106e65c88f2d3bef182ae952027e5753d"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"itoa 1.0.1",
|
||||
"libc",
|
||||
"num_threads",
|
||||
"time-macros",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "backend"
|
||||
version = "0.7.1"
|
||||
version = "1.0.1"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
@ -14,6 +14,8 @@ actix-web = "4.0.0-rc.1"
|
|||
actix-cors = "0.6.0"
|
||||
actix-governor = "0.3.0"
|
||||
|
||||
badge-maker = "0.2.1"
|
||||
|
||||
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "postgres", "chrono"] }
|
||||
|
||||
chrono = { version = "0.4.19", features = ["serde"] }
|
||||
|
|
|
@ -14,7 +14,7 @@ use config::Config;
|
|||
|
||||
use sqlx::{postgres::PgPoolOptions, PgPool};
|
||||
|
||||
use crate::routes::{get_paste, get_stats, new_paste};
|
||||
use crate::routes::{get_paste, get_stats, get_total_pastes_badge, get_version_badge, new_paste};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppState {
|
||||
|
@ -62,8 +62,12 @@ async fn main() -> io::Result<()> {
|
|||
web::scope("/p")
|
||||
.wrap(Governor::new(&paste_governor))
|
||||
.service(get_paste)
|
||||
.service(new_paste)
|
||||
// .service(get_raw_paste),
|
||||
.service(new_paste), // .service(get_raw_paste),
|
||||
)
|
||||
.service(
|
||||
web::scope("/b")
|
||||
.service(get_version_badge)
|
||||
.service(get_total_pastes_badge),
|
||||
)
|
||||
})
|
||||
.bind(address)?
|
||||
|
|
|
@ -4,8 +4,9 @@ use actix_web::{
|
|||
HttpResponse, Responder,
|
||||
};
|
||||
|
||||
use chrono::Duration;
|
||||
use badge_maker::{BadgeBuilder, Style};
|
||||
|
||||
use chrono::Duration;
|
||||
use nanoid::nanoid;
|
||||
use sqlx::{postgres::PgRow, types::chrono::Utc, Row};
|
||||
|
||||
|
@ -17,35 +18,7 @@ use crate::{
|
|||
AppState,
|
||||
};
|
||||
|
||||
#[get("/s")]
|
||||
pub async fn get_stats(state: web::Data<AppState>) -> impl Responder {
|
||||
let version = env!("CARGO_PKG_VERSION").to_string();
|
||||
// TODO: Maybe there's a less hacky way to do this..?
|
||||
let count: Result<i64, sqlx::Error> = sqlx::query(r#"SELECT COUNT(*) FROM pastes"#)
|
||||
.try_map(|row: PgRow| row.try_get::<i64, _>("count"))
|
||||
.fetch_one(&state.pool)
|
||||
.await;
|
||||
|
||||
if let Err(e) = count {
|
||||
eprintln!("Error occurred while retrieving paste count: {:?}", e);
|
||||
|
||||
return HttpResponse::InternalServerError().json(ApiResponse {
|
||||
success: false,
|
||||
data: ApiError {
|
||||
message: "Error occurred while retrieving paste count, please try again."
|
||||
.to_string(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
HttpResponse::Ok().json(ApiResponse {
|
||||
success: true,
|
||||
data: GetStatsResponse {
|
||||
count: count.unwrap(),
|
||||
version
|
||||
},
|
||||
})
|
||||
}
|
||||
// Pastes
|
||||
|
||||
#[get("/{id}")]
|
||||
pub async fn get_paste(state: web::Data<AppState>, id: web::Path<String>) -> impl Responder {
|
||||
|
@ -186,14 +159,11 @@ pub async fn new_paste(
|
|||
if state.config.logging.on_post_paste {
|
||||
println!("[POST] id={} length={}", id, content.len());
|
||||
}
|
||||
|
||||
HttpResponse::Ok().json(ApiResponse {
|
||||
success: true,
|
||||
data: NewPasteResponse {
|
||||
id,
|
||||
content,
|
||||
},
|
||||
})},
|
||||
success: true,
|
||||
data: NewPasteResponse { id, content },
|
||||
})
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error occurred while creating paste: {:?}", e);
|
||||
|
||||
|
@ -206,3 +176,86 @@ pub async fn new_paste(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stats
|
||||
|
||||
#[get("/s")]
|
||||
pub async fn get_stats(state: web::Data<AppState>) -> impl Responder {
|
||||
let version = env!("CARGO_PKG_VERSION").to_string();
|
||||
// TODO: Maybe there's a less hacky way to do this..?
|
||||
let count: Result<i64, sqlx::Error> = sqlx::query(r#"SELECT COUNT(*) FROM pastes"#)
|
||||
.try_map(|row: PgRow| row.try_get::<i64, _>("count"))
|
||||
.fetch_one(&state.pool)
|
||||
.await;
|
||||
|
||||
if let Err(e) = count {
|
||||
eprintln!("Error occurred while retrieving paste count: {:?}", e);
|
||||
|
||||
return HttpResponse::InternalServerError().json(ApiResponse {
|
||||
success: false,
|
||||
data: ApiError {
|
||||
message: "Error occurred while retrieving paste count, please try again."
|
||||
.to_string(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
HttpResponse::Ok().json(ApiResponse {
|
||||
success: true,
|
||||
data: GetStatsResponse {
|
||||
count: count.unwrap(),
|
||||
version,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Badges
|
||||
|
||||
#[get("/v")]
|
||||
pub async fn get_version_badge() -> impl Responder {
|
||||
let version = env!("CARGO_PKG_VERSION").to_string();
|
||||
|
||||
let badge = BadgeBuilder::new()
|
||||
.label("version")
|
||||
.message(&version)
|
||||
.color_parse("#31748f")
|
||||
.label_color_parse("#191724")
|
||||
.style(Style::FlatSquare)
|
||||
.build()
|
||||
.expect("Failed to build badge")
|
||||
.svg();
|
||||
|
||||
HttpResponse::Ok().content_type("image/svg+xml").body(badge)
|
||||
}
|
||||
|
||||
#[get("/t")]
|
||||
pub async fn get_total_pastes_badge(state: web::Data<AppState>) -> impl Responder {
|
||||
let count: Result<i64, sqlx::Error> = sqlx::query(r#"SELECT COUNT(*) FROM pastes"#)
|
||||
.try_map(|row: PgRow| row.try_get::<i64, _>("count"))
|
||||
.fetch_one(&state.pool)
|
||||
.await;
|
||||
|
||||
if let Err(e) = count {
|
||||
eprintln!("Error occurred while retrieving paste count: {:?}", e);
|
||||
|
||||
return HttpResponse::InternalServerError().json(ApiResponse {
|
||||
success: false,
|
||||
data: ApiError {
|
||||
message: "Error occurred while retrieving paste count, please try again."
|
||||
.to_string(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
let badge = BadgeBuilder::new()
|
||||
.label("total pastes")
|
||||
.message(&count.unwrap().to_string())
|
||||
.color_parse("#ebbcba")
|
||||
.label_color_parse("#191724")
|
||||
.style(Style::FlatSquare)
|
||||
.build()
|
||||
.expect("Failed to build badge")
|
||||
.svg();
|
||||
|
||||
HttpResponse::Ok().content_type("image/svg+xml").body(badge)
|
||||
}
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
# replace `example.tld` with your domain
|
||||
# replace `/location/of/zer0bin` with the location of the zer0bin folder
|
||||
# uncomment the `brotli on;` lines if you have the nginx brotoli plugin
|
||||
# uncomment the `ssl_certificate` lines if you have letsencrypt certs
|
||||
# comment out line 15 and uncomment line 16 if you have the nginx brotoli plugin
|
||||
# uncomment lines 51 and 52 if you have letsencrypt certs
|
||||
|
||||
server {
|
||||
#listen 80 is default
|
||||
server_name example.tld;
|
||||
return 301 https://example.tld$request_uri;
|
||||
# brotli on;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443;
|
||||
server_name example.tld;
|
||||
|
||||
gzip_static on;
|
||||
# brotli on;
|
||||
|
||||
root /location/of/zer0bin/frontend/dist;
|
||||
|
@ -21,10 +21,14 @@ server {
|
|||
|
||||
location / {
|
||||
index index.html;
|
||||
expires 30d;
|
||||
add_header Cache-Control "public, no-transform";
|
||||
}
|
||||
|
||||
location ~ \.(css|js|html) {
|
||||
try_files $uri =404;
|
||||
expires 30d;
|
||||
add_header Cache-Control "public, no-transform";
|
||||
}
|
||||
|
||||
location ^~ /.well-known/ {
|
||||
|
@ -37,11 +41,13 @@ server {
|
|||
proxy_pass http://localhost:8000/;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $host;
|
||||
add_header Last-Modified $date_gmt;
|
||||
add_header Cache-Control 'no-store, no-cache';
|
||||
if_modified_since off;
|
||||
expires off;
|
||||
etag off;
|
||||
}
|
||||
|
||||
expires 30d;
|
||||
add_header Cache-Control "public, no-transform";
|
||||
|
||||
# ssl_certificate /etc/letsencrypt/live/example.tld/fullchain.pem;
|
||||
# ssl_certificate_key /etc/letsencrypt/live/example.tld/privkey.pem;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
{
|
||||
"api_url": "https://example.tld/api"
|
||||
"api_url": "https://yourdomain.tld/api",
|
||||
"confetti_chance": "10"
|
||||
}
|
||||
|
|
|
@ -1,32 +1,30 @@
|
|||
{
|
||||
"name": "zer0bin",
|
||||
"source": "index.pug",
|
||||
"version": "0.7.1",
|
||||
"version": "1.0.1",
|
||||
"browserslist": "> 0.5%, last 2 versions, not dead",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "parcel index.pug",
|
||||
"build": "parcel build index.pug"
|
||||
"build": "parcel build index.pug --public-url /"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@parcel/compressor-brotli": "^2.3.2",
|
||||
"@parcel/compressor-gzip": "^2.3.2",
|
||||
"@parcel/config-default": "^2.3.2",
|
||||
"@parcel/transformer-pug": "2.3.2",
|
||||
"@parcel/transformer-sass": "^2.3.2",
|
||||
"@types/core-js": "^2.5.5",
|
||||
"@types/node": "^17.0.21",
|
||||
"parcel": "^2.3.2"
|
||||
"@types/node": "^17.0.21"
|
||||
},
|
||||
"description": "just a place to paste",
|
||||
"repository": "https://github.com/Domterion/zer0bin",
|
||||
"repository": "https://github.com/zer0bin-dev/zer0bin",
|
||||
"author": "Domterion, ThatOneCalculator",
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^4.7.0",
|
||||
"@ant-design/icons-svg": "^4.2.1",
|
||||
"@parcel/core": "^2.4.0",
|
||||
"@parcel/transformer-pug": "^2.4.0",
|
||||
"highlight.js": "^11.4.0",
|
||||
"js-confetti": "^0.10.2",
|
||||
"marked": "^4.0.12",
|
||||
"no-darkreader": "^1.0.1",
|
||||
"parcel": "^2.4.0",
|
||||
"smooth-scrollbar": "^8.7.4",
|
||||
"tippy.js": "^6.3.7"
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ githubButton.innerHTML += renderIconDefinitionToSVGElement(GithubOutlined, {
|
|||
|
||||
tippy("#save-button", {
|
||||
content: "Save paste<br><span class='keybind'>Ctrl + S</span>",
|
||||
placement: "bottom",
|
||||
animation: "scale",
|
||||
theme: "rosepine",
|
||||
allowHTML: true,
|
||||
|
@ -45,6 +46,7 @@ tippy("#save-button", {
|
|||
|
||||
tippy("#new-button", {
|
||||
content: "New paste<br><span class='keybind'>Ctrl + N</span>",
|
||||
placement: "bottom",
|
||||
animation: "scale",
|
||||
theme: "rosepine",
|
||||
allowHTML: true,
|
||||
|
@ -52,6 +54,7 @@ tippy("#new-button", {
|
|||
|
||||
tippy("#copy-button", {
|
||||
content: "Duplicate paste<br><span class='keybind'>Ctrl + D</span>",
|
||||
placement: "bottom",
|
||||
animation: "scale",
|
||||
theme: "rosepine",
|
||||
allowHTML: true,
|
||||
|
@ -66,7 +69,29 @@ tippy("#github-button", {
|
|||
})} ${renderIconDefinitionToSVGElement(HeartOutlined, {
|
||||
extraSVGAttrs: extraSVGAttrs,
|
||||
})}</span>`,
|
||||
placement: "bottom",
|
||||
animation: "scale",
|
||||
theme: "rosepine",
|
||||
allowHTML: true,
|
||||
})
|
||||
|
||||
const observer = new MutationObserver(callback)
|
||||
|
||||
function callback() {
|
||||
let theme = ""
|
||||
|
||||
if (window.location.pathname == "/") {
|
||||
theme = "rosepine"
|
||||
} else {
|
||||
theme = "rosepine-extended"
|
||||
}
|
||||
|
||||
document.querySelectorAll("button").forEach(function (btn) {
|
||||
//@ts-ignore
|
||||
btn._tippy.setProps({ theme: theme })
|
||||
})
|
||||
}
|
||||
|
||||
observer.observe(document.getElementById("code-view-pre"), {
|
||||
attributes: true,
|
||||
})
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import "no-darkreader"
|
||||
|
||||
import hljs from "highlight.js"
|
||||
import { marked } from "marked"
|
||||
import JSConfetti from "js-confetti"
|
||||
import Scrollbar from "smooth-scrollbar"
|
||||
|
||||
import config from "../config.json"
|
||||
const apiUrl = config.api_url
|
||||
const confettiChance = parseInt(config.confetti_chance)
|
||||
let rawContent = ""
|
||||
|
||||
const jsConfetti = new JSConfetti()
|
||||
|
@ -125,10 +127,18 @@ function addMessage(message: string) {
|
|||
|
||||
function viewPaste(content: string, views: string) {
|
||||
lineNumbers.innerHTML = ""
|
||||
for (let i = 1; i <= content.split("\n").length; i++) {
|
||||
lineNumbers.innerHTML = lineNumbers.innerHTML + `${i}<br>`
|
||||
if (
|
||||
content.startsWith("---") ||
|
||||
content.startsWith("md ") ||
|
||||
content.startsWith("md\n")
|
||||
) {
|
||||
codeView.innerHTML = marked.parse(content.substring(3))
|
||||
} else {
|
||||
for (let i = 1; i <= content.split("\n").length; i++) {
|
||||
lineNumbers.innerHTML = lineNumbers.innerHTML + `${i}<br>`
|
||||
}
|
||||
codeView.innerHTML = hljs.highlightAuto(content).value
|
||||
}
|
||||
codeView.innerHTML = hljs.highlightAuto(content).value
|
||||
|
||||
disable(saveButton)
|
||||
enable(newButton)
|
||||
|
@ -163,7 +173,7 @@ async function savePaste() {
|
|||
rawContent = res["data"]["content"]
|
||||
viewPaste(rawContent, "0")
|
||||
|
||||
const rand = Math.floor(Math.random() * 40)
|
||||
const rand = Math.floor(Math.random() * confettiChance * 6)
|
||||
|
||||
if (rand < 5) {
|
||||
jsConfetti.addConfetti({
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
@font-face {
|
||||
font-family: "Cartograph CF";
|
||||
src: url("../fonts/CartographCF-Regular.woff2") format("woff2"),
|
||||
url("../fonts/CartographCF-Regular.woff") format("woff"),
|
||||
url("../fonts/CartographCF-Regular.ttf") format("truetype");
|
||||
src: local("../fonts/CartographCF-Regular.woff2") format("woff2"),
|
||||
local("../fonts/CartographCF-Regular.woff") format("woff"),
|
||||
local("../fonts/CartographCF-Regular.ttf") format("truetype");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Cartograph CF";
|
||||
src: url("../fonts/CartographCF-RegularItalic.woff2") format("woff2"),
|
||||
url("../fonts/CartographCF-RegularItalic.woff") format("woff"),
|
||||
url("../fonts/CartographCF-RegularItalic.ttf") format("truetype");
|
||||
src: local("../fonts/CartographCF-RegularItalic.woff2") format("woff2"),
|
||||
local("../fonts/CartographCF-RegularItalic.woff") format("woff"),
|
||||
local("../fonts/CartographCF-RegularItalic.ttf") format("truetype");
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
|
|
|
@ -4,11 +4,11 @@ $font-mono: "Cartograph CF", ui-monospace, SFMono-Regular, Menlo, Monaco,
|
|||
Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
|
||||
@import "./font.scss";
|
||||
.tippy-box[data-theme~="rosepine"] {
|
||||
|
||||
.rosepine-parent {
|
||||
color: $text;
|
||||
background-color: $bg;
|
||||
opacity: 0.8;
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
font-family: $font-mono;
|
||||
> .tippy-backdrop {
|
||||
|
@ -18,3 +18,11 @@ $font-mono: "Cartograph CF", ui-monospace, SFMono-Regular, Menlo, Monaco,
|
|||
fill: $bg;
|
||||
}
|
||||
}
|
||||
.tippy-box[data-theme~="rosepine"] {
|
||||
@extend .rosepine-parent;
|
||||
margin-top: 0.3rem;
|
||||
}
|
||||
.tippy-box[data-theme~="rosepine-extended"] {
|
||||
@extend .rosepine-parent;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
|
1635
frontend/yarn.lock
1635
frontend/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue