From 74f1c1613d54c616d5ed7b7fd64073670eee45d8 Mon Sep 17 00:00:00 2001 From: Alexander Sporn Date: Fri, 16 Sep 2022 12:09:10 +0200 Subject: [PATCH 1/6] Add support for hosting the dashboard behind a proxy that adds a path prefix and sets the X-Forwarded-Prefix header value --- packages/authentication/jwt_handler.go | 10 ++++++++-- packages/dashboard/auth.go | 14 ++++++++++---- packages/dashboard/base.go | 1 + packages/dashboard/error.go | 2 +- packages/dashboard/renderer.go | 9 ++++++++- packages/dashboard/templates/base.tmpl | 2 +- 6 files changed, 29 insertions(+), 9 deletions(-) diff --git a/packages/authentication/jwt_handler.go b/packages/authentication/jwt_handler.go index 984339b0b0..ce976f04bf 100644 --- a/packages/authentication/jwt_handler.go +++ b/packages/authentication/jwt_handler.go @@ -15,6 +15,8 @@ import ( "github.com/iotaledger/wasp/packages/users" ) +const headerXForwardedPrefix = "X-Forwarded-Prefix" + type AuthHandler struct { Jwt *JWTAuth Users map[string]*users.UserData @@ -71,10 +73,14 @@ func (a *AuthHandler) handleJSONAuthRequest(c echo.Context, token string, errorR return c.JSON(http.StatusOK, shared.LoginResponse{JWT: token}) } +func (a *AuthHandler) redirect(c echo.Context, uri string) error { + return c.Redirect(http.StatusFound, c.Request().Header.Get(headerXForwardedPrefix)+uri) +} + func (a *AuthHandler) handleFormAuthRequest(c echo.Context, token string, errorResult error) error { if errorResult != nil { // TODO: Add sessions to get rid of the query parameter? - return c.Redirect(http.StatusFound, fmt.Sprintf("%s?error=%s", shared.AuthRoute(), errorResult)) + return a.redirect(c, fmt.Sprintf("%s?error=%s", shared.AuthRoute(), errorResult)) } cookie := http.Cookie{ @@ -88,7 +94,7 @@ func (a *AuthHandler) handleFormAuthRequest(c echo.Context, token string, errorR c.SetCookie(&cookie) - return c.Redirect(http.StatusFound, shared.AuthRouteSuccess()) + return a.redirect(c, shared.AuthRouteSuccess()) } func (a *AuthHandler) CrossAPIAuthHandler(c echo.Context) error { diff --git a/packages/dashboard/auth.go b/packages/dashboard/auth.go index 7cc6ee2c61..4459040218 100644 --- a/packages/dashboard/auth.go +++ b/packages/dashboard/auth.go @@ -17,6 +17,8 @@ import ( //go:embed templates/auth.tmpl var tplLogin string +const headerXForwardedPrefix = "X-Forwarded-Prefix" + func (d *Dashboard) authInit(e *echo.Echo, r renderer) Tab { e.GET(shared.AuthRouteSuccess(), d.handleAuthCheck) e.GET("/", d.handleAuthCheck) @@ -37,7 +39,7 @@ func (d *Dashboard) RenderAuthView(c echo.Context) error { auth, ok := c.Get("auth").(*authentication.AuthContext) if ok && auth.IsAuthenticated() { - return c.Redirect(http.StatusFound, "/config") + return d.redirect(c, "/config") } // TODO: Add sessions? @@ -54,14 +56,18 @@ func (d *Dashboard) handleAuthCheck(c echo.Context) error { auth, ok := c.Get("auth").(*authentication.AuthContext) if !ok { - return c.Redirect(http.StatusFound, shared.AuthRoute()) + return d.redirect(c, shared.AuthRoute()) } if auth.IsAuthenticated() { - return c.Redirect(http.StatusFound, "/config") + return d.redirect(c, "/config") } - return c.Redirect(http.StatusFound, shared.AuthRoute()) + return d.redirect(c, shared.AuthRoute()) +} + +func (d *Dashboard) redirect(c echo.Context, uri string) error { + return c.Redirect(http.StatusFound, c.Request().Header.Get(headerXForwardedPrefix)+uri) } type AuthTemplateParams struct { diff --git a/packages/dashboard/base.go b/packages/dashboard/base.go index 23928222cf..c9e5569d75 100644 --- a/packages/dashboard/base.go +++ b/packages/dashboard/base.go @@ -141,6 +141,7 @@ func (d *Dashboard) makeTemplate(e *echo.Echo, parts ...string) *template.Templa "webapiPort": d.wasp.WebAPIPort, "evmJSONRPCEndpoint": routes.EVMJSONRPC, "uri": func(s string, p ...interface{}) string { return e.Reverse(s, p...) }, + "href": func(s string) string { return s }, }) t = template.Must(t.Parse(tplBase)) for _, part := range parts { diff --git a/packages/dashboard/error.go b/packages/dashboard/error.go index 546ffeff63..29dd8af8e4 100644 --- a/packages/dashboard/error.go +++ b/packages/dashboard/error.go @@ -56,7 +56,7 @@ func (d *Dashboard) handleError(err error, c echo.Context) { authContext, ok := c.Get("auth").(*authentication.AuthContext) if ok && authContext.Scheme() == authentication.AuthJWT && he.Code == http.StatusUnauthorized { - err = c.Redirect(http.StatusFound, shared.AuthRoute()) + err = d.redirect(c, shared.AuthRoute()) } else { err = c.Render(he.Code, errorTplName, &ErrorTemplateParams{ BaseTemplateParams: d.BaseParams(c), diff --git a/packages/dashboard/renderer.go b/packages/dashboard/renderer.go index 072ba33806..b9569804ac 100644 --- a/packages/dashboard/renderer.go +++ b/packages/dashboard/renderer.go @@ -13,5 +13,12 @@ import ( type renderer map[string]*template.Template func (t renderer) Render(w io.Writer, name string, data interface{}, c echo.Context) error { - return t[name].ExecuteTemplate(w, "base", data) + return template.Must(t[name].Clone()).Funcs(template.FuncMap{ + "uri": func(s string, p ...interface{}) string { + return c.Request().Header.Get(headerXForwardedPrefix) + c.Echo().Reverse(s, p...) + }, + "href": func(s string) string { + return c.Request().Header.Get(headerXForwardedPrefix) + s + }, + }).ExecuteTemplate(w, "base", data) } diff --git a/packages/dashboard/templates/base.tmpl b/packages/dashboard/templates/base.tmpl index 62e17eabd6..c17c0799b7 100644 --- a/packages/dashboard/templates/base.tmpl +++ b/packages/dashboard/templates/base.tmpl @@ -48,7 +48,7 @@ {{ $href := index . 1 }} {{ $active := index . 2 }} - Date: Tue, 20 Sep 2022 11:23:10 +0300 Subject: [PATCH 2/6] Make command to fetch needed versions of dependencies --- Makefile | 8 ++++++-- packages/testutil/privtangle/privtangle.go | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 82f2c982a7..8a432ad6e8 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ TEST_ARG= BUILD_PKGS=./ ./tools/wasp-cli/ ./tools/cluster/wasp-cluster/ ./tools/snap-cli/ BUILD_CMD=go build -o . -tags $(BUILD_TAGS) -ldflags $(BUILD_LD_FLAGS) -INSTALL_CMD=go install -tags $(BUILD_TAGS) -ldflags $(BUILD_LD_FLAGS) +INSTALL_CMD=go install -tags $(BUILD_TAGS) -ldflags $(BUILD_LD_FLAGS) all: build-lint @@ -64,5 +64,9 @@ docker-build: --build-arg BUILD_LD_FLAGS='${BUILD_LD_FLAGS}' \ . -.PHONY: all build build-lint test test-short test-full install lint gofumpt-list docker-build +deps-versions: + @grep -n "====" packages/testutil/privtangle/privtangle.go | \ + awk -F ":" '{ print $$1 }' | \ + { read from ; read to; awk -v s="$$from" -v e="$$to" 'NR>1*s&&NR<1*e' packages/testutil/privtangle/privtangle.go; } +.PHONY: all build build-lint test test-short test-full install lint gofumpt-list docker-build deps-versions diff --git a/packages/testutil/privtangle/privtangle.go b/packages/testutil/privtangle/privtangle.go index 2170f5718e..23ac9a8cd9 100644 --- a/packages/testutil/privtangle/privtangle.go +++ b/packages/testutil/privtangle/privtangle.go @@ -29,11 +29,13 @@ import ( "github.com/iotaledger/wasp/packages/util" ) +// ===== Wasp dependencies ===== // DO NOT DELETE THIS LINE! It is needed for `make deps-versions` command // requires hornet, and inx plugins binaries to be in PATH // https://github.com/iotaledger/hornet (5b35e2a) // https://github.com/iotaledger/inx-indexer (7cdb3ed) // https://github.com/iotaledger/inx-coordinator (f84d8dd) // https://github.com/iotaledger/inx-faucet (c847f1c) (requires `git submodule update --init --recursive` before building ) +// ============================= // DO NOT DELETE THIS LINE! It is needed for `make deps-versions` command type LogFunc func(format string, args ...interface{}) From 210beded5b60e63ce21eff7cddac3e54ceac86f4 Mon Sep 17 00:00:00 2001 From: Julius Andrikonis Date: Tue, 20 Sep 2022 17:04:49 +0300 Subject: [PATCH 3/6] BugFix of chain halting due to nodes posting to ACS the same proposal on different state outputs --- packages/chain/consensus/action.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/chain/consensus/action.go b/packages/chain/consensus/action.go index 715a118aab..84a761e81a 100644 --- a/packages/chain/consensus/action.go +++ b/packages/chain/consensus/action.go @@ -507,7 +507,7 @@ func (c *consensus) receiveACS(values [][]byte, sessionID uint64, logIndex journ proposal, err := BatchProposalFromBytes(data) if err != nil { c.log.Errorf("receiveACS: wrong data received. Whole ACS ignored: %v", err) - c.resetWorkflow() + c.resetWorkflowNoCheck() return } acs[i] = proposal @@ -519,19 +519,19 @@ func (c *consensus) receiveACS(values [][]byte, sessionID uint64, logIndex journ if !prop.StateOutputID.Equals(c.stateOutput.ID()) { c.log.Warnf("receiveACS: ACS out of context or consensus failure: expected stateOuptudId: %v, contributor %v stateOutputID: %v ", isc.OID(c.stateOutput.ID()), prop.ValidatorIndex, isc.OID(prop.StateOutputID)) - c.resetWorkflow() + c.resetWorkflowNoCheck() return } if prop.ValidatorIndex >= c.committee.Size() { c.log.Warnf("receiveACS: wrong validator index in ACS: committee size is %v, validator index is %v", c.committee.Size(), prop.ValidatorIndex) - c.resetWorkflow() + c.resetWorkflowNoCheck() return } contributors = append(contributors, prop.ValidatorIndex) if _, already := contributorSet[prop.ValidatorIndex]; already { c.log.Errorf("receiveACS: duplicate contributor %v in ACS", prop.ValidatorIndex) - c.resetWorkflow() + c.resetWorkflowNoCheck() return } c.log.Debugf("receiveACS: contributor %v of ACS included", prop.ValidatorIndex) @@ -558,7 +558,7 @@ func (c *consensus) receiveACS(values [][]byte, sessionID uint64, logIndex journ // reached nodes and we have give it a time. Should not happen often c.log.Warnf("receiveACS: ACS intersection (light) is empty. reset workflow. State index: %d, ACS sessionID %d", c.stateOutput.GetStateIndex(), sessionID) - c.resetWorkflow() + c.resetWorkflowNoCheck() c.delayBatchProposalUntil = time.Now().Add(c.timers.ProposeBatchRetry) return } @@ -576,7 +576,7 @@ func (c *consensus) receiveACS(values [][]byte, sessionID uint64, logIndex journ // should not happen, unless insider attack c.log.Errorf("receiveACS: inconsistent ACS. Reset workflow. State index: %d, ACS sessionID %d, reason: %v", c.stateOutput.GetStateIndex(), sessionID, err) - c.resetWorkflow() + c.resetWorkflowNoCheck() c.delayBatchProposalUntil = time.Now().Add(c.timers.ProposeBatchRetry) } c.consensusBatch = &BatchProposal{ From 1c40b6749f8e5967422c062fcab32cb915ee864c Mon Sep 17 00:00:00 2001 From: muXxer Date: Tue, 20 Sep 2022 21:12:17 +0200 Subject: [PATCH 4/6] Fix gendoc template --- documentation/docs/configuration.md | 7 ++----- tools/gendoc/main.go | 26 ++++++++++++++++++-------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/documentation/docs/configuration.md b/documentation/docs/configuration.md index 11395c7f5d..fdc60fdb4b 100755 --- a/documentation/docs/configuration.md +++ b/documentation/docs/configuration.md @@ -1,9 +1,6 @@ - --- +# !!! DO NOT MODIFY !!! +# This file is auto-generated by the gendoc tool based on the source code of the app. description: This section describes the configuration parameters and their types for WASP. keywords: - IOTA Node diff --git a/tools/gendoc/main.go b/tools/gendoc/main.go index 113d44d552..6e8874c2fd 100644 --- a/tools/gendoc/main.go +++ b/tools/gendoc/main.go @@ -3,6 +3,7 @@ package main import ( "fmt" "os" + "strings" "github.com/iotaledger/hive.go/apputils/config" "github.com/iotaledger/hive.go/core/app" @@ -11,12 +12,7 @@ import ( func createMarkdownFile(app *app.App, markdownHeaderPath string, markdownFilePath string, ignoreFlags map[string]struct{}, replaceTopicNames map[string]string) { - markdownHeader := []byte(` -`) + markdownHeader := "" if markdownHeaderPath != "" { var err error @@ -25,12 +21,26 @@ This file is auto-generated by the gendoc tool based on the source code of the a panic(err) } - markdownHeader = append(markdownHeader, markdownHeaderFile...) + markdownHeader = string(markdownHeaderFile) + } + + if strings.HasPrefix(markdownHeader, "---") { + // header contains frontmatter code block + markdownHeader = strings.Replace(markdownHeader, "---", `--- +# !!! DO NOT MODIFY !!! +# This file is auto-generated by the gendoc tool based on the source code of the app.`, 1) + } else { + markdownHeader = ` +` + markdownHeader } println(fmt.Sprintf("Create markdown file for %s...", app.Info().Name)) md := config.GetConfigurationMarkdown(app.Config(), app.FlagSet(), ignoreFlags, replaceTopicNames) - if err := os.WriteFile(markdownFilePath, append(markdownHeader, []byte(md)...), os.ModePerm); err != nil { + if err := os.WriteFile(markdownFilePath, append([]byte(markdownHeader), []byte(md)...), os.ModePerm); err != nil { panic(err) } println(fmt.Sprintf("Markdown file for %s stored: %s", app.Info().Name, markdownFilePath)) From 7deb7ab2b2276208c8456743f763a14030d88411 Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Wed, 21 Sep 2022 13:03:04 +0100 Subject: [PATCH 5/6] lint fix --- packages/chain/chainimpl/chainimpl.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/chain/chainimpl/chainimpl.go b/packages/chain/chainimpl/chainimpl.go index a3923bf1cc..ecd5e56741 100644 --- a/packages/chain/chainimpl/chainimpl.go +++ b/packages/chain/chainimpl/chainimpl.go @@ -59,8 +59,6 @@ type chainObj struct { eventRequestProcessed *events.Event eventChainTransition *events.Event eventChainTransitionClosure *events.Closure - txInclusingClosure *events.Closure - milestonesClosure *events.Closure receiveChainPeerMessagesAttachID interface{} detachFromCommitteePeerMessagesFun func() chainPeers peering.PeerDomainProvider From ff28c2eca6cae938b61733b680c09a2138c5633f Mon Sep 17 00:00:00 2001 From: Dave de Fijter Date: Wed, 21 Sep 2022 16:51:26 +0200 Subject: [PATCH 6/6] Version bump --- packages/wasp/constants.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wasp/constants.go b/packages/wasp/constants.go index 9fb14dec1c..102984022a 100644 --- a/packages/wasp/constants.go +++ b/packages/wasp/constants.go @@ -4,7 +4,7 @@ var VersionHash string const ( // Version version number - Version = "0.3.1" + Version = "0.3.2" // Name app code name Name = "Wasp"