Finish refactoring
ci/woodpecker/push/test_golang Pipeline was successful Details

develop
Leonid Maslakov 2 months ago
parent 04cde598a0
commit 2d2a1b1486

@ -20,9 +20,7 @@ package main
import (
"errors"
"flag"
"fmt"
"io/ioutil"
"net/http"
"os"
"strconv"
@ -32,13 +30,19 @@ import (
"git.lcomrade.su/root/lenpaste/internal/config"
"git.lcomrade.su/root/lenpaste/internal/logger"
"git.lcomrade.su/root/lenpaste/internal/model"
"git.lcomrade.su/root/lenpaste/internal/netshare"
"git.lcomrade.su/root/lenpaste/internal/raw"
"git.lcomrade.su/root/lenpaste/internal/storage"
"git.lcomrade.su/root/lenpaste/internal/web"
"github.com/urfave/cli/v2"
)
func backgroundJob(cleanJobPeriod time.Duration, db storage.DB, log logger.Logger) {
func fatal(e error) {
fmt.Fprintln(os.Stderr, model.SmallName+": error:", e.Error())
os.Exit(1)
}
func backgroundJob(cleanJobPeriod time.Duration, db *storage.DB, log *logger.Logger) {
for {
// Delete expired pastes
count, err := db.PasteDeleteExpired()
@ -53,254 +57,36 @@ func backgroundJob(cleanJobPeriod time.Duration, db storage.DB, log logger.Logge
}
}
func readFile(path string) (string, error) {
// Open file
file, err := os.Open(path)
if err != nil {
return "", err
}
defer file.Close()
func run(cfgDir string) error {
// Setup logger
log := logger.New("2006/01/02 15:04:05")
// Read file
fileByte, err := ioutil.ReadAll(file)
// Read configurations files
cfg, err := config.Load(cfgDir)
if err != nil {
return "", err
}
// Return result
return string(fileByte), nil
}
func exitOnError(e error) {
fmt.Fprintln(os.Stderr, "error:", e.Error())
os.Exit(1)
}
func printHelp(noErrors bool) {
println("Usage:", os.Args[0], "[-db-source] [OPTION]...")
println("")
println(" -address ADDRESS:PORT (default: :80)")
println()
println(" -db-driver Currently supported drivers: 'sqlite3' and 'postgres' (default: sqlite3)")
println(" -db-source DB source.")
println(" -db-max-open-conns Maximum number of connections to the database. (default: 25)")
println(" -db-max-idle-conns Maximum number of idle connections to the database. (default: 5)")
println(" -db-cleanup-period Interval at which the DB is cleared of expired but not yet deleted pastes. (default: 3h)")
println()
println(" -robots-disallow Prohibits search engine crawlers from indexing site using robots.txt file.")
println()
println(" -title-max-length Maximum length of the paste title. If 0 disable title, if -1 disable length limit. (default: 100)")
println(" -body-max-length Maximum length of the paste body. If -1 disable length limit. Can't be -1. (default: 20000)")
println(" -max-paste-lifetime Maximum lifetime of the paste. Examples: 10m, 1h 30m, 12h, 1w, 30d, 365d. (default: unlimited)")
println()
println(" -get-pastes-per-5min Maximum number of pastes that can be VIEWED in 5 minutes from one IP. If 0 disable rate-limit. (default: 50)")
println(" -get-pastes-per-15min Maximum number of pastes that can be VIEWED in 15 minutes from one IP. If 0 disable rate-limit. (default: 100)")
println(" -get-pastes-per-1hour Maximum number of pastes that can be VIEWED in 1 hour from one IP. If 0 disable rate-limit. (default: 500)")
println(" -new-pastes-per-5min Maximum number of pastes that can be CREATED in 5 minutes from one IP. If 0 disable rate-limit. (default: 15)")
println(" -new-pastes-per-15min Maximum number of pastes that can be CREATED in 15 minutes from one IP. If 0 disable rate-limit. (default: 30)")
println(" -new-pastes-per-1hour Maximum number of pastes that can be CREATED in 1 hour from one IP. If 0 disable rate-limit. (default: 40)")
println()
println(" -server-about Path to the TXT file that contains the server description.")
println(" -server-rules Path to the TXT file that contains the server rules.")
println(" -server-terms Path to the TXT file that contains the server terms of use.")
println()
println(" -admin-name Name of the administrator of this server.")
println(" -admin-mail Email of the administrator of this server.")
println()
println(" -ui-default-lifetime Lifetime of paste will be set by default in WEB interface. Examples: 10min, 1h, 1d, 2w, 6mon, 1y.")
println(" -ui-default-theme Sets the default theme for the WEB interface. Examples: dark, light, my_theme. (default: dark)")
println(" -ui-themes-dir Loads external WEB interface themes from directory.")
println()
println(" -lenpasswd-file File in LenPasswd format. If set, authorization will be required to create pastes.")
println()
println(" -version Display version and exit.")
println(" -help Display this help and exit.")
println()
println("Exit status:")
println(" 0 if you used the -help or -version flag")
println(" 1 if there is an error during initialization")
println(" 2 if command line arguments are not entered correctly")
if noErrors == false {
os.Exit(2)
}
os.Exit(0)
}
func printVersion() {
println(model.Version)
os.Exit(0)
}
func printFlagNotSet(flg string) {
println("flag is not set:", flg)
os.Exit(2)
}
func main() {
var err error
// Read cmd args
flag.Usage = func() { printHelp(false) }
flagAddress := flag.String("address", ":80", "")
flagDbDriver := flag.String("db-driver", "sqlite3", "")
flagDbSource := flag.String("db-source", "", "")
flagDbMaxOpenConns := flag.Int("db-max-open-conns", 25, "")
flagDbMaxIdleConns := flag.Int("db-max-idle-conns", 5, "")
flagDbCleanupPeriod := flag.String("db-cleanup-period", "3h", "")
flagRobotsDisallow := flag.Bool("robots-disallow", false, "")
flagTitleMaxLen := flag.Int("title-max-length", 100, "")
flagBodyMaxLen := flag.Int("body-max-length", 20000, "")
flagMaxLifetime := flag.String("max-paste-lifetime", "unlimited", "")
flagGetPastesPer5Min := flag.Uint("get-pastes-per-5min", 50, "")
flagGetPastesPer15Min := flag.Uint("get-pastes-per-15min", 100, "")
flagGetPastesPer1Hour := flag.Uint("get-pastes-per-1hour", 500, "")
flagNewPastesPer5Min := flag.Uint("new-pastes-per-5min", 15, "")
flagNewPastesPer15Min := flag.Uint("new-pastes-per-15min", 30, "")
flagNewPastesPer1Hour := flag.Uint("new-pastes-per-1hour", 40, "")
flagServerAbout := flag.String("server-about", "", "")
flagServerRules := flag.String("server-rules", "", "")
flagServerTerms := flag.String("server-terms", "", "")
flagAdminName := flag.String("admin-name", "", "")
flagAdminMail := flag.String("admin-mail", "", "")
flagUiDefaultLifetime := flag.String("ui-default-lifetime", "", "")
flagUiDefaultTheme := flag.String("ui-default-theme", "dark", "")
flagUiThemesDir := flag.String("ui-themes-dir", "", "")
flagLenPasswdFile := flag.String("lenpasswd-file", "", "")
flagVersion := flag.Bool("version", false, "")
flagHelp := flag.Bool("help", false, "")
flag.Parse()
// -help flag
if *flagHelp == true {
printHelp(true)
}
// -version flag
if *flagVersion == true {
printVersion()
}
// -db-source flag
if *flagDbSource == "" {
printFlagNotSet("-db-source")
}
// -body-max-length flag
if *flagBodyMaxLen == 0 {
println("-body-max-length flag cannot be 0")
os.Exit(2)
}
// -max-paste-lifetime
maxLifeTime := int64(-1)
if *flagMaxLifetime != "never" && *flagMaxLifetime != "unlimited" {
maxLifeTime, err = parseDuration(*flagMaxLifetime)
if err != nil {
exitOnError(err)
}
if maxLifeTime < 600 {
println("-max-paste-lifetime flag cannot have a value less than 10 minutes")
os.Exit(2)
}
}
// -new-pastes-per-5min flag
if *flagNewPastesPer5Min < 0 {
println("-new-pastes-per-5min flag cannot be negative")
os.Exit(2)
}
// Load server about
serverAbout := ""
if *flagServerAbout != "" {
serverAbout, err = readFile(*flagServerAbout)
if err != nil {
exitOnError(err)
}
}
// Load server rules
serverRules := ""
if *flagServerRules != "" {
serverRules, err = readFile(*flagServerRules)
if err != nil {
exitOnError(err)
}
}
// Load server "terms of use"
serverTermsOfUse := ""
if *flagServerTerms != "" {
if serverRules == "" {
println("In order to set the Terms of Use you must also specify the Server Rules. Server rules - this is a document written clearly for ordinary users. A Terms of Use is needed to protect the owner of the server from legal problems.")
os.Exit(2)
}
serverTermsOfUse, err = readFile(*flagServerTerms)
if err != nil {
exitOnError(err)
}
return err
}
// Settings
log := logger.New("2006/01/02 15:04:05")
db, err := storage.NewPool(*flagDbDriver, *flagDbSource, *flagDbMaxOpenConns, *flagDbMaxIdleConns)
// Open and init database
db, err := storage.Open(cfg)
if err != nil {
exitOnError(err)
return err
}
defer db.Close()
cfg := &config.Config{
Log: log,
RateLimitGet: netshare.NewRateLimitSystem(*flagGetPastesPer5Min, *flagGetPastesPer15Min, *flagGetPastesPer1Hour),
RateLimitNew: netshare.NewRateLimitSystem(*flagNewPastesPer5Min, *flagNewPastesPer15Min, *flagNewPastesPer1Hour),
Version: Version,
TitleMaxLen: *flagTitleMaxLen,
BodyMaxLen: *flagBodyMaxLen,
MaxLifeTime: maxLifeTime,
ServerAbout: serverAbout,
ServerRules: serverRules,
ServerTermsOfUse: serverTermsOfUse,
AdminName: *flagAdminName,
AdminMail: *flagAdminMail,
RobotsDisallow: *flagRobotsDisallow,
UiDefaultLifetime: *flagUiDefaultLifetime,
UiDefaultTheme: *flagUiDefaultTheme,
UiThemesDir: *flagUiThemesDir,
LenPasswdFile: *flagLenPasswdFile,
err = db.InitDB()
if err != nil {
return err
}
// Load data for HTTP handlers
apiv1Data := apiv1.Load(log, db, cfg)
rawData := raw.Load(db, cfg)
rawData := raw.Load(log, db, cfg)
// Init data base
err = storage.InitDB(*flagDbDriver, *flagDbSource)
webData, err := web.Load(log, db, cfg)
if err != nil {
exitOnError(err)
}
// Load pages
webData, err := web.Load(db, cfg)
if err != nil {
exitOnError(err)
return err
}
// Handlers
@ -315,17 +101,40 @@ func main() {
})
// Run background job
jobDuration, err := time.ParseDuration(*flagDbCleanupPeriod)
if err != nil {
exitOnError(err)
}
go backgroundJob(jobDuration, db, log)
go backgroundJob(time.Second*time.Duration(cfg.DB.CleanupPeriod), db, log)
// Run HTTP server
log.Info("Run HTTP server on " + *flagAddress)
err = http.ListenAndServe(*flagAddress, nil)
log.Info("Run HTTP server on " + cfg.HTTP.Address)
return http.ListenAndServe(cfg.HTTP.Address, nil)
}
func main() {
app := &cli.App{
Name: model.SmallName,
Usage: "Open source analogue of PasteBin",
Version: model.Version,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "cfg-dir",
Aliases: []string{"d"},
Usage: "directory with Lenpaste config files",
},
},
DefaultCommand: "help",
EnableBashCompletion: true,
Commands: []*cli.Command{
{
Name: "run",
Usage: "Run as demon",
Action: func(ctx *cli.Context) error {
return run(ctx.String("config"))
},
},
},
}
err := app.Run(os.Args)
if err != nil {
exitOnError(err)
fatal(err)
}
}

@ -1,6 +1,6 @@
module git.lcomrade.su/root/lenpaste
go 1.16
go 1.18
replace git.lcomrade.su/root/lenpaste/internal => ./internal
@ -9,4 +9,12 @@ require (
github.com/alecthomas/chroma/v2 v2.7.0
github.com/lib/pq v1.10.7
github.com/mattn/go-sqlite3 v1.14.16
github.com/urfave/cli/v2 v2.25.1
)
require (
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
)

@ -1,16 +1,21 @@
git.lcomrade.su/root/lineend v1.0.0 h1:qcxrR4DS18Erx+pG/EspoDhEDai+mjgSYefwSK2dq5g=
git.lcomrade.su/root/lineend v1.0.0/go.mod h1:D0q3jMx0I1PFZjAFwkmUNW8D5tIw8rZJoeUAxhYD7Ec=
github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink=
github.com/alecthomas/assert/v2 v2.2.1/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
github.com/alecthomas/chroma/v2 v2.7.0 h1:hm1rY6c/Ob4eGclpQ7X/A3yhqBOZNUTk9q+yhyLIViI=
github.com/alecthomas/chroma/v2 v2.7.0/go.mod h1:yrkMI9807G1ROx13fhe1v6PN2DDeaR73L3d+1nmYQtw=
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/urfave/cli/v2 v2.25.1 h1:zw8dSP7ghX0Gmm8vugrs6q9Ku0wzweqPyshy+syu9Gw=
github.com/urfave/cli/v2 v2.25.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=

@ -38,12 +38,12 @@ func (data *Data) newHand(rw http.ResponseWriter, req *http.Request) error {
var err error
// Check auth
if data.cfg.LenPasswdFile != "" {
if data.cfg.Paths.LenPasswdFile != "" {
authOk := false
user, pass, authExist := req.BasicAuth()
if authExist {
authOk, err = lenpasswd.LoadAndCheck(data.cfg.LenPasswdFile, user, pass)
authOk, err = lenpasswd.LoadAndCheck(data.cfg.Paths.LenPasswdFile, user, pass)
if err != nil {
return err
}

@ -66,7 +66,7 @@ func (data *Data) getServerInfoHand(rw http.ResponseWriter, req *http.Request) e
AdminMail: data.cfg.Public.AdminMail,
Syntaxes: data.lexers,
UiDefaultLifeTime: data.cfg.Paste.UiDefaultLifetimeStr,
AuthRequired: data.cfg.LenPasswdFile != "",
AuthRequired: data.cfg.Paths.LenPasswdFile != "",
}
// Return response

@ -18,9 +18,12 @@
package config
import "git.lcomrade.su/root/lenpaste/internal/model"
import (
"git.lcomrade.su/root/lenpaste/internal/model"
)
type Config struct {
HTTP ConfigHTTP `json:"http"`
DB ConfigDB `json:"database"`
Public ConfigPublic `json:"public"`
UI ConfigUI `json:"ui"`
@ -30,8 +33,11 @@ type Config struct {
Rules map[string]string `json:"-"`
TermsOfUse map[string]string `json:"-"`
ThemesDir string `json:"-"`
LenPasswdFile string `json:"-"`
Paths ConfigPaths `json:"-"`
}
type ConfigHTTP struct {
Address string `json:"address"`
}
type ConfigDB struct {
@ -41,6 +47,9 @@ type ConfigDB struct {
MaxIdleConns int `json:"max_idle_conns"`
ConnMaxLifetime int64 `json:"-"`
ConnMaxLifetimeStr string `json:"conn_max_lifetime"`
CleanupPeriod int64 `json:"-"`
CleanupPeriodStr string `json:"cleanup_period"`
}
type ConfigPublic struct {
@ -55,14 +64,27 @@ type ConfigUI struct {
}
type ConfigPaste struct {
TitleMaxLen int `json:"title_max_len"`
BodyMaxLen int `json:"body_max_len"`
MaxLifetime int64 `json:"max_lifetime"`
TitleMaxLen int `json:"title_max_len"`
BodyMaxLen int `json:"body_max_len"`
MaxLifetime int64 `json:"-"`
MaxLifetimeStr string `json:"max_lifetime"`
UiDefaultLifetime int64 `json:"-"`
UiDefaultLifetimeStr string `json:"ui_default_lifetime"`
}
type ConfigPaths struct {
MainCfg string `json:"-"`
AboutDir string `json:"-"`
RulesDir string `json:"-"`
TermsDir string `json:"-"`
ThemesDir string `json:"-"`
LenPasswdFile string `json:"-"`
}
func (cfg *Config) GetAbout(locale string) string {
out, ok := cfg.About[locale]
if !ok {

@ -0,0 +1,168 @@
// Copyright (C) 2021-2023 Leonid Maslakov.
// This file is part of Lenpaste.
// Lenpaste is free software: you can redistribute it
// and/or modify it under the terms of the
// GNU Affero Public License as published by the
// Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
// Lenpaste is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero Public License for more details.
// You should have received a copy of the GNU Affero Public License along with Lenpaste.
// If not, see <https://www.gnu.org/licenses/>.
package config
import (
"bytes"
"encoding/json"
"errors"
"os"
"path/filepath"
"strings"
"git.lcomrade.su/root/lenpaste/internal/model"
)
func Load(cfgDir string) (*Config, error) {
// Default configuration
cfg := Config{
HTTP: ConfigHTTP{
Address: ":80",
},
DB: ConfigDB{
Driver: "",
Source: "",
MaxOpenConns: 25,
MaxIdleConns: 5,
ConnMaxLifetime: 5 * 60,
ConnMaxLifetimeStr: "5m",
},
Public: ConfigPublic{
AdminName: "",
AdminMail: "",
RobotsDisallow: false,
},
UI: ConfigUI{
DefaultTheme: "dark",
},
Paste: ConfigPaste{
TitleMaxLen: 100,
BodyMaxLen: 20000,
MaxLifetime: 0,
MaxLifetimeStr: "unlimited",
UiDefaultLifetime: 0,
UiDefaultLifetimeStr: "",
},
About: nil,
Rules: nil,
TermsOfUse: nil,
Paths: ConfigPaths{
MainCfg: filepath.Join(cfgDir, model.SmallName+".json"),
AboutDir: filepath.Join(cfgDir, "about"),
RulesDir: filepath.Join(cfgDir, "rules"),
TermsDir: filepath.Join(cfgDir, "terms"),
ThemesDir: filepath.Join(cfgDir, "themes"),
LenPasswdFile: filepath.Join(cfgDir, "lenpasswd"),
},
}
// Read main configuration file
cfgFile, err := os.Open(cfg.Paths.MainCfg)
if err != nil {
return nil, errors.New("config: " + err.Error())
}
defer cfgFile.Close()
err = json.NewDecoder(cfgFile).Decode(&cfg)
if err != nil {
return nil, errors.New("config: " + err.Error())
}
// Convert strings duration to time
cfg.DB.ConnMaxLifetime, err = parseDuration(cfg.DB.ConnMaxLifetimeStr)
if err != nil {
return nil, err
}
cfg.Paste.MaxLifetime, err = parseDuration(cfg.Paste.MaxLifetimeStr)
if err != nil {
return nil, err
}
cfg.Paste.UiDefaultLifetime, err = parseDuration(cfg.Paste.UiDefaultLifetimeStr)
if err != nil {
return nil, err
}
// Read about, rules and terms of use
cfg.About, err = loadL10nFiles(cfg.Paths.AboutDir, ".txt")
if err != nil {
return nil, errors.New("config: " + err.Error())
}
cfg.Rules, err = loadL10nFiles(cfg.Paths.RulesDir, ".txt")
if err != nil {
return nil, errors.New("config: " + err.Error())
}
cfg.TermsOfUse, err = loadL10nFiles(cfg.Paths.TermsDir, ".txt")
if err != nil {
return nil, errors.New("config: " + err.Error())
}
return &cfg, nil
}
func loadL10nFiles(dir, ext string) (map[string]string, error) {
// Get list files in directory
files, err := os.ReadDir(dir)
if err != nil {
return nil, err
}
// Read files
out := make(map[string]string)
for _, part := range files {
if part.IsDir() {
continue
}
fileName := part.Name()
if !strings.HasSuffix(fileName, ext) {
continue
}
// Read file and add it to map
fileByte, err := os.ReadFile(filepath.Join(dir, fileName))
if err != nil {
return nil, err
}
out[strings.TrimSuffix(fileName, ext)] = bytes.NewBuffer(fileByte).String()
}
// If map is empty return nil
if len(out) == 0 {
return nil, nil
}
return out, nil
}

@ -22,10 +22,9 @@ import (
"errors"
"strconv"
"strings"
"time"
)
func ParseDuration(s string) (time.Duration, error) {
func parseDuration(s string) (int64, error) {
var out int64
for _, part := range strings.Split(s, " ") {
@ -68,5 +67,5 @@ func ParseDuration(s string) (time.Duration, error) {
return 0, errors.New(`parse duration: invalid format "` + part + `"`)
}
return time.Duration(out) * time.Second, nil
return out, nil
}

@ -2,19 +2,18 @@ package config
import (
"testing"
"time"
)
func TestParseDuration(t *testing.T) {
testData := map[string]time.Duration{
"10m": time.Second * 60 * 10,
"1h 1d": time.Second * 60 * 60 * 25,
"1w": time.Second * 60 * 60 * 24 * 7,
"365d": time.Second * 60 * 60 * 24 * 365,
testData := map[string]int64{
"10m": 60 * 10,
"1h 1d": 60 * 60 * 25,
"1w": 60 * 60 * 24 * 7,
"365d": 60 * 60 * 24 * 365,
}
for s, exp := range testData {
res, err := ParseDuration(s)
res, err := parseDuration(s)
if err != nil {
t.Fatal(err)
}

@ -62,7 +62,7 @@ func LoadFile(path string) (Data, error) {
pass := lineSplit[1]
_, exist := data[user]
if exist == true {
if exist {
return nil, errors.New("lenpasswd: overriding user " + user + " in line " + strconv.Itoa(i))
}
@ -74,7 +74,7 @@ func LoadFile(path string) (Data, error) {
func (data Data) Check(user string, pass string) bool {
truePass, exist := data[user]
if exist == false {
if !exist {
return false
}

@ -30,12 +30,12 @@ import (
)
type Logger struct {
TimeFormat string
timeFormat string
}
func New(timeFormat string) Logger {
return Logger{
TimeFormat: timeFormat,
func New(timeFormat string) *Logger {
return &Logger{
timeFormat: timeFormat,
}
}
@ -54,17 +54,17 @@ func getTrace() string {
}
func (cfg *Logger) Info(msg string) {
fmt.Fprintln(os.Stdout, time.Now().Format(cfg.TimeFormat), "[INFO] ", msg)
fmt.Fprintln(os.Stdout, time.Now().Format(cfg.timeFormat), "[INFO] ", msg)
}
func (cfg *Logger) Error(e error) {
fmt.Fprintln(os.Stderr, time.Now().Format(cfg.TimeFormat), "[ERROR] ", getTrace(), e.Error())
fmt.Fprintln(os.Stderr, time.Now().Format(cfg.timeFormat), "[ERROR] ", getTrace(), e.Error())
}
func (cfg *Logger) HttpRequest(req *http.Request, code int) {
fmt.Fprintln(os.Stdout, time.Now().Format(cfg.TimeFormat), "[REQUEST]", netshare.GetClientAddr(req).String(), req.Method, code, req.URL.Path, "(User-Agent: "+req.UserAgent()+")")
fmt.Fprintln(os.Stdout, time.Now().Format(cfg.timeFormat), "[REQUEST]", netshare.GetClientAddr(req).String(), req.Method, code, req.URL.Path, "(User-Agent: "+req.UserAgent()+")")
}
func (cfg *Logger) HttpError(req *http.Request, e error) {
fmt.Fprintln(os.Stderr, time.Now().Format(cfg.TimeFormat), "[ERROR] ", netshare.GetClientAddr(req).String(), req.Method, 500, req.URL.Path, "(User-Agent: "+req.UserAgent()+")", "Error:", getTrace(), e.Error())
fmt.Fprintln(os.Stderr, time.Now().Format(cfg.timeFormat), "[ERROR] ", netshare.GetClientAddr(req).String(), req.Method, 500, req.URL.Path, "(User-Agent: "+req.UserAgent()+")", "Error:", getTrace(), e.Error())
}

@ -19,6 +19,7 @@
package model
const (
SmallName = "lenpaste"
Software = "Lenpaste"
BaseLocale = "en"
BaseTheme = "dark"

@ -88,7 +88,7 @@ func Load(log *logger.Logger, db *storage.DB, cfg *config.Config) (*Data, error)
}
// Load themes
data.themes, err = loadThemes(cfg.ThemesDir, data.l10n, cfg.UI.DefaultTheme)
data.themes, err = loadThemes(cfg.Paths.ThemesDir, data.l10n, cfg.UI.DefaultTheme)
if err != nil {
return nil, err
}

@ -51,12 +51,12 @@ func (data *Data) newPasteHand(rw http.ResponseWriter, req *http.Request) error
// Check auth
authOk := true
if data.cfg.LenPasswdFile != "" {
if data.cfg.Paths.LenPasswdFile != "" {
authOk = false
user, pass, authExist := req.BasicAuth()
if authExist {
authOk, err = lenpasswd.LoadAndCheck(data.cfg.LenPasswdFile, user, pass)
authOk, err = lenpasswd.LoadAndCheck(data.cfg.Paths.LenPasswdFile, user, pass)
if err != nil {
return err
}

@ -52,12 +52,12 @@ func (data *Data) settingsHand(rw http.ResponseWriter, req *http.Request) error
// Check auth
authOk := true
if data.cfg.LenPasswdFile != "" {
if data.cfg.Paths.LenPasswdFile != "" {
authOk = false
user, pass, authExist := req.BasicAuth()
if authExist {
authOk, err = lenpasswd.LoadAndCheck(data.cfg.LenPasswdFile, user, pass)
authOk, err = lenpasswd.LoadAndCheck(data.cfg.Paths.LenPasswdFile, user, pass)
if err != nil {
return err
}

Loading…
Cancel
Save