add README + golangci config + fix lint
This commit is contained in:
parent
eede129f84
commit
ffa9b52778
133
.golangci.yml
Normal file
133
.golangci.yml
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
linters-settings:
|
||||||
|
# depguard: // Specific for golangci repository
|
||||||
|
# list-type: blacklist
|
||||||
|
# packages:
|
||||||
|
# # logging is allowed only by logutils.Log, logrus
|
||||||
|
# # is allowed to use only in logutils package
|
||||||
|
# - github.com/sirupsen/logrus
|
||||||
|
# packages-with-error-message:
|
||||||
|
# - github.com/sirupsen/logrus: 'logging is allowed only by logutils.Log'
|
||||||
|
dupl:
|
||||||
|
threshold: 100
|
||||||
|
funlen:
|
||||||
|
lines: 100
|
||||||
|
statements: 50
|
||||||
|
gci:
|
||||||
|
sections:
|
||||||
|
prefix(fetchsysd)
|
||||||
|
goconst:
|
||||||
|
min-len: 2
|
||||||
|
min-occurrences: 2
|
||||||
|
gocritic:
|
||||||
|
enabled-tags:
|
||||||
|
- diagnostic
|
||||||
|
- experimental
|
||||||
|
- opinionated
|
||||||
|
- performance
|
||||||
|
- style
|
||||||
|
disabled-checks:
|
||||||
|
- dupImport # https://github.com/go-critic/go-critic/issues/845
|
||||||
|
- ifElseChain
|
||||||
|
- octalLiteral
|
||||||
|
# - whyNoLint
|
||||||
|
- wrapperFunc
|
||||||
|
gocyclo:
|
||||||
|
min-complexity: 15
|
||||||
|
goimports:
|
||||||
|
local-prefixes: localenv
|
||||||
|
mnd:
|
||||||
|
# don't include the "operation" and "assign"
|
||||||
|
checks:
|
||||||
|
- argument
|
||||||
|
- case
|
||||||
|
- condition
|
||||||
|
- return
|
||||||
|
govet:
|
||||||
|
shadow: true
|
||||||
|
# settings: // Specific for golangci repository
|
||||||
|
# printf:
|
||||||
|
# funcs:
|
||||||
|
# - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
|
||||||
|
# - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
|
||||||
|
# - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
|
||||||
|
# - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
|
||||||
|
lll:
|
||||||
|
line-length: 200
|
||||||
|
maligned:
|
||||||
|
suggest-new: true
|
||||||
|
misspell:
|
||||||
|
locale: US
|
||||||
|
nolintlint:
|
||||||
|
allow-leading-space: true # don't require machine-readable nolint directives (i.e. with no leading space)
|
||||||
|
allow-unused: false # report any unused nolint directives
|
||||||
|
require-explanation: false # don't require an explanation for nolint directives
|
||||||
|
require-specific: false # don't require nolint directives to be specific about which linter is being skipped
|
||||||
|
errcheck:
|
||||||
|
check-blank: true
|
||||||
|
exclude-functions:
|
||||||
|
- '(*github.com/gin-gonic/gin.Error).SetType'
|
||||||
|
- '(*github.com/gin-gonic/gin.Context).Error'
|
||||||
|
|
||||||
|
linters:
|
||||||
|
disable-all: true
|
||||||
|
enable:
|
||||||
|
- bodyclose
|
||||||
|
# - deadcode # deprecated (since v1.49.0)
|
||||||
|
# - depguard
|
||||||
|
- dogsled
|
||||||
|
- dupl
|
||||||
|
- errcheck
|
||||||
|
- copyloopvar
|
||||||
|
- exhaustive
|
||||||
|
- funlen
|
||||||
|
- gochecknoinits
|
||||||
|
- goconst
|
||||||
|
- gocritic
|
||||||
|
- gocyclo
|
||||||
|
- gofmt
|
||||||
|
- goimports
|
||||||
|
- mnd
|
||||||
|
- goprintffuncname
|
||||||
|
- gosec
|
||||||
|
- gosimple
|
||||||
|
- govet
|
||||||
|
- ineffassign
|
||||||
|
- lll
|
||||||
|
- misspell
|
||||||
|
- nakedret
|
||||||
|
- noctx
|
||||||
|
- nolintlint
|
||||||
|
# - rowserrcheck # https://github.com/golangci/golangci-lint/issues/2649
|
||||||
|
- staticcheck
|
||||||
|
# - structcheck # https://github.com/golangci/golangci-lint/issues/2649
|
||||||
|
- stylecheck
|
||||||
|
- typecheck
|
||||||
|
- unconvert
|
||||||
|
- unparam
|
||||||
|
- unused
|
||||||
|
# - varcheck # deprecated (since v1.49.0)
|
||||||
|
- whitespace
|
||||||
|
# - gochecknoglobals # too many global in ds9
|
||||||
|
|
||||||
|
# don't enable:
|
||||||
|
# - asciicheck
|
||||||
|
# - scopelint
|
||||||
|
# - gocognit
|
||||||
|
# - godot
|
||||||
|
# - godox
|
||||||
|
# - goerr113
|
||||||
|
# - interfacer
|
||||||
|
# - maligned
|
||||||
|
# - nestif
|
||||||
|
# - prealloc
|
||||||
|
# - testpackage
|
||||||
|
# - revive
|
||||||
|
# - wsl
|
||||||
|
|
||||||
|
# issues:
|
||||||
|
# Excluding configuration per-path, per-linter, per-text and per-source
|
||||||
|
# fix: true
|
||||||
|
|
||||||
|
run:
|
||||||
|
timeout: 5m
|
||||||
|
skip-dirs: []
|
||||||
3
README.md
Normal file
3
README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# librapi
|
||||||
|
|
||||||
|
A simple server to store, search and download books.
|
||||||
@ -113,7 +113,7 @@ func postLogin(w http.ResponseWriter, r *http.Request, s *services.SessionStore)
|
|||||||
http.Error(w, "unexpected error occurred", http.StatusInternalServerError)
|
http.Error(w, "unexpected error occurred", http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(400)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
fmt.Fprint(w, buf.String())
|
fmt.Fprint(w, buf.String())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -128,7 +128,7 @@ func postLogin(w http.ResponseWriter, r *http.Request, s *services.SessionStore)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(401)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
fmt.Fprint(w, buf.String())
|
fmt.Fprint(w, buf.String())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -137,7 +137,9 @@ func postLogin(w http.ResponseWriter, r *http.Request, s *services.SessionStore)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("unable to create a new session")
|
log.Err(err).Msg("unable to create a new session")
|
||||||
http.Error(w, "unexpected error occurred", http.StatusInternalServerError)
|
http.Error(w, "unexpected error occurred", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cookie := session.GenerateCookie()
|
cookie := session.GenerateCookie()
|
||||||
http.SetCookie(w, cookie)
|
http.SetCookie(w, cookie)
|
||||||
|
|
||||||
|
|||||||
@ -128,8 +128,8 @@ func extractBookForm(r *http.Request) BookForm {
|
|||||||
}
|
}
|
||||||
bf.Editor.Value = editor
|
bf.Editor.Value = editor
|
||||||
|
|
||||||
if a := r.FormValue(bf.Authors.Name); len(a) != 0 {
|
if a := r.FormValue(bf.Authors.Name); a != "" {
|
||||||
bf.Authors.Value = strings.Split(",", a)
|
bf.Authors.Value = strings.Split(a, ",")
|
||||||
} else {
|
} else {
|
||||||
bf.Authors.Err = ErrInvalidAuthors.Error()
|
bf.Authors.Err = ErrInvalidAuthors.Error()
|
||||||
}
|
}
|
||||||
@ -141,8 +141,8 @@ func extractBookForm(r *http.Request) BookForm {
|
|||||||
}
|
}
|
||||||
bf.Year.Value = year
|
bf.Year.Value = year
|
||||||
|
|
||||||
if kw := r.FormValue(bf.Keywords.Name); len(kw) != 0 {
|
if kw := r.FormValue(bf.Keywords.Name); kw != "" {
|
||||||
bf.Keywords.Value = strings.Split(",", kw)
|
bf.Keywords.Value = strings.Split(kw, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
file, fileh, err := r.FormFile(bf.File.Name)
|
file, fileh, err := r.FormFile(bf.File.Name)
|
||||||
@ -179,7 +179,7 @@ func postUploadFile(w http.ResponseWriter, r *http.Request, s *services.SessionS
|
|||||||
http.Error(w, "unexpected error occurred", http.StatusInternalServerError)
|
http.Error(w, "unexpected error occurred", http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(401)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
fmt.Fprint(w, buf.String())
|
fmt.Fprint(w, buf.String())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -192,7 +192,7 @@ func postUploadFile(w http.ResponseWriter, r *http.Request, s *services.SessionS
|
|||||||
}
|
}
|
||||||
|
|
||||||
if bf.HasErrors() {
|
if bf.HasErrors() {
|
||||||
w.WriteHeader(400)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
fmt.Fprint(w, buf.String())
|
fmt.Fprint(w, buf.String())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -202,12 +202,12 @@ func postUploadFile(w http.ResponseWriter, r *http.Request, s *services.SessionS
|
|||||||
|
|
||||||
dst, err := os.Create(filename)
|
dst, err := os.Create(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err := uploadForm.Execute(buf, &BookForm{Error: "unexpected error occured while creating file"}); err != nil {
|
if err := uploadForm.Execute(buf, &BookForm{Error: "unexpected error occurred while creating file"}); err != nil {
|
||||||
log.Err(err).Msg("unable to generate template")
|
log.Err(err).Msg("unable to generate template")
|
||||||
http.Error(w, "unexpected error occurred", http.StatusInternalServerError)
|
http.Error(w, "unexpected error occurred", http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
fmt.Fprint(w, buf.String())
|
fmt.Fprint(w, buf.String())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -215,13 +215,13 @@ func postUploadFile(w http.ResponseWriter, r *http.Request, s *services.SessionS
|
|||||||
defer dst.Close()
|
defer dst.Close()
|
||||||
|
|
||||||
if _, err := io.Copy(dst, bf.File.Value.file); err != nil {
|
if _, err := io.Copy(dst, bf.File.Value.file); err != nil {
|
||||||
if err := uploadForm.Execute(buf, &BookForm{Error: "unexpected error occured while uploading file"}); err != nil {
|
if err := uploadForm.Execute(buf, &BookForm{Error: "unexpected error occurred while uploading file"}); err != nil {
|
||||||
log.Err(err).Msg("unable to generate template")
|
log.Err(err).Msg("unable to generate template")
|
||||||
http.Error(w, "unexpected error occurred", http.StatusInternalServerError)
|
http.Error(w, "unexpected error occurred", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
fmt.Fprint(w, buf.String())
|
fmt.Fprint(w, buf.String())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -236,7 +236,7 @@ func postUploadFile(w http.ResponseWriter, r *http.Request, s *services.SessionS
|
|||||||
fmt.Fprint(w, buf.String())
|
fmt.Fprint(w, buf.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUploadFile(w http.ResponseWriter, r *http.Request) {
|
func getUploadFile(w http.ResponseWriter, _ *http.Request) {
|
||||||
uploadForm := templates.GetUploadForm()
|
uploadForm := templates.GetUploadForm()
|
||||||
if uploadForm == nil {
|
if uploadForm == nil {
|
||||||
log.Error().Msg("unable to load upload form")
|
log.Error().Msg("unable to load upload form")
|
||||||
|
|||||||
@ -30,12 +30,12 @@ var APISecure = sync.OnceValue[bool](func() bool {
|
|||||||
})
|
})
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrSessionIdCollision = errors.New("sessionId collision")
|
ErrSessionIDCollision = errors.New("sessionId collision")
|
||||||
ErrUnauthorized = errors.New("unauthorized")
|
ErrUnauthorized = errors.New("unauthorized")
|
||||||
)
|
)
|
||||||
|
|
||||||
func generateSessionID() (string, error) {
|
func generateSessionID() (string, error) {
|
||||||
sessionID := make([]byte, 32)
|
sessionID := make([]byte, 32) //nolint
|
||||||
if _, err := rand.Read(sessionID); err != nil {
|
if _, err := rand.Read(sessionID); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -45,7 +45,7 @@ func generateSessionID() (string, error) {
|
|||||||
|
|
||||||
type Session struct {
|
type Session struct {
|
||||||
l sync.RWMutex
|
l sync.RWMutex
|
||||||
sessionId string
|
sessionID string
|
||||||
expirationTime time.Time
|
expirationTime time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ func (s *Session) GenerateCookie() *http.Cookie {
|
|||||||
|
|
||||||
return &http.Cookie{
|
return &http.Cookie{
|
||||||
Name: "session_id",
|
Name: "session_id",
|
||||||
Value: s.sessionId,
|
Value: s.sessionID,
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
Secure: APISecure(),
|
Secure: APISecure(),
|
||||||
Expires: s.expirationTime,
|
Expires: s.expirationTime,
|
||||||
@ -97,13 +97,13 @@ func (s *SessionStore) purge() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, session := range toDelete {
|
for _, session := range toDelete {
|
||||||
log.Debug().Str("sessionId", session.sessionId).Msg("purge expired session")
|
log.Debug().Str("sessionId", session.sessionID).Msg("purge expired session")
|
||||||
delete(s.sessions, session.sessionId)
|
delete(s.sessions, session.sessionID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SessionStore) purgeWorker() {
|
func (s *SessionStore) purgeWorker() {
|
||||||
ticker := time.NewTicker(10 * time.Second)
|
ticker := time.NewTicker(10 * time.Second) //nolint
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@ -127,7 +127,7 @@ func (s *SessionStore) Done() <-chan struct{} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *SessionStore) NewSession() (*Session, error) {
|
func (s *SessionStore) NewSession() (*Session, error) {
|
||||||
sessionId, err := generateSessionID()
|
sessionID, err := generateSessionID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("unable to generate sessionId")
|
log.Err(err).Msg("unable to generate sessionId")
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -136,14 +136,14 @@ func (s *SessionStore) NewSession() (*Session, error) {
|
|||||||
s.l.Lock()
|
s.l.Lock()
|
||||||
defer s.l.Unlock()
|
defer s.l.Unlock()
|
||||||
|
|
||||||
if _, ok := s.sessions[sessionId]; ok {
|
if _, ok := s.sessions[sessionID]; ok {
|
||||||
log.Error().Str("sessionId", sessionId).Msg("sessionId collision")
|
log.Error().Str("sessionId", sessionID).Msg("sessionId collision")
|
||||||
return nil, ErrSessionIdCollision
|
return nil, ErrSessionIDCollision
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now().Add(APISessionExpirationDuration())
|
now := time.Now().Add(APISessionExpirationDuration())
|
||||||
session := Session{expirationTime: now, sessionId: sessionId}
|
session := Session{expirationTime: now, sessionID: sessionID}
|
||||||
s.sessions[sessionId] = &session
|
s.sessions[sessionID] = &session
|
||||||
|
|
||||||
return &session, nil
|
return &session, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user