Skip to content

Commit

Permalink
v0.2.9: Update dependencies and introduce golangci-lint
Browse files Browse the repository at this point in the history
  • Loading branch information
wneessen committed Nov 10, 2022
1 parent 0602fd6 commit 86eaadb
Show file tree
Hide file tree
Showing 16 changed files with 168 additions and 66 deletions.
49 changes: 49 additions & 0 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
#
# SPDX-License-Identifier: CC0-1.0

name: golangci-lint
on:
push:
tags:
- v*
branches:
- main
pull_request:
permissions:
contents: read
# Optional: allow read access to pull request. Use with `only-new-issues` option.
# pull-requests: read
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.19
- uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
version: latest

# Optional: working directory, useful for monorepos
# working-directory: somedir

# Optional: golangci-lint command line arguments.
# args: --issues-exit-code=0

# Optional: show only new issues if it's a pull request. The default value is `false`.
# only-new-issues: true

# Optional: if set to true then the all caching functionality will be complete disabled,
# takes precedence over all other caching options.
# skip-cache: true

# Optional: if set to true then the action don't cache or restore ~/go/pkg.
# skip-pkg-cache: true

# Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
# skip-build-cache: true
11 changes: 11 additions & 0 deletions .golangci.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
##
## SPDX-License-Identifier: MIT

[run]
go = "1.16"
tests = true

[linters]
enable = ["stylecheck", "whitespace", "containedctx", "contextcheck", "decorder",
"errname", "errorlint", "gofmt", "gofumpt"]
2 changes: 1 addition & 1 deletion api/api.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package api

import (
"github.com/ReneKroon/ttlcache/v2"
"github.com/jellydator/ttlcache/v2"
"github.com/wneessen/js-mailer/config"
)

Expand Down
8 changes: 5 additions & 3 deletions api/form.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package api

import (
"errors"
"fmt"
"github.com/ReneKroon/ttlcache/v2"

"github.com/jellydator/ttlcache/v2"
"github.com/wneessen/js-mailer/form"
)

Expand All @@ -11,7 +13,7 @@ import (
func (r *Route) GetForm(i string) (form.Form, error) {
var formObj form.Form
cacheForm, err := r.Cache.Get(fmt.Sprintf("formObj_%s", i))
if err != nil && err != ttlcache.ErrNotFound {
if err != nil && !errors.Is(err, ttlcache.ErrNotFound) {
return formObj, err
}
if cacheForm != nil {
Expand All @@ -21,7 +23,7 @@ func (r *Route) GetForm(i string) (form.Form, error) {
if err != nil {
return formObj, err
}
if err := r.Cache.Set(fmt.Sprintf("formObj_%s", formObj.Id), formObj); err != nil {
if err := r.Cache.Set(fmt.Sprintf("formObj_%s", formObj.ID), formObj); err != nil {
return formObj, err
}
}
Expand Down
3 changes: 2 additions & 1 deletion api/ping.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package api

import (
"github.com/labstack/echo/v4"
"net/http"

"github.com/labstack/echo/v4"
)

// PingResponse reflects the JSON structure for a ping response
Expand Down
10 changes: 5 additions & 5 deletions api/sendform.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ package api

import (
"fmt"
"net/http"
"time"

"github.com/labstack/echo/v4"
"github.com/wneessen/go-mail"
"github.com/wneessen/js-mailer/form"
"github.com/wneessen/js-mailer/response"
"net/http"
"time"
)

// SentSuccessful represents confirmation JSON structure for a successfully sent message
type SentSuccessful struct {
FormId string `json:"form_id"`
FormID string `json:"form_id"`
SendTime int64 `json:"send_time"`
ConfirmationSent bool `json:"confirmation_sent"`
ConfirmationRcpt string `json:"confirmation_rcpt"`
Expand Down Expand Up @@ -112,7 +113,7 @@ func (r *Route) SendForm(c echo.Context) error {
StatusCode: http.StatusOK,
Status: http.StatusText(http.StatusOK),
Data: SentSuccessful{
FormId: sr.FormObj.Id,
FormID: sr.FormObj.ID,
SendTime: time.Now().Unix(),
ConfirmationSent: confirmWasSent,
ConfirmationRcpt: confirmRcpt,
Expand Down Expand Up @@ -151,7 +152,6 @@ func GetMailClient(f *form.Form) (*mail.Client, error) {
mc, err := mail.NewClient(f.Server.Host, mail.WithPort(f.Server.Port),
mail.WithUsername(f.Server.Username), mail.WithPassword(f.Server.Password),
mail.WithSMTPAuth(mail.SMTPAuthPlain), mail.WithTimeout(serverTimeout))

if err != nil {
return mc, err
}
Expand Down
31 changes: 17 additions & 14 deletions api/sendform_mw.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@ import (
"bytes"
"crypto/sha256"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
"regexp"
"strings"

"github.com/ReneKroon/ttlcache/v2"
"github.com/jellydator/ttlcache/v2"
"github.com/labstack/echo/v4"
"github.com/wneessen/js-mailer/form"
"github.com/wneessen/js-mailer/response"
)

// SendFormRequest reflects the structure of the send form request data
type SendFormRequest struct {
FormId string `param:"fid"`
FormID string `param:"fid"`
FormObj *form.Form
Token string `param:"token"`
TokenResp *TokenResponse
Expand Down Expand Up @@ -56,21 +57,23 @@ func (r *Route) SendFormBindForm(next echo.HandlerFunc) echo.HandlerFunc {

// Let's retrieve the formObj from cache
cacheObj, err := r.Cache.Get(sr.Token)
if err == ttlcache.ErrNotFound {
return echo.NewHTTPError(http.StatusNotFound, "not a valid send URL")
}
if err != nil && err != ttlcache.ErrNotFound {
c.Logger().Errorf("failed to look up token in cache: %s", err)
return echo.NewHTTPError(http.StatusInternalServerError, &response.ErrorObj{
Message: "failed to look up token in cache",
Data: err.Error(),
})
if err != nil {
switch {
case errors.Is(err, ttlcache.ErrNotFound):
return echo.NewHTTPError(http.StatusNotFound, "not a valid send URL")
case !errors.Is(err, ttlcache.ErrNotFound):
c.Logger().Errorf("failed to look up token in cache: %s", err)
return echo.NewHTTPError(http.StatusInternalServerError, &response.ErrorObj{
Message: "failed to look up token in cache",
Data: err.Error(),
})
}
}
if cacheObj != nil {
TokenRespObj := cacheObj.(TokenResponse)
sr.TokenResp = &TokenRespObj
}
if sr.TokenResp != nil && sr.TokenResp.FormId != sr.FormId {
if sr.TokenResp != nil && sr.TokenResp.FormID != sr.FormID {
c.Logger().Warn("URL form id does not match the cached form object id")
return echo.NewHTTPError(http.StatusBadRequest, "invalid form id")
}
Expand All @@ -81,7 +84,7 @@ func (r *Route) SendFormBindForm(next echo.HandlerFunc) echo.HandlerFunc {
}()

// Let's try to read formobj from cache
formObj, err := r.GetForm(sr.FormId)
formObj, err := r.GetForm(sr.FormID)
if err != nil {
c.Logger().Errorf("failed get form object: %s", err)
return echo.NewHTTPError(http.StatusInternalServerError, "form lookup failed")
Expand Down Expand Up @@ -312,7 +315,7 @@ func (r *Route) SendFormCheckToken(next echo.HandlerFunc) echo.HandlerFunc {
return echo.NewHTTPError(http.StatusUnauthorized, "domain not allowed to access form")
}
tokenText := fmt.Sprintf("%s_%d_%d_%s_%s", reqOrigin, sr.TokenResp.CreateTime,
sr.TokenResp.ExpireTime, sr.FormObj.Id, sr.FormObj.Secret)
sr.TokenResp.ExpireTime, sr.FormObj.ID, sr.FormObj.Secret)
tokenSha := fmt.Sprintf("%x", sha256.Sum256([]byte(tokenText)))
if tokenSha != sr.Token {
c.Logger().Errorf("security token does not match")
Expand Down
23 changes: 12 additions & 11 deletions api/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,26 @@ package api
import (
"crypto/sha256"
"fmt"
"github.com/labstack/echo/v4"
"github.com/wneessen/js-mailer/response"
"net/http"
"net/url"
"time"

"github.com/labstack/echo/v4"
"github.com/wneessen/js-mailer/response"
)

// TokenRequest reflects the incoming gettoken request data that for the parameter binding
type TokenRequest struct {
FormId string `query:"formid" form:"formid"`
FormID string `query:"formid" form:"formid"`
}

// TokenResponse reflects the JSON response struct for token request
type TokenResponse struct {
Token string `json:"token"`
FormId string `json:"form_id"`
FormID string `json:"form_id"`
CreateTime int64 `json:"create_time,omitempty"`
ExpireTime int64 `json:"expire_time,omitempty"`
Url string `json:"url"`
URL string `json:"url"`
EncType string `json:"enc_type"`
Method string `json:"method"`
}
Expand All @@ -36,7 +37,7 @@ func (r *Route) GetToken(c echo.Context) error {
}

// Let's try to read formobj from cache
formObj, err := r.GetForm(fr.FormId)
formObj, err := r.GetForm(fr.FormID)
if err != nil {
c.Logger().Errorf("failed to get form object: %s", err)
return echo.NewHTTPError(http.StatusInternalServerError, &response.ErrorObj{
Expand All @@ -60,7 +61,7 @@ func (r *Route) GetToken(c echo.Context) error {
}
}
if !isValid {
c.Logger().Errorf("domain %q not in allowed domains list for form %s", reqOrigin, formObj.Id)
c.Logger().Errorf("domain %q not in allowed domains list for form %s", reqOrigin, formObj.ID)
return echo.NewHTTPError(http.StatusUnauthorized,
"domain is not authorized to access the requested form")
}
Expand All @@ -74,15 +75,15 @@ func (r *Route) GetToken(c echo.Context) error {
nowTime := time.Now()
expTime := time.Now().Add(time.Minute * 10)
tokenText := fmt.Sprintf("%s_%d_%d_%s_%s", reqOrigin, nowTime.Unix(), expTime.Unix(),
formObj.Id, formObj.Secret)
formObj.ID, formObj.Secret)
tokenSha := fmt.Sprintf("%x", sha256.Sum256([]byte(tokenText)))
respToken := TokenResponse{
Token: tokenSha,
FormId: formObj.Id,
FormID: formObj.ID,
CreateTime: nowTime.Unix(),
ExpireTime: expTime.Unix(),
Url: fmt.Sprintf("%s://%s/api/v1/send/%s/%s", reqScheme,
c.Request().Host, url.QueryEscape(formObj.Id), url.QueryEscape(tokenSha)),
URL: fmt.Sprintf("%s://%s/api/v1/send/%s/%s", reqScheme,
c.Request().Host, url.QueryEscape(formObj.ID), url.QueryEscape(tokenSha)),
EncType: "multipart/form-data",
Method: "post",
}
Expand Down
3 changes: 2 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package config

import (
"fmt"
"github.com/kkyr/fig"
"log"
"os"
"path/filepath"
"time"

"github.com/kkyr/fig"
)

// Config represents the global config object struct
Expand Down
9 changes: 5 additions & 4 deletions form/form.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package form

import (
"fmt"
"os"

"github.com/cyphar/filepath-securejoin"
"github.com/kkyr/fig"
"github.com/wneessen/js-mailer/config"
"os"
)

// Form reflect the configuration struct for form configurations
Expand All @@ -21,7 +22,7 @@ type Form struct {
Content string `fig:"content"`
}
Domains []string `fig:"domains" validate:"required"`
Id string `fig:"id" validate:"required"`
ID string `fig:"id" validate:"required"`
Recipients []string `fig:"recipients" validate:"required"`
ReplyTo struct {
Field string `json:"field"`
Expand Down Expand Up @@ -67,12 +68,12 @@ func NewForm(c *config.Config, i string) (Form, error) {
}
_, err = os.Stat(formPath)
if err != nil {
return Form{}, fmt.Errorf("failed to stat form config: %s", err)
return Form{}, fmt.Errorf("failed to stat form config: %w", err)
}
var formObj Form
if err := fig.Load(&formObj, fig.File(fmt.Sprintf("%s.json", i)),
fig.Dirs(c.Forms.Path)); err != nil {
return Form{}, fmt.Errorf("failed to read form config: %s", err)
return Form{}, fmt.Errorf("failed to read form config: %w", err)
}

return formObj, nil
Expand Down
8 changes: 7 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@ module github.com/wneessen/js-mailer
go 1.16

require (
github.com/ReneKroon/ttlcache/v2 v2.11.0
github.com/cyphar/filepath-securejoin v0.2.3
github.com/jellydator/ttlcache/v2 v2.11.1
github.com/kkyr/fig v0.3.0
github.com/labstack/echo/v4 v4.9.1
github.com/labstack/gommon v0.4.0
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/wneessen/go-mail v0.3.4
golang.org/x/crypto v0.2.0 // indirect
golang.org/x/sync v0.1.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading

0 comments on commit 86eaadb

Please sign in to comment.