Merge pull request #30 from ssb-ngi-pointer/bring-back-dev-mode

Bring back dev mode
This commit is contained in:
Henry 2021-02-22 16:56:03 +01:00 committed by GitHub
commit 56ef07d9f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 191 additions and 123 deletions

View File

@ -21,7 +21,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.15
go-version: 1.16
- name: Get dependencies
run: go get -v -t -d ./...

5
cmd/server/dev.go Normal file
View File

@ -0,0 +1,5 @@
// +build dev
package main
var development = true

View File

@ -45,8 +45,6 @@ var (
httpsDomain string
development bool
listenAddrDebug string
logToFile string
repoDir string
@ -96,7 +94,6 @@ func initFlags() {
flag.StringVar(&logToFile, "logs", "", "where to write debug output to (default is just stderr)")
flag.StringVar(&httpsDomain, "https-domain", "", "which domain to use for TLS and AllowedHosts checks")
flag.BoolVar(&development, "development", false, "enable development mode (disable security checks)")
flag.BoolVar(&flagPrintVersion, "version", false, "print version number and build date")

5
cmd/server/prod.go Normal file
View File

@ -0,0 +1,5 @@
// +build !dev
package main
var development = false

2
go.mod
View File

@ -27,7 +27,7 @@ require (
go.cryptoscope.co/muxrpc/v2 v2.0.0-20210202162901-fe642d405dc6
go.cryptoscope.co/netwrap v0.1.1
go.cryptoscope.co/secretstream v1.2.2
go.mindeco.de v1.7.3-0.20210216124941-2da08c6b0080
go.mindeco.de v1.8.0
go.mindeco.de/ssb-refs v0.1.1-0.20210108133850-cf1f44fea870
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9

2
go.sum
View File

@ -450,6 +450,8 @@ go.mindeco.de v1.7.2 h1:nuiz9ZJbRx+HHIobKi/J8rSE4A3cf8KArzQsjlF6f1o=
go.mindeco.de v1.7.2/go.mod h1:ePOcyktbpqzhMPRBDv2gUaDd3h8QtT+DUU1DK+VbQZE=
go.mindeco.de v1.7.3-0.20210216124941-2da08c6b0080 h1:wbrGjnr0dZetkGZURd9RhsXhYW0MC3cwovcy3kXXeKw=
go.mindeco.de v1.7.3-0.20210216124941-2da08c6b0080/go.mod h1:ePOcyktbpqzhMPRBDv2gUaDd3h8QtT+DUU1DK+VbQZE=
go.mindeco.de v1.8.0 h1:Vxob3XaDz85aD4wq8VbQxtradpHbmjciG2eSJLGaFV0=
go.mindeco.de v1.8.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/go.mod h1:OnBnV02ux4lLsZ39LID6yYLqSDp+dqTHb/3miYPkQFs=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=

4
web/assets/fixfouc.css Normal file
View File

@ -0,0 +1,4 @@
html {
visibility: hidden;
opacity: 0;
}

View File

@ -4,4 +4,18 @@
package web
import (
"net/http"
"path/filepath"
"go.mindeco.de/goutils"
)
const Production = false
// absolute path of where this package is located
var pkgDir = goutils.MustLocatePackage("github.com/ssb-ngi-pointer/go-ssb-room/web")
var Templates = http.Dir(filepath.Join(pkgDir, "templates"))
var Assets = http.Dir(filepath.Join(pkgDir, "assets"))

View File

@ -1,47 +0,0 @@
// SPDX-License-Identifier: MIT
// +build ignore
package main
import (
"log"
"os/exec"
"github.com/shurcooL/vfsgen"
"github.com/ssb-ngi-pointer/go-ssb-room/web"
)
func main() {
err := vfsgen.Generate(web.Templates, vfsgen.Options{
PackageName: "web",
BuildTags: "!dev",
VariableName: "Templates",
})
if err != nil {
log.Fatalln(err)
}
err = vfsgen.Generate(web.Assets, vfsgen.Options{
PackageName: "web",
BuildTags: "!dev",
VariableName: "Assets",
})
if err != nil {
log.Fatalln(err)
}
// nasty hack to strip duplicate type information
// https://github.com/shurcooL/vfsgen/issues/23
err = exec.Command("sed", "-i", "/^type vfsgen۰FS/,$d", "assets_vfsdata.go").Run()
if err != nil {
log.Fatalln(err)
}
// clean up the unused imports
err = exec.Command("goimports", "-w", ".").Run()
if err != nil {
log.Fatalln(err)
}
}

43
web/embedded_prod.go Normal file
View File

@ -0,0 +1,43 @@
// SPDX-License-Identifier: MIT
// +build !dev
package web
import (
"embed"
"io/fs"
"log"
"net/http"
)
// Production can be used to determain different aspects at compile time (like hot template reloading)
const Production = true
var (
Assets http.FileSystem
Templates http.FileSystem
)
// correct the paths by stripping their prefixes
func init() {
var err error
prefixedAssets, err := fs.Sub(embedAssets, "assets")
if err != nil {
log.Fatal(err)
}
Assets = http.FS(prefixedAssets)
prefixedTemplates, err := fs.Sub(embedTemplates, "templates")
if err != nil {
log.Fatal(err)
}
Templates = http.FS(prefixedTemplates)
}
//go:embed templates/*
var embedTemplates embed.FS
//go:embed assets/*
var embedAssets embed.FS

View File

@ -4,9 +4,13 @@ import (
"bytes"
"net/http"
"net/url"
"strings"
"testing"
"github.com/PuerkitoBio/goquery"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/ssb-ngi-pointer/go-ssb-room/admindb"
"github.com/ssb-ngi-pointer/go-ssb-room/web"
@ -75,6 +79,33 @@ func TestAllowListAdd(t *testing.T) {
a.Equal(newKey, added.Ref())
}
func TestAllowListDontAddInvalid(t *testing.T) {
ts := newSession(t)
a := assert.New(t)
r := require.New(t)
addURL, err := ts.Router.Get(router.AdminAllowListAdd).URL()
a.NoError(err)
newKey := "@some-garbage"
addVals := url.Values{
"pub_key": []string{newKey},
}
rec := ts.Client.PostForm(addURL.String(), addVals)
a.Equal(http.StatusBadRequest, rec.Code)
a.Equal(0, ts.AllowListDB.AddCallCount())
doc, err := goquery.NewDocumentFromReader(rec.Body)
r.NoError(err)
expErr := `bad request: feedRef: couldn't parse "@some-garbage"`
gotMsg := doc.Find("#errBody").Text()
if !a.True(strings.HasPrefix(gotMsg, expErr), "did not find errBody") {
t.Log(gotMsg)
}
}
func TestAllowList(t *testing.T) {
ts := newSession(t)
a := assert.New(t)

View File

@ -55,10 +55,11 @@ func newSession(t *testing.T) *testSession {
}
testFuncs["is_logged_in"] = func() *admindb.User { return nil }
r, err := render.New(http.FS(web.Templates),
r, err := render.New(web.Templates,
render.SetLogger(log),
render.BaseTemplates("templates/base.tmpl"),
render.AddTemplates(append(HTMLTemplates, "templates/error.tmpl")...),
render.BaseTemplates("base.tmpl"),
render.AddTemplates(append(HTMLTemplates, "error.tmpl")...),
render.ErrorTemplate("error.tmpl"),
render.FuncMap(testFuncs),
)
if err != nil {

View File

@ -15,9 +15,9 @@ import (
)
var HTMLTemplates = []string{
"templates/admin/dashboard.tmpl",
"templates/admin/allow-list.tmpl",
"templates/admin/allow-list-remove-confirm.tmpl",
"admin/dashboard.tmpl",
"admin/allow-list.tmpl",
"admin/allow-list-remove-confirm.tmpl",
}
// Handler supplies the elevated access pages to known users.
@ -25,7 +25,7 @@ var HTMLTemplates = []string{
func Handler(r *render.Renderer, roomState *roomstate.Manager, al admindb.AllowListService) http.Handler {
mux := &http.ServeMux{}
mux.HandleFunc("/dashboard", r.HTML("templates/admin/dashboard.tmpl", func(rw http.ResponseWriter, req *http.Request) (interface{}, error) {
mux.HandleFunc("/dashboard", r.HTML("admin/dashboard.tmpl", func(rw http.ResponseWriter, req *http.Request) (interface{}, error) {
lst := roomState.List()
return struct {
Clients []string
@ -38,9 +38,9 @@ func Handler(r *render.Renderer, roomState *roomstate.Manager, al admindb.AllowL
al: al,
}
mux.HandleFunc("/members", r.HTML("templates/admin/allow-list.tmpl", ah.overview))
mux.HandleFunc("/members", r.HTML("admin/allow-list.tmpl", ah.overview))
mux.HandleFunc("/members/add", ah.add)
mux.HandleFunc("/members/remove/confirm", r.HTML("templates/admin/allow-list-remove-confirm.tmpl", ah.removeConfirm))
mux.HandleFunc("/members/remove/confirm", r.HTML("admin/allow-list-remove-confirm.tmpl", ah.removeConfirm))
mux.HandleFunc("/members/remove", ah.remove)
return customStripPrefix("/admin", mux)

View File

@ -16,7 +16,7 @@ import (
)
var HTMLTemplates = []string{
"templates/auth/fallback_sign_in.tmpl",
"auth/fallback_sign_in.tmpl",
}
func Handler(m *mux.Router, r *render.Renderer, a *auth.Handler) http.Handler {
@ -24,7 +24,7 @@ func Handler(m *mux.Router, r *render.Renderer, a *auth.Handler) http.Handler {
m = router.Auth(nil)
}
m.Get(router.AuthFallbackSignInForm).Handler(r.HTML("templates/auth/fallback_sign_in.tmpl", func(w http.ResponseWriter, req *http.Request) (interface{}, error) {
m.Get(router.AuthFallbackSignInForm).Handler(r.HTML("auth/fallback_sign_in.tmpl", func(w http.ResponseWriter, req *http.Request) (interface{}, error) {
return map[string]interface{}{
csrf.TemplateTag: csrf.TemplateField(req),
}, nil

View File

@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"net/http"
"os"
"time"
"github.com/gorilla/csrf"
@ -44,34 +43,20 @@ func New(
var a *auth.Handler
embeddedFS := web.Templates
// f, err := embeddedFS.Open("templates/base.tmpl")
// if err != nil {
// etr, err := embeddedFS.ReadDir("templates")
// if err != nil {
// panic(err)
// }
// for i, e := range etr {
// fmt.Println(i, e)
// }
// return nil, fmt.Errorf("couldn't open base: %w", err)
// }
// f.Close()
r, err := render.New(http.FS(embeddedFS),
r, err := render.New(web.Templates,
render.SetLogger(logger),
render.BaseTemplates("templates/base.tmpl"),
render.BaseTemplates("base.tmpl"),
render.AddTemplates(concatTemplates(
[]string{
"templates/landing/index.tmpl",
"templates/landing/about.tmpl",
"templates/error.tmpl",
"landing/index.tmpl",
"landing/about.tmpl",
"error.tmpl",
},
news.HTMLTemplates,
roomsAuth.HTMLTemplates,
admin.HTMLTemplates,
)...),
render.ErrorTemplate("error.tmpl"),
render.FuncMap(web.TemplateFuncs(m)),
// TODO: move these to the i18n helper pkg
render.InjectTemplateFunc("i18npl", func(r *http.Request) interface{} {
@ -92,9 +77,7 @@ func New(
uid, ok := v.(int64)
if !ok {
// TODO: hook up logging
fmt.Fprintf(os.Stderr, "warning: not the expected ID type: %T\n", v)
return no
panic(fmt.Sprintf("warning: not the expected ID type from authenticated session: %T\n", v))
}
user, err := fs.GetByID(r.Context(), uid)
@ -145,7 +128,7 @@ func New(
msg = ih.LocalizeSimple("ErrorAlreadyAdded")
}
r.HTML("templates/error.tmpl", func(rw http.ResponseWriter, req *http.Request) (interface{}, error) {
r.HTML("error.tmpl", func(rw http.ResponseWriter, req *http.Request) (interface{}, error) {
return errorTemplateData{
Err: msg,
// TODO: localize?
@ -155,7 +138,7 @@ func New(
}).ServeHTTP(rw, req)
}
notAuthorizedH := r.HTML("templates/error.tmpl", func(rw http.ResponseWriter, req *http.Request) (interface{}, error) {
notAuthorizedH := r.HTML("error.tmpl", func(rw http.ResponseWriter, req *http.Request) (interface{}, error) {
statusCode := http.StatusUnauthorized
rw.WriteHeader(statusCode)
return errorTemplateData{
@ -200,12 +183,12 @@ func New(
adminHandler := a.Authenticate(admin.Handler(r, roomState, al))
mainMux.Handle("/admin/", adminHandler)
m.Get(router.CompleteIndex).Handler(r.StaticHTML("templates/landing/index.tmpl"))
m.Get(router.CompleteAbout).Handler(r.StaticHTML("templates/landing/about.tmpl"))
m.Get(router.CompleteIndex).Handler(r.StaticHTML("landing/index.tmpl"))
m.Get(router.CompleteAbout).Handler(r.StaticHTML("landing/about.tmpl"))
m.PathPrefix("/assets/").Handler(http.StripPrefix("/assets/", http.FileServer(http.FS(web.Assets))))
m.PathPrefix("/assets/").Handler(http.StripPrefix("/assets/", http.FileServer(web.Assets)))
m.NotFoundHandler = r.HTML("templates/error.tmpl", func(rw http.ResponseWriter, req *http.Request) (interface{}, error) {
m.NotFoundHandler = r.HTML("error.tmpl", func(rw http.ResponseWriter, req *http.Request) (interface{}, error) {
rw.WriteHeader(http.StatusNotFound)
msg := i18n.LocalizerFromRequest(locHelper, req).LocalizeSimple("PageNotFound")
return errorTemplateData{http.StatusNotFound, "Not Found", msg}, nil

View File

@ -11,8 +11,8 @@ import (
)
var HTMLTemplates = []string{
"templates/news/overview.tmpl",
"templates/news/post.tmpl",
"news/overview.tmpl",
"news/post.tmpl",
}
// Handler creates a http.Handler with all the archives routes attached to it
@ -21,8 +21,8 @@ func Handler(m *mux.Router, r *render.Renderer) http.Handler {
m = router.News(nil)
}
m.Get(router.NewsOverview).Handler(r.HTML("templates/news/overview.tmpl", showOverview))
m.Get(router.NewsPost).Handler(r.HTML("templates/news/post.tmpl", showPost))
m.Get(router.NewsOverview).Handler(r.HTML("news/overview.tmpl", showOverview))
m.Get(router.NewsPost).Handler(r.HTML("news/post.tmpl", showPost))
return m
}

View File

@ -32,10 +32,11 @@ func newSession(t *testing.T) *testSession {
testFuncs["is_logged_in"] = func() *admindb.User { return nil }
log, _ := logtest.KitLogger("feed", t)
r, err := render.New(http.FS(web.Templates),
r, err := render.New(web.Templates,
render.SetLogger(log),
render.BaseTemplates("templates/base.tmpl"),
render.AddTemplates(append(HTMLTemplates, "templates/error.tmpl")...),
render.BaseTemplates("base.tmpl"),
render.AddTemplates(append(HTMLTemplates, "error.tmpl")...),
render.ErrorTemplate("error.tmpl"),
render.FuncMap(testFuncs),
)
if err != nil {

View File

@ -87,7 +87,7 @@ func setup(t *testing.T) *testSession {
// (at least all the globals before starting with nested plurals)
// also replaces 'one' and 'other' in plurals
func justTheKeys() []byte {
f, err := i18n.Defaults.Open("defaults/active.en.toml")
f, err := i18n.Defaults.Open("active.en.toml")
if err != nil {
panic(err)
}

20
web/i18n/dev.go Normal file
View File

@ -0,0 +1,20 @@
// SPDX-License-Identifier: MIT
// +build dev
package i18n
import (
"io/fs"
"os"
"path/filepath"
"go.mindeco.de/goutils"
)
var Defaults fs.FS = os.DirFS(defaultsPath)
var (
pkgDir = goutils.MustLocatePackage("github.com/ssb-ngi-pointer/go-ssb-room/web/i18n")
defaultsPath = filepath.Join(pkgDir, "defaults")
)

View File

@ -4,7 +4,6 @@
package i18n
import (
"embed"
"fmt"
"io"
"io/fs"
@ -21,10 +20,6 @@ import (
"github.com/ssb-ngi-pointer/go-ssb-room/internal/repo"
)
// Defaults is an embedded filesystem containing translation defaults.
//go:embed defaults/*
var Defaults embed.FS
type Helper struct {
bundle *i18n.Bundle
}
@ -61,7 +56,7 @@ func New(r repo.Interface) (*Helper, error) {
}
// walk the embedded defaults
err := fs.WalkDir(Defaults, "defaults", func(path string, d fs.DirEntry, err error) error {
err := fs.WalkDir(Defaults, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}

25
web/i18n/prod.go Normal file
View File

@ -0,0 +1,25 @@
// SPDX-License-Identifier: MIT
// +build !dev
package i18n
import (
"embed"
"io/fs"
"log"
)
// Defaults is an embedded filesystem containing translation defaults.
var Defaults fs.FS
//go:embed defaults/*
var embedDefaults embed.FS
func init() {
var err error
Defaults, err = fs.Sub(embedDefaults, "defaults")
if err != nil {
log.Fatal(err)
}
}

View File

@ -1,8 +0,0 @@
// SPDX-License-Identifier: MIT
// +build !dev
package web
// Production can be used to determain different aspects at compile time (like hot template reloading)
const Production = true

View File

@ -4,7 +4,7 @@
<!-- complete base template -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>html{visibility:hidden;opacity:0;}</style>
<link href="/assets/fixfouc.css" rel="stylesheet">
<link href="/assets/style.css" rel="stylesheet">
<title>{{block "title" .}}Go-SSB Room Server{{end}}</title>
</head>

View File

@ -7,6 +7,10 @@
<div class="col-sm-12">
<p id="errBody">{{.Err}}</p>
<p>
<!-- this violates the CSP, since it's an inline script.
We probably want to solve https://github.com/ssb-ngi-pointer/go-ssb-room/issues/23
but until then it might be nice to include a _previous_ data from the rendere with an url of where to go.
-->
<a href="javascript:history.back()" class="btn btn-primary">Back</a>
</p>
</div>

View File

@ -3,7 +3,6 @@
package web
import (
"embed"
"fmt"
"html/template"
"io/ioutil"
@ -23,12 +22,6 @@ import (
"go.mindeco.de/logging"
)
//go:embed templates/*
var Templates embed.FS
//go:embed assets/*
var Assets embed.FS
// TemplateFuncs returns a map of template functions
func TemplateFuncs(m *mux.Router) template.FuncMap {
return template.FuncMap{