basic auth middleware setup
This commit is contained in:
parent
9639586d47
commit
01ed66d6df
|
@ -0,0 +1,29 @@
|
||||||
|
package admindb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.mindeco.de/http/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FallbackAuth might be helpful for scenarios where one lost access to his ssb device or key
|
||||||
|
type FallbackAuth interface {
|
||||||
|
auth.Auther
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthService defines functions needed for the challange/response system of sign-in with ssb
|
||||||
|
type AuthService interface{}
|
||||||
|
|
||||||
|
// RoomService deals with changing the privacy modes and managing the allow/deny lists of the room
|
||||||
|
type RoomService interface{}
|
||||||
|
|
||||||
|
// AliasService manages alias handle registration and lookup
|
||||||
|
type AliasService interface{}
|
||||||
|
|
||||||
|
// for tests we use generated mocks from these interfaces created with https://github.com/maxbrunsfeld/counterfeiter
|
||||||
|
|
||||||
|
//go:generate counterfeiter -o mockdb/auth.go . AuthService
|
||||||
|
|
||||||
|
//go:generate counterfeiter -o mockdb/auth_fallback.go . FallbackAuth
|
||||||
|
|
||||||
|
//go:generate counterfeiter -o mockdb/room.go . RoomService
|
||||||
|
|
||||||
|
//go:generate counterfeiter -o mockdb/alias.go . AliasService
|
|
@ -0,0 +1,37 @@
|
||||||
|
// Code generated by counterfeiter. DO NOT EDIT.
|
||||||
|
package mockdb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ssb-ngi-pointer/gossb-rooms/admindb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FakeAliasService struct {
|
||||||
|
invocations map[string][][]interface{}
|
||||||
|
invocationsMutex sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *FakeAliasService) Invocations() map[string][][]interface{} {
|
||||||
|
fake.invocationsMutex.RLock()
|
||||||
|
defer fake.invocationsMutex.RUnlock()
|
||||||
|
copiedInvocations := map[string][][]interface{}{}
|
||||||
|
for key, value := range fake.invocations {
|
||||||
|
copiedInvocations[key] = value
|
||||||
|
}
|
||||||
|
return copiedInvocations
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *FakeAliasService) recordInvocation(key string, args []interface{}) {
|
||||||
|
fake.invocationsMutex.Lock()
|
||||||
|
defer fake.invocationsMutex.Unlock()
|
||||||
|
if fake.invocations == nil {
|
||||||
|
fake.invocations = map[string][][]interface{}{}
|
||||||
|
}
|
||||||
|
if fake.invocations[key] == nil {
|
||||||
|
fake.invocations[key] = [][]interface{}{}
|
||||||
|
}
|
||||||
|
fake.invocations[key] = append(fake.invocations[key], args)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ admindb.AliasService = new(FakeAliasService)
|
|
@ -0,0 +1,37 @@
|
||||||
|
// Code generated by counterfeiter. DO NOT EDIT.
|
||||||
|
package mockdb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ssb-ngi-pointer/gossb-rooms/admindb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FakeAuthService struct {
|
||||||
|
invocations map[string][][]interface{}
|
||||||
|
invocationsMutex sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *FakeAuthService) Invocations() map[string][][]interface{} {
|
||||||
|
fake.invocationsMutex.RLock()
|
||||||
|
defer fake.invocationsMutex.RUnlock()
|
||||||
|
copiedInvocations := map[string][][]interface{}{}
|
||||||
|
for key, value := range fake.invocations {
|
||||||
|
copiedInvocations[key] = value
|
||||||
|
}
|
||||||
|
return copiedInvocations
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *FakeAuthService) recordInvocation(key string, args []interface{}) {
|
||||||
|
fake.invocationsMutex.Lock()
|
||||||
|
defer fake.invocationsMutex.Unlock()
|
||||||
|
if fake.invocations == nil {
|
||||||
|
fake.invocations = map[string][][]interface{}{}
|
||||||
|
}
|
||||||
|
if fake.invocations[key] == nil {
|
||||||
|
fake.invocations[key] = [][]interface{}{}
|
||||||
|
}
|
||||||
|
fake.invocations[key] = append(fake.invocations[key], args)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ admindb.AuthService = new(FakeAuthService)
|
|
@ -0,0 +1,118 @@
|
||||||
|
// Code generated by counterfeiter. DO NOT EDIT.
|
||||||
|
package mockdb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ssb-ngi-pointer/gossb-rooms/admindb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FakeFallbackAuth struct {
|
||||||
|
CheckStub func(string, string) (interface{}, error)
|
||||||
|
checkMutex sync.RWMutex
|
||||||
|
checkArgsForCall []struct {
|
||||||
|
arg1 string
|
||||||
|
arg2 string
|
||||||
|
}
|
||||||
|
checkReturns struct {
|
||||||
|
result1 interface{}
|
||||||
|
result2 error
|
||||||
|
}
|
||||||
|
checkReturnsOnCall map[int]struct {
|
||||||
|
result1 interface{}
|
||||||
|
result2 error
|
||||||
|
}
|
||||||
|
invocations map[string][][]interface{}
|
||||||
|
invocationsMutex sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *FakeFallbackAuth) Check(arg1 string, arg2 string) (interface{}, error) {
|
||||||
|
fake.checkMutex.Lock()
|
||||||
|
ret, specificReturn := fake.checkReturnsOnCall[len(fake.checkArgsForCall)]
|
||||||
|
fake.checkArgsForCall = append(fake.checkArgsForCall, struct {
|
||||||
|
arg1 string
|
||||||
|
arg2 string
|
||||||
|
}{arg1, arg2})
|
||||||
|
stub := fake.CheckStub
|
||||||
|
fakeReturns := fake.checkReturns
|
||||||
|
fake.recordInvocation("Check", []interface{}{arg1, arg2})
|
||||||
|
fake.checkMutex.Unlock()
|
||||||
|
if stub != nil {
|
||||||
|
return stub(arg1, arg2)
|
||||||
|
}
|
||||||
|
if specificReturn {
|
||||||
|
return ret.result1, ret.result2
|
||||||
|
}
|
||||||
|
return fakeReturns.result1, fakeReturns.result2
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *FakeFallbackAuth) CheckCallCount() int {
|
||||||
|
fake.checkMutex.RLock()
|
||||||
|
defer fake.checkMutex.RUnlock()
|
||||||
|
return len(fake.checkArgsForCall)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *FakeFallbackAuth) CheckCalls(stub func(string, string) (interface{}, error)) {
|
||||||
|
fake.checkMutex.Lock()
|
||||||
|
defer fake.checkMutex.Unlock()
|
||||||
|
fake.CheckStub = stub
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *FakeFallbackAuth) CheckArgsForCall(i int) (string, string) {
|
||||||
|
fake.checkMutex.RLock()
|
||||||
|
defer fake.checkMutex.RUnlock()
|
||||||
|
argsForCall := fake.checkArgsForCall[i]
|
||||||
|
return argsForCall.arg1, argsForCall.arg2
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *FakeFallbackAuth) CheckReturns(result1 interface{}, result2 error) {
|
||||||
|
fake.checkMutex.Lock()
|
||||||
|
defer fake.checkMutex.Unlock()
|
||||||
|
fake.CheckStub = nil
|
||||||
|
fake.checkReturns = struct {
|
||||||
|
result1 interface{}
|
||||||
|
result2 error
|
||||||
|
}{result1, result2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *FakeFallbackAuth) CheckReturnsOnCall(i int, result1 interface{}, result2 error) {
|
||||||
|
fake.checkMutex.Lock()
|
||||||
|
defer fake.checkMutex.Unlock()
|
||||||
|
fake.CheckStub = nil
|
||||||
|
if fake.checkReturnsOnCall == nil {
|
||||||
|
fake.checkReturnsOnCall = make(map[int]struct {
|
||||||
|
result1 interface{}
|
||||||
|
result2 error
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fake.checkReturnsOnCall[i] = struct {
|
||||||
|
result1 interface{}
|
||||||
|
result2 error
|
||||||
|
}{result1, result2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *FakeFallbackAuth) Invocations() map[string][][]interface{} {
|
||||||
|
fake.invocationsMutex.RLock()
|
||||||
|
defer fake.invocationsMutex.RUnlock()
|
||||||
|
fake.checkMutex.RLock()
|
||||||
|
defer fake.checkMutex.RUnlock()
|
||||||
|
copiedInvocations := map[string][][]interface{}{}
|
||||||
|
for key, value := range fake.invocations {
|
||||||
|
copiedInvocations[key] = value
|
||||||
|
}
|
||||||
|
return copiedInvocations
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *FakeFallbackAuth) recordInvocation(key string, args []interface{}) {
|
||||||
|
fake.invocationsMutex.Lock()
|
||||||
|
defer fake.invocationsMutex.Unlock()
|
||||||
|
if fake.invocations == nil {
|
||||||
|
fake.invocations = map[string][][]interface{}{}
|
||||||
|
}
|
||||||
|
if fake.invocations[key] == nil {
|
||||||
|
fake.invocations[key] = [][]interface{}{}
|
||||||
|
}
|
||||||
|
fake.invocations[key] = append(fake.invocations[key], args)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ admindb.FallbackAuth = new(FakeFallbackAuth)
|
|
@ -0,0 +1,37 @@
|
||||||
|
// Code generated by counterfeiter. DO NOT EDIT.
|
||||||
|
package mockdb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ssb-ngi-pointer/gossb-rooms/admindb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FakeRoomService struct {
|
||||||
|
invocations map[string][][]interface{}
|
||||||
|
invocationsMutex sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *FakeRoomService) Invocations() map[string][][]interface{} {
|
||||||
|
fake.invocationsMutex.RLock()
|
||||||
|
defer fake.invocationsMutex.RUnlock()
|
||||||
|
copiedInvocations := map[string][][]interface{}{}
|
||||||
|
for key, value := range fake.invocations {
|
||||||
|
copiedInvocations[key] = value
|
||||||
|
}
|
||||||
|
return copiedInvocations
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *FakeRoomService) recordInvocation(key string, args []interface{}) {
|
||||||
|
fake.invocationsMutex.Lock()
|
||||||
|
defer fake.invocationsMutex.Unlock()
|
||||||
|
if fake.invocations == nil {
|
||||||
|
fake.invocations = map[string][][]interface{}{}
|
||||||
|
}
|
||||||
|
if fake.invocations[key] == nil {
|
||||||
|
fake.invocations[key] = [][]interface{}{}
|
||||||
|
}
|
||||||
|
fake.invocations[key] = append(fake.invocations[key], args)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ admindb.RoomService = new(FakeRoomService)
|
|
@ -166,6 +166,16 @@ func runroomsrv() error {
|
||||||
return fmt.Errorf("failed to instantiate ssb server: %w", err)
|
return fmt.Errorf("failed to instantiate ssb server: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// open the HTTP listener
|
||||||
|
httpLis, err := net.Listen("tcp", listenAddrHTTP)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to open listener for HTTPdashboard: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := repo.New(repoDir)
|
||||||
|
|
||||||
|
db, err := sqlite.OpenOrCreate(r.GetPath("roomdb"))
|
||||||
|
|
||||||
c := make(chan os.Signal)
|
c := make(chan os.Signal)
|
||||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -173,6 +183,8 @@ func runroomsrv() error {
|
||||||
level.Warn(log).Log("event", "killed", "msg", "received signal, shutting down", "signal", sig.String())
|
level.Warn(log).Log("event", "killed", "msg", "received signal, shutting down", "signal", sig.String())
|
||||||
cancel()
|
cancel()
|
||||||
roomsrv.Shutdown()
|
roomsrv.Shutdown()
|
||||||
|
|
||||||
|
httpLis.Close()
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
err := roomsrv.Close()
|
err := roomsrv.Close()
|
||||||
|
@ -183,17 +195,14 @@ func runroomsrv() error {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// setup web dashboard handlers
|
// setup web dashboard handlers
|
||||||
dashboardH, err := handlers.New(nil, repo.New(repoDir))
|
dashboardH, err := handlers.New(
|
||||||
|
nil,
|
||||||
|
repo.New(repoDir),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create HTTPdashboard handler: %w", err)
|
return fmt.Errorf("failed to create HTTPdashboard handler: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// open the HTTP listener
|
|
||||||
httpLis, err := net.Listen("tcp", listenAddrHTTP)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to open listener for HTTPdashboard: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: setup other http goodies (such as CSRF and CSP)
|
// TODO: setup other http goodies (such as CSRF and CSP)
|
||||||
|
|
||||||
level.Info(log).Log(
|
level.Info(log).Log(
|
||||||
|
@ -207,7 +216,18 @@ func runroomsrv() error {
|
||||||
|
|
||||||
// start serving http connections
|
// start serving http connections
|
||||||
go func() {
|
go func() {
|
||||||
err = http.Serve(httpLis, dashboardH)
|
srv := http.Server{
|
||||||
|
Addr: httpLis.Addr().String(),
|
||||||
|
|
||||||
|
// Good practice to set timeouts to avoid Slowloris attacks.
|
||||||
|
WriteTimeout: time.Second * 15,
|
||||||
|
ReadTimeout: time.Second * 15,
|
||||||
|
IdleTimeout: time.Second * 60,
|
||||||
|
|
||||||
|
Handler: dashboardH,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = srv.Serve(httpLis)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
level.Error(log).Log("event", "http serve failed", "err", err)
|
level.Error(log).Log("event", "http serve failed", "err", err)
|
||||||
}
|
}
|
||||||
|
|
5
go.mod
5
go.mod
|
@ -5,7 +5,9 @@ go 1.15
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v0.3.1
|
github.com/BurntSushi/toml v0.3.1
|
||||||
github.com/go-kit/kit v0.10.0
|
github.com/go-kit/kit v0.10.0
|
||||||
github.com/gorilla/mux v1.7.3
|
github.com/gorilla/mux v1.8.0
|
||||||
|
github.com/gorilla/securecookie v1.1.1
|
||||||
|
github.com/gorilla/sessions v1.2.1
|
||||||
github.com/gorilla/websocket v1.4.2
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/keks/nocomment v0.0.0-20181007001506-30c6dcb4a472
|
github.com/keks/nocomment v0.0.0-20181007001506-30c6dcb4a472
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.1.2
|
github.com/nicksnyder/go-i18n/v2 v2.1.2
|
||||||
|
@ -22,6 +24,7 @@ require (
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect
|
||||||
golang.org/x/text v0.3.3
|
golang.org/x/text v0.3.3
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
exclude go.cryptoscope.co/ssb v0.0.0-20201207161753-31d0f24b7a79
|
exclude go.cryptoscope.co/ssb v0.0.0-20201207161753-31d0f24b7a79
|
||||||
|
|
16
go.sum
16
go.sum
|
@ -116,8 +116,13 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51
|
||||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
|
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||||
|
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
|
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||||
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
|
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
|
||||||
|
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
|
||||||
|
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
@ -206,7 +211,6 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE
|
||||||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||||
github.com/nicksnyder/go-i18n v1.10.1 h1:isfg77E/aCD7+0lD/D00ebR2MV5vgeQ276WYyDaCRQc=
|
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.1.2 h1:QHYxcUJnGHBaq7XbvgunmZ2Pn0focXFqTD61CkH146c=
|
github.com/nicksnyder/go-i18n/v2 v2.1.2 h1:QHYxcUJnGHBaq7XbvgunmZ2Pn0focXFqTD61CkH146c=
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.1.2/go.mod h1:d++QJC9ZVf7pa48qrsRWhMJ5pSHIPmS3OLqK1niyLxs=
|
github.com/nicksnyder/go-i18n/v2 v2.1.2/go.mod h1:d++QJC9ZVf7pa48qrsRWhMJ5pSHIPmS3OLqK1niyLxs=
|
||||||
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
|
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
|
||||||
|
@ -267,7 +271,6 @@ github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxr
|
||||||
github.com/shurcooL/go v0.0.0-20190121191506-3fef8c783dec/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
github.com/shurcooL/go v0.0.0-20190121191506-3fef8c783dec/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||||
github.com/shurcooL/go v0.0.0-20190330031554-6713ea532688/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
github.com/shurcooL/go v0.0.0-20190330031554-6713ea532688/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
||||||
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b h1:4kg1wyftSKxLtnPAvcRWakIPpokB9w780/KwrNLnfPA=
|
|
||||||
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk=
|
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk=
|
||||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||||
|
@ -286,7 +289,6 @@ github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3
|
||||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||||
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
@ -325,10 +327,6 @@ go.cryptoscope.co/secretstream v1.2.2 h1:kPxsgWrTDFyS9ZklcD0si1KGljPLz6mmPKnFQjG
|
||||||
go.cryptoscope.co/secretstream v1.2.2/go.mod h1:7nRGZ7fTqSgQAnv2Y4m8xQsS3MFxvB7I0C19reUNlXg=
|
go.cryptoscope.co/secretstream v1.2.2/go.mod h1:7nRGZ7fTqSgQAnv2Y4m8xQsS3MFxvB7I0C19reUNlXg=
|
||||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||||
go.mindeco.de v0.0.0-20191122233605-f02621a5bca7 h1:si0O0lnNT3SHzEBwuFfqWBaZlME/FnXWlxyZGdri3D8=
|
|
||||||
go.mindeco.de v0.0.0-20191122233605-f02621a5bca7/go.mod h1:ePOcyktbpqzhMPRBDv2gUaDd3h8QtT+DUU1DK+VbQZE=
|
|
||||||
go.mindeco.de v1.6.0 h1:mrO5+eaJou/5a7ob+lMfH+DudT1TJ7oSjYqMTGaoYUA=
|
|
||||||
go.mindeco.de v1.6.0/go.mod h1:ePOcyktbpqzhMPRBDv2gUaDd3h8QtT+DUU1DK+VbQZE=
|
|
||||||
go.mindeco.de/ssb-refs v0.1.1-0.20210108133850-cf1f44fea870 h1:TCI3AefMAaOYECvppn30+CfEB0Fn8IES1SKvvacc3/c=
|
go.mindeco.de/ssb-refs v0.1.1-0.20210108133850-cf1f44fea870 h1:TCI3AefMAaOYECvppn30+CfEB0Fn8IES1SKvvacc3/c=
|
||||||
go.mindeco.de/ssb-refs v0.1.1-0.20210108133850-cf1f44fea870/go.mod h1:OnBnV02ux4lLsZ39LID6yYLqSDp+dqTHb/3miYPkQFs=
|
go.mindeco.de/ssb-refs v0.1.1-0.20210108133850-cf1f44fea870/go.mod h1:OnBnV02ux4lLsZ39LID6yYLqSDp+dqTHb/3miYPkQFs=
|
||||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
|
@ -456,9 +454,11 @@ gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|
|
@ -15,6 +15,8 @@ import (
|
||||||
"go.mindeco.de/goutils"
|
"go.mindeco.de/goutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const Production = false
|
||||||
|
|
||||||
// absolute path of where this package is located
|
// absolute path of where this package is located
|
||||||
var pkgDir = goutils.MustLocatePackage("github.com/ssb-ngi-pointer/gossb-rooms/web")
|
var pkgDir = goutils.MustLocatePackage("github.com/ssb-ngi-pointer/gossb-rooms/web")
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"go.mindeco.de/http/render"
|
||||||
|
|
||||||
|
"github.com/ssb-ngi-pointer/gossb-rooms/web/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
var HTMLTemplates = []string{
|
||||||
|
"/admin/dashboard.tmpl",
|
||||||
|
}
|
||||||
|
|
||||||
|
func Handler(m *mux.Router, r *render.Renderer) http.Handler {
|
||||||
|
if m == nil {
|
||||||
|
m = router.Admin(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Get(router.AdminDashboard).HandlerFunc(r.HTML("/admin/dashboard.tmpl", dashboard))
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func dashboard(rw http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||||
|
return struct {
|
||||||
|
Name string
|
||||||
|
}{"test"}, nil
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"go.mindeco.de/http/auth"
|
||||||
|
"go.mindeco.de/http/render"
|
||||||
|
|
||||||
|
"github.com/ssb-ngi-pointer/gossb-rooms/web/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Handler(m *mux.Router, r *render.Renderer, a *auth.Handler) http.Handler {
|
||||||
|
if m == nil {
|
||||||
|
m = router.Auth(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Get(router.AuthFallbackSignInForm).Handler(r.StaticHTML("/auth/fallback_sign_in.tmpl"))
|
||||||
|
m.Get(router.AuthFallbackSignIn).HandlerFunc(a.Authorize)
|
||||||
|
m.Get(router.AuthFallbackSignOut).HandlerFunc(a.Logout)
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
package auth
|
|
|
@ -1,21 +1,33 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/gorilla/securecookie"
|
||||||
|
"github.com/gorilla/sessions"
|
||||||
|
"go.mindeco.de/http/auth"
|
||||||
"go.mindeco.de/http/render"
|
"go.mindeco.de/http/render"
|
||||||
|
|
||||||
|
"github.com/ssb-ngi-pointer/gossb-rooms/admindb"
|
||||||
"github.com/ssb-ngi-pointer/gossb-rooms/internal/repo"
|
"github.com/ssb-ngi-pointer/gossb-rooms/internal/repo"
|
||||||
"github.com/ssb-ngi-pointer/gossb-rooms/web"
|
"github.com/ssb-ngi-pointer/gossb-rooms/web"
|
||||||
|
"github.com/ssb-ngi-pointer/gossb-rooms/web/handlers/admin"
|
||||||
|
roomsAuth "github.com/ssb-ngi-pointer/gossb-rooms/web/handlers/auth"
|
||||||
"github.com/ssb-ngi-pointer/gossb-rooms/web/handlers/news"
|
"github.com/ssb-ngi-pointer/gossb-rooms/web/handlers/news"
|
||||||
"github.com/ssb-ngi-pointer/gossb-rooms/web/i18n"
|
"github.com/ssb-ngi-pointer/gossb-rooms/web/i18n"
|
||||||
"github.com/ssb-ngi-pointer/gossb-rooms/web/router"
|
"github.com/ssb-ngi-pointer/gossb-rooms/web/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
// New initializes the whole web stack for rooms, with all the sub-modules and routing.
|
// New initializes the whole web stack for rooms, with all the sub-modules and routing.
|
||||||
func New(m *mux.Router, repo repo.Interface) (http.Handler, error) {
|
func New(
|
||||||
|
m *mux.Router,
|
||||||
|
repo repo.Interface,
|
||||||
|
as admindb.AuthService,
|
||||||
|
fs admindb.FallbackAuth,
|
||||||
|
) (http.Handler, error) {
|
||||||
if m == nil {
|
if m == nil {
|
||||||
m = router.CompleteApp()
|
m = router.CompleteApp()
|
||||||
}
|
}
|
||||||
|
@ -27,10 +39,15 @@ func New(m *mux.Router, repo repo.Interface) (http.Handler, error) {
|
||||||
|
|
||||||
r, err := render.New(web.Templates,
|
r, err := render.New(web.Templates,
|
||||||
render.BaseTemplates("/base.tmpl"),
|
render.BaseTemplates("/base.tmpl"),
|
||||||
render.AddTemplates(append(news.HTMLTemplates,
|
render.AddTemplates(concatTemplates(
|
||||||
|
[]string{
|
||||||
"/landing/index.tmpl",
|
"/landing/index.tmpl",
|
||||||
"/landing/about.tmpl",
|
"/landing/about.tmpl",
|
||||||
"/error.tmpl")...),
|
"/error.tmpl",
|
||||||
|
},
|
||||||
|
news.HTMLTemplates,
|
||||||
|
admin.HTMLTemplates,
|
||||||
|
)...),
|
||||||
render.FuncMap(web.TemplateFuncs(m)),
|
render.FuncMap(web.TemplateFuncs(m)),
|
||||||
// TODO: add plural and template data variants
|
// TODO: add plural and template data variants
|
||||||
// TODO: move these to the i18n helper pkg
|
// TODO: move these to the i18n helper pkg
|
||||||
|
@ -45,7 +62,48 @@ func New(m *mux.Router, repo repo.Interface) (http.Handler, error) {
|
||||||
return nil, fmt.Errorf("web Handler: failed to create renderer: %w", err)
|
return nil, fmt.Errorf("web Handler: failed to create renderer: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: generate & persist me
|
||||||
|
// repo.GetPath("web-cookie")
|
||||||
|
store := &sessions.CookieStore{
|
||||||
|
Codecs: securecookie.CodecsFromPairs(
|
||||||
|
bytes.Repeat([]byte("acab"), 8),
|
||||||
|
bytes.Repeat([]byte("beef"), 8),
|
||||||
|
// securecookie.GenerateRandomKey(32), // new key every time we startup
|
||||||
|
// securecookie.GenerateRandomKey(32),
|
||||||
|
),
|
||||||
|
Options: &sessions.Options{
|
||||||
|
Path: "/",
|
||||||
|
MaxAge: 30,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
notAuthorizedH := r.HTML("/error.tmpl", func(rw http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||||
|
statusCode := http.StatusUnauthorized
|
||||||
|
rw.WriteHeader(statusCode)
|
||||||
|
return errorTemplateData{
|
||||||
|
statusCode,
|
||||||
|
"Unauthorized",
|
||||||
|
"you are not authorized to access the requested site",
|
||||||
|
}, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
a, err := auth.NewHandler(fs,
|
||||||
|
auth.SetStore(store),
|
||||||
|
auth.SetNotAuthorizedHandler(notAuthorizedH),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("web Handler: failed to init fallback auth system: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// hookup handlers to the router
|
// hookup handlers to the router
|
||||||
|
roomsAuth.Handler(m, r, a)
|
||||||
|
|
||||||
|
adminRouter := m.PathPrefix("/admin").Subrouter()
|
||||||
|
adminRouter.Use(a.Authenticate)
|
||||||
|
|
||||||
|
// we dont strip path here because it somehow fucks with the middleware setup
|
||||||
|
adminRouter.PathPrefix("/").Handler(admin.Handler(adminRouter, r))
|
||||||
|
|
||||||
m.PathPrefix("/news").Handler(http.StripPrefix("/news", news.Handler(m, r)))
|
m.PathPrefix("/news").Handler(http.StripPrefix("/news", news.Handler(m, r)))
|
||||||
|
|
||||||
m.Get(router.CompleteIndex).Handler(r.StaticHTML("/landing/index.tmpl"))
|
m.Get(router.CompleteIndex).Handler(r.StaticHTML("/landing/index.tmpl"))
|
||||||
|
@ -53,10 +111,34 @@ func New(m *mux.Router, repo repo.Interface) (http.Handler, error) {
|
||||||
|
|
||||||
m.PathPrefix("/assets/").Handler(http.StripPrefix("/assets/", http.FileServer(web.Assets)))
|
m.PathPrefix("/assets/").Handler(http.StripPrefix("/assets/", http.FileServer(web.Assets)))
|
||||||
|
|
||||||
m.NotFoundHandler = http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
m.NotFoundHandler = r.HTML("/error.tmpl", func(rw http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||||
fmt.Fprintf(rw, "404: url not found")
|
rw.WriteHeader(http.StatusNotFound)
|
||||||
|
return errorTemplateData{http.StatusNotFound, "Not Found", "the requested page wasnt found.."}, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: disable in non-dev
|
if web.Production {
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
return r.GetReloader()(m), nil
|
return r.GetReloader()(m), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// utils
|
||||||
|
|
||||||
|
type errorTemplateData struct {
|
||||||
|
StatusCode int
|
||||||
|
Status string
|
||||||
|
Err string
|
||||||
|
}
|
||||||
|
|
||||||
|
func concatTemplates(lst ...[]string) []string {
|
||||||
|
var catted []string
|
||||||
|
|
||||||
|
for _, tpls := range lst {
|
||||||
|
for _, t := range tpls {
|
||||||
|
catted = append(catted, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return catted
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/ssb-ngi-pointer/gossb-rooms/web/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIndex(t *testing.T) {
|
||||||
|
setup(t)
|
||||||
|
t.Cleanup(teardown)
|
||||||
|
|
||||||
|
a := assert.New(t)
|
||||||
|
r := require.New(t)
|
||||||
|
|
||||||
|
url, err := testRouter.Get(router.CompleteIndex).URL()
|
||||||
|
r.Nil(err)
|
||||||
|
html, resp := testClient.GetHTML(url.String(), nil)
|
||||||
|
a.Equal(http.StatusOK, resp.Code, "wrong HTTP status code")
|
||||||
|
a.Equal("Index landing page", html.Find("#welcome").Text())
|
||||||
|
val, has := html.Find("#logo").Attr("src")
|
||||||
|
a.True(has, "logo src attribute not found")
|
||||||
|
a.Equal("/assets/img/test-hermie.png", val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAbout(t *testing.T) {
|
||||||
|
setup(t)
|
||||||
|
t.Cleanup(teardown)
|
||||||
|
|
||||||
|
a := assert.New(t)
|
||||||
|
r := require.New(t)
|
||||||
|
|
||||||
|
url, err := testRouter.Get(router.CompleteAbout).URL()
|
||||||
|
r.Nil(err)
|
||||||
|
html, resp := testClient.GetHTML(url.String(), nil)
|
||||||
|
a.Equal(http.StatusOK, resp.Code, "wrong HTTP status code")
|
||||||
|
found := html.Find("h1").Text()
|
||||||
|
a.Equal("The about page", found)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNotFound(t *testing.T) {
|
||||||
|
setup(t)
|
||||||
|
t.Cleanup(teardown)
|
||||||
|
|
||||||
|
a := assert.New(t)
|
||||||
|
|
||||||
|
html, resp := testClient.GetHTML("/some/random/ASDKLANZXC", nil)
|
||||||
|
a.Equal(http.StatusNotFound, resp.Code, "wrong HTTP status code")
|
||||||
|
found := html.Find("h1").Text()
|
||||||
|
a.Equal("Error #404 - Not Found", found)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewsRegisterd(t *testing.T) {
|
||||||
|
setup(t)
|
||||||
|
t.Cleanup(teardown)
|
||||||
|
|
||||||
|
a := assert.New(t)
|
||||||
|
|
||||||
|
html, resp := testClient.GetHTML("/news/", nil)
|
||||||
|
a.Equal(http.StatusOK, resp.Code, "wrong HTTP status code")
|
||||||
|
found := html.Find("h1").Text()
|
||||||
|
t.Log(found)
|
||||||
|
// a.Equal("fooo", found)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRestricted(t *testing.T) {
|
||||||
|
setup(t)
|
||||||
|
t.Cleanup(teardown)
|
||||||
|
|
||||||
|
a := assert.New(t)
|
||||||
|
|
||||||
|
html, resp := testClient.GetHTML("/admin/", nil)
|
||||||
|
a.Equal(http.StatusUnauthorized, resp.Code, "wrong HTTP status code")
|
||||||
|
found := html.Find("h1").Text()
|
||||||
|
a.Equal("Error #401 - Unauthorized", found)
|
||||||
|
}
|
|
@ -17,8 +17,6 @@ var (
|
||||||
testMux *http.ServeMux
|
testMux *http.ServeMux
|
||||||
testClient *tester.Tester
|
testClient *tester.Tester
|
||||||
testRouter = router.News(nil)
|
testRouter = router.News(nil)
|
||||||
|
|
||||||
testAssets = http.Dir("../../templates")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func setup(t *testing.T) {
|
func setup(t *testing.T) {
|
||||||
|
@ -27,7 +25,7 @@ func setup(t *testing.T) {
|
||||||
testFuncs["i18n"] = func(msgID string) string { return msgID }
|
testFuncs["i18n"] = func(msgID string) string { return msgID }
|
||||||
|
|
||||||
log, _ := logtest.KitLogger("feed", t)
|
log, _ := logtest.KitLogger("feed", t)
|
||||||
r, err := render.New(testAssets, //TODO: embedd web.Assets,
|
r, err := render.New(web.Templates,
|
||||||
render.SetLogger(log),
|
render.SetLogger(log),
|
||||||
render.BaseTemplates("/testing/base.tmpl"),
|
render.BaseTemplates("/testing/base.tmpl"),
|
||||||
render.AddTemplates(append(HTMLTemplates, "/error.tmpl")...),
|
render.AddTemplates(append(HTMLTemplates, "/error.tmpl")...),
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"go.mindeco.de/http/tester"
|
||||||
|
|
||||||
|
"github.com/ssb-ngi-pointer/gossb-rooms/admindb/mockdb"
|
||||||
|
"github.com/ssb-ngi-pointer/gossb-rooms/internal/repo"
|
||||||
|
"github.com/ssb-ngi-pointer/gossb-rooms/web/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
testMux *http.ServeMux
|
||||||
|
testClient *tester.Tester
|
||||||
|
testRouter = router.CompleteApp()
|
||||||
|
|
||||||
|
// mocked dbs
|
||||||
|
testAuthDB *mockdb.FakeAuthService
|
||||||
|
testAuthFallbackDB *mockdb.FakeFallbackAuth
|
||||||
|
)
|
||||||
|
|
||||||
|
func setup(t *testing.T) {
|
||||||
|
|
||||||
|
testRepoPath := filepath.Join("testrun", t.Name())
|
||||||
|
os.RemoveAll(testRepoPath)
|
||||||
|
testRepo := repo.New(testRepoPath)
|
||||||
|
|
||||||
|
testAuthDB = new(mockdb.FakeAuthService)
|
||||||
|
testAuthFallbackDB = new(mockdb.FakeFallbackAuth)
|
||||||
|
h, err := New(
|
||||||
|
testRouter,
|
||||||
|
testRepo,
|
||||||
|
testAuthDB,
|
||||||
|
testAuthFallbackDB,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(errors.Wrap(err, "setup: handler init failed"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// log, _ := logtest.KitLogger("complete", t)
|
||||||
|
|
||||||
|
testMux = http.NewServeMux()
|
||||||
|
testMux.Handle("/", h)
|
||||||
|
testClient = tester.New(testMux, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func teardown() {
|
||||||
|
testMux = nil
|
||||||
|
testClient = nil
|
||||||
|
testAuthFallbackDB = nil
|
||||||
|
testAuthFallbackDB = nil
|
||||||
|
}
|
|
@ -22,7 +22,7 @@ func New(r repo.Interface) (*Helper, error) {
|
||||||
bundle := i18n.NewBundle(language.English)
|
bundle := i18n.NewBundle(language.English)
|
||||||
bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
|
bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
|
||||||
|
|
||||||
// TODO: could additionally embedd the defaults together with the html assets and templates
|
// TODO: could additionally embedd the defaults like we do with the html assets and templates
|
||||||
|
|
||||||
err := filepath.Walk(r.GetPath("i18n"), func(path string, info os.FileInfo, err error) error {
|
err := filepath.Walk(r.GetPath("i18n"), func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -44,8 +44,8 @@ func New(r repo.Interface) (*Helper, error) {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
return nil, err
|
return nil, fmt.Errorf("i18n: failed to iterate localizations: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Helper{bundle: bundle}, nil
|
return &Helper{bundle: bundle}, nil
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
// +build !dev
|
||||||
|
|
||||||
|
package web
|
||||||
|
|
||||||
|
// Production can be used to determain different aspects at compile time (like hot template reloading)
|
||||||
|
const Production = true
|
|
@ -0,0 +1,21 @@
|
||||||
|
package router
|
||||||
|
|
||||||
|
import "github.com/gorilla/mux"
|
||||||
|
|
||||||
|
// constant names for the named routes
|
||||||
|
const (
|
||||||
|
AdminDashboard = "admin:dashboard"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Admin constructs a mux.Router containing the routes for the admin dashboard and settings pages
|
||||||
|
func Admin(m *mux.Router) *mux.Router {
|
||||||
|
if m == nil {
|
||||||
|
m = mux.NewRouter()
|
||||||
|
}
|
||||||
|
|
||||||
|
// we dont strip path here because it somehow fucks with the middleware setup
|
||||||
|
m.Path("/admin").Methods("GET").Name(AdminDashboard)
|
||||||
|
// m.Path("/admin/settings").Methods("GET").Name(AdminSettings)
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
|
@ -4,8 +4,12 @@ import "github.com/gorilla/mux"
|
||||||
|
|
||||||
// constant names for the named routes
|
// constant names for the named routes
|
||||||
const (
|
const (
|
||||||
AuthSignIn = "Auth:SignIn"
|
AuthFallbackSignInForm = "Auth:Fallback:Form:SignIn"
|
||||||
AuthSignOut = "Auth:SignOut"
|
AuthFallbackSignIn = "Auth:Fallback:SignIn"
|
||||||
|
AuthFallbackSignOut = "Auth:Fallback:SignOut"
|
||||||
|
|
||||||
|
AuthWithSSBSignIn = "Auth:WithSSB:SignIn"
|
||||||
|
AuthWithSSBSignOut = "Auth:WithSSB:SignOut"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewSignin constructs a mux.Router containing the routes for sign-in and -out
|
// NewSignin constructs a mux.Router containing the routes for sign-in and -out
|
||||||
|
@ -14,8 +18,13 @@ func Auth(m *mux.Router) *mux.Router {
|
||||||
m = mux.NewRouter()
|
m = mux.NewRouter()
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Path("/signIn").Methods("GET").Name(AuthSignIn)
|
// register fallback
|
||||||
m.Path("/signOut").Methods("GET").Name(AuthSignOut)
|
m.Path("/fallback/signin").Methods("GET").Name(AuthFallbackSignInForm)
|
||||||
|
m.Path("/fallback/signin").Methods("POST").Name(AuthFallbackSignIn)
|
||||||
|
m.Path("/fallback/signOut").Methods("GET").Name(AuthFallbackSignOut)
|
||||||
|
|
||||||
|
m.Path("/withssb/signIn").Methods("GET").Name(AuthWithSSBSignIn)
|
||||||
|
m.Path("/withssb/signOut").Methods("GET").Name(AuthWithSSBSignOut)
|
||||||
|
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package router
|
package router
|
||||||
|
|
||||||
import "github.com/gorilla/mux"
|
import (
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
// constant names for the named routes
|
// constant names for the named routes
|
||||||
const (
|
const (
|
||||||
|
@ -13,7 +15,7 @@ func CompleteApp() *mux.Router {
|
||||||
m := mux.NewRouter()
|
m := mux.NewRouter()
|
||||||
|
|
||||||
Auth(m.PathPrefix("/auth").Subrouter())
|
Auth(m.PathPrefix("/auth").Subrouter())
|
||||||
// Admin(m.PathPrefix("/profile").Subrouter())
|
Admin(m.PathPrefix("/admin").Subrouter())
|
||||||
News(m.PathPrefix("/news").Subrouter())
|
News(m.PathPrefix("/news").Subrouter())
|
||||||
|
|
||||||
m.Path("/").Methods("GET").Name(CompleteIndex)
|
m.Path("/").Methods("GET").Name(CompleteIndex)
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
{{ define "title" }}{{i18n "AdminOverview"}}{{ end }}
|
||||||
|
{{ define "content" }}
|
||||||
|
<div class="page-header">
|
||||||
|
<h1 id="welcome">{{i18n "AdminWelcome"}}</h1>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<p>super cool dashboard!</p>
|
||||||
|
</div>
|
||||||
|
</div> <!-- /row -->
|
||||||
|
{{end}}
|
|
@ -0,0 +1,13 @@
|
||||||
|
{{ define "title" }}fallback sign-in{{ end }}
|
||||||
|
{{ define "content" }}
|
||||||
|
<div class="page-header">
|
||||||
|
<h1 id="welcome">Fallback sign-in</h1>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<form action="POST">
|
||||||
|
<input type="submit">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div> <!-- /row -->
|
||||||
|
{{end}}
|
|
@ -1,9 +1,9 @@
|
||||||
{{ define "title" }}Landing - Index{{ end }}
|
{{ define "title" }}Landing - Index{{ end }}
|
||||||
{{ define "content" }}
|
{{ define "content" }}
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>Index landing page</h1>
|
<h1 id="welcome">Index landing page</h1>
|
||||||
|
|
||||||
<img src="/assets/img/test-hermie.png">
|
<img id="logo" src="/assets/img/test-hermie.png">
|
||||||
|
|
||||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Sed faucibus turpis in eu mi bibendum. A arcu cursus vitae congue mauris rhoncus aenean vel elit. Aliquet bibendum enim facilisis gravida neque convallis. Tempor orci eu lobortis elementum nibh tellus molestie. Sit amet est placerat in egestas erat imperdiet. Amet consectetur adipiscing elit duis tristique sollicitudin nibh sit amet. Ultrices in iaculis nunc sed. Odio facilisis mauris sit amet massa. Sed vulputate mi sit amet mauris commodo quis imperdiet. Hendrerit dolor magna eget est lorem ipsum dolor sit amet. Neque vitae tempus quam pellentesque nec nam. Quis risus sed vulputate odio ut. Tincidunt lobortis feugiat vivamus at augue.</p>
|
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Sed faucibus turpis in eu mi bibendum. A arcu cursus vitae congue mauris rhoncus aenean vel elit. Aliquet bibendum enim facilisis gravida neque convallis. Tempor orci eu lobortis elementum nibh tellus molestie. Sit amet est placerat in egestas erat imperdiet. Amet consectetur adipiscing elit duis tristique sollicitudin nibh sit amet. Ultrices in iaculis nunc sed. Odio facilisis mauris sit amet massa. Sed vulputate mi sit amet mauris commodo quis imperdiet. Hendrerit dolor magna eget est lorem ipsum dolor sit amet. Neque vitae tempus quam pellentesque nec nam. Quis risus sed vulputate odio ut. Tincidunt lobortis feugiat vivamus at augue.</p>
|
||||||
<p>Sem nulla pharetra diam sit amet nisl. Sed odio morbi quis commodo odio aenean sed adipiscing. In ornare quam viverra orci sagittis. Elit eget gravida cum sociis natoque. Auctor neque vitae tempus quam. Porttitor massa id neque aliquam vestibulum morbi blandit cursus risus. Ornare lectus sit amet est placerat in egestas erat. Ut enim blandit volutpat maecenas. Fermentum odio eu feugiat pretium nibh. At risus viverra adipiscing at. Et egestas quis ipsum suspendisse. Mollis nunc sed id semper risus in hendrerit. Semper feugiat nibh sed pulvinar.</p>
|
<p>Sem nulla pharetra diam sit amet nisl. Sed odio morbi quis commodo odio aenean sed adipiscing. In ornare quam viverra orci sagittis. Elit eget gravida cum sociis natoque. Auctor neque vitae tempus quam. Porttitor massa id neque aliquam vestibulum morbi blandit cursus risus. Ornare lectus sit amet est placerat in egestas erat. Ut enim blandit volutpat maecenas. Fermentum odio eu feugiat pretium nibh. At risus viverra adipiscing at. Et egestas quis ipsum suspendisse. Mollis nunc sed id semper risus in hendrerit. Semper feugiat nibh sed pulvinar.</p>
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue