Implement basic configuration and storage structure

This commit is contained in:
Lukas SP 2020-08-22 23:24:38 +02:00
parent 9bd6044e39
commit ba0aebdb62
8 changed files with 132 additions and 20 deletions

View File

@ -1,5 +1,8 @@
package main
import "github.com/Lukaesebrot/pasty/internal/env"
func main() {
// TODO: Implement startup logic
// Load the optional .env file
env.Load()
}

5
go.mod
View File

@ -3,7 +3,8 @@ module github.com/Lukaesebrot/pasty
go 1.15
require (
github.com/alexedwards/argon2id v0.0.0-20200802152012-2464efd3196b
github.com/bwmarrin/snowflake v0.3.0
github.com/fasthttp/router v1.2.4 // indirect
github.com/valyala/fasthttp v1.16.0 // indirect
github.com/joho/godotenv v1.3.0
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 // indirect
)

25
go.sum
View File

@ -1,22 +1,15 @@
github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4=
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/alexedwards/argon2id v0.0.0-20200802152012-2464efd3196b h1:rcCpjI1OMGtBY8nnBvExeM1pXNoaM35zqmXBGpgJR2o=
github.com/alexedwards/argon2id v0.0.0-20200802152012-2464efd3196b/go.mod h1:GFtu6vaWaRJV5EvSFaVqgq/3Iq95xyYElBV/aupGzUo=
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
github.com/fasthttp/router v1.2.4 h1:RBWbCv4vVf+boczSZh/rX9PDSdR9F8I9zSnVJx5YJfU=
github.com/fasthttp/router v1.2.4/go.mod h1:Au2V1CaqqAdzQQcPKrbkFAsImd1aHpadrce21AIPnvE=
github.com/klauspost/compress v1.10.7 h1:7rix8v8GpI3ZBb0nSozFRgbtXKv+hOe+qfEpZqybrAg=
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/savsgio/gotils v0.0.0-20200616100644-13ff1fd2c28c h1:KKqhycXW1WVNkX7r4ekTV2gFkbhdyihlWD8c0/FiWmk=
github.com/savsgio/gotils v0.0.0-20200616100644-13ff1fd2c28c/go.mod h1:TWNAOTaVzGOXq8RbEvHnhzA/A2sLZzgn0m6URjnukY8=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.15.1/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA=
github.com/valyala/fasthttp v1.16.0 h1:9zAqOYLl8Tuy3E5R6ckzGDJ1g8+pw15oQp2iL9Jl6gQ=
github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 h1:bXoxMPcSLOq08zI3/c5dEBT6lE4eh+jOh886GHrn6V8=
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

21
internal/env/env.go vendored Normal file
View File

@ -0,0 +1,21 @@
package env
import (
"github.com/Lukaesebrot/pasty/internal/static"
"github.com/joho/godotenv"
"os"
)
// Load loads an optional .env file
func Load() {
godotenv.Load()
}
// Get returns the content of the environment variable with the given key or the given fallback
func Get(key, fallback string) string {
found := os.Getenv(static.EnvironmentVariablePrefix + key)
if found == "" {
return fallback
}
return found
}

View File

@ -0,0 +1,27 @@
package pastes
import (
"github.com/Lukaesebrot/pasty/internal/env"
"math/rand"
"strconv"
)
// deletionTokenContents represents the characters a deletion token may contain
const deletionTokenContents = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#+-.,"
// generateDeletionToken generates a new deletion token
func generateDeletionToken() (string, error) {
// Read the deletion token length
rawLength := env.Get("DELETION_TOKEN_LENGTH", "12")
length, err := strconv.Atoi(rawLength)
if err != nil {
return "", err
}
// Generate the deletion token
bytes := make([]byte, length)
for i := range bytes {
bytes[i] = deletionTokenContents[rand.Int63()%int64(len(deletionTokenContents))]
}
return string(bytes), nil
}

View File

@ -1,6 +1,16 @@
package pastes
import "github.com/bwmarrin/snowflake"
import (
"github.com/alexedwards/argon2id"
"github.com/bwmarrin/snowflake"
)
func init() {
snowflakeNode, _ = snowflake.NewNode(1)
}
// snowflakeNode holds the current snowflake node
var snowflakeNode *snowflake.Node
// Paste represents a saved paste
type Paste struct {
@ -9,3 +19,39 @@ type Paste struct {
SuggestedSyntaxType string `json:"suggestedSyntaxType" bson:"suggestedSyntaxType"`
DeletionToken string `json:"deletionToken" bson:"deletionToken"`
}
// Create creates a new paste object using the given content
func Create(content string) (*Paste, error) {
// TODO: Generate the suggested syntax type
suggestedSyntaxType := ""
// Generate the deletion token
deletionToken, err := generateDeletionToken()
if err != nil {
return nil, err
}
// Return the paste object
return &Paste{
ID: snowflakeNode.Generate(),
Content: content,
SuggestedSyntaxType: suggestedSyntaxType,
DeletionToken: deletionToken,
}, nil
}
// HashDeletionToken hashes the current deletion token of a paste
func (paste *Paste) HashDeletionToken() error {
hash, err := argon2id.CreateHash(paste.DeletionToken, argon2id.DefaultParams)
if err != nil {
return err
}
paste.DeletionToken = hash
return nil
}
// CheckDeletionToken checks whether or not the given deletion token is correct
func (paste *Paste) CheckDeletionToken(deletionToken string) bool {
match, err := argon2id.ComparePasswordAndHash(deletionToken, paste.DeletionToken)
return err != nil && match
}

View File

@ -0,0 +1,7 @@
package static
// These variables represent the values that may be changed using ldflags
var (
Version = "dev"
EnvironmentVariablePrefix = "PASTY_"
)

View File

@ -0,0 +1,14 @@
package storage
import (
"github.com/Lukaesebrot/pasty/internal/pastes"
"github.com/bwmarrin/snowflake"
)
// Storage represents a storage type
type Storage interface {
initialize() error
get(id snowflake.ID) (*pastes.Paste, error)
save(paste *pastes.Paste) error
delete(id snowflake.ID) error
}