Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# Created by https://www.toptal.com/developers/gitignore/api/jetbrains+all,go
# Edit at https://www.toptal.com/developers/gitignore?templates=jetbrains+all,go

Expand Down Expand Up @@ -114,6 +113,4 @@ modules.xml

# End of https://www.toptal.com/developers/gitignore/api/jetbrains+all,go

web/*.gz
data/
.env
.env
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ RUN go build \
FROM gcr.io/distroless/base:latest
WORKDIR /root
COPY --from=build /app/pasty .
COPY web ./web/
COPY internal/web/web ./web/
EXPOSE 8080
CMD ["./pasty"]
18 changes: 1 addition & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,6 @@
# pasty
Pasty is a fast and lightweight code pasting server

## !!! Important deprecation notices !!!

> This version of pasty uses a new field name for the so far called `deletionToken`: `modificationToken`.
> Instances using **PostgreSQL** are **not affected** as a corresponding SQL migration will run before the first startup.
> If you however use **another storage driver** you may have to **update the entries** by hand or using a simple query, depending on your driver as I don't plan to ship migrations for every single storage driver.
> It may be important to know that the **data migrator has been upgraded** too. This may serve as a **convenient workaround** (export data (field will be renamed) and import data with changed field names again).
>
> The old `deletionToken` field will be processed corresponding to these changes but I strongly recommend updating old pastes if possible.

> Additionally, I changed the three `DELETION_TOKEN*`environment variables to their corresponding `MODIFICATION_TOKEN*` ones:
> - `DELETION_TOKENS` -> `MODIFICATION_TOKENS`
> - `DELETION_TOKEN_MASTER` -> `MODIFICATION_TOKEN_MASTER`
> - `DELETION_TOKEN_LENGTH` -> `MODIFICATION_TOKEN_LENGTH`
>
> Again, **the old ones will still work** because I do not want to jumble your configurations. However, **please consider updating** them to stay future-proof ^^.

pasty is a fast and lightweight code pasting server.

## Support

Expand Down
163 changes: 131 additions & 32 deletions cmd/pasty/main.go
Original file line number Diff line number Diff line change
@@ -1,52 +1,151 @@
package main

import (
"log"
"time"

"context"
"errors"
"github.com/lus/pasty/internal/cleanup"
"github.com/lus/pasty/internal/config"
"github.com/lus/pasty/internal/consolecommands"
"github.com/lus/pasty/internal/meta"
"github.com/lus/pasty/internal/reports"
"github.com/lus/pasty/internal/storage"
"github.com/lus/pasty/internal/storage/postgres"
"github.com/lus/pasty/internal/storage/sqlite"
"github.com/lus/pasty/internal/web"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"net/http"
"os"
"os/signal"
"strings"
)

func main() {
// Load the configuration
log.Println("Loading the application configuration...")
config.Load()
// Set up the logger
zerolog.TimeFieldFormat = zerolog.TimeFormatUnixMs
if !meta.IsProdEnvironment() {
log.Logger = log.Output(zerolog.ConsoleWriter{
Out: os.Stderr,
})
log.Warn().Msg("This distribution was compiled for development mode and is thus not meant to be run in production!")
}

// Load the configured storage driver
log.Println("Loading the configured storage driver...")
err := storage.Load()
// Load the configuration
config.Compatibility()
cfg, err := config.Load()
if err != nil {
panic(err)
log.Fatal().Err(err).Msg("Could not load the configuration.")
}
defer func() {
log.Println("Terminating the storage driver...")
err := storage.Current.Terminate()

// Adjust the log level
if !meta.IsProdEnvironment() {
zerolog.SetGlobalLevel(zerolog.DebugLevel)
} else {
level, err := zerolog.ParseLevel(cfg.LogLevel)
if err != nil {
log.Fatalln(err)
log.Warn().Msg("An invalid log level was configured. Falling back to 'info'.")
level = zerolog.InfoLevel
}
zerolog.SetGlobalLevel(level)
}

// Determine the correct storage driver to use
var driver storage.Driver
switch strings.TrimSpace(strings.ToLower(cfg.StorageDriver)) {
case "postgres":
driver = postgres.New(cfg.Postgres.DSN)
break
case "sqlite":
driver = sqlite.New(cfg.SQLite.File)
break
case "file":
// TODO: Readme notice
log.Fatal().Msg("You have configured the legacy 'file' storage driver. This storage driver has been removed in favor of PostgreSQL and SQLite, but the latter one may be a seamless alternative for you. Head over to the projects README for more information.")
break
case "mongodb":
case "s3":
// TODO: Readme notice
log.Fatal().Msg("You have configured a legacy storage driver. This storage driver has been removed in favor of PostgreSQL and SQLite, but the migration process is well-documented. Head over to the projects README for more information.")
break
default:
log.Fatal().Str("driver_name", cfg.StorageDriver).Msg("An invalid storage driver name was given.")
return
}

// Initialize the configured storage driver
log.Info().Str("driver_name", cfg.StorageDriver).Msg("Initializing the storage driver...")
if err := driver.Initialize(context.Background()); err != nil {
log.Fatal().Err(err).Str("driver_name", cfg.StorageDriver).Msg("The storage driver could not be initialized.")
return
}
defer func() {
log.Info().Msg("Shutting down the storage driver...")
if err := driver.Close(); err != nil {
log.Err(err).Str("driver_name", cfg.StorageDriver).Msg("Could not shut down the storage driver.")
}
}()

// Schedule the AutoDelete task
if config.Current.AutoDelete.Enabled {
log.Println("Scheduling the AutoDelete task...")
go func() {
for {
// Run the cleanup sequence
deleted, err := storage.Current.Cleanup()
if err != nil {
log.Fatalln(err)
}
log.Printf("AutoDelete: Deleted %d expired pastes", deleted)

// Wait until the process should repeat
time.Sleep(config.Current.AutoDelete.TaskInterval)
}
// Schedule the cleanup task if configured
if cfg.Cleanup.Enabled {
task := &cleanup.Task{
Interval: cfg.Cleanup.TaskInterval,
MaxPasteAge: cfg.Cleanup.PasteLifetime,
Repository: driver.Pastes(),
}
log.Info().Msg("Scheduling the cleanup task...")
task.Start()
defer func() {
log.Info().Msg("Shutting down the cleanup task...")
task.Stop()
}()
}

// Serve the web resources
log.Println("Serving the web resources...")
panic(web.Serve())
// Start the web server
log.Info().Str("address", cfg.Address).Msg("Starting the web server...")
webServer := &web.Server{
Address: cfg.Address,
Storage: driver,
PasteIDLength: cfg.PasteIDLength,
PasteIDCharset: cfg.PasteIDCharset,
PasteLengthCap: cfg.PasteLengthCap,
ModificationTokensEnabled: cfg.ModificationTokensEnabled,
ModificationTokenLength: cfg.ModificationTokenLength,
ModificationTokenCharset: cfg.ModificationTokenCharset,
}
if cfg.Reports.Enabled {
webServer.ReportClient = &reports.Client{
WebhookURL: cfg.Reports.WebhookURL,
WebhookToken: cfg.Reports.WebhookToken,
}
}
if cfg.ModificationTokenMaster != "" {
webServer.AdminTokens = []string{cfg.ModificationTokenMaster}
}
go func() {
if err := webServer.Start(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Fatal().Err(err).Msg("Could not start the web server.")
}
}()
defer func() {
log.Info().Msg("Shutting down the web server...")
if err := webServer.Shutdown(context.Background()); err != nil {
log.Err(err).Msg("Could not shut down the web server.")
}
}()

// Listen to console commands if enabled
if !cfg.ConsoleCommandsEnabled {
log.Info().Msg("The application has been started. Use Ctrl+C to shut it down.")
} else {
log.Info().Msg("The application has been started and listens to console commands. Use Ctrl+C or 'stop' to shut it down.")
go (&consolecommands.Router{
Config: cfg,
Storage: driver,
}).Listen()
}

// Wait for an interrupt signal
shutdownChan := make(chan os.Signal, 1)
signal.Notify(shutdownChan, os.Interrupt)
<-shutdownChan
}
82 changes: 0 additions & 82 deletions cmd/transfer/main.go

This file was deleted.

58 changes: 40 additions & 18 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,23 +1,45 @@
module github.com/lus/pasty

go 1.16
go 1.20

require (
github.com/alexedwards/argon2id v0.0.0-20200802152012-2464efd3196b
github.com/fasthttp/router v1.2.4
github.com/go-stack/stack v1.8.1 // indirect
github.com/golang-migrate/migrate/v4 v4.14.2-0.20201125065321-a53e6fc42574
github.com/golang/snappy v0.0.4 // indirect
github.com/jackc/pgx/v4 v4.11.0
github.com/johejo/golang-migrate-extra v0.0.0-20210217013041-51a992e50d16
github.com/joho/godotenv v1.3.0
github.com/klauspost/compress v1.15.1 // indirect
github.com/minio/minio-go/v7 v7.0.5
github.com/ulule/limiter/v3 v3.5.0
github.com/valyala/fasthttp v1.16.0
github.com/xdg-go/scram v1.1.1 // indirect
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
go.mongodb.org/mongo-driver v1.8.4
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
github.com/alexedwards/argon2id v0.0.0-20230305115115-4b3c3280a736
github.com/go-chi/chi/v5 v5.0.8
github.com/golang-migrate/migrate/v4 v4.16.1
github.com/jackc/pgx/v5 v5.3.1
github.com/joho/godotenv v1.5.1
github.com/kelseyhightower/envconfig v1.4.0
github.com/rs/zerolog v1.29.1
modernc.org/sqlite v1.23.1
)

require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/puddle/v2 v2.2.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
go.uber.org/atomic v1.11.0 // indirect
golang.org/x/crypto v0.9.0 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/sync v0.2.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/tools v0.9.1 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.40.0 // indirect
modernc.org/ccgo/v3 v3.16.13 // indirect
modernc.org/libc v1.22.5 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.5.0 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect
)
Loading