Merge pull request #207 from ssb-ngi-pointer/bugfixing

Bugfixing
This commit is contained in:
Henry 2021-05-10 14:04:29 +02:00 committed by GitHub
commit 8b52e4b2a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 144 additions and 14 deletions

2
go.mod
View File

@ -29,7 +29,7 @@ require (
github.com/volatiletech/sqlboiler-sqlite3 v0.0.0-20210314195744-a1c697a68aef // indirect
github.com/volatiletech/sqlboiler/v4 v4.5.0
github.com/volatiletech/strmangle v0.0.1
go.cryptoscope.co/muxrpc/v2 v2.0.2
go.cryptoscope.co/muxrpc/v2 v2.0.4
go.cryptoscope.co/netwrap v0.1.1
go.cryptoscope.co/secretstream v1.2.2
go.mindeco.de v1.11.0

2
go.sum
View File

@ -501,6 +501,8 @@ go.cryptoscope.co/muxrpc/v2 v2.0.1 h1:U1dS1dsFk7/LygH8o2qsWy8dHB5g3YeLtm0lsN7c1C
go.cryptoscope.co/muxrpc/v2 v2.0.1/go.mod h1:MgaeojIkWY3lLuoNw1mlMT3b3jiZwOj/fgsoGZp/VNA=
go.cryptoscope.co/muxrpc/v2 v2.0.2 h1:UdlGHY+EEYZpJz5HWnWz0r34pULYxJHfFTeqLvv+7sA=
go.cryptoscope.co/muxrpc/v2 v2.0.2/go.mod h1:MgaeojIkWY3lLuoNw1mlMT3b3jiZwOj/fgsoGZp/VNA=
go.cryptoscope.co/muxrpc/v2 v2.0.4 h1:NLN//zPt9UKFelnPNBh3fefrQ/TFylCflPZhKiDtK3U=
go.cryptoscope.co/muxrpc/v2 v2.0.4/go.mod h1:MgaeojIkWY3lLuoNw1mlMT3b3jiZwOj/fgsoGZp/VNA=
go.cryptoscope.co/netwrap v0.1.0/go.mod h1:7zcYswCa4CT+ct54e9uH9+IIbYYETEMHKDNpzl8Ukew=
go.cryptoscope.co/netwrap v0.1.1 h1:JLzzGKEvrUrkKzu3iM0DhpHmt+L/gYqmpcf1lJMUyFs=
go.cryptoscope.co/netwrap v0.1.1/go.mod h1:7zcYswCa4CT+ct54e9uH9+IIbYYETEMHKDNpzl8Ukew=

View File

@ -71,8 +71,12 @@ func (h connectHandler) HandleDuplex(ctx context.Context, req *muxrpc.Request, p
return err
}
// see if we have and endpoint for the target
// make sure they dont want to connect to themselves
if caller.Equal(&arg.Target) {
return fmt.Errorf("can't connect to self")
}
// see if we have and endpoint for the target
edp, has := h.state.Has(arg.Target)
if !has {
return fmt.Errorf("could not connect to:%s", arg.Target.Ref())

View File

@ -15,7 +15,6 @@ import (
refs "go.mindeco.de/ssb-refs"
kitlog "github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"go.cryptoscope.co/muxrpc/v2"
)
@ -29,18 +28,15 @@ type Handler struct {
}
func (h *Handler) isRoom(context.Context, *muxrpc.Request) (interface{}, error) {
level.Debug(h.logger).Log("called", "isRoom")
return true, nil
}
func (h *Handler) ping(context.Context, *muxrpc.Request) (interface{}, error) {
now := time.Now().UnixNano() / 1000
level.Debug(h.logger).Log("called", "ping")
return now, nil
}
func (h *Handler) announce(_ context.Context, req *muxrpc.Request) (interface{}, error) {
level.Debug(h.logger).Log("called", "announce")
ref, err := network.GetFeedRefFromAddr(req.RemoteAddr())
if err != nil {
return nil, err
@ -63,8 +59,6 @@ func (h *Handler) leave(_ context.Context, req *muxrpc.Request) (interface{}, er
}
func (h *Handler) endpoints(ctx context.Context, req *muxrpc.Request, snk *muxrpc.ByteSink) error {
level.Debug(h.logger).Log("called", "endpoints")
toPeer := newForwarder(snk)
// for future updates

View File

@ -92,7 +92,7 @@ func (h aliasesHandler) revoke(rw http.ResponseWriter, req *http.Request) {
return
}
status := http.StatusTemporaryRedirect
status := http.StatusTemporaryRedirect // TODO: should be SeeOther because it's method POST coming in
err = h.db.Revoke(ctx, aliasName)
if err != nil {
h.flashes.AddError(rw, req, err)

View File

@ -22,6 +22,7 @@ import (
"github.com/ssb-ngi-pointer/go-ssb-room/web"
weberrors "github.com/ssb-ngi-pointer/go-ssb-room/web/errors"
"github.com/ssb-ngi-pointer/go-ssb-room/web/i18n"
"github.com/ssb-ngi-pointer/go-ssb-room/web/members"
"github.com/ssb-ngi-pointer/go-ssb-room/web/router"
)
@ -155,10 +156,11 @@ func Handler(
noticeDB: dbs.Notices,
pinnedDB: dbs.PinnedNotices,
}
mux.HandleFunc("/notice/edit", r.HTML("admin/notice-edit.tmpl", nh.edit))
mux.HandleFunc("/notice/translation/draft", r.HTML("admin/notice-edit.tmpl", nh.draftTranslation))
mux.HandleFunc("/notice/translation/add", nh.addTranslation)
mux.HandleFunc("/notice/save", nh.save)
onlyModsAndAdmins := checkMemberRole(r.Error, roomdb.RoleModerator, roomdb.RoleAdmin)
mux.Handle("/notice/edit", onlyModsAndAdmins(r.HTML("admin/notice-edit.tmpl", nh.edit)))
mux.Handle("/notice/translation/draft", onlyModsAndAdmins(r.HTML("admin/notice-edit.tmpl", nh.draftTranslation)))
mux.Handle("/notice/translation/add", onlyModsAndAdmins(http.HandlerFunc(nh.addTranslation)))
mux.Handle("/notice/save", onlyModsAndAdmins(http.HandlerFunc(nh.save)))
// path:/ matches everything that isn't registerd (ie. its the "Not Found handler")
mux.HandleFunc("/", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
@ -168,6 +170,35 @@ func Handler(
return customStripPrefix("/admin", mux)
}
func checkMemberRole(eh render.ErrorHandlerFunc, roles ...roomdb.Role) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
currentMember := members.FromContext(req.Context())
if currentMember == nil {
err := weberrors.ErrRedirect{Path: "/admin/dashboard", Reason: fmt.Errorf("not an member")}
eh(rw, req, http.StatusSeeOther, err)
return
}
var roleMatched = false
for _, r := range roles {
if currentMember.Role == r {
roleMatched = true
break
}
}
if !roleMatched {
err := weberrors.ErrRedirect{Path: "/admin/dashboard", Reason: weberrors.ErrNotAuthorized}
eh(rw, req, http.StatusSeeOther, err)
return
}
next.ServeHTTP(rw, req)
})
}
}
// how many elements does a paginated page have by default
const defaultPageSize = 20

View File

@ -7,6 +7,7 @@ import (
"github.com/ssb-ngi-pointer/go-ssb-room/roomdb"
"github.com/ssb-ngi-pointer/go-ssb-room/web/router"
"github.com/ssb-ngi-pointer/go-ssb-room/web/webassert"
"github.com/stretchr/testify/assert"
)
@ -131,3 +132,90 @@ func TestNoticesEditButtonVisible(t *testing.T) {
a.EqualValues(1, doc.Find(editButtonSelector).Length())
}
func TestNoticesCreateOnlyModsAndHigher(t *testing.T) {
ts := setup(t)
a := assert.New(t)
ts.ConfigDB.GetPrivacyModeReturns(roomdb.ModeCommunity, nil)
// first, we confirm that we can't access the page when not logged in
draftNotice := ts.URLTo(router.AdminNoticeDraftTranslation, "name", roomdb.NoticeNews)
doc, resp := ts.Client.GetHTML(draftNotice)
a.Equal(http.StatusForbidden, resp.Code)
// start preparing the ~login dance~
// TODO: make this code reusable and share it with the login => /dashboard http:200 test
// TODO: refactor login dance for re-use in testing / across tests
// when dealing with cookies we also need to have an Host and URL-Scheme
// for the jar to save and load them correctly
formEndpoint := ts.URLTo(router.AuthFallbackLogin)
doc, resp = ts.Client.GetHTML(formEndpoint)
a.Equal(http.StatusOK, resp.Code)
csrfCookie := resp.Result().Cookies()
a.True(len(csrfCookie) > 0, "should have one cookie for CSRF protection validation")
csrfTokenElem := doc.Find(`form#password-fallback input[type="hidden"]`)
a.Equal(1, csrfTokenElem.Length())
csrfName, has := csrfTokenElem.Attr("name")
a.True(has, "should have a name attribute")
csrfValue, has := csrfTokenElem.Attr("value")
a.True(has, "should have value attribute")
loginVals := url.Values{
"user": []string{"test"},
"pass": []string{"test"},
csrfName: []string{csrfValue},
}
// have the database return okay for any user
testUser := roomdb.Member{ID: 123, Role: roomdb.RoleMember}
ts.AuthFallbackDB.CheckReturns(testUser.ID, nil)
ts.MembersDB.GetByIDReturns(testUser, nil)
postEndpoint := ts.URLTo(router.AuthFallbackFinalize)
// construct HTTP Header with Referer and Cookie
var refererHeader = make(http.Header)
refererHeader.Set("Referer", "https://localhost")
ts.Client.SetHeaders(refererHeader)
resp = ts.Client.PostForm(postEndpoint, loginVals)
a.Equal(http.StatusSeeOther, resp.Code, "wrong HTTP status code for sign in")
// now we are logged in, but we shouldn't be able to get the draft page
doc, resp = ts.Client.GetHTML(draftNotice)
a.Equal(http.StatusSeeOther, resp.Code)
dashboardURL := ts.URLTo(router.AdminDashboard)
a.Equal(dashboardURL.Path, resp.Header().Get("Location"))
a.True(len(resp.Result().Cookies()) > 0, "got a cookie")
webassert.HasFlashMessages(t, ts.Client, dashboardURL, "ErrorNotAuthorized")
// also shouldnt be allowed to save/post
id := []string{"1"}
title := []string{"SSB Breaking News: This Test Is Great"}
content := []string{"Absolutely Thrilling Content"}
language := []string{"en-GB"}
// POST a correct request to the save handler, and verify that the save was handled using the mock database)
u := ts.URLTo(router.AdminNoticeSave)
formValues := url.Values{"id": id, "title": title, "content": content, "language": language, csrfName: []string{csrfValue}}
resp = ts.Client.PostForm(u, formValues)
a.Equal(http.StatusSeeOther, resp.Code, "POST should work")
a.Equal(0, ts.NoticeDB.SaveCallCount(), "noticedb should not save the notice")
a.Equal(dashboardURL.Path, resp.Header().Get("Location"))
a.True(len(resp.Result().Cookies()) > 0, "got a cookie")
webassert.HasFlashMessages(t, ts.Client, dashboardURL, "ErrorNotAuthorized")
}

View File

@ -5,6 +5,7 @@ package handlers
import (
"bytes"
"net/http"
"net/url"
"os"
"path/filepath"
"testing"
@ -99,7 +100,14 @@ func setup(t *testing.T) *testSession {
// instantiate the urlTo helper (constructs urls for us!)
// the cookiejar in our custom http/tester needs a non-empty domain and scheme
ts.URLTo = web.NewURLTo(router.CompleteApp(), ts.NetworkInfo)
mkUrl := web.NewURLTo(router.CompleteApp(), ts.NetworkInfo)
ts.URLTo = func(name string, vals ...interface{}) *url.URL {
u := mkUrl(name, vals...)
if u.Path == "" || u.Host == "" {
t.Fatal("failed to make URL for: ", name, vals)
}
return u
}
ts.SignalBridge = signinwithssb.NewSignalBridge()

View File

@ -21,6 +21,7 @@ import (
"github.com/ssb-ngi-pointer/go-ssb-room/internal/network"
"github.com/ssb-ngi-pointer/go-ssb-room/internal/repo"
"github.com/ssb-ngi-pointer/go-ssb-room/roomdb"
refs "go.mindeco.de/ssb-refs"
)
@ -69,6 +70,8 @@ func NewURLTo(appRouter *mux.Router, netInfo network.ServerEndpointDetails) URLM
params = append(params, strconv.FormatInt(v, 10))
case refs.FeedRef:
params = append(params, v.Ref())
case roomdb.PinnedNoticeName:
params = append(params, string(v))
default:
level.Error(l).Log("msg", "invalid param type", "param", fmt.Sprintf("%T", p), "route", routeName)
return &url.URL{}