Skip to content

Commit

Permalink
Merge branch 'umputun:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
saosangmo authored Jun 7, 2022
2 parents 2f6da7f + fe4db30 commit 0782fb3
Show file tree
Hide file tree
Showing 77 changed files with 7,507 additions and 848 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
/.vscode/
/.idea/
/bin/
/.git/

# source files
docker-compose.yml
Expand Down
5 changes: 2 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM umputun/baseimage:buildgo-v1.8.0 as build-backend
FROM umputun/baseimage:buildgo-v1.9.1 as build-backend

ARG CI
ARG GITHUB_REF
Expand All @@ -8,7 +8,6 @@ ARG SKIP_BACKEND_TEST
ARG BACKEND_TEST_TIMEOUT

ADD backend /build/backend
ADD .git/ /build/backend/.git/
WORKDIR /build/backend

ENV GOFLAGS="-mod=vendor"
Expand Down Expand Up @@ -73,7 +72,7 @@ RUN if [ -z "$SKIP_FRONTEND_BUILD" ] ; then \
; fi
RUN rm -rf ./node_modules

FROM umputun/baseimage:app-v1.8.0
FROM umputun/baseimage:app-v1.9.1

WORKDIR /srv

Expand Down
6 changes: 3 additions & 3 deletions Dockerfile.artifacts
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,18 @@ RUN cd /srv/frontend && \
npm run build && \
rm -rf ./node_modules

FROM umputun/baseimage:buildgo-latest as build-backend
FROM umputun/baseimage:buildgo-v1.9.1 as build-backend

ARG GITHUB_TOKEN
ARG GITHUB_REF
ARG GITHUB_SHA
ENV SKIP_BACKEND_TEST=true

WORKDIR /build/backend
ADD backend /build/backend
ADD README.md /build/
ADD LICENSE /build/

ADD .git/ /build/backend/.git/

COPY --from=build-frontend /srv/frontend/public/ web

RUN \
Expand Down
21 changes: 14 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
OS=linux
ARCH=amd64
GITHUB_REF=$(shell git rev-parse --symbolic-full-name HEAD)
GITHUB_SHA=$(shell git rev-parse --short HEAD)

bin:
docker build -f Dockerfile.artifacts -t remark42.bin .
Expand All @@ -9,22 +11,26 @@ bin:
docker rm -f remark42.bin

docker:
docker build -t umputun/remark42 --build-arg SKIP_FRONTEND_TEST=true --build-arg SKIP_BACKEND_TEST=true .
docker build -t umputun/remark42 --build-arg GITHUB_REF=$(GITHUB_REF) --build-arg GITHUB_SHA=$(GITHUB_SHA) \
--build-arg CI=true --build-arg SKIP_FRONTEND_TEST=true --build-arg SKIP_BACKEND_TEST=true .

dockerx:
docker buildx build --build-arg SKIP_FRONTEND_TEST=true --build-arg SKIP_BACKEND_TEST=true \
--progress=plain --platform linux/amd64,linux/arm/v7,linux/arm64 \
-t ghcr.io/umputun/remark42:master -t umputun/remark42:master .
docker buildx build --build-arg GITHUB_REF=$(GITHUB_REF) --build-arg GITHUB_SHA=$(GITHUB_SHA) --build-arg CI=true \
--build-arg SKIP_FRONTEND_TEST=true --build-arg SKIP_BACKEND_TEST=true \
--progress=plain --platform linux/amd64,linux/arm/v7,linux/arm64 \
-t ghcr.io/umputun/remark42:master -t umputun/remark42:master .

release:
docker build -f Dockerfile.artifacts --no-cache --pull -t remark42.bin .
docker build -f Dockerfile.artifacts --no-cache --pull --build-arg CI=true \
--build-arg GITHUB_REF=$(GITHUB_REF) --build-arg GITHUB_SHA=$(GITHUB_SHA) -t remark42.bin .
- @docker rm -f remark42.bin 2>/dev/null || exit 0
- @mkdir -p bin
docker run -d --name=remark42.bin remark42.bin
docker cp remark42.bin:/artifacts/remark42.linux-amd64.tar.gz bin/remark42.linux-amd64.tar.gz
docker cp remark42.bin:/artifacts/remark42.linux-386.tar.gz bin/remark42.linux-386.tar.gz
docker cp remark42.bin:/artifacts/remark42.linux-arm64.tar.gz bin/remark42.linux-arm64.tar.gz
docker cp remark42.bin:/artifacts/remark42.darwin-amd64.tar.gz bin/remark42.darwin-amd64.tar.gz
docker cp remark42.bin:/artifacts/remark42.darwin-arm64.tar.gz bin/remark42.darwin-arm64.tar.gz
docker cp remark42.bin:/artifacts/remark42.freebsd-amd64.tar.gz bin/remark42.freebsd-amd64.tar.gz
docker cp remark42.bin:/artifacts/remark42.windows-amd64.zip bin/remark42.windows-amd64.zip
docker rm -f remark42.bin
Expand All @@ -39,8 +45,9 @@ frontend:
docker-compose -f compose-dev-frontend.yml build

rundev:
docker pull umputun/baseimage:buildgo-latest
SKIP_BACKEND_TEST=true SKIP_FRONTEND_TEST=true docker-compose -f compose-private.yml build
docker pull umputun/baseimage:buildgo-v1.9.1
SKIP_BACKEND_TEST=true SKIP_FRONTEND_TEST=true GITHUB_REF=$(GITHUB_REF) GITHUB_SHA=$(GITHUB_SHA) CI=true \
docker-compose -f compose-private.yml build
docker-compose -f compose-private.yml up

.PHONY: bin backend
2 changes: 1 addition & 1 deletion backend/_example/memory_store/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ require (
go.etcd.io/bbolt v1.3.6 // indirect
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9 // indirect
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 // indirect
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
Expand Down
4 changes: 2 additions & 2 deletions backend/_example/memory_store/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
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=
Expand Down
8 changes: 8 additions & 0 deletions backend/app/cmd/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,49 +143,57 @@ func TestServerApp_AnonMode(t *testing.T) {
assert.Equal(t, http.StatusCreated, resp.StatusCode)

// try to login with non-latin name
time.Sleep(time.Second)
resp, err = client.Get(fmt.Sprintf("http://localhost:%d/auth/anonymous/login?user=Раз_Два%20%20Три_34567&aud=remark", port))
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusOK, resp.StatusCode)

// try to login with bad name
time.Sleep(time.Second)
resp, err = client.Get(fmt.Sprintf("http://localhost:%d/auth/anonymous/login?user=**blah123&aud=remark", port))
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusForbidden, resp.StatusCode)

// try to login with short name
time.Sleep(time.Second)
resp, err = client.Get(fmt.Sprintf("http://localhost:%d/auth/anonymous/login?user=bl%%20%%20&aud=remark", port))
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusForbidden, resp.StatusCode)

// try to login with name what have space in prefix
time.Sleep(time.Second)
resp, err = client.Get(fmt.Sprintf("http://localhost:%d/auth/anonymous/login?user=%%20somebody&aud=remark", port))
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusForbidden, resp.StatusCode)

// try to login with name what have space in suffix
time.Sleep(time.Second)
resp, err = client.Get(fmt.Sprintf("http://localhost:%d/auth/anonymous/login?user=somebody%%20&aud=remark", port))
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusForbidden, resp.StatusCode)

// try to login with long name
time.Sleep(time.Second)
ln := strings.Repeat("x", 65)
resp, err = client.Get(fmt.Sprintf("http://localhost:%d/auth/anonymous/login?user=%s&aud=remark", port, ln))
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusForbidden, resp.StatusCode)

// try to login with admin name
time.Sleep(time.Second)
resp, err = client.Get(fmt.Sprintf("http://localhost:%d/auth/anonymous/login?user=umpUtun&aud=remark", port))
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusOK, resp.StatusCode)

// try to add a comment as anonymous with admin name
time.Sleep(time.Second)
req, err = http.NewRequest("POST", fmt.Sprintf("http://localhost:%d/api/v1/comment", port),
strings.NewReader(`{"text": "test 123", "locator":{"url": "https://radio-t.com/blah1", "site": "remark"}}`))
require.NoError(t, err)
Expand Down
48 changes: 47 additions & 1 deletion backend/app/rest/api/rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"encoding/json"
"fmt"
"net/http"
"net/mail"
"regexp"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -223,7 +225,8 @@ func (s *Rest) routes() chi.Router {

router.Group(func(r chi.Router) {
r.Use(middleware.Timeout(5 * time.Second))
r.Use(logInfoWithBody, tollbooth_chi.LimitHandler(tollbooth.NewLimiter(10, nil)), middleware.NoCache)
r.Use(logInfoWithBody, tollbooth_chi.LimitHandler(tollbooth.NewLimiter(2, nil)), middleware.NoCache)
r.Use(validEmaiAuth()) // reject suspicious email logins
r.Mount("/auth", authHandler)
})

Expand Down Expand Up @@ -650,6 +653,49 @@ func subscribersOnly(enable bool) func(http.Handler) http.Handler {
}
}

// validEmaiAuth is a middleware for auth endpoints for email method.
// it rejects login request if user, site or email are suspicious
func validEmaiAuth() func(http.Handler) http.Handler {

reUser := regexp.MustCompile(`^[\p{L}\d\s_]{4,64}$`) // matches ui side validation, adding min/max limitation
reSite := regexp.MustCompile(`^[a-zA-Z\d\s_]{1,64}$`)

return func(h http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {

if r.URL.Path != "/auth/email/login" {
// not email login, skip the check
h.ServeHTTP(w, r)
return
}

if u := r.URL.Query().Get("user"); u != "" {
if !reUser.MatchString(u) {
http.Error(w, "Access denied", http.StatusForbidden)
return
}
}

if a := r.URL.Query().Get("address"); a != "" {
if _, err := mail.ParseAddress(a); err != nil {
http.Error(w, "Access denied", http.StatusForbidden)
return
}
}

if s := r.URL.Query().Get("site"); s != "" {
if !reSite.MatchString(s) {
http.Error(w, "Access denied", http.StatusForbidden)
return
}
}

h.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}
}

func parseError(err error, defaultCode int) (code int) {
code = defaultCode

Expand Down
2 changes: 1 addition & 1 deletion backend/app/rest/api/rest_private.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ func (s *private) createCommentCtrl(w http.ResponseWriter, r *http.Request) {
s.notifyService.Submit(notify.Request{Comment: finalComment})
}

log.Printf("[DEBUG] created commend %+v", finalComment)
log.Printf("[DEBUG] created comment %+v", finalComment)

render.Status(r, http.StatusCreated)
render.JSON(w, r, &finalComment)
Expand Down
31 changes: 31 additions & 0 deletions backend/app/rest/api/rest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,37 @@ func TestRest_subscribersOnly(t *testing.T) {
}
}

func Test_validEmaiAuth(t *testing.T) {
tbl := []struct {
req string
status int
}{
{"/auth/email/login?site=remark42&address=umputun%example.com&user=someone", http.StatusOK},
{"/auth/email/login?site=remark42&address=umputun%example.com&user=someone+blah", http.StatusOK},
{"/auth/email/login?site=remark42&address=umputun%example.com&user=Евгений+Умпутун", http.StatusOK},
{"/auth/email/login?site=remark42&address=umputun%example.com&user=12", http.StatusForbidden},
{"/auth/email/login?site=remark42&address=umputun%example.com&user=..blah+blah", http.StatusForbidden},
{"/auth/email/login?site=remark42&address=umputun%example.com&user=someonelooong+loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong", http.StatusForbidden},
{"/auth/twitter/login?site=remark42&address=umputun%example.com&user=..blah+blah", http.StatusOK},
{"/auth/email/login?site=remark42&address=umputun%example.com", http.StatusOK},
{"/auth/email/login?site=remark42&address=umputun+example.com&user=someone", http.StatusForbidden},
{"/auth/email/login?site=bad!site&address=umputun%example.com&user=someone", http.StatusForbidden},
{"/auth/email/login?site=loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooongsite&address=umputun%example.com&user=someone", http.StatusForbidden},
}

for i, tt := range tbl {
t.Run(strconv.Itoa(i), func(t *testing.T) {
req := httptest.NewRequest("GET", "http://example.com"+tt.req, http.NoBody)
w := httptest.NewRecorder()
h := validEmaiAuth()(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
h.ServeHTTP(w, req)
resp := w.Result()
assert.Equal(t, tt.status, resp.StatusCode)
assert.NoError(t, resp.Body.Close())
})
}
}

// randomPath pick a file or folder name which is not in use for sure
func randomPath(tempDir, basename, suffix string) (string, error) {
for i := 0; i < 10; i++ {
Expand Down
8 changes: 4 additions & 4 deletions backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (
github.com/go-chi/chi/v5 v5.0.7
github.com/go-chi/cors v1.2.1
github.com/go-chi/render v1.0.1
github.com/go-pkgz/auth v1.19.0
github.com/go-pkgz/auth v1.19.1-0.20220605174438-06e72788bcbb
github.com/go-pkgz/jrpc v0.2.0
github.com/go-pkgz/lcw v0.8.1
github.com/go-pkgz/lgr v0.10.4
Expand Down Expand Up @@ -39,7 +39,7 @@ require (
)

require (
cloud.google.com/go/compute v1.6.0 // indirect
cloud.google.com/go/compute v1.6.1 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
Expand All @@ -57,7 +57,7 @@ require (
github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/klauspost/compress v1.15.1 // indirect
github.com/klauspost/compress v1.15.2 // indirect
github.com/nullrocks/identicon v0.0.0-20180626043057-7875f45b0022 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
Expand All @@ -70,7 +70,7 @@ require (
go.mongodb.org/mongo-driver v1.9.1 // indirect
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
google.golang.org/appengine v1.6.7 // indirect
Expand Down
Loading

0 comments on commit 0782fb3

Please sign in to comment.