From ac7c5e8cd28e9a491d7eeb560dd0fe5aed0d94df Mon Sep 17 00:00:00 2001 From: tobi <31960611+tsmethurst@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:12:31 +0200 Subject: [PATCH] session name fix (#185) --- internal/router/session.go | 30 ++++++++++-- internal/router/session_test.go | 87 +++++++++++++++++++++++++++++++++ internal/router/template.go | 18 +++++++ 3 files changed, 131 insertions(+), 4 deletions(-) create mode 100644 internal/router/session_test.go diff --git a/internal/router/session.go b/internal/router/session.go index a42f04bfb..3276c38aa 100644 --- a/internal/router/session.go +++ b/internal/router/session.go @@ -23,6 +23,7 @@ import ( "errors" "fmt" "net/http" + "net/url" "github.com/gin-contrib/sessions" "github.com/gin-contrib/sessions/memstore" @@ -31,8 +32,8 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/db" ) -// SessionOptions returns the standard set of options to use for each session. -func SessionOptions(cfg *config.Config) sessions.Options { +// sessionOptions returns the standard set of options to use for each session. +func sessionOptions(cfg *config.Config) sessions.Options { return sessions.Options{ Path: "/", Domain: cfg.Host, @@ -43,6 +44,22 @@ func SessionOptions(cfg *config.Config) sessions.Options { } } +func sessionName(cfg *config.Config) (string, error) { + // parse the protocol + host + u, err := url.Parse(fmt.Sprintf("%s://%s", cfg.Protocol, cfg.Host)) + if err != nil { + return "", err + } + + // take the hostname without any port attached + strippedHostname := u.Hostname() + if strippedHostname == "" { + return "", fmt.Errorf("could not derive hostname without port from %s://%s", cfg.Protocol, cfg.Host) + } + + return fmt.Sprintf("gotosocial-%s", strippedHostname), nil +} + func useSession(ctx context.Context, cfg *config.Config, sessionDB db.Session, engine *gin.Engine) error { // check if we have a saved router session already rs, err := sessionDB.GetSession(ctx) @@ -54,8 +71,13 @@ func useSession(ctx context.Context, cfg *config.Config, sessionDB db.Session, e } store := memstore.NewStore(rs.Auth, rs.Crypt) - store.Options(SessionOptions(cfg)) - sessionName := fmt.Sprintf("gotosocial-%s", cfg.Host) + store.Options(sessionOptions(cfg)) + + sessionName, err := sessionName(cfg) + if err != nil { + return err + } + engine.Use(sessions.Sessions(sessionName, store)) return nil } diff --git a/internal/router/session_test.go b/internal/router/session_test.go new file mode 100644 index 000000000..7c2d324fd --- /dev/null +++ b/internal/router/session_test.go @@ -0,0 +1,87 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +package router + +import ( + "testing" + + "github.com/stretchr/testify/suite" + "github.com/superseriousbusiness/gotosocial/internal/config" +) + +type SessionTestSuite struct { + suite.Suite +} + +func (suite *SessionTestSuite) TestDeriveSessionNameLocalhostWithPort() { + cfg := &config.Config{ + Protocol: "http", + Host: "localhost:8080", + } + + sessionName, err := sessionName(cfg) + suite.NoError(err) + suite.Equal("gotosocial-localhost", sessionName) +} + +func (suite *SessionTestSuite) TestDeriveSessionNameLocalhost() { + cfg := &config.Config{ + Protocol: "http", + Host: "localhost", + } + + sessionName, err := sessionName(cfg) + suite.NoError(err) + suite.Equal("gotosocial-localhost", sessionName) +} + +func (suite *SessionTestSuite) TestDeriveSessionNoProtocol() { + cfg := &config.Config{ + Host: "localhost", + } + + sessionName, err := sessionName(cfg) + suite.EqualError(err, "parse \"://localhost\": missing protocol scheme") + suite.Equal("", sessionName) +} + +func (suite *SessionTestSuite) TestDeriveSessionNoHost() { + cfg := &config.Config{ + Protocol: "https", + } + + sessionName, err := sessionName(cfg) + suite.EqualError(err, "could not derive hostname without port from https://") + suite.Equal("", sessionName) +} + +func (suite *SessionTestSuite) TestDeriveSessionOK() { + cfg := &config.Config{ + Protocol: "https", + Host: "example.org", + } + + sessionName, err := sessionName(cfg) + suite.NoError(err) + suite.Equal("gotosocial-example.org", sessionName) +} + +func TestSessionTestSuite(t *testing.T) { + suite.Run(t, &SessionTestSuite{}) +} diff --git a/internal/router/template.go b/internal/router/template.go index 787ade799..e7bdc3edf 100644 --- a/internal/router/template.go +++ b/internal/router/template.go @@ -1,3 +1,21 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + package router import (