Compare commits
3 Commits
d85c9cb53c
...
f8f0302564
Author | SHA1 | Date | |
---|---|---|---|
f8f0302564 | |||
7b6a425908 | |||
591c24bab7 |
24
.drone.yml
24
.drone.yml
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
kind: pipeline
|
kind: pipeline
|
||||||
type: docker
|
type: docker
|
||||||
name: build
|
name: lint and test
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: lint
|
- name: lint
|
||||||
@ -18,10 +18,30 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- go test ./...
|
- go test ./...
|
||||||
|
|
||||||
- name: docker
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: build docker images
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- "lint and test"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: build master image
|
||||||
image: plugins/docker
|
image: plugins/docker
|
||||||
when:
|
when:
|
||||||
branch: ["master"]
|
branch: ["master"]
|
||||||
|
settings:
|
||||||
|
registry: code.pztrn.name
|
||||||
|
username: drone
|
||||||
|
password:
|
||||||
|
from_secret: drone_secret
|
||||||
|
repo: code.pztrn.name/pztrn/fastpastebin
|
||||||
|
auto_tag: true
|
||||||
|
|
||||||
|
- name: build tagged image
|
||||||
|
image: plugins/docker
|
||||||
|
when:
|
||||||
event: ["tag"]
|
event: ["tag"]
|
||||||
settings:
|
settings:
|
||||||
registry: code.pztrn.name
|
registry: code.pztrn.name
|
||||||
|
@ -15,6 +15,8 @@ linters:
|
|||||||
# This linter MIGHT BE good, but who decided that I want keepFor in
|
# This linter MIGHT BE good, but who decided that I want keepFor in
|
||||||
# JSON instead of keep_for for KeepFor field?
|
# JSON instead of keep_for for KeepFor field?
|
||||||
- tagliatelle
|
- tagliatelle
|
||||||
|
# Deprecated.
|
||||||
|
- exhaustivestruct
|
||||||
linters-settings:
|
linters-settings:
|
||||||
lll:
|
lll:
|
||||||
line-length: 420
|
line-length: 420
|
||||||
|
@ -28,13 +28,13 @@ import (
|
|||||||
"go.dev.pztrn.name/fastpastebin/internal/context"
|
"go.dev.pztrn.name/fastpastebin/internal/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
var c *context.Context
|
var ctx *context.Context
|
||||||
|
|
||||||
// New initializes pastes package and adds necessary HTTP and API
|
// New initializes pastes package and adds necessary HTTP and API
|
||||||
// endpoints.
|
// endpoints.
|
||||||
func New(cc *context.Context) {
|
func New(cc *context.Context) {
|
||||||
c = cc
|
ctx = cc
|
||||||
|
|
||||||
c.Echo.GET("/database_not_available", dbNotAvailableGet)
|
ctx.Echo.GET("/database_not_available", dbNotAvailableGet)
|
||||||
c.Echo.GET("/database_not_available/raw", dbNotAvailableRawGet)
|
ctx.Echo.GET("/database_not_available/raw", dbNotAvailableRawGet)
|
||||||
}
|
}
|
||||||
|
@ -28,12 +28,12 @@ import (
|
|||||||
"go.dev.pztrn.name/fastpastebin/internal/context"
|
"go.dev.pztrn.name/fastpastebin/internal/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
var c *context.Context
|
var ctx *context.Context
|
||||||
|
|
||||||
// New initializes pastes package and adds necessary HTTP and API
|
// New initializes pastes package and adds necessary HTTP and API
|
||||||
// endpoints.
|
// endpoints.
|
||||||
func New(cc *context.Context) {
|
func New(cc *context.Context) {
|
||||||
c = cc
|
ctx = cc
|
||||||
|
|
||||||
c.Echo.GET("/", indexGet)
|
ctx.Echo.GET("/", indexGet)
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,8 @@ import (
|
|||||||
// Index of this site.
|
// Index of this site.
|
||||||
func indexGet(ectx echo.Context) error {
|
func indexGet(ectx echo.Context) error {
|
||||||
// We should check if database connection available.
|
// We should check if database connection available.
|
||||||
dbConn := c.Database.GetDatabaseConnection()
|
dbConn := ctx.Database.GetDatabaseConnection()
|
||||||
if c.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil {
|
if ctx.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil {
|
||||||
// nolint:wrapcheck
|
// nolint:wrapcheck
|
||||||
return ectx.Redirect(http.StatusFound, "/database_not_available")
|
return ectx.Redirect(http.StatusFound, "/database_not_available")
|
||||||
}
|
}
|
||||||
|
@ -32,30 +32,30 @@ import (
|
|||||||
|
|
||||||
var regexInts = regexp.MustCompile("[0-9]+")
|
var regexInts = regexp.MustCompile("[0-9]+")
|
||||||
|
|
||||||
var c *context.Context
|
var ctx *context.Context
|
||||||
|
|
||||||
// New initializes pastes package and adds necessary HTTP and API
|
// New initializes pastes package and adds necessary HTTP and API
|
||||||
// endpoints.
|
// endpoints.
|
||||||
func New(cc *context.Context) {
|
func New(cc *context.Context) {
|
||||||
c = cc
|
ctx = cc
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// HTTP endpoints.
|
// HTTP endpoints.
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// New paste.
|
// New paste.
|
||||||
c.Echo.POST("/paste/", pastePOSTWebInterface)
|
ctx.Echo.POST("/paste/", pastePOSTWebInterface)
|
||||||
// Show public paste.
|
// Show public paste.
|
||||||
c.Echo.GET("/paste/:id", pasteGETWebInterface)
|
ctx.Echo.GET("/paste/:id", pasteGETWebInterface)
|
||||||
// Show RAW representation of public paste.
|
// Show RAW representation of public paste.
|
||||||
c.Echo.GET("/paste/:id/raw", pasteRawGETWebInterface)
|
ctx.Echo.GET("/paste/:id/raw", pasteRawGETWebInterface)
|
||||||
// Show private paste.
|
// Show private paste.
|
||||||
c.Echo.GET("/paste/:id/:timestamp", pasteGETWebInterface)
|
ctx.Echo.GET("/paste/:id/:timestamp", pasteGETWebInterface)
|
||||||
// Show RAW representation of private paste.
|
// Show RAW representation of private paste.
|
||||||
c.Echo.GET("/paste/:id/:timestamp/raw", pasteRawGETWebInterface)
|
ctx.Echo.GET("/paste/:id/:timestamp/raw", pasteRawGETWebInterface)
|
||||||
// Verify access to passworded paste.
|
// Verify access to passworded paste.
|
||||||
c.Echo.GET("/paste/:id/:timestamp/verify", pastePasswordedVerifyGet)
|
ctx.Echo.GET("/paste/:id/:timestamp/verify", pastePasswordedVerifyGet)
|
||||||
c.Echo.POST("/paste/:id/:timestamp/verify", pastePasswordedVerifyPost)
|
ctx.Echo.POST("/paste/:id/:timestamp/verify", pastePasswordedVerifyPost)
|
||||||
// Pastes list.
|
// Pastes list.
|
||||||
c.Echo.GET("/pastes/", pastesGET)
|
ctx.Echo.GET("/pastes/", pastesGET)
|
||||||
c.Echo.GET("/pastes/:page", pastesGET)
|
ctx.Echo.GET("/pastes/:page", pastesGET)
|
||||||
}
|
}
|
||||||
|
@ -31,16 +31,16 @@ const (
|
|||||||
// value (they both will be ignored), but private will.
|
// value (they both will be ignored), but private will.
|
||||||
func pasteGetData(pasteID int, timestamp int64, cookieValue string) (*structs.Paste, string) {
|
func pasteGetData(pasteID int, timestamp int64, cookieValue string) (*structs.Paste, string) {
|
||||||
// Get paste.
|
// Get paste.
|
||||||
paste, err1 := c.Database.GetPaste(pasteID)
|
paste, err1 := ctx.Database.GetPaste(pasteID)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
c.Logger.Error().Err(err1).Int("paste ID", pasteID).Msg("Failed to get paste")
|
ctx.Logger.Error().Err(err1).Int("paste ID", pasteID).Msg("Failed to get paste")
|
||||||
|
|
||||||
return nil, pasteNotFound
|
return nil, pasteNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if paste is expired.
|
// Check if paste is expired.
|
||||||
if paste.IsExpired() {
|
if paste.IsExpired() {
|
||||||
c.Logger.Error().Int("paste ID", pasteID).Msg("Paste is expired")
|
ctx.Logger.Error().Int("paste ID", pasteID).Msg("Paste is expired")
|
||||||
|
|
||||||
return nil, pasteExpired
|
return nil, pasteExpired
|
||||||
}
|
}
|
||||||
@ -49,7 +49,7 @@ func pasteGetData(pasteID int, timestamp int64, cookieValue string) (*structs.Pa
|
|||||||
if paste.Private {
|
if paste.Private {
|
||||||
pasteTS := paste.CreatedAt.Unix()
|
pasteTS := paste.CreatedAt.Unix()
|
||||||
if timestamp != pasteTS {
|
if timestamp != pasteTS {
|
||||||
c.Logger.Error().Int("paste ID", pasteID).Int64("paste timestamp", pasteTS).Int64("provided timestamp", timestamp).Msg("Incorrect timestamp provided for private paste")
|
ctx.Logger.Error().Int("paste ID", pasteID).Int64("paste timestamp", pasteTS).Int64("provided timestamp", timestamp).Msg("Incorrect timestamp provided for private paste")
|
||||||
|
|
||||||
return nil, pasteTimestampInvalid
|
return nil, pasteTimestampInvalid
|
||||||
}
|
}
|
||||||
@ -78,7 +78,7 @@ func pasteGETWebInterface(ectx echo.Context) error {
|
|||||||
// error.
|
// error.
|
||||||
pasteID, _ := strconv.Atoi(regexInts.FindAllString(pasteIDRaw, 1)[0])
|
pasteID, _ := strconv.Atoi(regexInts.FindAllString(pasteIDRaw, 1)[0])
|
||||||
pasteIDStr := strconv.Itoa(pasteID)
|
pasteIDStr := strconv.Itoa(pasteID)
|
||||||
c.Logger.Debug().Int("paste ID", pasteID).Msg("Trying to get paste data")
|
ctx.Logger.Debug().Int("paste ID", pasteID).Msg("Trying to get paste data")
|
||||||
|
|
||||||
// Check if we have timestamp passed.
|
// Check if we have timestamp passed.
|
||||||
// If passed timestamp is invalid (isn't a real UNIX timestamp) we
|
// If passed timestamp is invalid (isn't a real UNIX timestamp) we
|
||||||
@ -89,7 +89,7 @@ func pasteGETWebInterface(ectx echo.Context) error {
|
|||||||
if tsProvidedStr != "" {
|
if tsProvidedStr != "" {
|
||||||
tsProvided, err := strconv.ParseInt(tsProvidedStr, 10, 64)
|
tsProvided, err := strconv.ParseInt(tsProvidedStr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Error().Err(err).Int("paste ID", pasteID).Int64("provided timestamp", tsProvided).Msg("Invalid timestamp provided for getting private paste")
|
ctx.Logger.Error().Err(err).Int("paste ID", pasteID).Int64("provided timestamp", tsProvided).Msg("Invalid timestamp provided for getting private paste")
|
||||||
|
|
||||||
errtpl := templater.GetErrorTemplate(ectx, "Paste #"+pasteIDStr+" not found")
|
errtpl := templater.GetErrorTemplate(ectx, "Paste #"+pasteIDStr+" not found")
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ func pasteGETWebInterface(ectx echo.Context) error {
|
|||||||
// If passed cookie value was invalid - go to paste authorization
|
// If passed cookie value was invalid - go to paste authorization
|
||||||
// page.
|
// page.
|
||||||
if err == pasteCookieInvalid {
|
if err == pasteCookieInvalid {
|
||||||
c.Logger.Info().Int("paste ID", pasteID).Msg("Invalid cookie, redirecting to auth page")
|
ctx.Logger.Info().Int("paste ID", pasteID).Msg("Invalid cookie, redirecting to auth page")
|
||||||
|
|
||||||
// nolint:wrapcheck
|
// nolint:wrapcheck
|
||||||
return ectx.Redirect(http.StatusMovedPermanently, "/paste/"+pasteIDStr+"/"+ectx.Param("timestamp")+"/verify")
|
return ectx.Redirect(http.StatusMovedPermanently, "/paste/"+pasteIDStr+"/"+ectx.Param("timestamp")+"/verify")
|
||||||
@ -159,7 +159,7 @@ func pasteGETWebInterface(ectx echo.Context) error {
|
|||||||
// Tokenize paste data.
|
// Tokenize paste data.
|
||||||
lexered, err3 := lexer.Tokenise(nil, paste.Data)
|
lexered, err3 := lexer.Tokenise(nil, paste.Data)
|
||||||
if err3 != nil {
|
if err3 != nil {
|
||||||
c.Logger.Error().Err(err3).Msg("Failed to tokenize paste data")
|
ctx.Logger.Error().Err(err3).Msg("Failed to tokenize paste data")
|
||||||
}
|
}
|
||||||
// Get style for HTML output.
|
// Get style for HTML output.
|
||||||
style := styles.Get("monokai")
|
style := styles.Get("monokai")
|
||||||
@ -174,7 +174,7 @@ func pasteGETWebInterface(ectx echo.Context) error {
|
|||||||
|
|
||||||
err4 := formatter.Format(buf, style, lexered)
|
err4 := formatter.Format(buf, style, lexered)
|
||||||
if err4 != nil {
|
if err4 != nil {
|
||||||
c.Logger.Error().Err(err4).Msg("Failed to format paste data")
|
ctx.Logger.Error().Err(err4).Msg("Failed to format paste data")
|
||||||
}
|
}
|
||||||
|
|
||||||
pasteData["pastedata"] = buf.String()
|
pasteData["pastedata"] = buf.String()
|
||||||
@ -195,9 +195,9 @@ func pastePasswordedVerifyGet(ectx echo.Context) error {
|
|||||||
pasteID, _ := strconv.Atoi(regexInts.FindAllString(pasteIDRaw, 1)[0])
|
pasteID, _ := strconv.Atoi(regexInts.FindAllString(pasteIDRaw, 1)[0])
|
||||||
|
|
||||||
// Get paste.
|
// Get paste.
|
||||||
paste, err1 := c.Database.GetPaste(pasteID)
|
paste, err1 := ctx.Database.GetPaste(pasteID)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
c.Logger.Error().Err(err1).Int("paste ID", pasteID).Msg("Failed to get paste data")
|
ctx.Logger.Error().Err(err1).Int("paste ID", pasteID).Msg("Failed to get paste data")
|
||||||
|
|
||||||
errtpl := templater.GetErrorTemplate(ectx, "Paste #"+pasteIDRaw+" not found")
|
errtpl := templater.GetErrorTemplate(ectx, "Paste #"+pasteIDRaw+" not found")
|
||||||
|
|
||||||
@ -209,19 +209,19 @@ func pastePasswordedVerifyGet(ectx echo.Context) error {
|
|||||||
cookie, err := ectx.Cookie("PASTE-" + strconv.Itoa(pasteID))
|
cookie, err := ectx.Cookie("PASTE-" + strconv.Itoa(pasteID))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// No cookie, redirect to auth page.
|
// No cookie, redirect to auth page.
|
||||||
c.Logger.Debug().Msg("Paste cookie found, checking it...")
|
ctx.Logger.Debug().Msg("Paste cookie found, checking it...")
|
||||||
|
|
||||||
// Generate cookie value to check.
|
// Generate cookie value to check.
|
||||||
cookieValue := paste.GenerateCryptedCookieValue()
|
cookieValue := paste.GenerateCryptedCookieValue()
|
||||||
|
|
||||||
if cookieValue == cookie.Value {
|
if cookieValue == cookie.Value {
|
||||||
c.Logger.Info().Msg("Valid cookie, redirecting to paste page...")
|
ctx.Logger.Info().Msg("Valid cookie, redirecting to paste page...")
|
||||||
|
|
||||||
// nolint:wrapcheck
|
// nolint:wrapcheck
|
||||||
return ectx.Redirect(http.StatusMovedPermanently, "/paste/"+pasteIDRaw+"/"+ectx.Param("timestamp"))
|
return ectx.Redirect(http.StatusMovedPermanently, "/paste/"+pasteIDRaw+"/"+ectx.Param("timestamp"))
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Logger.Debug().Msg("Invalid cookie, showing auth page")
|
ctx.Logger.Debug().Msg("Invalid cookie, showing auth page")
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTML data.
|
// HTML data.
|
||||||
@ -238,9 +238,9 @@ func pastePasswordedVerifyGet(ectx echo.Context) error {
|
|||||||
// POST for "/paste/PASTE_ID/TIMESTAMP/verify" - a password verify page.
|
// POST for "/paste/PASTE_ID/TIMESTAMP/verify" - a password verify page.
|
||||||
func pastePasswordedVerifyPost(ectx echo.Context) error {
|
func pastePasswordedVerifyPost(ectx echo.Context) error {
|
||||||
// We should check if database connection available.
|
// We should check if database connection available.
|
||||||
dbConn := c.Database.GetDatabaseConnection()
|
dbConn := ctx.Database.GetDatabaseConnection()
|
||||||
|
|
||||||
if c.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil {
|
if ctx.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil {
|
||||||
// nolint:wrapcheck
|
// nolint:wrapcheck
|
||||||
return ectx.Redirect(http.StatusFound, "/database_not_available")
|
return ectx.Redirect(http.StatusFound, "/database_not_available")
|
||||||
}
|
}
|
||||||
@ -250,12 +250,12 @@ func pastePasswordedVerifyPost(ectx echo.Context) error {
|
|||||||
// We already get numbers from string, so we will not check strconv.Atoi()
|
// We already get numbers from string, so we will not check strconv.Atoi()
|
||||||
// error.
|
// error.
|
||||||
pasteID, _ := strconv.Atoi(regexInts.FindAllString(pasteIDRaw, 1)[0])
|
pasteID, _ := strconv.Atoi(regexInts.FindAllString(pasteIDRaw, 1)[0])
|
||||||
c.Logger.Debug().Int("paste ID", pasteID).Msg("Requesting paste")
|
ctx.Logger.Debug().Int("paste ID", pasteID).Msg("Requesting paste")
|
||||||
|
|
||||||
// Get paste.
|
// Get paste.
|
||||||
paste, err1 := c.Database.GetPaste(pasteID)
|
paste, err1 := ctx.Database.GetPaste(pasteID)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
c.Logger.Error().Err(err1).Int("paste ID", pasteID).Msg("Failed to get paste")
|
ctx.Logger.Error().Err(err1).Int("paste ID", pasteID).Msg("Failed to get paste")
|
||||||
errtpl := templater.GetErrorTemplate(ectx, "Paste #"+strconv.Itoa(pasteID)+" not found")
|
errtpl := templater.GetErrorTemplate(ectx, "Paste #"+strconv.Itoa(pasteID)+" not found")
|
||||||
|
|
||||||
// nolint:wrapcheck
|
// nolint:wrapcheck
|
||||||
@ -264,7 +264,7 @@ func pastePasswordedVerifyPost(ectx echo.Context) error {
|
|||||||
|
|
||||||
params, err2 := ectx.FormParams()
|
params, err2 := ectx.FormParams()
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
c.Logger.Debug().Msg("No form parameters passed")
|
ctx.Logger.Debug().Msg("No form parameters passed")
|
||||||
|
|
||||||
errtpl := templater.GetErrorTemplate(ectx, "Paste #"+strconv.Itoa(pasteID)+" not found")
|
errtpl := templater.GetErrorTemplate(ectx, "Paste #"+strconv.Itoa(pasteID)+" not found")
|
||||||
|
|
||||||
@ -295,8 +295,8 @@ func pastePasswordedVerifyPost(ectx echo.Context) error {
|
|||||||
// Web interface version.
|
// Web interface version.
|
||||||
func pasteRawGETWebInterface(ectx echo.Context) error {
|
func pasteRawGETWebInterface(ectx echo.Context) error {
|
||||||
// We should check if database connection available.
|
// We should check if database connection available.
|
||||||
dbConn := c.Database.GetDatabaseConnection()
|
dbConn := ctx.Database.GetDatabaseConnection()
|
||||||
if c.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil {
|
if ctx.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil {
|
||||||
// nolint:wrapcheck
|
// nolint:wrapcheck
|
||||||
return ectx.Redirect(http.StatusFound, "/database_not_available/raw")
|
return ectx.Redirect(http.StatusFound, "/database_not_available/raw")
|
||||||
}
|
}
|
||||||
@ -305,19 +305,19 @@ func pasteRawGETWebInterface(ectx echo.Context) error {
|
|||||||
// We already get numbers from string, so we will not check strconv.Atoi()
|
// We already get numbers from string, so we will not check strconv.Atoi()
|
||||||
// error.
|
// error.
|
||||||
pasteID, _ := strconv.Atoi(regexInts.FindAllString(pasteIDRaw, 1)[0])
|
pasteID, _ := strconv.Atoi(regexInts.FindAllString(pasteIDRaw, 1)[0])
|
||||||
c.Logger.Debug().Int("paste ID", pasteID).Msg("Requesting paste data")
|
ctx.Logger.Debug().Int("paste ID", pasteID).Msg("Requesting paste data")
|
||||||
|
|
||||||
// Get paste.
|
// Get paste.
|
||||||
paste, err1 := c.Database.GetPaste(pasteID)
|
paste, err1 := ctx.Database.GetPaste(pasteID)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
c.Logger.Error().Err(err1).Int("paste ID", pasteID).Msg("Failed to get paste from database")
|
ctx.Logger.Error().Err(err1).Int("paste ID", pasteID).Msg("Failed to get paste from database")
|
||||||
|
|
||||||
// nolint:wrapcheck
|
// nolint:wrapcheck
|
||||||
return ectx.HTML(http.StatusBadRequest, "Paste #"+pasteIDRaw+" does not exist.")
|
return ectx.HTML(http.StatusBadRequest, "Paste #"+pasteIDRaw+" does not exist.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if paste.IsExpired() {
|
if paste.IsExpired() {
|
||||||
c.Logger.Error().Int("paste ID", pasteID).Msg("Paste is expired")
|
ctx.Logger.Error().Int("paste ID", pasteID).Msg("Paste is expired")
|
||||||
|
|
||||||
// nolint:wrapcheck
|
// nolint:wrapcheck
|
||||||
return ectx.HTML(http.StatusBadRequest, "Paste #"+pasteIDRaw+" does not exist.")
|
return ectx.HTML(http.StatusBadRequest, "Paste #"+pasteIDRaw+" does not exist.")
|
||||||
@ -329,7 +329,7 @@ func pasteRawGETWebInterface(ectx echo.Context) error {
|
|||||||
|
|
||||||
tsProvided, err2 := strconv.ParseInt(tsProvidedStr, 10, 64)
|
tsProvided, err2 := strconv.ParseInt(tsProvidedStr, 10, 64)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
c.Logger.Error().Err(err2).Int("paste ID", pasteID).Str("provided timestamp", tsProvidedStr).Msg("Invalid timestamp provided for getting private paste")
|
ctx.Logger.Error().Err(err2).Int("paste ID", pasteID).Str("provided timestamp", tsProvidedStr).Msg("Invalid timestamp provided for getting private paste")
|
||||||
|
|
||||||
// nolint:wrapcheck
|
// nolint:wrapcheck
|
||||||
return ectx.String(http.StatusBadRequest, "Paste #"+pasteIDRaw+" not found")
|
return ectx.String(http.StatusBadRequest, "Paste #"+pasteIDRaw+" not found")
|
||||||
@ -337,7 +337,7 @@ func pasteRawGETWebInterface(ectx echo.Context) error {
|
|||||||
|
|
||||||
pasteTS := paste.CreatedAt.Unix()
|
pasteTS := paste.CreatedAt.Unix()
|
||||||
if tsProvided != pasteTS {
|
if tsProvided != pasteTS {
|
||||||
c.Logger.Error().Int("paste ID", pasteID).Int64("provided timestamp", tsProvided).Int64("paste timestamp", pasteTS).Msg("Incorrect timestamp provided for private paste")
|
ctx.Logger.Error().Int("paste ID", pasteID).Int64("provided timestamp", tsProvided).Int64("paste timestamp", pasteTS).Msg("Incorrect timestamp provided for private paste")
|
||||||
|
|
||||||
// nolint:wrapcheck
|
// nolint:wrapcheck
|
||||||
return ectx.String(http.StatusBadRequest, "Paste #"+pasteIDRaw+" not found")
|
return ectx.String(http.StatusBadRequest, "Paste #"+pasteIDRaw+" not found")
|
||||||
@ -348,7 +348,7 @@ func pasteRawGETWebInterface(ectx echo.Context) error {
|
|||||||
// ToDo: figure out how to handle passworded pastes here.
|
// ToDo: figure out how to handle passworded pastes here.
|
||||||
// Return error for now.
|
// Return error for now.
|
||||||
if paste.Password != "" {
|
if paste.Password != "" {
|
||||||
c.Logger.Error().Int("paste ID", pasteID).Msg("Cannot render paste as raw: passworded paste. Patches welcome!")
|
ctx.Logger.Error().Int("paste ID", pasteID).Msg("Cannot render paste as raw: passworded paste. Patches welcome!")
|
||||||
return ectx.String(http.StatusBadRequest, "Paste #"+pasteIDRaw+" not found")
|
return ectx.String(http.StatusBadRequest, "Paste #"+pasteIDRaw+" not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,15 +22,15 @@ const KeepPastesForever = "forever"
|
|||||||
// requests comes from browsers via web interface.
|
// requests comes from browsers via web interface.
|
||||||
func pastePOSTWebInterface(ectx echo.Context) error {
|
func pastePOSTWebInterface(ectx echo.Context) error {
|
||||||
// We should check if database connection available.
|
// We should check if database connection available.
|
||||||
dbConn := c.Database.GetDatabaseConnection()
|
dbConn := ctx.Database.GetDatabaseConnection()
|
||||||
if c.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil {
|
if ctx.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil {
|
||||||
// nolint:wrapcheck
|
// nolint:wrapcheck
|
||||||
return ectx.Redirect(http.StatusFound, "/database_not_available")
|
return ectx.Redirect(http.StatusFound, "/database_not_available")
|
||||||
}
|
}
|
||||||
|
|
||||||
params, err := ectx.FormParams()
|
params, err := ectx.FormParams()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Error().Msg("Passed paste form is empty")
|
ctx.Logger.Error().Msg("Passed paste form is empty")
|
||||||
|
|
||||||
errtpl := templater.GetErrorTemplate(ectx, "Cannot create empty paste")
|
errtpl := templater.GetErrorTemplate(ectx, "Cannot create empty paste")
|
||||||
|
|
||||||
@ -38,11 +38,11 @@ func pastePOSTWebInterface(ectx echo.Context) error {
|
|||||||
return ectx.HTML(http.StatusBadRequest, errtpl)
|
return ectx.HTML(http.StatusBadRequest, errtpl)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Logger.Debug().Msgf("Received parameters: %+v", params)
|
ctx.Logger.Debug().Msgf("Received parameters: %+v", params)
|
||||||
|
|
||||||
// Do nothing if paste contents is empty.
|
// Do nothing if paste contents is empty.
|
||||||
if len(params["paste-contents"][0]) == 0 {
|
if len(params["paste-contents"][0]) == 0 {
|
||||||
c.Logger.Debug().Msg("Empty paste submitted, ignoring")
|
ctx.Logger.Debug().Msg("Empty paste submitted, ignoring")
|
||||||
|
|
||||||
errtpl := templater.GetErrorTemplate(ectx, "Empty pastes aren't allowed.")
|
errtpl := templater.GetErrorTemplate(ectx, "Empty pastes aren't allowed.")
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ func pastePOSTWebInterface(ectx echo.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !strings.ContainsAny(params["paste-keep-for"][0], "Mmhd") && params["paste-keep-for"][0] != KeepPastesForever {
|
if !strings.ContainsAny(params["paste-keep-for"][0], "Mmhd") && params["paste-keep-for"][0] != KeepPastesForever {
|
||||||
c.Logger.Debug().Str("field value", params["paste-keep-for"][0]).Msg("'Keep paste for' field have invalid value")
|
ctx.Logger.Debug().Str("field value", params["paste-keep-for"][0]).Msg("'Keep paste for' field have invalid value")
|
||||||
|
|
||||||
errtpl := templater.GetErrorTemplate(ectx, "Invalid 'Paste should be available for' parameter passed. Please do not try to hack us ;).")
|
errtpl := templater.GetErrorTemplate(ectx, "Invalid 'Paste should be available for' parameter passed. Please do not try to hack us ;).")
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ func pastePOSTWebInterface(ectx echo.Context) error {
|
|||||||
|
|
||||||
// Verify captcha.
|
// Verify captcha.
|
||||||
if !captcha.Verify(params["paste-captcha-id"][0], params["paste-captcha-solution"][0]) {
|
if !captcha.Verify(params["paste-captcha-id"][0], params["paste-captcha-solution"][0]) {
|
||||||
c.Logger.Debug().Str("captcha ID", params["paste-captcha-id"][0]).Str("captcha solution", params["paste-captcha-solution"][0]).Msg("Invalid captcha solution")
|
ctx.Logger.Debug().Str("captcha ID", params["paste-captcha-id"][0]).Str("captcha solution", params["paste-captcha-solution"][0]).Msg("Invalid captcha solution")
|
||||||
|
|
||||||
errtpl := templater.GetErrorTemplate(ectx, "Invalid captcha solution.")
|
errtpl := templater.GetErrorTemplate(ectx, "Invalid captcha solution.")
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ func pastePOSTWebInterface(ectx echo.Context) error {
|
|||||||
return ectx.HTML(http.StatusBadRequest, errtpl)
|
return ectx.HTML(http.StatusBadRequest, errtpl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// nolint:exhaustivestruct
|
// nolint:exhaustruct
|
||||||
paste := &structs.Paste{
|
paste := &structs.Paste{
|
||||||
Title: params["paste-title"][0],
|
Title: params["paste-title"][0],
|
||||||
Data: params["paste-contents"][0],
|
Data: params["paste-contents"][0],
|
||||||
@ -95,11 +95,11 @@ func pastePOSTWebInterface(ectx echo.Context) error {
|
|||||||
keepFor, err = strconv.Atoi(keepForRaw)
|
keepFor, err = strconv.Atoi(keepForRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if params["paste-keep-for"][0] == KeepPastesForever {
|
if params["paste-keep-for"][0] == KeepPastesForever {
|
||||||
c.Logger.Debug().Msg("Keeping paste forever!")
|
ctx.Logger.Debug().Msg("Keeping paste forever!")
|
||||||
|
|
||||||
keepFor = 0
|
keepFor = 0
|
||||||
} else {
|
} else {
|
||||||
c.Logger.Debug().Err(err).Msg("Failed to parse 'Keep for' integer")
|
ctx.Logger.Debug().Err(err).Msg("Failed to parse 'Keep for' integer")
|
||||||
|
|
||||||
errtpl := templater.GetErrorTemplate(ectx, "Invalid 'Paste should be available for' parameter passed. Please do not try to hack us ;).")
|
errtpl := templater.GetErrorTemplate(ectx, "Invalid 'Paste should be available for' parameter passed. Please do not try to hack us ;).")
|
||||||
|
|
||||||
@ -138,9 +138,9 @@ func pastePOSTWebInterface(ectx echo.Context) error {
|
|||||||
_ = paste.CreatePassword(pastePassword[0])
|
_ = paste.CreatePassword(pastePassword[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
pasteID, err2 := c.Database.SavePaste(paste)
|
pasteID, err2 := ctx.Database.SavePaste(paste)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
c.Logger.Error().Err(err2).Msg("Failed to save paste")
|
ctx.Logger.Error().Err(err2).Msg("Failed to save paste")
|
||||||
|
|
||||||
errtpl := templater.GetErrorTemplate(ectx, "Failed to save paste. Please, try again later.")
|
errtpl := templater.GetErrorTemplate(ectx, "Failed to save paste. Please, try again later.")
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ func pastePOSTWebInterface(ectx echo.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
newPasteIDAsString := strconv.FormatInt(pasteID, 10)
|
newPasteIDAsString := strconv.FormatInt(pasteID, 10)
|
||||||
c.Logger.Debug().Msg("Paste saved, URL: /paste/" + newPasteIDAsString)
|
ctx.Logger.Debug().Msg("Paste saved, URL: /paste/" + newPasteIDAsString)
|
||||||
|
|
||||||
// Private pastes have it's timestamp in URL.
|
// Private pastes have it's timestamp in URL.
|
||||||
if paste.Private {
|
if paste.Private {
|
||||||
|
@ -39,8 +39,8 @@ import (
|
|||||||
// Web interface version.
|
// Web interface version.
|
||||||
func pastesGET(ectx echo.Context) error {
|
func pastesGET(ectx echo.Context) error {
|
||||||
// We should check if database connection available.
|
// We should check if database connection available.
|
||||||
dbConn := c.Database.GetDatabaseConnection()
|
dbConn := ctx.Database.GetDatabaseConnection()
|
||||||
if c.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil {
|
if ctx.Config.Database.Type != flatfiles.FlatFileDialect && dbConn == nil {
|
||||||
// nolint:wrapcheck
|
// nolint:wrapcheck
|
||||||
return ectx.Redirect(http.StatusFound, "/database_not_available")
|
return ectx.Redirect(http.StatusFound, "/database_not_available")
|
||||||
}
|
}
|
||||||
@ -54,17 +54,17 @@ func pastesGET(ectx echo.Context) error {
|
|||||||
page, _ = strconv.Atoi(pageRaw)
|
page, _ = strconv.Atoi(pageRaw)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Logger.Debug().Int("page", page).Msg("Requested page")
|
ctx.Logger.Debug().Int("page", page).Msg("Requested page")
|
||||||
|
|
||||||
// Get pastes IDs.
|
// Get pastes IDs.
|
||||||
pastes, err3 := c.Database.GetPagedPastes(page)
|
pastes, err3 := ctx.Database.GetPagedPastes(page)
|
||||||
c.Logger.Debug().Int("count", len(pastes)).Msg("Got pastes")
|
ctx.Logger.Debug().Int("count", len(pastes)).Msg("Got pastes")
|
||||||
|
|
||||||
pastesString := "No pastes to show."
|
pastesString := "No pastes to show."
|
||||||
|
|
||||||
// Show "No pastes to show" on any error for now.
|
// Show "No pastes to show" on any error for now.
|
||||||
if err3 != nil {
|
if err3 != nil {
|
||||||
c.Logger.Error().Err(err3).Msg("Failed to get pastes list from database")
|
ctx.Logger.Error().Err(err3).Msg("Failed to get pastes list from database")
|
||||||
|
|
||||||
noPastesToShowTpl := templater.GetErrorTemplate(ectx, "No pastes to show.")
|
noPastesToShowTpl := templater.GetErrorTemplate(ectx, "No pastes to show.")
|
||||||
|
|
||||||
@ -100,8 +100,8 @@ func pastesGET(ectx echo.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pagination.
|
// Pagination.
|
||||||
pages := c.Database.GetPastesPages()
|
pages := ctx.Database.GetPastesPages()
|
||||||
c.Logger.Debug().Int("total pages", pages).Int("current page", page).Msg("Paging data")
|
ctx.Logger.Debug().Int("total pages", pages).Int("current page", page).Msg("Paging data")
|
||||||
paginationHTML := pagination.CreateHTML(page, pages, "/pastes/")
|
paginationHTML := pagination.CreateHTML(page, pages, "/pastes/")
|
||||||
|
|
||||||
pasteListTpl := templater.GetTemplate(ectx, "pastelist_list.html", map[string]string{"pastes": pastesString, "pagination": paginationHTML})
|
pasteListTpl := templater.GetTemplate(ectx, "pastelist_list.html", map[string]string{"pastes": pastesString, "pagination": paginationHTML})
|
||||||
|
25
go.mod
25
go.mod
@ -3,20 +3,21 @@ module go.dev.pztrn.name/fastpastebin
|
|||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/alecthomas/chroma v0.8.2
|
github.com/alecthomas/chroma v0.10.0
|
||||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
|
||||||
github.com/dlclark/regexp2 v1.4.0 // indirect
|
github.com/go-sql-driver/mysql v1.6.0
|
||||||
github.com/go-sql-driver/mysql v1.5.0
|
github.com/jmoiron/sqlx v1.3.5
|
||||||
github.com/jmoiron/sqlx v1.2.0
|
github.com/kr/pretty v0.3.0 // indirect
|
||||||
github.com/labstack/echo v3.3.10+incompatible
|
github.com/labstack/echo v3.3.10+incompatible
|
||||||
github.com/labstack/gommon v0.3.0 // indirect
|
github.com/labstack/gommon v0.3.1 // indirect
|
||||||
github.com/lib/pq v1.9.0
|
github.com/lib/pq v1.10.6
|
||||||
github.com/pressly/goose v2.6.0+incompatible
|
github.com/pressly/goose v2.7.0+incompatible
|
||||||
github.com/rs/zerolog v1.20.0
|
github.com/rs/zerolog v1.27.0
|
||||||
go.dev.pztrn.name/flagger v0.0.0-20200617193309-89bc9818b76c
|
go.dev.pztrn.name/flagger v0.0.0-20211119225333-c010875aa337
|
||||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
|
||||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b
|
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 // indirect
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
mvdan.cc/gofumpt v0.1.1 // indirect
|
|
||||||
)
|
)
|
||||||
|
163
go.sum
163
go.sum
@ -1,15 +1,7 @@
|
|||||||
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
|
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
|
||||||
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
|
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
|
||||||
github.com/alecthomas/chroma v0.8.2 h1:x3zkuE2lUk/RIekyAJ3XRqSCP4zwWDfcw/YJCuCAACg=
|
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/alecthomas/chroma v0.8.2/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo=
|
|
||||||
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
|
|
||||||
github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
|
|
||||||
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
|
|
||||||
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
|
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
|
||||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
|
|
||||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@ -17,118 +9,83 @@ github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f h1:q/DpyjJjZs94bziQ
|
|||||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f/go.mod h1:QGrK8vMWWHQYQ3QU9bw9Y9OPNfxccGzfb41qjvVeXtY=
|
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f/go.mod h1:QGrK8vMWWHQYQ3QU9bw9Y9OPNfxccGzfb41qjvVeXtY=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
|
|
||||||
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
|
||||||
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
|
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/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
|
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
|
||||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
|
||||||
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
|
|
||||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
|
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||||
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
|
github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
|
||||||
github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
|
github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
|
||||||
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
|
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
|
||||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8=
|
github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
|
||||||
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||||
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
|
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
|
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
|
||||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
|
||||||
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
|
|
||||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pressly/goose v2.6.0+incompatible h1:3f8zIQ8rfgP9tyI0Hmcs2YNAqUCL1c+diLe3iU8Qd/k=
|
github.com/pressly/goose v2.7.0+incompatible h1:PWejVEv07LCerQEzMMeAtjuyCKbyprZ/LBa6K5P0OCQ=
|
||||||
github.com/pressly/goose v2.6.0+incompatible/go.mod h1:m+QHWCqxR3k8D9l7qfzuC/djtlfzxr34mozWDYEu1z8=
|
github.com/pressly/goose v2.7.0+incompatible/go.mod h1:m+QHWCqxR3k8D9l7qfzuC/djtlfzxr34mozWDYEu1z8=
|
||||||
github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rs/zerolog v1.20.0 h1:38k9hgtUBdxFwE34yS8rTHmHBa4eN16E4DJlv177LNs=
|
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
github.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
|
github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs=
|
||||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
|
||||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
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/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
|
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
|
||||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
go.dev.pztrn.name/flagger v0.0.0-20211119225333-c010875aa337 h1:OerezdlV+T80z1tCzOQg6HSpjheU3dmxHbUbQ8NVSAs=
|
||||||
go.dev.pztrn.name/flagger v0.0.0-20200617193309-89bc9818b76c h1:+GgFefaTLsYDS0lXc8LNzTo6tcsA9qO3EkTAKduPAsI=
|
go.dev.pztrn.name/flagger v0.0.0-20211119225333-c010875aa337/go.mod h1:ttPExQNCubgqqO5Y19LfIBKqmWtBocY7P9MXQEECuZo=
|
||||||
go.dev.pztrn.name/flagger v0.0.0-20200617193309-89bc9818b76c/go.mod h1:ttPExQNCubgqqO5Y19LfIBKqmWtBocY7P9MXQEECuZo=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
|
||||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
|
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8=
|
|
||||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
|
|
||||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
|
|
||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 h1:rHZQSjJdAI4Xf5Qzeh2bBc5YJIkPFVM6oDtMFYmgws0=
|
||||||
|
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c h1:dS09fXwOFF9cXBnIzZexIuUBj95U1NyQjkEhkgidDow=
|
|
||||||
golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
mvdan.cc/gofumpt v0.1.1 h1:bi/1aS/5W00E2ny5q65w9SnKpWEF/UIOqDYBILpo9rA=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
mvdan.cc/gofumpt v0.1.1/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
@ -32,18 +32,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
c *context.Context
|
ctx *context.Context
|
||||||
log zerolog.Logger
|
log zerolog.Logger
|
||||||
)
|
)
|
||||||
|
|
||||||
// New initializes captcha package and adds necessary HTTP and API
|
// New initializes captcha package and adds necessary HTTP and API
|
||||||
// endpoints.
|
// endpoints.
|
||||||
func New(cc *context.Context) {
|
func New(cc *context.Context) {
|
||||||
c = cc
|
ctx = cc
|
||||||
log = c.Logger.With().Str("type", "internal").Str("package", "captcha").Logger()
|
log = ctx.Logger.With().Str("type", "internal").Str("package", "captcha").Logger()
|
||||||
|
|
||||||
// New paste.
|
// New paste.
|
||||||
c.Echo.GET("/captcha/:id.png", echo.WrapHandler(captcha.Server(captcha.StdWidth, captcha.StdHeight)))
|
ctx.Echo.GET("/captcha/:id.png", echo.WrapHandler(captcha.Server(captcha.StdWidth, captcha.StdHeight)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCaptcha creates new captcha string.
|
// NewCaptcha creates new captcha string.
|
||||||
|
@ -100,7 +100,7 @@ func (c *Context) LoadConfiguration() {
|
|||||||
|
|
||||||
c.Logger.Debug().Str("path", configPath).Msg("Configuration file path")
|
c.Logger.Debug().Str("path", configPath).Msg("Configuration file path")
|
||||||
|
|
||||||
// nolint:exhaustivestruct
|
// nolint:exhaustruct
|
||||||
c.Config = &config.Struct{}
|
c.Config = &config.Struct{}
|
||||||
|
|
||||||
// Read configuration file.
|
// Read configuration file.
|
||||||
|
@ -31,6 +31,6 @@ const (
|
|||||||
|
|
||||||
// New creates new context.
|
// New creates new context.
|
||||||
func New() *Context {
|
func New() *Context {
|
||||||
// nolint:exhaustivestruct
|
// nolint:exhaustruct
|
||||||
return &Context{}
|
return &Context{}
|
||||||
}
|
}
|
||||||
|
@ -12,44 +12,44 @@ import (
|
|||||||
|
|
||||||
// Puts memory usage into log lines.
|
// Puts memory usage into log lines.
|
||||||
func (c *Context) getMemoryUsage(event *zerolog.Event, level zerolog.Level, message string) {
|
func (c *Context) getMemoryUsage(event *zerolog.Event, level zerolog.Level, message string) {
|
||||||
var m runtime.MemStats
|
var memstats runtime.MemStats
|
||||||
|
|
||||||
runtime.ReadMemStats(&m)
|
runtime.ReadMemStats(&memstats)
|
||||||
|
|
||||||
event.Str("memalloc", fmt.Sprintf("%dMB", m.Alloc/1024/1024))
|
event.Str("memalloc", fmt.Sprintf("%dMB", memstats.Alloc/1024/1024))
|
||||||
event.Str("memsys", fmt.Sprintf("%dMB", m.Sys/1024/1024))
|
event.Str("memsys", fmt.Sprintf("%dMB", memstats.Sys/1024/1024))
|
||||||
event.Str("numgc", fmt.Sprintf("%d", m.NumGC))
|
event.Str("numgc", fmt.Sprintf("%d", memstats.NumGC))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes logger.
|
// Initializes logger.
|
||||||
func (c *Context) initializeLogger() {
|
func (c *Context) initializeLogger() {
|
||||||
// Устанавливаем форматирование логгера.
|
// Устанавливаем форматирование логгера.
|
||||||
// nolint:exhaustivestruct
|
// nolint:exhaustruct
|
||||||
output := zerolog.ConsoleWriter{Out: os.Stdout, NoColor: false, TimeFormat: time.RFC3339}
|
output := zerolog.ConsoleWriter{Out: os.Stdout, NoColor: false, TimeFormat: time.RFC3339}
|
||||||
output.FormatLevel = func(lvlRaw interface{}) string {
|
output.FormatLevel = func(lvlRaw interface{}) string {
|
||||||
var v string
|
var lvl string
|
||||||
|
|
||||||
if lvl, ok := lvlRaw.(string); ok {
|
if lvlAsString, ok := lvlRaw.(string); ok {
|
||||||
lvl = strings.ToUpper(lvl)
|
lvlAsString = strings.ToUpper(lvlAsString)
|
||||||
switch lvl {
|
switch lvlAsString {
|
||||||
case "DEBUG":
|
case "DEBUG":
|
||||||
v = fmt.Sprintf("\x1b[30m%-5s\x1b[0m", lvl)
|
lvl = fmt.Sprintf("\x1b[30m%-5s\x1b[0m", lvlAsString)
|
||||||
case "ERROR":
|
case "ERROR":
|
||||||
v = fmt.Sprintf("\x1b[31m%-5s\x1b[0m", lvl)
|
lvl = fmt.Sprintf("\x1b[31m%-5s\x1b[0m", lvlAsString)
|
||||||
case "FATAL":
|
case "FATAL":
|
||||||
v = fmt.Sprintf("\x1b[35m%-5s\x1b[0m", lvl)
|
lvl = fmt.Sprintf("\x1b[35m%-5s\x1b[0m", lvlAsString)
|
||||||
case "INFO":
|
case "INFO":
|
||||||
v = fmt.Sprintf("\x1b[32m%-5s\x1b[0m", lvl)
|
lvl = fmt.Sprintf("\x1b[32m%-5s\x1b[0m", lvlAsString)
|
||||||
case "PANIC":
|
case "PANIC":
|
||||||
v = fmt.Sprintf("\x1b[36m%-5s\x1b[0m", lvl)
|
lvl = fmt.Sprintf("\x1b[36m%-5s\x1b[0m", lvlAsString)
|
||||||
case "WARN":
|
case "WARN":
|
||||||
v = fmt.Sprintf("\x1b[33m%-5s\x1b[0m", lvl)
|
lvl = fmt.Sprintf("\x1b[33m%-5s\x1b[0m", lvlAsString)
|
||||||
default:
|
default:
|
||||||
v = lvl
|
lvl = lvlAsString
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("| %s |", v)
|
return fmt.Sprintf("| %s |", lvl)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Logger = zerolog.New(output).With().Timestamp().Logger()
|
c.Logger = zerolog.New(output).With().Timestamp().Logger()
|
||||||
|
@ -46,7 +46,7 @@ type Database struct {
|
|||||||
// a subject of change in future.
|
// a subject of change in future.
|
||||||
func (db *Database) cleanup() {
|
func (db *Database) cleanup() {
|
||||||
for {
|
for {
|
||||||
c.Logger.Info().Msg("Starting pastes cleanup procedure...")
|
ctx.Logger.Info().Msg("Starting pastes cleanup procedure...")
|
||||||
|
|
||||||
pages := db.db.GetPastesPages()
|
pages := db.db.GetPastesPages()
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ func (db *Database) cleanup() {
|
|||||||
for i := 0; i < pages; i++ {
|
for i := 0; i < pages; i++ {
|
||||||
pastes, err := db.db.GetPagedPastes(i)
|
pastes, err := db.db.GetPagedPastes(i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Error().Err(err).Int("page", i).Msg("Failed to perform database cleanup")
|
ctx.Logger.Error().Err(err).Int("page", i).Msg("Failed to perform database cleanup")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, paste := range pastes {
|
for _, paste := range pastes {
|
||||||
@ -68,11 +68,11 @@ func (db *Database) cleanup() {
|
|||||||
for _, pasteID := range pasteIDsToRemove {
|
for _, pasteID := range pasteIDsToRemove {
|
||||||
err := db.DeletePaste(pasteID)
|
err := db.DeletePaste(pasteID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Error().Err(err).Int("paste", pasteID).Msg("Failed to delete paste!")
|
ctx.Logger.Error().Err(err).Int("paste", pasteID).Msg("Failed to delete paste!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Logger.Info().Msg("Pastes cleanup done.")
|
ctx.Logger.Info().Msg("Pastes cleanup done.")
|
||||||
|
|
||||||
time.Sleep(time.Hour)
|
time.Sleep(time.Hour)
|
||||||
}
|
}
|
||||||
@ -107,16 +107,16 @@ func (db *Database) GetPastesPages() int {
|
|||||||
|
|
||||||
// Initialize initializes connection to database.
|
// Initialize initializes connection to database.
|
||||||
func (db *Database) Initialize() {
|
func (db *Database) Initialize() {
|
||||||
c.Logger.Info().Msg("Initializing database connection...")
|
ctx.Logger.Info().Msg("Initializing database connection...")
|
||||||
|
|
||||||
if c.Config.Database.Type == "mysql" {
|
if ctx.Config.Database.Type == "mysql" {
|
||||||
mysql.New(c)
|
mysql.New(ctx)
|
||||||
} else if c.Config.Database.Type == flatfiles.FlatFileDialect {
|
} else if ctx.Config.Database.Type == flatfiles.FlatFileDialect {
|
||||||
flatfiles.New(c)
|
flatfiles.New(ctx)
|
||||||
} else if c.Config.Database.Type == "postgresql" {
|
} else if ctx.Config.Database.Type == "postgresql" {
|
||||||
postgresql.New(c)
|
postgresql.New(ctx)
|
||||||
} else {
|
} else {
|
||||||
c.Logger.Fatal().Str("type", c.Config.Database.Type).Msg("Unknown database type")
|
ctx.Logger.Fatal().Str("type", ctx.Config.Database.Type).Msg("Unknown database type")
|
||||||
}
|
}
|
||||||
|
|
||||||
go db.cleanup()
|
go db.cleanup()
|
||||||
|
@ -32,14 +32,14 @@ import (
|
|||||||
const FlatFileDialect = "flatfiles"
|
const FlatFileDialect = "flatfiles"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
c *context.Context
|
ctx *context.Context
|
||||||
f *FlatFiles
|
flf *FlatFiles
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(cc *context.Context) {
|
func New(cc *context.Context) {
|
||||||
c = cc
|
ctx = cc
|
||||||
// nolint:exhaustivestruct
|
// nolint:exhaustruct
|
||||||
f = &FlatFiles{}
|
flf = &FlatFiles{}
|
||||||
|
|
||||||
c.Database.RegisterDialect(dialectinterface.Interface(Handler{}))
|
ctx.Database.RegisterDialect(dialectinterface.Interface(Handler{}))
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ func (ff *FlatFiles) DeletePaste(pasteID int) error {
|
|||||||
// Delete from disk.
|
// Delete from disk.
|
||||||
err := os.Remove(filepath.Join(ff.path, "pastes", strconv.Itoa(pasteID)+".json"))
|
err := os.Remove(filepath.Join(ff.path, "pastes", strconv.Itoa(pasteID)+".json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Error().Err(err).Msg("Failed to delete paste!")
|
ctx.Logger.Error().Err(err).Msg("Failed to delete paste!")
|
||||||
|
|
||||||
// nolint:wrapcheck
|
// nolint:wrapcheck
|
||||||
return err
|
return err
|
||||||
@ -83,25 +83,25 @@ func (ff *FlatFiles) GetDatabaseConnection() *sql.DB {
|
|||||||
func (ff *FlatFiles) GetPaste(pasteID int) (*structs.Paste, error) {
|
func (ff *FlatFiles) GetPaste(pasteID int) (*structs.Paste, error) {
|
||||||
ff.writeMutex.Lock()
|
ff.writeMutex.Lock()
|
||||||
pastePath := filepath.Join(ff.path, "pastes", strconv.Itoa(pasteID)+".json")
|
pastePath := filepath.Join(ff.path, "pastes", strconv.Itoa(pasteID)+".json")
|
||||||
c.Logger.Debug().Str("path", pastePath).Msg("Trying to load paste data")
|
ctx.Logger.Debug().Str("path", pastePath).Msg("Trying to load paste data")
|
||||||
|
|
||||||
pasteInBytes, err := ioutil.ReadFile(pastePath)
|
pasteInBytes, err := ioutil.ReadFile(pastePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Debug().Err(err).Msg("Failed to read paste from storage")
|
ctx.Logger.Debug().Err(err).Msg("Failed to read paste from storage")
|
||||||
|
|
||||||
// nolint:wrapcheck
|
// nolint:wrapcheck
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Logger.Debug().Int("paste bytes", len(pasteInBytes)).Msg("Loaded paste")
|
ctx.Logger.Debug().Int("paste bytes", len(pasteInBytes)).Msg("Loaded paste")
|
||||||
ff.writeMutex.Unlock()
|
ff.writeMutex.Unlock()
|
||||||
|
|
||||||
// nolint:exhaustivestruct
|
// nolint:exhaustruct
|
||||||
paste := &structs.Paste{}
|
paste := &structs.Paste{}
|
||||||
|
|
||||||
err1 := json.Unmarshal(pasteInBytes, paste)
|
err1 := json.Unmarshal(pasteInBytes, paste)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
c.Logger.Error().Err(err1).Msgf("Failed to parse paste")
|
ctx.Logger.Error().Err(err1).Msgf("Failed to parse paste")
|
||||||
|
|
||||||
// nolint:wrapcheck
|
// nolint:wrapcheck
|
||||||
return nil, err1
|
return nil, err1
|
||||||
@ -114,7 +114,7 @@ func (ff *FlatFiles) GetPagedPastes(page int) ([]structs.Paste, error) {
|
|||||||
// Pagination.
|
// Pagination.
|
||||||
startPagination := 0
|
startPagination := 0
|
||||||
if page > 1 {
|
if page > 1 {
|
||||||
startPagination = (page - 1) * c.Config.Pastes.Pagination
|
startPagination = (page - 1) * ctx.Config.Pastes.Pagination
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iteration one - get only public pastes.
|
// Iteration one - get only public pastes.
|
||||||
@ -130,38 +130,38 @@ func (ff *FlatFiles) GetPagedPastes(page int) ([]structs.Paste, error) {
|
|||||||
pastesData := make([]structs.Paste, 0)
|
pastesData := make([]structs.Paste, 0)
|
||||||
|
|
||||||
for idx, paste := range publicPastes {
|
for idx, paste := range publicPastes {
|
||||||
if len(pastesData) == c.Config.Pastes.Pagination {
|
if len(pastesData) == ctx.Config.Pastes.Pagination {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if idx < startPagination {
|
if idx < startPagination {
|
||||||
c.Logger.Debug().Int("paste index", idx).Msg("Paste isn't in pagination query: too low index")
|
ctx.Logger.Debug().Int("paste index", idx).Msg("Paste isn't in pagination query: too low index")
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idx-1 >= startPagination && page > 1 && idx > startPagination+((page-1)*c.Config.Pastes.Pagination)) || (idx-1 >= startPagination && page == 1 && idx > startPagination+(page*c.Config.Pastes.Pagination)) {
|
if (idx-1 >= startPagination && page > 1 && idx > startPagination+((page-1)*ctx.Config.Pastes.Pagination)) || (idx-1 >= startPagination && page == 1 && idx > startPagination+(page*ctx.Config.Pastes.Pagination)) {
|
||||||
c.Logger.Debug().Int("paste index", idx).Msg("Paste isn't in pagination query: too high index")
|
ctx.Logger.Debug().Int("paste index", idx).Msg("Paste isn't in pagination query: too high index")
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Logger.Debug().Int("ID", paste.ID).Int("index", idx).Msg("Getting paste data")
|
ctx.Logger.Debug().Int("ID", paste.ID).Int("index", idx).Msg("Getting paste data")
|
||||||
|
|
||||||
// Get paste data.
|
// Get paste data.
|
||||||
// nolint:exhaustivestruct
|
// nolint:exhaustruct
|
||||||
pasteData := &structs.Paste{}
|
pasteData := &structs.Paste{}
|
||||||
|
|
||||||
pasteRawData, err := ioutil.ReadFile(filepath.Join(ff.path, "pastes", strconv.Itoa(paste.ID)+".json"))
|
pasteRawData, err := ioutil.ReadFile(filepath.Join(ff.path, "pastes", strconv.Itoa(paste.ID)+".json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Error().Err(err).Msg("Failed to read paste data")
|
ctx.Logger.Error().Err(err).Msg("Failed to read paste data")
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err1 := json.Unmarshal(pasteRawData, pasteData)
|
err1 := json.Unmarshal(pasteRawData, pasteData)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
c.Logger.Error().Err(err1).Msg("Failed to parse paste data")
|
ctx.Logger.Error().Err(err1).Msg("Failed to parse paste data")
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -185,9 +185,9 @@ func (ff *FlatFiles) GetPastesPages() int {
|
|||||||
ff.writeMutex.Unlock()
|
ff.writeMutex.Unlock()
|
||||||
|
|
||||||
// Calculate pages.
|
// Calculate pages.
|
||||||
pages := len(publicPastes) / c.Config.Pastes.Pagination
|
pages := len(publicPastes) / ctx.Config.Pastes.Pagination
|
||||||
// Check if we have any remainder. Add 1 to pages count if so.
|
// Check if we have any remainder. Add 1 to pages count if so.
|
||||||
if len(publicPastes)%c.Config.Pastes.Pagination > 0 {
|
if len(publicPastes)%ctx.Config.Pastes.Pagination > 0 {
|
||||||
pages++
|
pages++
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,14 +195,14 @@ func (ff *FlatFiles) GetPastesPages() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ff *FlatFiles) Initialize() {
|
func (ff *FlatFiles) Initialize() {
|
||||||
c.Logger.Info().Msg("Initializing flatfiles storage...")
|
ctx.Logger.Info().Msg("Initializing flatfiles storage...")
|
||||||
|
|
||||||
path := c.Config.Database.Path
|
path := ctx.Config.Database.Path
|
||||||
// Get proper paste file path.
|
// Get proper paste file path.
|
||||||
if strings.Contains(c.Config.Database.Path, "~") {
|
if strings.Contains(ctx.Config.Database.Path, "~") {
|
||||||
curUser, err := user.Current()
|
curUser, err := user.Current()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Error().Msg("Failed to get current user. Will replace '~' for '/' in storage path!")
|
ctx.Logger.Error().Msg("Failed to get current user. Will replace '~' for '/' in storage path!")
|
||||||
|
|
||||||
path = strings.Replace(path, "~", "/", -1)
|
path = strings.Replace(path, "~", "/", -1)
|
||||||
}
|
}
|
||||||
@ -213,40 +213,40 @@ func (ff *FlatFiles) Initialize() {
|
|||||||
path, _ = filepath.Abs(path)
|
path, _ = filepath.Abs(path)
|
||||||
ff.path = path
|
ff.path = path
|
||||||
|
|
||||||
c.Logger.Debug().Msgf("Storage path is now: %s", ff.path)
|
ctx.Logger.Debug().Msgf("Storage path is now: %s", ff.path)
|
||||||
|
|
||||||
// Create directory if necessary.
|
// Create directory if necessary.
|
||||||
if _, err := os.Stat(ff.path); err != nil {
|
if _, err := os.Stat(ff.path); err != nil {
|
||||||
c.Logger.Debug().Str("directory", ff.path).Msg("Directory does not exist, creating...")
|
ctx.Logger.Debug().Str("directory", ff.path).Msg("Directory does not exist, creating...")
|
||||||
_ = os.MkdirAll(ff.path, os.ModePerm)
|
_ = os.MkdirAll(ff.path, os.ModePerm)
|
||||||
} else {
|
} else {
|
||||||
c.Logger.Debug().Str("directory", ff.path).Msg("Directory already exists")
|
ctx.Logger.Debug().Str("directory", ff.path).Msg("Directory already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create directory for pastes.
|
// Create directory for pastes.
|
||||||
if _, err := os.Stat(filepath.Join(ff.path, "pastes")); err != nil {
|
if _, err := os.Stat(filepath.Join(ff.path, "pastes")); err != nil {
|
||||||
c.Logger.Debug().Str("directory", ff.path).Msg("Directory does not exist, creating...")
|
ctx.Logger.Debug().Str("directory", ff.path).Msg("Directory does not exist, creating...")
|
||||||
_ = os.MkdirAll(filepath.Join(ff.path, "pastes"), os.ModePerm)
|
_ = os.MkdirAll(filepath.Join(ff.path, "pastes"), os.ModePerm)
|
||||||
} else {
|
} else {
|
||||||
c.Logger.Debug().Str("directory", ff.path).Msg("Directory already exists")
|
ctx.Logger.Debug().Str("directory", ff.path).Msg("Directory already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load pastes index.
|
// Load pastes index.
|
||||||
ff.pastesIndex = []Index{}
|
ff.pastesIndex = []Index{}
|
||||||
if _, err := os.Stat(filepath.Join(ff.path, "pastes", "index.json")); err != nil {
|
if _, err := os.Stat(filepath.Join(ff.path, "pastes", "index.json")); err != nil {
|
||||||
c.Logger.Warn().Msg("Pastes index file does not exist, will create new one")
|
ctx.Logger.Warn().Msg("Pastes index file does not exist, will create new one")
|
||||||
} else {
|
} else {
|
||||||
indexData, err := ioutil.ReadFile(filepath.Join(ff.path, "pastes", "index.json"))
|
indexData, err := ioutil.ReadFile(filepath.Join(ff.path, "pastes", "index.json"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Fatal().Msg("Failed to read contents of index file!")
|
ctx.Logger.Fatal().Msg("Failed to read contents of index file!")
|
||||||
}
|
}
|
||||||
|
|
||||||
err1 := json.Unmarshal(indexData, &ff.pastesIndex)
|
err1 := json.Unmarshal(indexData, &ff.pastesIndex)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
c.Logger.Error().Err(err1).Msg("Failed to parse index file contents from JSON into internal structure. Will create new index file. All of your previous pastes will became unavailable.")
|
ctx.Logger.Error().Err(err1).Msg("Failed to parse index file contents from JSON into internal structure. Will create new index file. All of your previous pastes will became unavailable.")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Logger.Debug().Int("pastes count", len(ff.pastesIndex)).Msg("Parsed pastes index")
|
ctx.Logger.Debug().Int("pastes count", len(ff.pastesIndex)).Msg("Parsed pastes index")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,7 +257,7 @@ func (ff *FlatFiles) SavePaste(paste *structs.Paste) (int64, error) {
|
|||||||
pasteID := len(filesOnDisk) + 1
|
pasteID := len(filesOnDisk) + 1
|
||||||
paste.ID = pasteID
|
paste.ID = pasteID
|
||||||
|
|
||||||
c.Logger.Debug().Int("new paste ID", pasteID).Msg("Writing paste to disk")
|
ctx.Logger.Debug().Int("new paste ID", pasteID).Msg("Writing paste to disk")
|
||||||
|
|
||||||
data, err := json.Marshal(paste)
|
data, err := json.Marshal(paste)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -276,7 +276,7 @@ func (ff *FlatFiles) SavePaste(paste *structs.Paste) (int64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add it to cache.
|
// Add it to cache.
|
||||||
// nolint:exhaustivestruct
|
// nolint:exhaustruct
|
||||||
indexData := Index{}
|
indexData := Index{}
|
||||||
indexData.ID = pasteID
|
indexData.ID = pasteID
|
||||||
indexData.Private = paste.Private
|
indexData.Private = paste.Private
|
||||||
@ -287,18 +287,18 @@ func (ff *FlatFiles) SavePaste(paste *structs.Paste) (int64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ff *FlatFiles) Shutdown() {
|
func (ff *FlatFiles) Shutdown() {
|
||||||
c.Logger.Info().Msg("Saving indexes...")
|
ctx.Logger.Info().Msg("Saving indexes...")
|
||||||
|
|
||||||
indexData, err := json.Marshal(ff.pastesIndex)
|
indexData, err := json.Marshal(ff.pastesIndex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Error().Err(err).Msg("Failed to encode index data into JSON")
|
ctx.Logger.Error().Err(err).Msg("Failed to encode index data into JSON")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err1 := ioutil.WriteFile(filepath.Join(ff.path, "pastes", "index.json"), indexData, 0o600)
|
err1 := ioutil.WriteFile(filepath.Join(ff.path, "pastes", "index.json"), indexData, 0o600)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
c.Logger.Error().Err(err1).Msg("Failed to write index data to file. Pretty sure that you've lost your pastes.")
|
ctx.Logger.Error().Err(err1).Msg("Failed to write index data to file. Pretty sure that you've lost your pastes.")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -33,33 +33,33 @@ import (
|
|||||||
type Handler struct{}
|
type Handler struct{}
|
||||||
|
|
||||||
func (dbh Handler) DeletePaste(pasteID int) error {
|
func (dbh Handler) DeletePaste(pasteID int) error {
|
||||||
return f.DeletePaste(pasteID)
|
return flf.DeletePaste(pasteID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) GetDatabaseConnection() *sql.DB {
|
func (dbh Handler) GetDatabaseConnection() *sql.DB {
|
||||||
return f.GetDatabaseConnection()
|
return flf.GetDatabaseConnection()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) GetPaste(pasteID int) (*structs.Paste, error) {
|
func (dbh Handler) GetPaste(pasteID int) (*structs.Paste, error) {
|
||||||
return f.GetPaste(pasteID)
|
return flf.GetPaste(pasteID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) GetPagedPastes(page int) ([]structs.Paste, error) {
|
func (dbh Handler) GetPagedPastes(page int) ([]structs.Paste, error) {
|
||||||
return f.GetPagedPastes(page)
|
return flf.GetPagedPastes(page)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) GetPastesPages() int {
|
func (dbh Handler) GetPastesPages() int {
|
||||||
return f.GetPastesPages()
|
return flf.GetPastesPages()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) Initialize() {
|
func (dbh Handler) Initialize() {
|
||||||
f.Initialize()
|
flf.Initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) SavePaste(p *structs.Paste) (int64, error) {
|
func (dbh Handler) SavePaste(p *structs.Paste) (int64, error) {
|
||||||
return f.SavePaste(p)
|
return flf.SavePaste(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) Shutdown() {
|
func (dbh Handler) Shutdown() {
|
||||||
f.Shutdown()
|
flf.Shutdown()
|
||||||
}
|
}
|
||||||
|
@ -30,14 +30,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
c *context.Context
|
ctx *context.Context
|
||||||
d *Database
|
dbAdapter *Database
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(cc *context.Context) {
|
func New(cc *context.Context) {
|
||||||
c = cc
|
ctx = cc
|
||||||
// nolint:exhaustivestruct
|
// nolint:exhaustruct
|
||||||
d = &Database{}
|
dbAdapter = &Database{}
|
||||||
|
|
||||||
c.Database.RegisterDialect(dialectinterface.Interface(Handler{}))
|
ctx.Database.RegisterDialect(dialectinterface.Interface(Handler{}))
|
||||||
}
|
}
|
||||||
|
@ -33,33 +33,33 @@ import (
|
|||||||
type Handler struct{}
|
type Handler struct{}
|
||||||
|
|
||||||
func (dbh Handler) DeletePaste(pasteID int) error {
|
func (dbh Handler) DeletePaste(pasteID int) error {
|
||||||
return d.DeletePaste(pasteID)
|
return dbAdapter.DeletePaste(pasteID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) GetDatabaseConnection() *sql.DB {
|
func (dbh Handler) GetDatabaseConnection() *sql.DB {
|
||||||
return d.GetDatabaseConnection()
|
return dbAdapter.GetDatabaseConnection()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) GetPaste(pasteID int) (*structs.Paste, error) {
|
func (dbh Handler) GetPaste(pasteID int) (*structs.Paste, error) {
|
||||||
return d.GetPaste(pasteID)
|
return dbAdapter.GetPaste(pasteID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) GetPagedPastes(page int) ([]structs.Paste, error) {
|
func (dbh Handler) GetPagedPastes(page int) ([]structs.Paste, error) {
|
||||||
return d.GetPagedPastes(page)
|
return dbAdapter.GetPagedPastes(page)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) GetPastesPages() int {
|
func (dbh Handler) GetPastesPages() int {
|
||||||
return d.GetPastesPages()
|
return dbAdapter.GetPastesPages()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) Initialize() {
|
func (dbh Handler) Initialize() {
|
||||||
d.Initialize()
|
dbAdapter.Initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) SavePaste(p *structs.Paste) (int64, error) {
|
func (dbh Handler) SavePaste(p *structs.Paste) (int64, error) {
|
||||||
return d.SavePaste(p)
|
return dbAdapter.SavePaste(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) Shutdown() {
|
func (dbh Handler) Shutdown() {
|
||||||
d.Shutdown()
|
dbAdapter.Shutdown()
|
||||||
}
|
}
|
||||||
|
@ -29,16 +29,16 @@ import (
|
|||||||
"go.dev.pztrn.name/fastpastebin/internal/context"
|
"go.dev.pztrn.name/fastpastebin/internal/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
var c *context.Context
|
var ctx *context.Context
|
||||||
|
|
||||||
// New initializes migrations.
|
// New initializes migrations.
|
||||||
func New(cc *context.Context) {
|
func New(cc *context.Context) {
|
||||||
c = cc
|
ctx = cc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrate launching migrations.
|
// Migrate launching migrations.
|
||||||
func Migrate() {
|
func Migrate() {
|
||||||
c.Logger.Info().Msg("Migrating database...")
|
ctx.Logger.Info().Msg("Migrating database...")
|
||||||
|
|
||||||
_ = goose.SetDialect("mysql")
|
_ = goose.SetDialect("mysql")
|
||||||
goose.AddNamedMigration("1_initial.go", InitialUp, nil)
|
goose.AddNamedMigration("1_initial.go", InitialUp, nil)
|
||||||
@ -47,13 +47,13 @@ func Migrate() {
|
|||||||
goose.AddNamedMigration("4_passworded_pastes.go", PasswordedPastesUp, PasswordedPastesDown)
|
goose.AddNamedMigration("4_passworded_pastes.go", PasswordedPastesUp, PasswordedPastesDown)
|
||||||
// Add new migrations BEFORE this message.
|
// Add new migrations BEFORE this message.
|
||||||
|
|
||||||
dbConn := c.Database.GetDatabaseConnection()
|
dbConn := ctx.Database.GetDatabaseConnection()
|
||||||
if dbConn != nil {
|
if dbConn != nil {
|
||||||
err := goose.Up(dbConn, ".")
|
err := goose.Up(dbConn, ".")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Panic().Msgf("Failed to migrate database to latest version: %s", err.Error())
|
ctx.Logger.Panic().Msgf("Failed to migrate database to latest version: %s", err.Error())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.Logger.Warn().Msg("Current database dialect isn't supporting migrations, skipping")
|
ctx.Logger.Warn().Msg("Current database dialect isn't supporting migrations, skipping")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ func (db *Database) GetDatabaseConnection() *sql.DB {
|
|||||||
func (db *Database) GetPaste(pasteID int) (*structs.Paste, error) {
|
func (db *Database) GetPaste(pasteID int) (*structs.Paste, error) {
|
||||||
db.check()
|
db.check()
|
||||||
|
|
||||||
// nolint:exhaustivestruct
|
// nolint:exhaustruct
|
||||||
paste := &structs.Paste{}
|
paste := &structs.Paste{}
|
||||||
|
|
||||||
err := db.db.Get(paste, db.db.Rebind("SELECT * FROM `pastes` WHERE id=?"), pasteID)
|
err := db.db.Get(paste, db.db.Rebind("SELECT * FROM `pastes` WHERE id=?"), pasteID)
|
||||||
@ -103,10 +103,10 @@ func (db *Database) GetPagedPastes(page int) ([]structs.Paste, error) {
|
|||||||
// Pagination.
|
// Pagination.
|
||||||
startPagination := 0
|
startPagination := 0
|
||||||
if page > 1 {
|
if page > 1 {
|
||||||
startPagination = (page - 1) * c.Config.Pastes.Pagination
|
startPagination = (page - 1) * ctx.Config.Pastes.Pagination
|
||||||
}
|
}
|
||||||
|
|
||||||
err := db.db.Select(&pastesRaw, db.db.Rebind("SELECT * FROM `pastes` WHERE private != true ORDER BY id DESC LIMIT ? OFFSET ?"), c.Config.Pastes.Pagination, startPagination)
|
err := db.db.Select(&pastesRaw, db.db.Rebind("SELECT * FROM `pastes` WHERE private != true ORDER BY id DESC LIMIT ? OFFSET ?"), ctx.Config.Pastes.Pagination, startPagination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// nolint:wrapcheck
|
// nolint:wrapcheck
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -142,9 +142,9 @@ func (db *Database) GetPastesPages() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate pages.
|
// Calculate pages.
|
||||||
pages := len(pastes) / c.Config.Pastes.Pagination
|
pages := len(pastes) / ctx.Config.Pastes.Pagination
|
||||||
// Check if we have any remainder. Add 1 to pages count if so.
|
// Check if we have any remainder. Add 1 to pages count if so.
|
||||||
if len(pastes)%c.Config.Pastes.Pagination > 0 {
|
if len(pastes)%ctx.Config.Pastes.Pagination > 0 {
|
||||||
pages++
|
pages++
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,23 +153,23 @@ func (db *Database) GetPastesPages() int {
|
|||||||
|
|
||||||
// Initialize initializes MySQL/MariaDB connection.
|
// Initialize initializes MySQL/MariaDB connection.
|
||||||
func (db *Database) Initialize() {
|
func (db *Database) Initialize() {
|
||||||
c.Logger.Info().Msg("Initializing database connection...")
|
ctx.Logger.Info().Msg("Initializing database connection...")
|
||||||
|
|
||||||
// There might be only user, without password. MySQL/MariaDB driver
|
// There might be only user, without password. MySQL/MariaDB driver
|
||||||
// in DSN wants "user" or "user:password", "user:" is invalid.
|
// in DSN wants "user" or "user:password", "user:" is invalid.
|
||||||
var userpass string
|
var userpass string
|
||||||
if c.Config.Database.Password == "" {
|
if ctx.Config.Database.Password == "" {
|
||||||
userpass = c.Config.Database.Username
|
userpass = ctx.Config.Database.Username
|
||||||
} else {
|
} else {
|
||||||
userpass = c.Config.Database.Username + ":" + c.Config.Database.Password
|
userpass = ctx.Config.Database.Username + ":" + ctx.Config.Database.Password
|
||||||
}
|
}
|
||||||
|
|
||||||
dbConnString := fmt.Sprintf("%s@tcp(%s:%s)/%s?parseTime=true&collation=utf8mb4_unicode_ci&charset=utf8mb4", userpass, c.Config.Database.Address, c.Config.Database.Port, c.Config.Database.Database)
|
dbConnString := fmt.Sprintf("%s@tcp(%s:%s)/%s?parseTime=true&collation=utf8mb4_unicode_ci&charset=utf8mb4", userpass, ctx.Config.Database.Address, ctx.Config.Database.Port, ctx.Config.Database.Database)
|
||||||
c.Logger.Debug().Str("DSN", dbConnString).Msgf("Database connection string composed")
|
ctx.Logger.Debug().Str("DSN", dbConnString).Msgf("Database connection string composed")
|
||||||
|
|
||||||
dbConn, err := sqlx.Connect("mysql", dbConnString)
|
dbConn, err := sqlx.Connect("mysql", dbConnString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Error().Err(err).Msg("Failed to connect to database")
|
ctx.Logger.Error().Err(err).Msg("Failed to connect to database")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -177,12 +177,12 @@ func (db *Database) Initialize() {
|
|||||||
// Force UTC for current connection.
|
// Force UTC for current connection.
|
||||||
_ = dbConn.MustExec("SET @@session.time_zone='+00:00';")
|
_ = dbConn.MustExec("SET @@session.time_zone='+00:00';")
|
||||||
|
|
||||||
c.Logger.Info().Msg("Database connection established")
|
ctx.Logger.Info().Msg("Database connection established")
|
||||||
|
|
||||||
db.db = dbConn
|
db.db = dbConn
|
||||||
|
|
||||||
// Perform migrations.
|
// Perform migrations.
|
||||||
migrations.New(c)
|
migrations.New(ctx)
|
||||||
migrations.Migrate()
|
migrations.Migrate()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,7 +208,7 @@ func (db *Database) Shutdown() {
|
|||||||
if db.db != nil {
|
if db.db != nil {
|
||||||
err := db.db.Close()
|
err := db.db.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Error().Err(err).Msg("Failed to close database connection")
|
ctx.Logger.Error().Err(err).Msg("Failed to close database connection")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,14 +30,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
c *context.Context
|
ctx *context.Context
|
||||||
d *Database
|
dbAdapter *Database
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(cc *context.Context) {
|
func New(cc *context.Context) {
|
||||||
c = cc
|
ctx = cc
|
||||||
// nolint:exhaustivestruct
|
// nolint:exhaustruct
|
||||||
d = &Database{}
|
dbAdapter = &Database{}
|
||||||
|
|
||||||
c.Database.RegisterDialect(dialectinterface.Interface(Handler{}))
|
ctx.Database.RegisterDialect(dialectinterface.Interface(Handler{}))
|
||||||
}
|
}
|
||||||
|
@ -33,33 +33,33 @@ import (
|
|||||||
type Handler struct{}
|
type Handler struct{}
|
||||||
|
|
||||||
func (dbh Handler) DeletePaste(pasteID int) error {
|
func (dbh Handler) DeletePaste(pasteID int) error {
|
||||||
return d.DeletePaste(pasteID)
|
return dbAdapter.DeletePaste(pasteID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) GetDatabaseConnection() *sql.DB {
|
func (dbh Handler) GetDatabaseConnection() *sql.DB {
|
||||||
return d.GetDatabaseConnection()
|
return dbAdapter.GetDatabaseConnection()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) GetPaste(pasteID int) (*structs.Paste, error) {
|
func (dbh Handler) GetPaste(pasteID int) (*structs.Paste, error) {
|
||||||
return d.GetPaste(pasteID)
|
return dbAdapter.GetPaste(pasteID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) GetPagedPastes(page int) ([]structs.Paste, error) {
|
func (dbh Handler) GetPagedPastes(page int) ([]structs.Paste, error) {
|
||||||
return d.GetPagedPastes(page)
|
return dbAdapter.GetPagedPastes(page)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) GetPastesPages() int {
|
func (dbh Handler) GetPastesPages() int {
|
||||||
return d.GetPastesPages()
|
return dbAdapter.GetPastesPages()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) Initialize() {
|
func (dbh Handler) Initialize() {
|
||||||
d.Initialize()
|
dbAdapter.Initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) SavePaste(p *structs.Paste) (int64, error) {
|
func (dbh Handler) SavePaste(p *structs.Paste) (int64, error) {
|
||||||
return d.SavePaste(p)
|
return dbAdapter.SavePaste(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) Shutdown() {
|
func (dbh Handler) Shutdown() {
|
||||||
d.Shutdown()
|
dbAdapter.Shutdown()
|
||||||
}
|
}
|
||||||
|
@ -29,16 +29,16 @@ import (
|
|||||||
"go.dev.pztrn.name/fastpastebin/internal/context"
|
"go.dev.pztrn.name/fastpastebin/internal/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
var c *context.Context
|
var ctx *context.Context
|
||||||
|
|
||||||
// New initializes migrations.
|
// New initializes migrations.
|
||||||
func New(cc *context.Context) {
|
func New(cc *context.Context) {
|
||||||
c = cc
|
ctx = cc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrate launching migrations.
|
// Migrate launching migrations.
|
||||||
func Migrate() {
|
func Migrate() {
|
||||||
c.Logger.Info().Msg("Migrating database...")
|
ctx.Logger.Info().Msg("Migrating database...")
|
||||||
|
|
||||||
_ = goose.SetDialect("postgres")
|
_ = goose.SetDialect("postgres")
|
||||||
goose.AddNamedMigration("1_initial.go", InitialUp, nil)
|
goose.AddNamedMigration("1_initial.go", InitialUp, nil)
|
||||||
@ -47,14 +47,14 @@ func Migrate() {
|
|||||||
goose.AddNamedMigration("4_passworded_pastes.go", PasswordedPastesUp, PasswordedPastesDown)
|
goose.AddNamedMigration("4_passworded_pastes.go", PasswordedPastesUp, PasswordedPastesDown)
|
||||||
// Add new migrations BEFORE this message.
|
// Add new migrations BEFORE this message.
|
||||||
|
|
||||||
dbConn := c.Database.GetDatabaseConnection()
|
dbConn := ctx.Database.GetDatabaseConnection()
|
||||||
if dbConn != nil {
|
if dbConn != nil {
|
||||||
err := goose.Up(dbConn, ".")
|
err := goose.Up(dbConn, ".")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Info().Msgf("%+v", err)
|
ctx.Logger.Info().Msgf("%+v", err)
|
||||||
c.Logger.Panic().Msgf("Failed to migrate database to latest version: %s", err.Error())
|
ctx.Logger.Panic().Msgf("Failed to migrate database to latest version: %s", err.Error())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.Logger.Warn().Msg("Current database dialect isn't supporting migrations, skipping")
|
ctx.Logger.Warn().Msg("Current database dialect isn't supporting migrations, skipping")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ package postgresql
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
// PostgreSQL driver.
|
// PostgreSQL driver.
|
||||||
@ -83,7 +84,7 @@ func (db *Database) GetDatabaseConnection() *sql.DB {
|
|||||||
func (db *Database) GetPaste(pasteID int) (*structs.Paste, error) {
|
func (db *Database) GetPaste(pasteID int) (*structs.Paste, error) {
|
||||||
db.check()
|
db.check()
|
||||||
|
|
||||||
// nolint:exhaustivestruct
|
// nolint:exhaustruct
|
||||||
paste := &structs.Paste{}
|
paste := &structs.Paste{}
|
||||||
|
|
||||||
err := db.db.Get(paste, db.db.Rebind("SELECT * FROM pastes WHERE id=$1"), pasteID)
|
err := db.db.Get(paste, db.db.Rebind("SELECT * FROM pastes WHERE id=$1"), pasteID)
|
||||||
@ -113,10 +114,10 @@ func (db *Database) GetPagedPastes(page int) ([]structs.Paste, error) {
|
|||||||
// Pagination.
|
// Pagination.
|
||||||
startPagination := 0
|
startPagination := 0
|
||||||
if page > 1 {
|
if page > 1 {
|
||||||
startPagination = (page - 1) * c.Config.Pastes.Pagination
|
startPagination = (page - 1) * ctx.Config.Pastes.Pagination
|
||||||
}
|
}
|
||||||
|
|
||||||
err := db.db.Select(&pastesRaw, db.db.Rebind("SELECT * FROM pastes WHERE private != true ORDER BY id DESC LIMIT $1 OFFSET $2"), c.Config.Pastes.Pagination, startPagination)
|
err := db.db.Select(&pastesRaw, db.db.Rebind("SELECT * FROM pastes WHERE private != true ORDER BY id DESC LIMIT $1 OFFSET $2"), ctx.Config.Pastes.Pagination, startPagination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// nolint:wrapcheck
|
// nolint:wrapcheck
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -158,9 +159,9 @@ func (db *Database) GetPastesPages() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate pages.
|
// Calculate pages.
|
||||||
pages := len(pastes) / c.Config.Pastes.Pagination
|
pages := len(pastes) / ctx.Config.Pastes.Pagination
|
||||||
// Check if we have any remainder. Add 1 to pages count if so.
|
// Check if we have any remainder. Add 1 to pages count if so.
|
||||||
if len(pastes)%c.Config.Pastes.Pagination > 0 {
|
if len(pastes)%ctx.Config.Pastes.Pagination > 0 {
|
||||||
pages++
|
pages++
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,31 +170,31 @@ func (db *Database) GetPastesPages() int {
|
|||||||
|
|
||||||
// Initialize initializes MySQL/MariaDB connection.
|
// Initialize initializes MySQL/MariaDB connection.
|
||||||
func (db *Database) Initialize() {
|
func (db *Database) Initialize() {
|
||||||
c.Logger.Info().Msg("Initializing database connection...")
|
ctx.Logger.Info().Msg("Initializing database connection...")
|
||||||
|
|
||||||
var userpass string
|
var userpass string
|
||||||
if c.Config.Database.Password == "" {
|
if ctx.Config.Database.Password == "" {
|
||||||
userpass = c.Config.Database.Username
|
userpass = ctx.Config.Database.Username
|
||||||
} else {
|
} else {
|
||||||
userpass = c.Config.Database.Username + ":" + c.Config.Database.Password
|
userpass = ctx.Config.Database.Username + ":" + ctx.Config.Database.Password
|
||||||
}
|
}
|
||||||
|
|
||||||
dbConnString := fmt.Sprintf("postgres://%s@%s:%s/%s?connect_timeout=10&fallback_application_name=fastpastebin&sslmode=disable", userpass, c.Config.Database.Address, c.Config.Database.Port, c.Config.Database.Database)
|
dbConnString := fmt.Sprintf("postgres://%s@%s/%s?connect_timeout=10&fallback_application_name=fastpastebin&sslmode=disable", userpass, net.JoinHostPort(ctx.Config.Database.Address, ctx.Config.Database.Port), ctx.Config.Database.Database)
|
||||||
c.Logger.Debug().Str("DSN", dbConnString).Msg("Database connection string composed")
|
ctx.Logger.Debug().Str("DSN", dbConnString).Msg("Database connection string composed")
|
||||||
|
|
||||||
dbConn, err := sqlx.Connect("postgres", dbConnString)
|
dbConn, err := sqlx.Connect("postgres", dbConnString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Error().Err(err).Msg("Failed to connect to database")
|
ctx.Logger.Error().Err(err).Msg("Failed to connect to database")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Logger.Info().Msg("Database connection established")
|
ctx.Logger.Info().Msg("Database connection established")
|
||||||
|
|
||||||
db.db = dbConn
|
db.db = dbConn
|
||||||
|
|
||||||
// Perform migrations.
|
// Perform migrations.
|
||||||
migrations.New(c)
|
migrations.New(ctx)
|
||||||
migrations.Migrate()
|
migrations.Migrate()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,22 +207,22 @@ func (db *Database) SavePaste(paste *structs.Paste) (int64, error) {
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var id int64
|
var newPasteID int64
|
||||||
|
|
||||||
err = stmt.Get(&id, paste)
|
err = stmt.Get(&newPasteID, paste)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// nolint:wrapcheck
|
// nolint:wrapcheck
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return id, nil
|
return newPasteID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *Database) Shutdown() {
|
func (db *Database) Shutdown() {
|
||||||
if db.db != nil {
|
if db.db != nil {
|
||||||
err := db.db.Close()
|
err := db.db.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Error().Err(err).Msg("Failed to close database connection")
|
ctx.Logger.Error().Err(err).Msg("Failed to close database connection")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,15 +30,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
c *context.Context
|
ctx *context.Context
|
||||||
d *Database
|
dbAdapter *Database
|
||||||
)
|
)
|
||||||
|
|
||||||
// New initializes database structure.
|
// New initializes database structure.
|
||||||
func New(cc *context.Context) {
|
func New(cc *context.Context) {
|
||||||
c = cc
|
ctx = cc
|
||||||
// nolint:exhaustivestruct
|
// nolint:exhaustruct
|
||||||
d = &Database{}
|
dbAdapter = &Database{}
|
||||||
|
|
||||||
c.RegisterDatabaseInterface(databaseinterface.Interface(Handler{}))
|
ctx.RegisterDatabaseInterface(databaseinterface.Interface(Handler{}))
|
||||||
}
|
}
|
||||||
|
@ -36,38 +36,38 @@ import (
|
|||||||
type Handler struct{}
|
type Handler struct{}
|
||||||
|
|
||||||
func (dbh Handler) DeletePaste(pasteID int) error {
|
func (dbh Handler) DeletePaste(pasteID int) error {
|
||||||
return d.DeletePaste(pasteID)
|
return dbAdapter.DeletePaste(pasteID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) GetDatabaseConnection() *sql.DB {
|
func (dbh Handler) GetDatabaseConnection() *sql.DB {
|
||||||
return d.GetDatabaseConnection()
|
return dbAdapter.GetDatabaseConnection()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) GetPaste(pasteID int) (*structs.Paste, error) {
|
func (dbh Handler) GetPaste(pasteID int) (*structs.Paste, error) {
|
||||||
return d.GetPaste(pasteID)
|
return dbAdapter.GetPaste(pasteID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) GetPagedPastes(page int) ([]structs.Paste, error) {
|
func (dbh Handler) GetPagedPastes(page int) ([]structs.Paste, error) {
|
||||||
return d.GetPagedPastes(page)
|
return dbAdapter.GetPagedPastes(page)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) GetPastesPages() int {
|
func (dbh Handler) GetPastesPages() int {
|
||||||
return d.GetPastesPages()
|
return dbAdapter.GetPastesPages()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize initializes connection to database.
|
// Initialize initializes connection to database.
|
||||||
func (dbh Handler) Initialize() {
|
func (dbh Handler) Initialize() {
|
||||||
d.Initialize()
|
dbAdapter.Initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) RegisterDialect(di dialectinterface.Interface) {
|
func (dbh Handler) RegisterDialect(di dialectinterface.Interface) {
|
||||||
d.RegisterDialect(di)
|
dbAdapter.RegisterDialect(di)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) SavePaste(p *structs.Paste) (int64, error) {
|
func (dbh Handler) SavePaste(p *structs.Paste) (int64, error) {
|
||||||
return d.SavePaste(p)
|
return dbAdapter.SavePaste(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbh Handler) Shutdown() {
|
func (dbh Handler) Shutdown() {
|
||||||
d.Shutdown()
|
dbAdapter.Shutdown()
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@ func CreateHTML(currentPage int, pages int, linksBase string) string {
|
|||||||
var (
|
var (
|
||||||
ellipsisStartAdded = false
|
ellipsisStartAdded = false
|
||||||
ellipsisEndAdded = false
|
ellipsisEndAdded = false
|
||||||
|
// nolint:varnamelen
|
||||||
i = 2
|
i = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
c *context.Context
|
ctx *context.Context
|
||||||
log zerolog.Logger
|
log zerolog.Logger
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -123,6 +123,6 @@ func GetTemplate(ectx echo.Context, name string, data map[string]string) string
|
|||||||
|
|
||||||
// Initialize initializes package.
|
// Initialize initializes package.
|
||||||
func Initialize(cc *context.Context) {
|
func Initialize(cc *context.Context) {
|
||||||
c = cc
|
ctx = cc
|
||||||
log = c.Logger.With().Str("type", "internal").Str("package", "templater").Logger()
|
log = ctx.Logger.With().Str("type", "internal").Str("package", "templater").Logger()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user