Compare commits

...

109 Commits
v1.2 ... main

Author SHA1 Message Date
Leonid Maslakov 8b0c612326 Fix: Dockerfile
ci/woodpecker/push/test_docker Pipeline was successful Details
4 months ago
Leonid Maslakov d9f7264936 Update CHANGELOG.md 4 months ago
Pardesi_Cat b0241bdefd
Translated using Weblate (Bengali (India))
Currently translated at 100.0% (159 of 159 strings)

Translation: Lenpaste/Main
Translate-URL: https://translate.codeberg.org/projects/lenpaste/main/bn_IN/
4 months ago
Leonid Maslakov 84f5c5c943 Update docs 4 months ago
Leonid Maslakov f922dfa043
Translated using Weblate (Bengali (India))
Currently translated at 100.0% (159 of 159 strings)

Translation: Lenpaste/Main
Translate-URL: https://translate.codeberg.org/projects/lenpaste/main/bn_IN/
4 months ago
Leonid Maslakov 6228cd3ecf Translate theme names 4 months ago
Leonid Maslakov b5b9025bc3 Add X-Real-IP support
ci/woodpecker/push/test_golang Pipeline was successful Details
4 months ago
Leonid Maslakov 5037eac2e6 Add HTTP Server header
ci/woodpecker/push/test_golang Pipeline was successful Details
4 months ago
Leonid Maslakov 5a29c80d76 Fix: locale and theme complite percent
ci/woodpecker/push/test_golang Pipeline was successful Details
4 months ago
Leonid Maslakov a614bede39 Update docs 5 months ago
Leonid Maslakov 0e0a076008 Merge branch 'develop' of git.lcomrade.su:root/lenpaste into develop
ci/woodpecker/push/test_golang Pipeline was successful Details
5 months ago
Leonid Maslakov 7f4c1d9bff Add trace log to logger 5 months ago
Leonid Maslakov 707409f856
Translated using Weblate (Bengali (India))
Currently translated at 100.0% (159 of 159 strings)

Translation: Lenpaste/Main
Translate-URL: https://translate.codeberg.org/projects/lenpaste/main/bn_IN/
5 months ago
Pardesi_Cat a2e8776a39
Translated using Weblate (Bengali (India))
Currently translated at 100.0% (159 of 159 strings)

Translation: Lenpaste/Main
Translate-URL: https://translate.codeberg.org/projects/lenpaste/main/bn_IN/
5 months ago
Pardesi_Cat 67d0a172b0
Translated using Weblate (Bengali (India))
Currently translated at 100.0% (159 of 159 strings)

Translation: Lenpaste/Main
Translate-URL: https://translate.codeberg.org/projects/lenpaste/main/bn_IN/
5 months ago
Anonymous d139cdc0a5
Translated using Weblate (Bengali (India))
Currently translated at 100.0% (159 of 159 strings)

Translation: Lenpaste/Main
Translate-URL: https://translate.codeberg.org/projects/lenpaste/main/bn_IN/
5 months ago
Hiajen 1dfe3892e4
Translated using Weblate (German)
Currently translated at 100.0% (159 of 159 strings)

Translation: Lenpaste/Main
Translate-URL: https://translate.codeberg.org/projects/lenpaste/main/de/
5 months ago
Leonid Maslakov 8e54f405ad Add Hiajen as translator 5 months ago
Leonid Maslakov 3a9729e9a5
Translated using Weblate (Bengali (India))
Currently translated at 100.0% (159 of 159 strings)

Translation: Lenpaste/Main
Translate-URL: https://translate.codeberg.org/projects/lenpaste/main/bn_IN/
5 months ago
Leonid Maslakov a54180d464 Refactor API, RAW and WEB
ci/woodpecker/push/test_golang Pipeline was successful Details
5 months ago
Leonid Maslakov b19f86642b Fix
ci/woodpecker/push/test_golang Pipeline was successful Details
5 months ago
Leonid Maslakov a4c525c1d8 Merge branch 'develop' of git.lcomrade.su:root/lenpaste into develop
ci/woodpecker/push/test_golang Pipeline failed Details
5 months ago
Leonid Maslakov 3b66c1687e Update copyrights 5 months ago
Codeberg Translate e35042d1a1
Merge branch 'origin/develop' into Weblate. 5 months ago
Leonid Maslakov 17d68e4757
Translated using Weblate (Bengali (India))
Currently translated at 100.0% (159 of 159 strings)

Translation: Lenpaste/Main
Translate-URL: https://translate.codeberg.org/projects/lenpaste/main/bn_IN/
5 months ago
Leonid Maslakov 8519132e30 Fix: de.locale 5 months ago
Leonid Maslakov 736ab71b8d Merge branch 'develop' of git.lcomrade.su:root/lenpaste into develop 5 months ago
Leonid Maslakov 7bad4b83af Add custom style to summary 5 months ago
Pardesi_Cat 7c1a807796
Translated using Weblate (Bengali (India))
Currently translated at 100.0% (159 of 159 strings)

Translation: Lenpaste/Main
Translate-URL: https://translate.codeberg.org/projects/lenpaste/main/bn_IN/
5 months ago
mondstern a53a831484
Translated using Weblate (German)
Currently translated at 3.1% (5 of 159 strings)

Translation: Lenpaste/Main
Translate-URL: https://translate.codeberg.org/projects/lenpaste/main/de/
5 months ago
mondstern 6d45f0d0e6
Added translation using Weblate (German) 5 months ago
Leonid Maslakov cab3650f06
Translated using Weblate (Russian)
Currently translated at 100.0% (159 of 159 strings)

Translation: Lenpaste/Main
Translate-URL: https://translate.codeberg.org/projects/lenpaste/main/ru/
5 months ago
Leonid Maslakov fe4f584997 Fix: README 5 months ago
Leonid Maslakov d099a8eee7 Update README 5 months ago
Leonid Maslakov 819d536aca Update APIv1 docs 5 months ago
Leonid Maslakov c75911e25f Update README.md 5 months ago
Leonid Maslakov 7bccb34e1c Fix: locale 2 5 months ago
Leonid Maslakov 0d03099ce3 Fix: locale 5 months ago
Leonid Maslakov fb2ed20d35 Migrate locales to JSON format
ci/woodpecker/push/test_golang Pipeline was successful Details
5 months ago
Leonid Maslakov c679ef808e Rollback locale 5 months ago
Leonid Maslakov 6dfd4d067e Fix 5 months ago
Leonid Maslakov 753a2c5ace Fix locale format
ci/woodpecker/push/test_golang Pipeline was successful Details
5 months ago
Leonid Maslakov 7ef7a7659a Merge branch 'develop' of git.lcomrade.su:root/lenpaste into develop 5 months ago
Leonid Maslakov 37ec41b6b0 Give up Crowdin! 5 months ago
Translate [Bot] f141a3f2f2 [skip ci] Updated translations
ci/woodpecker/cron/crowdin_download Pipeline was successful Details
6 months ago
Translate [Bot] 41a7e18455 [skip ci] Updated translations
ci/woodpecker/cron/crowdin_download Pipeline was successful Details
6 months ago
Translate [Bot] 90bbd0e7d8 [skip ci] Updated translations
ci/woodpecker/cron/crowdin_download Pipeline was successful Details
6 months ago
Translate [Bot] a9204a09a8 [skip ci] Updated translations
ci/woodpecker/cron/crowdin_download Pipeline was successful Details
6 months ago
Leonid Maslakov a25ea41974 Fix: entrypoint.sh
ci/woodpecker/push/crowdin_download Pipeline was successful Details
ci/woodpecker/push/test_shell Pipeline was successful Details
ci/woodpecker/cron/crowdin_download Pipeline was successful Details
6 months ago
Leonid Maslakov 3fc8803728 Remove strange file
ci/woodpecker/push/crowdin_download Pipeline was successful Details
6 months ago
Leonid Maslakov 79ad723555 Add Pardesi_Cat as translator
ci/woodpecker/push/crowdin_download Pipeline was successful Details
ci/woodpecker/push/test_golang Pipeline was successful Details
ci/woodpecker/cron/crowdin_download Pipeline was successful Details
6 months ago
Translate [Bot] 466db797f3 [skip ci] Updated translations 6 months ago
Translate [Bot] 1a94855a17 [skip ci] Updated translations
ci/woodpecker/cron/crowdin_download Pipeline was successful Details
6 months ago
Leonid Maslakov e2ff6390f7 Fix: Crowdin download pipeline
ci/woodpecker/push/crowdin_download Pipeline was successful Details
ci/woodpecker/push/test_shell Pipeline was successful Details
ci/woodpecker/cron/crowdin_download Pipeline was successful Details
6 months ago
Leonid Maslakov d980603769 Fast docs fix
ci/woodpecker/push/crowdin_download Pipeline was successful Details
ci/woodpecker/cron/crowdin_download Pipeline was successful Details
6 months ago
Leonid Maslakov 5e2e38f904 Update docs
ci/woodpecker/push/crowdin_download Pipeline was successful Details
ci/woodpecker/push/test_golang Pipeline was successful Details
6 months ago
Leonid Maslakov aa374ee297 Apply get rate limit to emb_help, emb, raw and dl
ci/woodpecker/push/crowdin_download Pipeline was successful Details
ci/woodpecker/push/test_golang Pipeline was successful Details
ci/woodpecker/cron/crowdin_download Pipeline was successful Details
6 months ago
Leonid Maslakov da7d6d44fe Add rate limit to paste get. Fix: ratelimits
ci/woodpecker/push/crowdin_download Pipeline was successful Details
ci/woodpecker/push/test_golang Pipeline was successful Details
6 months ago
Leonid Maslakov ea6a9866aa Fix: entrypoint.sh POSIX style
ci/woodpecker/push/crowdin_download Pipeline was successful Details
ci/woodpecker/push/test_shell Pipeline was successful Details
6 months ago
Leonid Maslakov cdd784b3a8 Add shell check pipline
ci/woodpecker/push/crowdin_download Pipeline was successful Details
ci/woodpecker/push/test_shell Pipeline failed Details
6 months ago
Leonid Maslakov f9f4126d0e Add 15 min and 1 hour ratelimit
ci/woodpecker/push/crowdin_download Pipeline was successful Details
ci/woodpecker/push/crowdin_upload Pipeline was successful Details
ci/woodpecker/push/test_golang Pipeline was successful Details
6 months ago
Leonid Maslakov b6a3f10766 Fix 3
ci/woodpecker/push/crowdin_download Pipeline was successful Details
ci/woodpecker/cron/crowdin_download Pipeline was successful Details
6 months ago
Leonid Maslakov 4b1cd8914d Fix 2
ci/woodpecker/push/crowdin_download Pipeline was successful Details
6 months ago
Leonid Maslakov 6fe99cb93a Fix
ci/woodpecker/cron/crowdin_download Pipeline was successful Details
6 months ago
Leonid Maslakov 1b35c936d1 Fix: Woodpecker CI crone
ci/woodpecker/cron/crowdin_download Pipeline was successful Details
6 months ago
Leonid Maslakov 4648a35fa5 Fix: Go testing CI
ci/woodpecker/push/test_golang Pipeline was successful Details
ci/woodpecker/cron/crowdin_download Pipeline was successful Details
6 months ago
Leonid Maslakov 368a87a065 Allow load external themes 6 months ago
Leonid Maslakov 28e4f8e868 Fix Dockerfile
ci/woodpecker/push/test_docker Pipeline was successful Details
6 months ago
Leonid Maslakov a2728e00ea Fix: Docker test CI
ci/woodpecker/push/test_docker Pipeline failed Details
6 months ago
Leonid Maslakov d82acefa61 Update CI
ci/woodpecker/push/crowdin_upload Pipeline was successful Details
ci/woodpecker/push/test Pipeline was successful Details
ci/woodpecker/push/test_docker Pipeline failed Details
6 months ago
Leonid Maslakov 6c129c0efe Add Docker test Ci
ci/woodpecker/push/crowdin Pipeline was successful Details
ci/woodpecker/push/test_docker Pipeline was successful Details
6 months ago
Leonid Maslakov 74d533438c Fix: history scroll
ci/woodpecker/push/crowdin Pipeline was successful Details
6 months ago
Leonid Maslakov 8793be1773 Update README
ci/woodpecker/push/crowdin Pipeline was successful Details
ci/woodpecker/cron/crowdin Pipeline was successful Details
6 months ago
Leonid Maslakov 23ad8a853a Update piplines
ci/woodpecker/push/crowdin Pipeline was successful Details
ci/woodpecker/push/test Pipeline was successful Details
ci/woodpecker/cron/crowdin Pipeline was successful Details
6 months ago
Leonid Maslakov e6ff08caf3 Fix: docs_api_libs.tmpl
ci/woodpecker/push/crowdin Pipeline was successful Details
ci/woodpecker/push/test Pipeline was successful Details
ci/woodpecker/cron/crowdin Pipeline was successful Details
ci/woodpecker/cron/test Pipeline was successful Details
6 months ago
Leonid Maslakov c19ee48155 Add CI Go test
ci/woodpecker/push/crowdin Pipeline was successful Details
ci/woodpecker/push/test Pipeline was successful Details
6 months ago
Leonid Maslakov ca36af0da7 Setup CI cron
ci/woodpecker/push/crowdin Pipeline was successful Details
ci/woodpecker/cron/crowdin Pipeline was successful Details
6 months ago
Leonid Maslakov 33aa50b4ae Fix CI 2
ci/woodpecker/push/crowdin Pipeline was successful Details
6 months ago
Leonid Maslakov 98684a56ad Fix CI
ci/woodpecker/push/crowdin Pipeline failed Details
6 months ago
Leonid Maslakov 6832dbb44a Add Woodpecker pipline 6 months ago
Leonid Maslakov 7e7ff98391 Update locale
continuous-integration/drone/push Build is failing Details
6 months ago
Leonid Maslakov 0b1df8b2f8 Try fix CI pipline
continuous-integration/drone/push Build is failing Details
6 months ago
Leonid Maslakov 9b620dcca6 Setup Drone CI
continuous-integration/drone/push Build is failing Details
6 months ago
Leonid Maslakov 1ee93c2e07 Add server default theme change support 6 months ago
Leonid Maslakov 2a2fd8f7d1 Add theme localization 6 months ago
Leonid Maslakov de5f54fe98 Small style fix 6 months ago
Leonid Maslakov 8e9909bfea Fix: web Content-Type 6 months ago
Leonid Maslakov 92e9ba6574 Fix: author params max length in settings 6 months ago
Leonid Maslakov 926c1267f8 Fix: translate 6 months ago
Leonid Maslakov 4b8f9aed01 Extend theme params 6 months ago
Leonid Maslakov caaa89855e Add chrome theme change support 6 months ago
Leonid Maslakov e597b3fa8e Add light theme 6 months ago
Leonid Maslakov 64fea0e67f Migrate to theme engine 6 months ago
Leonid Maslakov 2a410ab1ef Start work on theme support 6 months ago
Leonid Maslakov 4b2cf81b23 Add translate percentage display 6 months ago
Leonid Maslakov c6da499294 Fix: locale 6 months ago
Leonid Maslakov fd271fd419 Update locale files format 6 months ago
Leonid Maslakov c12d9a4f4f Fix: ratelimit ip store 6 months ago
Leonid Maslakov db9b9065ab Fix: ratelimits 6 months ago
Leonid Maslakov 333d27e269 Fix 7 months ago
Leonid Maslakov de4d1475b8 Style: customize checkbox 7 months ago
Leonid Maslakov 0a7fa188b6 Small CSS fix 7 months ago
Leonid Maslakov 06e99ccf49 Fix: history.js on Safari IOS 7-10 7 months ago
Leonid Maslakov 4af55ff3d6 Optimize memory usage 7 months ago
Leonid Maslakov ac549ce81b Fix: go vet errors 7 months ago
Leonid Maslakov 0868e0d7a7 Switch to DB pool. Fix: errors output. 7 months ago
Leonid Maslakov 12800c5ffb Update deps 7 months ago
Leonid Maslakov 1c4fe2136d Start fixing ratelimit + revers proxy error 7 months ago
Leonid Maslakov bec7ac0c85 Fix: main.tmpl 7 months ago

@ -0,0 +1,12 @@
when:
event: [push, pull_request]
branch: develop
path: ["Dockerfile", ".woodpecker/test_docker.yml"]
pipeline:
check:
image: hadolint/hadolint:latest-alpine
pull: true
commands:
- hadolint --version
- hadolint Dockerfile

@ -0,0 +1,20 @@
when:
event: [push, pull_request]
branch: develop
path: ["**/*.go", ".woodpecker/test_golang.yml"]
matrix:
GO_VERSION:
- 1.16
- 1.17
- 1.18
- 1.19
pipeline:
build:
image: golang:${GO_VERSION}
pull: true
commands:
- go mod download
- go test ./...
- go vet ./...

@ -0,0 +1,12 @@
when:
event: [push, pull_request]
branch: develop
path: ["**/*.sh", ".woodpecker/test_shell.yml"]
pipeline:
check:
image: koalaman/shellcheck-alpine
pull: true
commands:
- shellcheck --version
- shellcheck $(find ./ -type f -name '*.sh')

@ -2,6 +2,15 @@
Semantic versioning is used (https://semver.org/).
## v1.3
- UI: Added custom themes support. Added light theme.
- UI: Added translations into Bengali and German (thanks Pardesi_Cat and Hiajen).
- UI: Check boxes and spoilers now have a custom design.
- Admin: Added support for `X-Real-IP` header for reverse proxy.
- Admin: Added Server response header (for example: `Lenpaste/1.3`).
- Fix: many bugs and errors.
- Dev: Improved quality of `Dockerfile` and `entrypoint.sh`
## v1.2
- UI: Add history tab.
- UI: Add copy to clipboard button.

@ -1,9 +1,9 @@
# BUILD
FROM golang:1.18.7-alpine as build
FROM golang:1.18.10-alpine3.17 as build
WORKDIR /build
RUN apk update && apk upgrade && apk add --no-cache make git gcc musl-dev
RUN apk add --no-cache make=4.3-r1 git=2.38.3-r1 gcc=12.2.1_git20220924-r4 musl-dev=1.2.3-r4
COPY ./go.mod ./
COPY go.sum ./
@ -15,7 +15,7 @@ RUN make
# RUN
FROM alpine:latest as run
FROM alpine:3.17.1 as run
WORKDIR /

@ -3,6 +3,7 @@
## Features
- No need to register
- Supports multiple languages
- Uses cookies only to store settings
- Can work without JavaScript
- Has its own API
@ -16,7 +17,7 @@
| [paste.lcomrade.su](https://paste.lcomrade.su) | Server managed by the Lenpaste developer. |
| [code.dbt3ch.com](https://code.dbt3ch.com) | Server is managed by DB Tech. He made a [video about Lenpaste v1.1](https://www.youtube.com/watch?v=YxcHxsZHh9A). |
| [notepad.co.il](https://notepad.co.il) | Server managed by Shlomi Porush. He reported the bug and made some suggestions. |
| [lenp.pardesicat.xyz](https://lenp.pardesicat.xyz) | Server managed by Pardesi_Cat. He helped correct the documentation. |
| [lenp.pardesicat.xyz](https://lenp.pardesicat.xyz) | Server managed by Pardesi_Cat. He translated Lenpaste into Bengali and helped correct the documentation. |
Find more public servers here or add your own: https://monitor.lcomrade.su/?srv=lenpaste
@ -25,7 +26,7 @@ Find more public servers here or add your own: https://monitor.lcomrade.su/?srv=
## Launch your own server
1. If you don't already have Docker installed, do so:
```
apt-get install -y docker docker.io docker-compose
apt-get install -y docker.io docker-compose
```
2. Use a file like this `docker-compose.yml`:
@ -40,23 +41,46 @@ services:
restart: always
environment:
# All parameters are optional
#
# HTTP server
- LENPASTE_ADDRESS=:80 # ADDRES:PORT for HTTP server.
#
# Database settings
- LENPASTE_DB_DRIVER=sqlite3 # Currently supported drivers: 'sqlite3' and 'postgres'.
- LENPASTE_DB_SOURCE=/data/lenpaste.db # DB source.
- LENPASTE_DB_MAX_OPEN_CONNS=25 # Maximum number of connections to the database.
- LENPASTE_DB_MAX_IDLE_CONNS=5 # Maximum number of idle connections to the database.
- LENPASTE_DB_CLEANUP_PERIOD=3h # Interval at which the DB is cleared of expired but not yet deleted pastes.
#
# Search engines
- LENPASTE_ROBOTS_DISALLOW=false # Prohibits search engine crawlers from indexing site using robots.txt file.
#
# Storage limits
- LENPASTE_TITLE_MAX_LENGTH=100 # Maximum length of the paste title. If 0 disable title, if -1 disable length limit.
- LENPASTE_BODY_MAX_LENGTH=20000 # Maximum length of the paste body. If -1 disable length limit. Can't be -1.
- LENPASTE_MAX_PASTE_LIFETIME=unlimited # Maximum lifetime of the paste. Examples: 10m, 1h 30m, 12h, 7w, 30d, 365d.
- LENPASTE_NEW_PASTES_PER_5MIN=15 # Maximum number of paste that can be created in 5 minutes from one IP. If 0 disable rate-limit.
#
# Rate limits
- LENPASTE_GET_PASTES_PER_5MIN=50 # Maximum number of pastes that can be VIEWED in 5 minutes from one IP. If 0 disable rate-limit.
- LENPASTE_GET_PASTES_PER_15MIN=100 # Maximum number of pastes that can be VIEWED in 15 minutes from one IP. If 0 disable rate-limit.
- LENPASTE_GET_PASTES_PER_1HOUR=500 # Maximum number of pastes that can be VIEWED in 1 hour from one IP. If 0 disable rate-limit.
- LENPASTE_NEW_PASTES_PER_5MIN=15 # Maximum number of pastes that can be CREATED in 5 minutes from one IP. If 0 disable rate-limit.
- LENPASTE_NEW_PASTES_PER_15MIN=30 # Maximum number of pastes that can be CREATED in 15 minutes from one IP. If 0 disable rate-limit.
- LENPASTE_NEW_PASTES_PER_1HOUR=40 # Maximum number of pastes that can be CREATED in 1 hour from one IP. If 0 disable rate-limit.
#
# Information about server admin
- LENPASTE_ADMIN_NAME= # Name of the administrator of this server.
- LENPASTE_ADMIN_MAIL= # Email of the administrator of this server.
#
# WEB interface settings
- LENPASTE_UI_DEFAULT_LIFETIME= # Lifetime of paste will be set by default in WEB interface. Examples: 10min, 1h, 1d, 2w, 6mon, 1y.
- LENPASTE_UI_DEFAULT_THEME=dark # Sets the default theme for the WEB interface. Examples: dark, light.
volumes:
# /data/lenpaste.db - SQLite DB if used.
# /data/about - About this server (TXT file).
# /data/rules - This server rules (TXT file).
# /data/terms - This server "terms of use" (TXT file).
# /data/themes/* - External WEB interface themes.
# /data/lenpasswd - If this file exists, the server will ask for auth to create new pastes.
# File format: USER:PLAIN_PASSWORD on each line.
- "${PWD}/data:/data"
@ -82,6 +106,7 @@ sudo apt update
sudo apt -y install git make gcc golang
git clone https://git.lcomrade.su/root/lenpaste.git
cd ./lenpaste/
git checkout vX.X
make
```
@ -98,7 +123,7 @@ So you can build your own image to run on an officially unsupported architecture
On Debian/Ubuntu:
```
sudo apt update
sudo apt -y install git docker docker.io
sudo apt -y install git docker.io
git clone https://git.lcomrade.su/root/lenpaste.git
cd ./lenpaste/
git checkout vX.X
@ -112,7 +137,6 @@ You can use it in `docker-compose.yml` or copy it to another machine.
## Other documentation
For all:
- [Roadmap for new release](ROADMAP.md)
- [Frequently Asked Questions](FAQ.md)
For instance administrators:
@ -121,27 +145,40 @@ For instance administrators:
- [Rate limiting](docs/ratelimits.md)
- [Add Lenpaste to Search Engines](docs/search_engines.md)
- [Make Lenpaste server private](docs/private_server.md)
- [Themes for WEB interface](docs/themes.md)
For contributors:
- [Translate on Codeberg Weblate](https://translate.codeberg.org/projects/lenpaste/)
- [Themes for WEB interface](docs/themes.md)
For developers:
Lenpaste API:
- [Lenpaste API](https://paste.lcomrade.su/docs/apiv1)
- [Libraries for working with API](https://paste.lcomrade.su/docs/api_libs)
## Might be interesting
Manuals:
Might be interesting:
- [How to Install LenPaste on Your Synology NAS](https://mariushosting.com/how-to-install-lenpaste-on-your-synology-nas/) (WEB site)
- [Lenpaste | TrueCharts](https://truecharts.org/docs/charts/incubator/lenpaste/) (WEB site)
Reviews:
- [Pastebin Clone in Docker with Lenpaste](https://www.youtube.com/watch?v=YxcHxsZHh9A) (YouTube video)
## Bugs and Suggestion
If you have any questions or suggestions, you can write here:
- Join to Matrix room: [`#lenpaste:lcomrade.su`](https://matrix.to/#/#lenpaste:lcomrade.su)
- Contact me: Leonid Maslakov <root@lcomrade.su>
## Contribute
What can I do?
- Translate Lenpaste to you Language: [Codeberg Weblate/Lenpaste](https://translate.codeberg.org/projects/lenpaste/)
- Write an article (DevTo, Medium, your website, and so on) or make a video (YouTube, PeerTube, and so on).
A link to your article/video will be included in this README.
- Create or update a package:
- Create NixOS package.
- Update TrueCharts package.
- Other.
- Install the Lenpaste server and add it to [Lenmonitor](https://monitor.lcomrade.su/).
- Recommend Lenpaste to your friends.
## Contacts
- Matrix room: [`#lenpaste:lcomrade.su`](https://matrix.to/#/#lenpaste:lcomrade.su)
- Contact me: Leonid Maslakov \<root@lcomrade.su\>

@ -1,4 +1,4 @@
// Copyright (C) 2021-2022 Leonid Maslakov.
// Copyright (C) 2021-2023 Leonid Maslakov.
// This file is part of Lenpaste.
@ -21,6 +21,7 @@ package main
import (
"errors"
"flag"
"fmt"
"git.lcomrade.su/root/lenpaste/internal/apiv1"
"git.lcomrade.su/root/lenpaste/internal/config"
"git.lcomrade.su/root/lenpaste/internal/logger"
@ -38,7 +39,7 @@ import (
var Version = "unknown"
func backgroundJob(cleanJobPeriod time.Duration, db storage.DB, log logger.Config) {
func backgroundJob(cleanJobPeriod time.Duration, db storage.DB, log logger.Logger) {
for {
// Delete expired pastes
count, err := db.PasteDeleteExpired()
@ -72,7 +73,7 @@ func readFile(path string) (string, error) {
}
func exitOnError(e error) {
println("error:", e.Error())
fmt.Fprintln(os.Stderr, "error:", e.Error())
os.Exit(1)
}
@ -80,21 +81,39 @@ func printHelp(noErrors bool) {
println("Usage:", os.Args[0], "[-db-source] [OPTION]...")
println("")
println(" -address ADDRESS:PORT (default: :80)")
println()
println(" -db-driver Currently supported drivers: 'sqlite3' and 'postgres' (default: sqlite3)")
println(" -db-source DB source.")
println(" -db-max-open-conns Maximum number of connections to the database. (default: 25)")
println(" -db-max-idle-conns Maximum number of idle connections to the database. (default: 5)")
println(" -db-cleanup-period Interval at which the DB is cleared of expired but not yet deleted pastes. (default: 3h)")
println()
println(" -robots-disallow Prohibits search engine crawlers from indexing site using robots.txt file.")
println()
println(" -title-max-length Maximum length of the paste title. If 0 disable title, if -1 disable length limit. (default: 100)")
println(" -body-max-length Maximum length of the paste body. If -1 disable length limit. Can't be -1. (default: 20000)")
println(" -max-paste-lifetime Maximum lifetime of the paste. Examples: 10m, 1h 30m, 12h, 1w, 30d, 365d. (default: unlimited)")
println(" -new-pastes-per-5min Maximum number of paste that can be created in 5 minutes from one IP. If 0 disable rate-limit. (default: 15)")
println()
println(" -get-pastes-per-5min Maximum number of pastes that can be VIEWED in 5 minutes from one IP. If 0 disable rate-limit. (default: 50)")
println(" -get-pastes-per-15min Maximum number of pastes that can be VIEWED in 15 minutes from one IP. If 0 disable rate-limit. (default: 100)")
println(" -get-pastes-per-1hour Maximum number of pastes that can be VIEWED in 1 hour from one IP. If 0 disable rate-limit. (default: 500)")
println(" -new-pastes-per-5min Maximum number of pastes that can be CREATED in 5 minutes from one IP. If 0 disable rate-limit. (default: 15)")
println(" -new-pastes-per-15min Maximum number of pastes that can be CREATED in 15 minutes from one IP. If 0 disable rate-limit. (default: 30)")
println(" -new-pastes-per-1hour Maximum number of pastes that can be CREATED in 1 hour from one IP. If 0 disable rate-limit. (default: 40)")
println()
println(" -server-about Path to the TXT file that contains the server description.")
println(" -server-rules Path to the TXT file that contains the server rules.")
println(" -server-terms Path to the TXT file that contains the server terms of use.")
println()
println(" -admin-name Name of the administrator of this server.")
println(" -admin-mail Email of the administrator of this server.")
println()
println(" -ui-default-lifetime Lifetime of paste will be set by default in WEB interface. Examples: 10min, 1h, 1d, 2w, 6mon, 1y.")
println(" -ui-default-theme Sets the default theme for the WEB interface. Examples: dark, light, my_theme. (default: dark)")
println(" -ui-themes-dir Loads external WEB interface themes from directory.")
println()
println(" -lenpasswd-file File in LenPasswd format. If set, authorization will be required to create pastes.")
println()
println(" -version Display version and exit.")
println(" -help Display this help and exit.")
println()
@ -175,21 +194,39 @@ func main() {
flag.Usage = func() { printHelp(false) }
flagAddress := flag.String("address", ":80", "")
flagDbDriver := flag.String("db-driver", "sqlite3", "")
flagDbSource := flag.String("db-source", "", "")
flagDbMaxOpenConns := flag.Int("db-max-open-conns", 25, "")
flagDbMaxIdleConns := flag.Int("db-max-idle-conns", 5, "")
flagDbCleanupPeriod := flag.String("db-cleanup-period", "3h", "")
flagRobotsDisallow := flag.Bool("robots-disallow", false, "")
flagTitleMaxLen := flag.Int("title-max-length", 100, "")
flagBodyMaxLen := flag.Int("body-max-length", 20000, "")
flagMaxLifetime := flag.String("max-paste-lifetime", "unlimited", "")
flagNewPastesPer5Min := flag.Int("new-pastes-per-5min", 15, "")
flagGetPastesPer5Min := flag.Uint("get-pastes-per-5min", 50, "")
flagGetPastesPer15Min := flag.Uint("get-pastes-per-15min", 100, "")
flagGetPastesPer1Hour := flag.Uint("get-pastes-per-1hour", 500, "")
flagNewPastesPer5Min := flag.Uint("new-pastes-per-5min", 15, "")
flagNewPastesPer15Min := flag.Uint("new-pastes-per-15min", 30, "")
flagNewPastesPer1Hour := flag.Uint("new-pastes-per-1hour", 40, "")
flagServerAbout := flag.String("server-about", "", "")
flagServerRules := flag.String("server-rules", "", "")
flagServerTerms := flag.String("server-terms", "", "")
flagAdminName := flag.String("admin-name", "", "")
flagAdminMail := flag.String("admin-mail", "", "")
flagUiDefaultLifetime := flag.String("ui-default-lifetime", "", "")
flagUiDefaultTheme := flag.String("ui-default-theme", "dark", "")
flagUiThemesDir := flag.String("ui-themes-dir", "", "")
flagLenPasswdFile := flag.String("lenpasswd-file", "", "")
flagVersion := flag.Bool("version", false, "")
flagHelp := flag.Bool("help", false, "")
@ -270,19 +307,17 @@ func main() {
}
// Settings
db := storage.DB{
DriverName: *flagDbDriver,
DataSourceName: *flagDbSource,
}
log := logger.New("2006/01/02 15:04:05")
log := logger.Config{
TimeFormat: "2006/01/02 15:04:05",
db, err := storage.NewPool(*flagDbDriver, *flagDbSource, *flagDbMaxOpenConns, *flagDbMaxIdleConns)
if err != nil {
exitOnError(err)
}
cfg := config.Config{
DB: db,
Log: log,
RateLimit: netshare.NewRateLimit(*flagNewPastesPer5Min),
RateLimitGet: netshare.NewRateLimitSystem(*flagGetPastesPer5Min, *flagGetPastesPer15Min, *flagGetPastesPer1Hour),
RateLimitNew: netshare.NewRateLimitSystem(*flagNewPastesPer5Min, *flagNewPastesPer15Min, *flagNewPastesPer1Hour),
Version: Version,
TitleMaxLen: *flagTitleMaxLen,
BodyMaxLen: *flagBodyMaxLen,
@ -294,109 +329,36 @@ func main() {
AdminMail: *flagAdminMail,
RobotsDisallow: *flagRobotsDisallow,
UiDefaultLifetime: *flagUiDefaultLifetime,
UiDefaultTheme: *flagUiDefaultTheme,
UiThemesDir: *flagUiThemesDir,
LenPasswdFile: *flagLenPasswdFile,
}
apiv1Data := apiv1.Load(cfg)
apiv1Data := apiv1.Load(db, cfg)
rawData := raw.Load(cfg)
rawData := raw.Load(db, cfg)
// Init data base
err = db.InitDB()
err = storage.InitDB(*flagDbDriver, *flagDbSource)
if err != nil {
exitOnError(err)
}
// Load pages
webData, err := web.Load(cfg)
webData, err := web.Load(db, cfg)
if err != nil {
exitOnError(err)
}
// Handlers
http.HandleFunc("/robots.txt", func(rw http.ResponseWriter, req *http.Request) {
webData.RobotsTxtHand(rw, req)
})
if *flagRobotsDisallow == false {
http.HandleFunc("/sitemap.xml", func(rw http.ResponseWriter, req *http.Request) {
webData.SitemapHand(rw, req)
})
}
http.HandleFunc("/style.css", func(rw http.ResponseWriter, req *http.Request) {
webData.StyleCSSHand(rw, req)
})
http.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) {
webData.MainHand(rw, req)
})
http.HandleFunc("/main.js", func(rw http.ResponseWriter, req *http.Request) {
webData.MainJSHand(rw, req)
})
http.HandleFunc("/history.js", func(rw http.ResponseWriter, req *http.Request) {
webData.HistoryJSHand(rw, req)
})
http.HandleFunc("/code.js", func(rw http.ResponseWriter, req *http.Request) {
webData.CodeJSHand(rw, req)
})
http.HandleFunc("/paste.js", func(rw http.ResponseWriter, req *http.Request) {
webData.PasteJSHand(rw, req)
})
http.HandleFunc("/settings", func(rw http.ResponseWriter, req *http.Request) {
webData.SettingsHand(rw, req)
webData.Handler(rw, req)
})
http.HandleFunc("/terms", func(rw http.ResponseWriter, req *http.Request) {
webData.TermsOfUseHand(rw, req)
})
http.HandleFunc("/raw/", func(rw http.ResponseWriter, req *http.Request) {
rawData.RawHand(rw, req)
})
http.HandleFunc("/dl/", func(rw http.ResponseWriter, req *http.Request) {
webData.DlHand(rw, req)
rawData.Hand(rw, req)
})
http.HandleFunc("/emb/", func(rw http.ResponseWriter, req *http.Request) {
webData.EmbeddedHand(rw, req)
})
http.HandleFunc("/emb_help/", func(rw http.ResponseWriter, req *http.Request) {
webData.EmbeddedHelpHand(rw, req)
})
http.HandleFunc("/about", func(rw http.ResponseWriter, req *http.Request) {
webData.AboutHand(rw, req)
})
http.HandleFunc("/about/authors", func(rw http.ResponseWriter, req *http.Request) {
webData.AuthorsHand(rw, req)
})
http.HandleFunc("/about/license", func(rw http.ResponseWriter, req *http.Request) {
webData.LicenseHand(rw, req)
})
http.HandleFunc("/about/source_code", func(rw http.ResponseWriter, req *http.Request) {
webData.SourceCodePageHand(rw, req)
})
http.HandleFunc("/docs", func(rw http.ResponseWriter, req *http.Request) {
webData.DocsHand(rw, req)
})
http.HandleFunc("/docs/apiv1", func(rw http.ResponseWriter, req *http.Request) {
webData.DocsApiV1Hand(rw, req)
})
http.HandleFunc("/docs/api_libs", func(rw http.ResponseWriter, req *http.Request) {
webData.DocsApiLibsHand(rw, req)
})
http.HandleFunc("/api/", func(rw http.ResponseWriter, req *http.Request) {
apiv1Data.MainHand(rw, req)
})
http.HandleFunc("/api/v1/new", func(rw http.ResponseWriter, req *http.Request) {
apiv1Data.NewHand(rw, req)
})
http.HandleFunc("/api/v1/get", func(rw http.ResponseWriter, req *http.Request) {
apiv1Data.GetHand(rw, req)
})
http.HandleFunc("/api/v1/getServerInfo", func(rw http.ResponseWriter, req *http.Request) {
apiv1Data.GetServerInfoHand(rw, req)
apiv1Data.Hand(rw, req)
})
// Run background job

@ -6,6 +6,11 @@ The default settings are optimal.
Each individual IP address has its own rate limit.
Also the rate limits of different actions do not depend on each other.
| Acts on | Measured in | Default | Docker variable | CLI flag |
|---------------------|--------------------------|---------|--------------------------------|------------------------|
| New paste creation. | New pastes per 5 minute. | `15` | `LENPASTE_NEW_PASTES_PER_5MIN` | `-new-pastes-per-5min` |
| Acts on | Measured in | Default | Docker variable | CLI flag |
|---------------------|---------------------------|---------|---------------------------------|-------------------------|
| New paste creation. | New pastes per 5 minute. | `15` | `LENPASTE_NEW_PASTES_PER_5MIN` | `-new-pastes-per-5min` |
| New paste creation. | New pastes per 15 minute. | `15` | `LENPASTE_NEW_PASTES_PER_15MIN` | `-new-pastes-per-15min` |
| New paste creation. | New pastes per 1 hour. | `40` | `LENPASTE_NEW_PASTES_PER_1HOUR` | `-new-pastes-per-1hour` |
| Paste page get. | Get pastes per 5 minute. | `50` | `LENPASTE_GET_PASTES_PER_5MIN` | `-get-pastes-per-5min` |
| Paste page get. | Get pastes per 15 minute. | `100` | `LENPASTE_GET_PASTES_PER_15MIN` | `-get-pastes-per-15min` |
| Paste page get. | Get pastes per 1 hour. | `500` | `LENPASTE_GET_PASTES_PER_1HOUR` | `-get-pastes-per-1hour` |

@ -18,6 +18,8 @@ http {
# Required for Lenpaste to work correctly.
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}

@ -0,0 +1,24 @@
# Themes for WEB interface
## Introduction
Lenpaste has two built-in themes: dart and light.
You can switch between the themes in the settings.
You can also add your own themes by placing them in the `/data/themes/` directory in Docker.
If you work with bare metal, specify the path to the themes folder using the `-ui-themes-dir` flag.
## Specife default server theme
You can also specify the default theme with the `LENPASTE_UI_DEFAULT_THEME` variable in Docker.
Or the `-ui-default-theme` flag for bare metal.
The value of this parameter must match the name of the theme file without an extension.
For example: `dark`, `light`, `my_theme`.
## Create custom theme
Use one of the themes from the `./internal/web/data/theme/` directory as a base.
The extension `.theme` in the file name is mandatory.
If you miss a theme parameter, it will be replaced by the default one.

@ -5,19 +5,19 @@ RUN_CMD="lenpaste"
# LENPASTE_ADDRESS
if [[ -n "$LENPASTE_ADDRESS" ]]; then
if [ -n "$LENPASTE_ADDRESS" ]; then
RUN_CMD="$RUN_CMD -address $LENPASTE_ADDRESS"
fi
# LENPASTE_DB_DRIVER
if [[ -n "$LENPASTE_DB_DRIVER" ]]; then
if [ -n "$LENPASTE_DB_DRIVER" ]; then
RUN_CMD="$RUN_CMD -db-driver '$LENPASTE_DB_DRIVER'"
fi
# LENPASTE_DB_SOURCE
if [[ -z "$LENPASTE_DB_DRIVER" || "$LENPASTE_DB_DRIVER" == "sqlite3" ]]; then
if [ -z "$LENPASTE_DB_DRIVER" ] || [ "$LENPASTE_DB_DRIVER" = "sqlite3" ]; then
RUN_CMD="$RUN_CMD -db-source /data/lenpaste.db"
else
@ -25,17 +25,29 @@ else
fi
# LENPASTE_DB_MAX_OPEN_CONNS
if [ -n "$LENPASTE_DB_MAX_OPEN_CONNS" ]; then
RUN_CMD="$RUN_CMD -db-max-open-conns '$LENPASTE_DB_MAX_OPEN_CONNS'"
fi
# LENPASTE_DB_MAX_IDLE_CONNS
if [ -n "$LENPASTE_DB_MAX_IDLE_CONNS" ]; then
RUN_CMD="$RUN_CMD -db-max-idle-conns '$LENPASTE_DB_MAX_IDLE_CONNS'"
fi
# LENPASTE_DB_CLEANUP_PERIOD
if [[ -n "$LENPASTE_DB_CLEANUP_PERIOD" ]]; then
if [ -n "$LENPASTE_DB_CLEANUP_PERIOD" ]; then
RUN_CMD="$RUN_CMD -db-cleanup-period '$LENPASTE_DB_CLEANUP_PERIOD'"
fi
# LENPASTE_ROBOTS_DISALLOW
if [[ "$LENPASTE_ROBOTS_DISALLOW" == "true" ]]; then
if [ "$LENPASTE_ROBOTS_DISALLOW" = "true" ]; then
RUN_CMD="$RUN_CMD -robots-disallow"
else
if [[ "$LENPASTE_ROBOTS_DISALLOW" != "" && "$LENPASTE_ROBOTS_DISALLOW" != "false" ]]; then
if [ "$LENPASTE_ROBOTS_DISALLOW" != "" ] && [ "$LENPASTE_ROBOTS_DISALLOW" != "false" ]; then
echo "[ENTRYPOINT] Error: unknown: LENPASTE_ROBOTS_DISALLOW = $LENPASTE_ROBOTS_DISALLOW"
exit 2
fi
@ -43,65 +55,101 @@ fi
# LENPASTE_TITLE_MAX_LENGTH
if [[ -n "$LENPASTE_TITLE_MAX_LENGTH" ]]; then
if [ -n "$LENPASTE_TITLE_MAX_LENGTH" ]; then
RUN_CMD="$RUN_CMD -title-max-length '$LENPASTE_TITLE_MAX_LENGTH'"
fi
# LENPASTE_BODY_MAX_LENGTH
if [[ -n "$LENPASTE_BODY_MAX_LENGTH" ]]; then
if [ -n "$LENPASTE_BODY_MAX_LENGTH" ]; then
RUN_CMD="$RUN_CMD -body-max-length '$LENPASTE_BODY_MAX_LENGTH'"
fi
# LENPASTE_MAX_PASTE_LIFETIME
if [[ -n "$LENPASTE_MAX_PASTE_LIFETIME" ]]; then
if [ -n "$LENPASTE_MAX_PASTE_LIFETIME" ]; then
RUN_CMD="$RUN_CMD -max-paste-lifetime '$LENPASTE_MAX_PASTE_LIFETIME'"
fi
# LENPASTE_NEW_PASTES_PER_5MIN
if [[ -n "$LENPASTE_NEW_PASTES_PER_5MIN" ]]; then
# Rate limits to get
if [ -n "$LENPASTE_GET_PASTES_PER_5MIN" ]; then
RUN_CMD="$RUN_CMD -get-pastes-per-5min '$LENPASTE_GET_PASTES_PER_5MIN'"
fi
if [ -n "$LENPASTE_GET_PASTES_PER_15MIN" ]; then
RUN_CMD="$RUN_CMD -get-pastes-per-15min '$LENPASTE_GET_PASTES_PER_15MIN'"
fi
if [ -n "$LENPASTE_GET_PASTES_PER_1HOUR" ]; then
RUN_CMD="$RUN_CMD -get-pastes-per-1hour '$LENPASTE_GET_PASTES_PER_1HOUR'"
fi
# Rate limits to create
if [ -n "$LENPASTE_NEW_PASTES_PER_5MIN" ]; then
RUN_CMD="$RUN_CMD -new-pastes-per-5min '$LENPASTE_NEW_PASTES_PER_5MIN'"
fi
# LENPASTE_UI_DEFAULT_LIFETIME
if [[ -n "$LENPASTE_UI_DEFAULT_LIFETIME" ]]; then
RUN_CMD="$RUN_CMD -ui-default-lifetime '$LENPASTE_UI_DEFAULT_LIFETIME'"
if [ -n "$LENPASTE_NEW_PASTES_PER_15MIN" ]; then
RUN_CMD="$RUN_CMD -new-pastes-per-15min '$LENPASTE_NEW_PASTES_PER_15MIN'"
fi
if [ -n "$LENPASTE_NEW_PASTES_PER_1HOUR" ]; then
RUN_CMD="$RUN_CMD -new-pastes-per-1hour '$LENPASTE_NEW_PASTES_PER_1HOUR'"
fi
# Server about
if [[ -f "/data/about" ]]; then
if [ -f "/data/about" ]; then
RUN_CMD="$RUN_CMD -server-about /data/about"
fi
# Server rules
if [[ -f "/data/rules" ]]; then
if [ -f "/data/rules" ]; then
RUN_CMD="$RUN_CMD -server-rules /data/rules"
fi
# Server terms of use
if [[ -f "/data/terms" ]]; then
if [ -f "/data/terms" ]; then
RUN_CMD="$RUN_CMD -server-terms /data/terms"
fi
# LENPASTE_ADMIN_NAME
if [[ -n "$LENPASTE_ADMIN_NAME" ]]; then
if [ -n "$LENPASTE_ADMIN_NAME" ]; then
RUN_CMD="$RUN_CMD -admin-name '$LENPASTE_ADMIN_NAME'"
fi
# LENPASTE_ADMIN_MAIL
if [[ -n "$LENPASTE_ADMIN_MAIL" ]]; then
if [ -n "$LENPASTE_ADMIN_MAIL" ]; then
RUN_CMD="$RUN_CMD -admin-mail '$LENPASTE_ADMIN_MAIL'"
fi
# LENPASTE_UI_DEFAULT_LIFETIME
if [ -n "$LENPASTE_UI_DEFAULT_LIFETIME" ]; then
RUN_CMD="$RUN_CMD -ui-default-lifetime '$LENPASTE_UI_DEFAULT_LIFETIME'"
fi
# LENPASTE_UI_DEFAULT_THEME
if [ -n "$LENPASTE_UI_DEFAULT_THEME" ]; then
RUN_CMD="$RUN_CMD -ui-default-theme $LENPASTE_UI_DEFAULT_THEME"
fi
# External UI themes
if [ -d "/data/themes" ]; then
RUN_CMD="$RUN_CMD -ui-themes-dir /data/themes"
fi
# Lenpsswd file
if [[ -f "/data/lenpasswd" ]]; then
if [ -f "/data/lenpasswd" ]; then
RUN_CMD="$RUN_CMD -lenpasswd-file /data/lenpasswd"
fi

@ -6,7 +6,7 @@ replace git.lcomrade.su/root/lenpaste/internal => ./internal
require (
git.lcomrade.su/root/lineend v1.0.0
github.com/alecthomas/chroma/v2 v2.3.0
github.com/alecthomas/chroma/v2 v2.4.0
github.com/lib/pq v1.10.7
github.com/mattn/go-sqlite3 v1.14.15
github.com/mattn/go-sqlite3 v1.14.16
)

@ -1,26 +1,16 @@
git.lcomrade.su/root/lineend v1.0.0 h1:qcxrR4DS18Erx+pG/EspoDhEDai+mjgSYefwSK2dq5g=
git.lcomrade.su/root/lineend v1.0.0/go.mod h1:D0q3jMx0I1PFZjAFwkmUNW8D5tIw8rZJoeUAxhYD7Ec=
github.com/alecthomas/chroma/v2 v2.3.0 h1:83xfxrnjv8eK+Cf8qZDzNo3PPF9IbTWHs7z28GY6D0U=
github.com/alecthomas/chroma/v2 v2.3.0/go.mod h1:mZxeWZlxP2Dy+/8cBob2PYd8O2DwNAzave5AY7A2eQw=
github.com/alecthomas/assert/v2 v2.2.0 h1:f6L/b7KE2bfA+9O4FL3CM/xJccDEwPVYd5fALBiuwvw=
github.com/alecthomas/assert/v2 v2.2.0/go.mod h1:b/+1DI2Q6NckYi+3mXyH3wFb8qG37K/DuK80n7WefXA=
github.com/alecthomas/chroma/v2 v2.4.0 h1:Loe2ZjT5x3q1bcWwemqyqEi8p11/IV/ncFCeLYDpWC4=
github.com/alecthomas/chroma/v2 v2.4.0/go.mod h1:6kHzqF5O6FUSJzBXW7fXELjb+e+7OXW4UpoPqMO7IBQ=
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE=
github.com/alecthomas/repr v0.1.0/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=

@ -1,4 +1,4 @@
// Copyright (C) 2021-2022 Leonid Maslakov.
// Copyright (C) 2021-2023 Leonid Maslakov.
// This file is part of Lenpaste.
@ -24,52 +24,87 @@ import (
"git.lcomrade.su/root/lenpaste/internal/netshare"
"git.lcomrade.su/root/lenpaste/internal/storage"
chromaLexers "github.com/alecthomas/chroma/v2/lexers"
"net/http"
)
type Data struct {
Log logger.Config
Log logger.Logger
DB storage.DB
RateLimit netshare.RateLimit
RateLimitNew *netshare.RateLimitSystem
RateLimitGet *netshare.RateLimitSystem
Lexers *[]string
Lexers []string
Version *string
Version string
TitleMaxLen *int
BodyMaxLen *int
MaxLifeTime *int64
TitleMaxLen int
BodyMaxLen int
MaxLifeTime int64
ServerAbout *string
ServerRules *string
ServerTermsOfUse *string
ServerAbout string
ServerRules string
ServerTermsOfUse string
AdminName *string
AdminMail *string
AdminName string
AdminMail string
LenPasswdFile *string
LenPasswdFile string
UiDefaultLifeTime *string
UiDefaultLifeTime string
}
func Load(cfg config.Config) Data {
func Load(db storage.DB, cfg config.Config) *Data {
lexers := chromaLexers.Names(false)
return Data{
DB: cfg.DB,
return &Data{
DB: db,
Log: cfg.Log,
RateLimit: cfg.RateLimit,
Lexers: &lexers,
Version: &cfg.Version,
TitleMaxLen: &cfg.TitleMaxLen,
BodyMaxLen: &cfg.BodyMaxLen,
MaxLifeTime: &cfg.MaxLifeTime,
ServerAbout: &cfg.ServerAbout,
ServerRules: &cfg.ServerRules,
ServerTermsOfUse: &cfg.ServerTermsOfUse,
AdminName: &cfg.AdminName,
AdminMail: &cfg.AdminMail,
LenPasswdFile: &cfg.LenPasswdFile,
UiDefaultLifeTime: &cfg.UiDefaultLifetime,
RateLimitNew: cfg.RateLimitNew,
RateLimitGet: cfg.RateLimitGet,
Lexers: lexers,
Version: cfg.Version,
TitleMaxLen: cfg.TitleMaxLen,
BodyMaxLen: cfg.BodyMaxLen,
MaxLifeTime: cfg.MaxLifeTime,
ServerAbout: cfg.ServerAbout,
ServerRules: cfg.ServerRules,
ServerTermsOfUse: cfg.ServerTermsOfUse,
AdminName: cfg.AdminName,
AdminMail: cfg.AdminMail,
LenPasswdFile: cfg.LenPasswdFile,
UiDefaultLifeTime: cfg.UiDefaultLifetime,
}
}
func (data *Data) Hand(rw http.ResponseWriter, req *http.Request) {
// Process request
var err error
rw.Header().Set("Server", config.Software+"/"+data.Version)
switch req.URL.Path {
// Search engines
case "/api/v1/new":
err = data.newHand(rw, req)
case "/api/v1/get":
err = data.getHand(rw, req)
case "/api/v1/getServerInfo":
err = data.getServerInfoHand(rw, req)
default:
err = netshare.ErrNotFound
}
// Log
if err == nil {
data.Log.HttpRequest(req, 200)
} else {
code, err := data.writeError(rw, req, err)
if err != nil {
data.Log.HttpError(req, err)
} else {
data.Log.HttpRequest(req, code)
}
}
}

@ -1,4 +1,4 @@
// Copyright (C) 2021-2022 Leonid Maslakov.
// Copyright (C) 2021-2023 Leonid Maslakov.
// This file is part of Lenpaste.
@ -20,6 +20,7 @@ package apiv1
import (
"encoding/json"
"errors"
"git.lcomrade.su/root/lenpaste/internal/netshare"
"git.lcomrade.su/root/lenpaste/internal/storage"
"net/http"
@ -31,9 +32,11 @@ type errorType struct {
Error string `json:"error"`
}
func (data Data) writeError(rw http.ResponseWriter, req *http.Request, e error) {
func (data *Data) writeError(rw http.ResponseWriter, req *http.Request, e error) (int, error) {
var resp errorType
var eTmp429 *netshare.ErrTooManyRequests
if e == netshare.ErrBadRequest {
resp.Code = 400
resp.Error = "Bad Request"
@ -59,19 +62,14 @@ func (data Data) writeError(rw http.ResponseWriter, req *http.Request, e error)
resp.Code = 413
resp.Error = "Payload Too Large"
} else if e == netshare.ErrTooManyRequests {
} else if errors.As(e, &eTmp429) {
resp.Code = 429
resp.Error = "Too Many Requests"
rw.Header().Set("Retry-After", strconv.Itoa(netshare.RateLimitPeriod))
rw.Header().Set("Retry-After", strconv.FormatInt(eTmp429.RetryAfter, 10))
} else {
resp.Code = 500
resp.Error = "Internal Server Error"
data.Log.HttpError(req, e)
}
if resp.Code >= 500 && e != netshare.ErrInternal {
data.Log.HttpError(req, e)
}
rw.Header().Set("Content-Type", "application/json")
@ -79,7 +77,8 @@ func (data Data) writeError(rw http.ResponseWriter, req *http.Request, e error)
err := json.NewEncoder(rw).Encode(resp)
if err != nil {
data.Log.HttpError(req, err)
return
return 500, err
}
return resp.Code, nil
}

@ -1,4 +1,4 @@
// Copyright (C) 2021-2022 Leonid Maslakov.
// Copyright (C) 2021-2023 Leonid Maslakov.
// This file is part of Lenpaste.
@ -26,14 +26,16 @@ import (
)
// GET /api/v1/get
func (data Data) GetHand(rw http.ResponseWriter, req *http.Request) {
// Log request
data.Log.HttpRequest(req)
func (data *Data) getHand(rw http.ResponseWriter, req *http.Request) error {
// Check rate limit
err := data.RateLimitGet.CheckAndUse(netshare.GetClientAddr(req))
if err != nil {
return err
}
// Check method
if req.Method != "GET" {
data.writeError(rw, req, netshare.ErrMethodNotAllowed)
return
return netshare.ErrMethodNotAllowed
}
// Get paste ID
@ -43,15 +45,13 @@ func (data Data) GetHand(rw http.ResponseWriter, req *http.Request) {
// Check paste id
if pasteID == "" {
data.writeError(rw, req, netshare.ErrBadRequest)
return
return netshare.ErrBadRequest
}
// Get paste
paste, err := data.DB.PasteGet(pasteID)
if err != nil {
data.writeError(rw, req, err)
return
return err
}
// If "one use" paste
@ -60,8 +60,7 @@ func (data Data) GetHand(rw http.ResponseWriter, req *http.Request) {
// Delete paste
err = data.DB.PasteDelete(pasteID)
if err != nil {
data.writeError(rw, req, err)
return
return err
}
} else {
@ -75,10 +74,5 @@ func (data Data) GetHand(rw http.ResponseWriter, req *http.Request) {
// Return response
rw.Header().Set("Content-Type", "application/json")