Linter to CI #17

Merged
ada merged 2 commits from ada/ci/lint into main 2024-04-10 20:13:44 +02:00
12 changed files with 199 additions and 83 deletions

25
.golangci.yaml Normal file
View file

@ -0,0 +1,25 @@
linters:
enable-all: true
disable:
# Deprecated
- varcheck
- ifshort
- interfacer
- maligned
- deadcode
- scopelint
- golint
- structcheck
- exhaustivestruct
- nosnakecase
# Too extremist/unusable
- depguard
- varnamelen
- exhaustruct
- wsl
- contextcheck
- wrapcheck
linters-settings:
lll:
# Too short byt default
line-length: 160

11
.woodpecker/lint.yml Normal file
View file

@ -0,0 +1,11 @@
steps:
lint:
image: golang:1.22
commands:
- go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
- golangci-lint run
when:
- event: pull_request
repo: gnouseu/plakken
- event: push
branch: main

View file

@ -4,19 +4,21 @@ import (
"log" "log"
"os" "os"
"strconv" "strconv"
"git.gnous.eu/gnouseu/plakken/internal/constant"
) )
// InitConfig Structure for program initialisation // InitConfig Structure for program initialisation.
type InitConfig struct { type InitConfig struct {
ListenAddress string ListenAddress string
RedisAddress string RedisAddress string
RedisUser string RedisUser string
RedisPassword string RedisPassword string
RedisDB int RedisDB int
UrlLength uint8 URLLength uint8
ada marked this conversation as resolved Outdated
Outdated
Review

why ?

why ?
} }
// GetConfig Initialise configuration form .env // GetConfig Initialise configuration form .env.
func GetConfig() InitConfig { func GetConfig() InitConfig {
listenAddress := os.Getenv("PLAKKEN_LISTEN") listenAddress := os.Getenv("PLAKKEN_LISTEN")
redisAddress := os.Getenv("PLAKKEN_REDIS_ADDRESS") redisAddress := os.Getenv("PLAKKEN_REDIS_ADDRESS")
@ -37,7 +39,7 @@ func GetConfig() InitConfig {
log.Fatal("Invalid PLAKKEN_URL_LENGTH") log.Fatal("Invalid PLAKKEN_URL_LENGTH")
} }
if urlLength > 255 { if urlLength > constant.MaxURLLength {
log.Fatal("PLAKKEN_URL_LENGTH cannot be greater than 255") log.Fatal("PLAKKEN_URL_LENGTH cannot be greater than 255")
} }
@ -47,6 +49,6 @@ func GetConfig() InitConfig {
RedisUser: os.Getenv("PLAKKEN_REDIS_USER"), RedisUser: os.Getenv("PLAKKEN_REDIS_USER"),
RedisPassword: os.Getenv("PLAKKEN_REDIS_PASSWORD"), RedisPassword: os.Getenv("PLAKKEN_REDIS_PASSWORD"),
RedisDB: redisDB, RedisDB: redisDB,
UrlLength: uint8(urlLength), URLLength: uint8(urlLength),
} }
} }

View file

@ -11,4 +11,8 @@ const (
ArgonThreads = 4 ArgonThreads = 4
ArgonKeyLength = 32 ArgonKeyLength = 32
ArgonIterations = 2 ArgonIterations = 2
MaxURLLength = 255
SecondsInDay = 86400
SecondsInHour = 3600
SecondsInMinute = 60
) )

View file

@ -13,9 +13,9 @@ type DBConfig struct {
DB *redis.Client DB *redis.Client
} }
var ctx = context.Background() var ctx = context.Background() //nolint:gochecknoglobals
// InitDB initialise redis connection settings // InitDB initialise redis connection settings.
func InitDB(addr string, user string, password string, db int) *redis.Options { func InitDB(addr string, user string, password string, db int) *redis.Options {
DBConfig := &redis.Options{ DBConfig := &redis.Options{
Addr: addr, Addr: addr,
@ -27,18 +27,20 @@ func InitDB(addr string, user string, password string, db int) *redis.Options {
return DBConfig return DBConfig
} }
// ConnectDB make new database connection // ConnectDB make new database connection.
func ConnectDB(dbConfig *redis.Options) *redis.Client { func ConnectDB(dbConfig *redis.Options) *redis.Client {
localDb := redis.NewClient(dbConfig) localDB := redis.NewClient(dbConfig)
return localDb
return localDB
} }
// Ping test connection to Redis database // Ping test connection to Redis database.
func Ping(db *redis.Client) error { func Ping(db *redis.Client) error {
status := db.Ping(ctx) status := db.Ping(ctx)
if status.String() != "ping: PONG" { if status.String() != "ping: PONG" {
return &pingError{} return &pingError{}
} }
return nil return nil
} }
@ -65,7 +67,7 @@ func (config DBConfig) InsertPaste(key string, content string, secret string, tt
} }
} }
func (config DBConfig) UrlExist(url string) bool { func (config DBConfig) URLExist(url string) bool {
return config.DB.Exists(ctx, url).Val() == 1 return config.DB.Exists(ctx, url).Val() == 1
} }

View file

@ -1,4 +1,4 @@
package httpServer package httpserver
import ( import (
"embed" "embed"
@ -12,7 +12,7 @@ import (
type ServerConfig struct { type ServerConfig struct {
HTTPServer *http.Server HTTPServer *http.Server
UrlLength uint8 URLLength uint8
DB *redis.Client DB *redis.Client
Static embed.FS Static embed.FS
Templates embed.FS Templates embed.FS
@ -29,11 +29,11 @@ func (config ServerConfig) home(w http.ResponseWriter, _ *http.Request) {
} }
} }
// Configure HTTP router // Configure HTTP router.
func (config ServerConfig) router() { func (config ServerConfig) router() {
WebConfig := plak.WebConfig{ WebConfig := plak.WebConfig{
DB: config.DB, DB: config.DB,
UrlLength: config.UrlLength, URLLength: config.URLLength,
Templates: config.Templates, Templates: config.Templates,
} }
staticFiles := http.FS(config.Static) staticFiles := http.FS(config.Static)
@ -46,7 +46,7 @@ func (config ServerConfig) router() {
http.HandleFunc("DELETE /{key}", WebConfig.DeleteRequest) http.HandleFunc("DELETE /{key}", WebConfig.DeleteRequest)
} }
// Config Configure HTTP server // Config Configure HTTP server.
func Config(listenAddress string) *http.Server { func Config(listenAddress string) *http.Server {
server := &http.Server{ server := &http.Server{
Addr: listenAddress, Addr: listenAddress,
@ -57,7 +57,7 @@ func Config(listenAddress string) *http.Server {
return server return server
} }
// Server Start HTTP server // Server Start HTTP server.
func (config ServerConfig) Server() { func (config ServerConfig) Server() {
log.Println("Listening on " + config.HTTPServer.Addr) log.Println("Listening on " + config.HTTPServer.Addr)

View file

@ -5,6 +5,7 @@ import (
"bytes" "bytes"
"crypto/rand" "crypto/rand"
"encoding/base64" "encoding/base64"
"encoding/hex"
"fmt" "fmt"
"strconv" "strconv"
"strings" "strings"
@ -18,7 +19,7 @@ type argon2idHash struct {
hash []byte hash []byte
} }
// Argon2id config // Argon2id config.
type config struct { type config struct {
saltLength uint8 saltLength uint8
memory uint32 memory uint32
@ -27,7 +28,7 @@ type config struct {
iterations uint32 iterations uint32
} }
// generateSecret for password hashing or token generation // generateSecret for password hashing or token generation.
func generateSecret(length uint8) ([]byte, error) { func generateSecret(length uint8) ([]byte, error) {
secret := make([]byte, length) secret := make([]byte, length)
@ -39,26 +40,26 @@ func generateSecret(length uint8) ([]byte, error) {
return secret, err return secret, err
} }
// GenerateToken generate hexadecimal token // GenerateToken generate hexadecimal token.
func GenerateToken() (string, error) { func GenerateToken() (string, error) {
secret, err := generateSecret(constant.TokenLength) secret, err := generateSecret(constant.TokenLength)
if err != nil { if err != nil {
return "", err return "", err
} }
token := fmt.Sprintf("%x", secret) token := hex.EncodeToString(secret)
return token, nil return token, nil
} }
// generateArgon2ID Generate an argon2id hash from source string and specified salt // generateArgon2ID Generate an argon2id hash from source string and specified salt.
func (config config) generateArgon2ID(source string, salt []byte) []byte { func (config config) generateArgon2ID(source string, salt []byte) []byte {
hash := argon2.IDKey([]byte(source), salt, config.iterations, config.memory, config.threads, config.keyLength) hash := argon2.IDKey([]byte(source), salt, config.iterations, config.memory, config.threads, config.keyLength)
return hash return hash
} }
// Password hash a source string with argon2id, return properly encoded hash // Password hash a source string with argon2id, return properly encoded hash.
func Password(password string) (string, error) { func Password(password string) (string, error) {
config := config{ config := config{
saltLength: constant.ArgonSaltSize, saltLength: constant.ArgonSaltSize,
@ -95,10 +96,10 @@ func VerifyPassword(password string, hash string) (bool, error) {
return bytes.Equal(result, argon2Hash.hash), nil return bytes.Equal(result, argon2Hash.hash), nil
} }
// parseHash parse existing encoded argon2id string // parseHash parse existing encoded argon2id string.
func parseHash(source string) (argon2idHash, config, error) { func parseHash(source string) (argon2idHash, config, error) {
separateItem := strings.Split(source, "$") separateItem := strings.Split(source, "$")
if len(separateItem) != 6 { if len(separateItem) != 6 { //nolint:gomnd
return argon2idHash{}, config{}, &parseError{message: "Hash format is not valid"} return argon2idHash{}, config{}, &parseError{message: "Hash format is not valid"}
} }
@ -107,7 +108,7 @@ func parseHash(source string) (argon2idHash, config, error) {
} }
separateParam := strings.Split(separateItem[3], ",") separateParam := strings.Split(separateItem[3], ",")
if len(separateParam) != 3 { if len(separateParam) != 3 { //nolint:gomnd
return argon2idHash{}, config{}, &parseError{message: "Hash config is not valid"} return argon2idHash{}, config{}, &parseError{message: "Hash config is not valid"}
} }
@ -126,22 +127,35 @@ func parseHash(source string) (argon2idHash, config, error) {
keyLength := uint32(len(hash)) keyLength := uint32(len(hash))
var memory int var memory int
memory, err = strconv.Atoi(strings.Replace(separateParam[0], "m=", "", -1)) memory, err = strconv.Atoi(strings.ReplaceAll(separateParam[0], "m=", ""))
if err != nil { if err != nil {
return argon2idHash{}, config{}, err return argon2idHash{}, config{}, err
} }
var iterations int var iterations int
iterations, err = strconv.Atoi(strings.Replace(separateParam[1], "t=", "", -1)) iterations, err = strconv.Atoi(strings.ReplaceAll(separateParam[1], "t=", ""))
if err != nil { if err != nil {
return argon2idHash{}, config{}, err return argon2idHash{}, config{}, err
} }
var threads int var threads int
threads, err = strconv.Atoi(strings.Replace(separateParam[2], "p=", "", -1)) threads, err = strconv.Atoi(strings.ReplaceAll(separateParam[2], "p=", ""))
if err != nil { if err != nil {
return argon2idHash{}, config{}, err return argon2idHash{}, config{}, err
} }
return argon2idHash{salt: salt, hash: hash}, config{saltLength: saltLength, memory: uint32(memory), threads: uint8(threads), iterations: uint32(iterations), keyLength: keyLength}, nil argon2idStruct := argon2idHash{
salt: salt,
hash: hash,
}
hashConfig := config{
saltLength: saltLength,
memory: uint32(memory),
threads: uint8(threads),
iterations: uint32(iterations),
keyLength: keyLength,
}
return argon2idStruct, hashConfig, nil
} }

View file

@ -6,10 +6,12 @@ import (
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"git.gnous.eu/gnouseu/plakken/internal/constant"
) )
// GenerateUrl generate random string for plak url // GenerateURL generate random string for plak url.
func GenerateUrl(length uint8) string { func GenerateURL(length uint8) string {
listChars := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") listChars := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
b := make([]rune, length) b := make([]rune, length)
for i := range b { for i := range b {
@ -19,7 +21,7 @@ func GenerateUrl(length uint8) string {
return string(b) return string(b)
} }
// CheckCharRedundant verify is a character is redundant in a string // CheckCharRedundant verify is a character is redundant in a string.
func CheckCharRedundant(source string, char string) bool { // Verify if a char is redundant func CheckCharRedundant(source string, char string) bool { // Verify if a char is redundant
return strings.Count(source, char) > 1 return strings.Count(source, char) > 1
} }
@ -34,22 +36,24 @@ func parseIntBeforeSeparator(source *string, sep string) (int, error) { // retur
value, err = strconv.Atoi(strings.Split(*source, sep)[0]) value, err = strconv.Atoi(strings.Split(*source, sep)[0])
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return 0, &parseIntBeforeSeparatorError{message: *source + ": cannot parse value as int"} return 0, &parseIntBeforeSeparatorError{message: *source + ": cannot parse value as int"}
} }
if value < 0 { // Only positive value is correct if value < 0 { // Only positive value is correct
return 0, &parseIntBeforeSeparatorError{message: *source + ": format only take positive value"} return 0, &parseIntBeforeSeparatorError{message: *source + ": format only take positive value"}
} }
if value > 99 { if value > 99 { //nolint:gomnd
return 0, &parseIntBeforeSeparatorError{message: *source + ": Format only take two number"} return 0, &parseIntBeforeSeparatorError{message: *source + ": Format only take two number"}
} }
*source = strings.Join(strings.Split(*source, sep)[1:], "") *source = strings.Join(strings.Split(*source, sep)[1:], "")
} }
return value, nil return value, nil
} }
// ParseExpiration Parse "1d1h1m1s" duration format. Return 0 & error if error // ParseExpiration Parse "1d1h1m1s" duration format. Return 0 & error if error.
func ParseExpiration(source string) (int, error) { func ParseExpiration(source string) (int, error) {
var expiration int var expiration int
var tempOutput int var tempOutput int
@ -61,39 +65,44 @@ func ParseExpiration(source string) (int, error) {
source = strings.ToLower(source) source = strings.ToLower(source)
tempOutput, err = parseIntBeforeSeparator(&source, "d") tempOutput, err = parseIntBeforeSeparator(&source, "d")
expiration = tempOutput * 86400 expiration = tempOutput * constant.SecondsInDay
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return 0, &ParseExpirationError{message: "Invalid syntax"} return 0, &ParseExpirationError{message: "Invalid syntax"}
} }
tempOutput, err = parseIntBeforeSeparator(&source, "h") tempOutput, err = parseIntBeforeSeparator(&source, "h")
expiration += tempOutput * 3600 expiration += tempOutput * constant.SecondsInHour
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return 0, &ParseExpirationError{message: "Invalid syntax"} return 0, &ParseExpirationError{message: "Invalid syntax"}
} }
tempOutput, err = parseIntBeforeSeparator(&source, "m") tempOutput, err = parseIntBeforeSeparator(&source, "m")
expiration += tempOutput * 60 expiration += tempOutput * constant.SecondsInMinute
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return 0, &ParseExpirationError{message: "Invalid syntax"} return 0, &ParseExpirationError{message: "Invalid syntax"}
} }
tempOutput, err = parseIntBeforeSeparator(&source, "s") tempOutput, err = parseIntBeforeSeparator(&source, "s")
expiration += tempOutput * 1 expiration += tempOutput * 1
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return 0, &ParseExpirationError{message: "Invalid syntax"} return 0, &ParseExpirationError{message: "Invalid syntax"}
} }
return expiration, nil return expiration, nil
} }
// ValidKey Verify if a key is valid (only letter, number, - and _) // ValidKey Verify if a key is valid (only letter, number, - and _).
func ValidKey(key string) bool { func ValidKey(key string) bool {
result, err := regexp.MatchString("^[a-zA-Z0-9_.-]*$", key) result, err := regexp.MatchString("^[a-zA-Z0-9_.-]*$", key)
if err != nil { if err != nil {
return false return false
} }
log.Println(key, result) log.Println(key, result)
return result return result
} }

View file

@ -3,6 +3,7 @@ package plak
import ( import (
"context" "context"
"embed" "embed"
"html/template"
"io" "io"
"log" "log"
"net/http" "net/http"
@ -13,19 +14,17 @@ import (
"git.gnous.eu/gnouseu/plakken/internal/secret" "git.gnous.eu/gnouseu/plakken/internal/secret"
"git.gnous.eu/gnouseu/plakken/internal/utils" "git.gnous.eu/gnouseu/plakken/internal/utils"
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
"html/template"
) )
var ctx = context.Background() var ctx = context.Background() //nolint:gochecknoglobals
type WebConfig struct { type WebConfig struct {
DB *redis.Client DB *redis.Client
UrlLength uint8 URLLength uint8
Templates embed.FS Templates embed.FS
} }
// plak "Object" for plak // plak "Object" for plak.
type plak struct { type plak struct {
Key string Key string
Content string Content string
@ -33,7 +32,7 @@ type plak struct {
DB *redis.Client DB *redis.Client
} }
// create a plak // create a plak.
func (plak plak) create() (string, error) { func (plak plak) create() (string, error) {
dbConf := database.DBConfig{ dbConf := database.DBConfig{
DB: plak.DB, DB: plak.DB,
@ -44,7 +43,7 @@ func (plak plak) create() (string, error) {
return "", err return "", err
} }
if dbConf.UrlExist(plak.Key) { if dbConf.URLExist(plak.Key) {
return "", &createError{message: "key already exist"} return "", &createError{message: "key already exist"}
} }
@ -59,21 +58,23 @@ func (plak plak) create() (string, error) {
return token, nil return token, nil
} }
// PostCreate manage POST request for create plak // PostCreate manage POST request for create plak.
func (config WebConfig) PostCreate(w http.ResponseWriter, r *http.Request) { func (config WebConfig) PostCreate(w http.ResponseWriter, r *http.Request) {
content := r.FormValue("content") content := r.FormValue("content")
if content == "" { if content == "" {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
filename := r.FormValue("filename") filename := r.FormValue("filename")
var key string var key string
if len(filename) == 0 { if len(filename) == 0 {
key = utils.GenerateUrl(config.UrlLength) key = utils.GenerateURL(config.URLLength)
} else { } else {
if !utils.ValidKey(filename) { if !utils.ValidKey(filename) {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
key = filename key = filename
@ -90,6 +91,7 @@ func (config WebConfig) PostCreate(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
log.Println(err) log.Println(err)
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
return return
} }
@ -103,16 +105,18 @@ func (config WebConfig) PostCreate(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
log.Println(err) log.Println(err)
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
return return
} }
http.Redirect(w, r, "/"+key, http.StatusSeeOther) http.Redirect(w, r, "/"+key, http.StatusSeeOther)
} }
// CurlCreate PostCreate plak with minimum param, ideal for curl. Force 7 day expiration // CurlCreate PostCreate plak with minimum param, ideal for curl. Force 7 day expiration.
func (config WebConfig) CurlCreate(w http.ResponseWriter, r *http.Request) { func (config WebConfig) CurlCreate(w http.ResponseWriter, r *http.Request) {
if r.ContentLength == 0 { if r.ContentLength == 0 {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
@ -122,7 +126,7 @@ func (config WebConfig) CurlCreate(w http.ResponseWriter, r *http.Request) {
log.Println(err) log.Println(err)
} }
key := utils.GenerateUrl(config.UrlLength) key := utils.GenerateURL(config.URLLength)
plak := plak{ plak := plak{
Key: key, Key: key,
@ -135,6 +139,7 @@ func (config WebConfig) CurlCreate(w http.ResponseWriter, r *http.Request) {
token, err = plak.create() token, err = plak.create()
if err != nil { if err != nil {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
@ -154,7 +159,7 @@ func (config WebConfig) CurlCreate(w http.ResponseWriter, r *http.Request) {
} }
} }
// View for plak // View for plak.
func (config WebConfig) View(w http.ResponseWriter, r *http.Request) { func (config WebConfig) View(w http.ResponseWriter, r *http.Request) {
dbConf := database.DBConfig{ dbConf := database.DBConfig{
DB: config.DB, DB: config.DB,
@ -162,7 +167,8 @@ func (config WebConfig) View(w http.ResponseWriter, r *http.Request) {
var currentPlak plak var currentPlak plak
key := r.PathValue("key") key := r.PathValue("key")
if dbConf.UrlExist(key) { //nolint:nestif
if dbConf.URLExist(key) {
currentPlak = plak{ currentPlak = plak{
Key: key, Key: key,
DB: config.DB, DB: config.DB,
@ -179,12 +185,14 @@ func (config WebConfig) View(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
log.Println(err) log.Println(err)
return return
} }
err = t.Execute(w, currentPlak) err = t.Execute(w, currentPlak)
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
log.Println(err) log.Println(err)
return return
} }
} }
@ -193,7 +201,7 @@ func (config WebConfig) View(w http.ResponseWriter, r *http.Request) {
} }
} }
// DeleteRequest manage plak deletion endpoint // DeleteRequest manage plak deletion endpoint.
func (config WebConfig) DeleteRequest(w http.ResponseWriter, r *http.Request) { func (config WebConfig) DeleteRequest(w http.ResponseWriter, r *http.Request) {
dbConf := database.DBConfig{ dbConf := database.DBConfig{
DB: config.DB, DB: config.DB,
@ -201,7 +209,8 @@ func (config WebConfig) DeleteRequest(w http.ResponseWriter, r *http.Request) {
key := r.PathValue("key") key := r.PathValue("key")
var valid bool var valid bool
if dbConf.UrlExist(key) { //nolint:nestif
if dbConf.URLExist(key) {
var err error var err error
token := r.URL.Query().Get("secret") token := r.URL.Query().Get("secret")
@ -209,7 +218,6 @@ func (config WebConfig) DeleteRequest(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
log.Println(err) log.Println(err)
return
} }
if valid { if valid {
@ -223,29 +231,31 @@ func (config WebConfig) DeleteRequest(w http.ResponseWriter, r *http.Request) {
} }
w.WriteHeader(http.StatusNoContent) w.WriteHeader(http.StatusNoContent)
return
} else { } else {
w.WriteHeader(http.StatusForbidden) w.WriteHeader(http.StatusForbidden)
return
} }
return
} }
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
} }
// delete DeleteRequest plak from database // delete DeleteRequest plak from database.
func (plak plak) delete() error { func (plak plak) delete() error {
err := plak.DB.Del(ctx, plak.Key).Err() err := plak.DB.Del(ctx, plak.Key).Err()
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return &deletePlakError{name: plak.Key, err: err} return &deletePlakError{name: plak.Key, err: err}
} }
return nil return nil
} }
// getContent get plak content // getContent get plak content.
func (plak plak) getContent() plak { func (plak plak) getContent() plak {
plak.Content = plak.DB.HGet(ctx, plak.Key, "content").Val() plak.Content = plak.DB.HGet(ctx, plak.Key, "content").Val()
return plak return plak
} }

View file

@ -6,7 +6,7 @@ import (
"git.gnous.eu/gnouseu/plakken/internal/config" "git.gnous.eu/gnouseu/plakken/internal/config"
"git.gnous.eu/gnouseu/plakken/internal/database" "git.gnous.eu/gnouseu/plakken/internal/database"
"git.gnous.eu/gnouseu/plakken/internal/httpServer" "git.gnous.eu/gnouseu/plakken/internal/httpserver"
) )
var ( var (
@ -25,9 +25,9 @@ func main() {
log.Fatal(err) log.Fatal(err)
} }
serverConfig := httpServer.ServerConfig{ serverConfig := httpserver.ServerConfig{
HTTPServer: httpServer.Config(initConfig.ListenAddress), HTTPServer: httpserver.Config(initConfig.ListenAddress),
UrlLength: initConfig.UrlLength, URLLength: initConfig.URLLength,
DB: db, DB: db,
Static: static, Static: static,
Templates: templates, Templates: templates,

View file

@ -10,8 +10,17 @@ import (
"golang.org/x/crypto/argon2" "golang.org/x/crypto/argon2"
) )
func TestPasswordFormat(t *testing.T) { func TestSecret(t *testing.T) {
regex := fmt.Sprintf("\\$argon2id\\$v=%d\\$m=%d,t=%d,p=%d\\$[A-Za-z0-9+/]*\\$[A-Za-z0-9+/]*$", argon2.Version, constant.ArgonMemory, constant.ArgonIterations, constant.ArgonThreads) t.Parallel()
testPasswordFormat(t)
testVerifyPassword(t)
testVerifyPasswordInvalid(t)
}
func testPasswordFormat(t *testing.T) {
t.Helper()
regex := fmt.Sprintf("\\$argon2id\\$v=%d\\$m=%d,t=%d,p=%d\\$[A-Za-z0-9+/]*\\$[A-Za-z0-9+/]*$", argon2.Version, constant.ArgonMemory, constant.ArgonIterations, constant.ArgonThreads) //nolint:lll
got, err := secret.Password("Password!") got, err := secret.Password("Password!")
if err != nil { if err != nil {
@ -24,8 +33,9 @@ func TestPasswordFormat(t *testing.T) {
} }
} }
func TestVerifyPassword(t *testing.T) { func testVerifyPassword(t *testing.T) {
result, err := secret.VerifyPassword("Password!", "$argon2id$v=19$m=65536,t=2,p=4$A+t5YGpyy1BHCbvk/LP1xQ$eNuUj6B2ZqXlGi6KEqep39a7N4nysUIojuPXye+Ypp0") t.Helper()
result, err := secret.VerifyPassword("Password!", "$argon2id$v=19$m=65536,t=2,p=4$A+t5YGpyy1BHCbvk/LP1xQ$eNuUj6B2ZqXlGi6KEqep39a7N4nysUIojuPXye+Ypp0") //nolint:lll
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -35,8 +45,9 @@ func TestVerifyPassword(t *testing.T) {
} }
} }
func TestVerifyPasswordInvalid(t *testing.T) { func testVerifyPasswordInvalid(t *testing.T) {
result, err := secret.VerifyPassword("notsamepassword", "$argon2id$v=19$m=65536,t=2,p=4$A+t5YGpyy1BHCbvk/LP1xQ$eNuUj6B2ZqXlGi6KEqep39a7N4nysUIojuPXye+Ypp0") t.Helper()
result, err := secret.VerifyPassword("notsamepassword", "$argon2id$v=19$m=65536,t=2,p=4$A+t5YGpyy1BHCbvk/LP1xQ$eNuUj6B2ZqXlGi6KEqep39a7N4nysUIojuPXye+Ypp0") //nolint:lll
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View file

@ -7,7 +7,25 @@ import (
"git.gnous.eu/gnouseu/plakken/internal/utils" "git.gnous.eu/gnouseu/plakken/internal/utils"
) )
func TestCheckCharNotRedundantTrue(t *testing.T) { // Test CheckCharRedundant with redundant char func TestUtils(t *testing.T) {
t.Parallel()
testCheckCharNotRedundantTrue(t)
testCheckCharNotRedundantFalse(t)
testParseExpirationFull(t)
testParseExpirationMissing(t)
testParseExpirationWithCaps(t)
testParseExpirationNull(t)
testParseExpirationNegative(t)
testParseExpirationInvalid(t)
testParseExpirationInvalidRedundant(t)
testParseExpirationInvalidTooHigh(t)
testValidKey(t)
testInValidKey(t)
}
func testCheckCharNotRedundantTrue(t *testing.T) { // Test CheckCharRedundant with redundant char
t.Helper()
want := true want := true
got := utils.CheckCharRedundant("2d1h3md4h7s", "h") got := utils.CheckCharRedundant("2d1h3md4h7s", "h")
if got != want { if got != want {
@ -15,7 +33,8 @@ func TestCheckCharNotRedundantTrue(t *testing.T) { // Test CheckCharRedundant wi
} }
} }
func TestCheckCharNotRedundantFalse(t *testing.T) { // Test CheckCharRedundant with not redundant char func testCheckCharNotRedundantFalse(t *testing.T) { // Test CheckCharRedundant with not redundant char
t.Helper()
want := false want := false
got := utils.CheckCharRedundant("2d1h3m47s", "h") got := utils.CheckCharRedundant("2d1h3m47s", "h")
if got != want { if got != want {
@ -23,7 +42,8 @@ func TestCheckCharNotRedundantFalse(t *testing.T) { // Test CheckCharRedundant w
} }
} }
func TestParseExpirationFull(t *testing.T) { // test parseExpirationFull with all valid separator func testParseExpirationFull(t *testing.T) { // test parseExpirationFull with all valid separator
t.Helper()
result, _ := utils.ParseExpiration("2d1h3m47s") result, _ := utils.ParseExpiration("2d1h3m47s")
correctValue := 176627 correctValue := 176627
if result != correctValue { if result != correctValue {
@ -31,7 +51,8 @@ func TestParseExpirationFull(t *testing.T) { // test parseExpirationFull with al
} }
} }
func TestParseExpirationMissing(t *testing.T) { // test parseExpirationFull with all valid separator func testParseExpirationMissing(t *testing.T) { // test parseExpirationFull with all valid separator
t.Helper()
result, _ := utils.ParseExpiration("1h47s") result, _ := utils.ParseExpiration("1h47s")
correctValue := 3647 correctValue := 3647
if result != correctValue { if result != correctValue {
@ -39,7 +60,8 @@ func TestParseExpirationMissing(t *testing.T) { // test parseExpirationFull with
} }
} }
func TestParseExpirationWithCaps(t *testing.T) { // test parseExpirationFull with all valid separator func testParseExpirationWithCaps(t *testing.T) { // test parseExpirationFull with all valid separator
t.Helper()
result, _ := utils.ParseExpiration("2D1h3M47s") result, _ := utils.ParseExpiration("2D1h3M47s")
correctValue := 176627 correctValue := 176627
if result != correctValue { if result != correctValue {
@ -47,7 +69,8 @@ func TestParseExpirationWithCaps(t *testing.T) { // test parseExpirationFull wit
} }
} }
func TestParseExpirationNull(t *testing.T) { // test ParseExpirationFull with all valid separator func testParseExpirationNull(t *testing.T) { // test ParseExpirationFull with all valid separator
t.Helper()
result, _ := utils.ParseExpiration("0") result, _ := utils.ParseExpiration("0")
correctValue := 0 correctValue := 0
if result != correctValue { if result != correctValue {
@ -55,7 +78,8 @@ func TestParseExpirationNull(t *testing.T) { // test ParseExpirationFull with al
} }
} }
func TestParseExpirationNegative(t *testing.T) { // test ParseExpirationFull with all valid separator func testParseExpirationNegative(t *testing.T) { // test ParseExpirationFull with all valid separator
t.Helper()
_, got := utils.ParseExpiration("-42h1m4s") _, got := utils.ParseExpiration("-42h1m4s")
want := &utils.ParseExpirationError{} want := &utils.ParseExpirationError{}
if !errors.As(got, &want) { if !errors.As(got, &want) {
@ -63,16 +87,17 @@ func TestParseExpirationNegative(t *testing.T) { // test ParseExpirationFull wit
} }
} }
func TestParseExpirationInvalid(t *testing.T) { // test ParseExpirationFull with all valid separator func testParseExpirationInvalid(t *testing.T) { // test ParseExpirationFull with all valid separator
t.Helper()
_, got := utils.ParseExpiration("8h42h1m1d4s") _, got := utils.ParseExpiration("8h42h1m1d4s")
want := &utils.ParseExpirationError{} want := &utils.ParseExpirationError{}
if !errors.As(got, &want) { if !errors.As(got, &want) {
t.Fatal("Error in ParseExpirationFull, want : ", want, "got : ", got) t.Fatal("Error in ParseExpirationFull, want : ", want, "got : ", got)
} }
} }
func TestParseExpirationInvalidRedundant(t *testing.T) { // test ParseExpirationFull with all valid separator func testParseExpirationInvalidRedundant(t *testing.T) { // test ParseExpirationFull with all valid separator
t.Helper()
_, got := utils.ParseExpiration("8h42h1m1h4s") _, got := utils.ParseExpiration("8h42h1m1h4s")
want := &utils.ParseExpirationError{} want := &utils.ParseExpirationError{}
if !errors.As(got, &want) { if !errors.As(got, &want) {
@ -80,7 +105,8 @@ func TestParseExpirationInvalidRedundant(t *testing.T) { // test ParseExpiration
} }
} }
func TestParseExpirationInvalidTooHigh(t *testing.T) { // test ParseExpirationFull with all valid separator func testParseExpirationInvalidTooHigh(t *testing.T) { // test ParseExpirationFull with all valid separator
t.Helper()
_, got := utils.ParseExpiration("2d1h3m130s") _, got := utils.ParseExpiration("2d1h3m130s")
want := &utils.ParseExpirationError{} want := &utils.ParseExpirationError{}
if !errors.As(got, &want) { if !errors.As(got, &want) {
@ -88,7 +114,8 @@ func TestParseExpirationInvalidTooHigh(t *testing.T) { // test ParseExpirationFu
} }
} }
func TestValidKey(t *testing.T) { // test ValidKey with a valid key func testValidKey(t *testing.T) { // test ValidKey with a valid key
t.Helper()
got := utils.ValidKey("ab_a-C42") got := utils.ValidKey("ab_a-C42")
want := true want := true
@ -97,7 +124,8 @@ func TestValidKey(t *testing.T) { // test ValidKey with a valid key
} }
} }
func TestInValidKey(t *testing.T) { // test ValidKey with invalid key func testInValidKey(t *testing.T) { // test ValidKey with invalid key
t.Helper()
got := utils.ValidKey("ab_?a-C42") got := utils.ValidKey("ab_?a-C42")
want := false want := false