mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-04 11:24:56 +00:00
refactor!: move go-chi/session into Gitea (#39504)
The `gitea.com/go-chi/session` package only exists for Gitea, so it moves into `modules/session` to fix its bugs directly. Fixes the flake in https://github.com/go-gitea/gitea/actions/runs/36726154500/job/109923538400. - Sessions are only written back when changed, so a read-only request can't revert a concurrent change or restore a logged-out session, like https://github.com/go-macaron/session/commit/ae808a4a4660c802965c834299ab08f167effd12 - The session cookie is only set once a session holds data - Every backend refreshes the expiry on load and file sessions are written atomically - Also fix https://github.com/go-gitea/gitea/issues/36176 ## ⚠️ BREAKING ⚠️ * the `mysql`, `postgres`, `couchbase` and `memcache` session providers are removed, use `file`, `db` or `redis` instead * login-related cookies are renamed to `gitea_session` and `gitea_remember`, if you'd like to use the old names, set `COOKIE_NAME` and `COOKIE_REMEMBER_NAME` in app.ini --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
@@ -6,100 +6,52 @@ package integration
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"gitea.dev/modules/json"
|
||||
"gitea.dev/modules/setting"
|
||||
"gitea.dev/modules/test"
|
||||
"gitea.dev/routers"
|
||||
"gitea.dev/tests"
|
||||
|
||||
"gitea.com/go-chi/session"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func getSessionID(t *testing.T, resp *httptest.ResponseRecorder) string {
|
||||
cookies := resp.Result().Cookies()
|
||||
found := false
|
||||
sessionID := ""
|
||||
for _, cookie := range cookies {
|
||||
func getSessionID(resp *httptest.ResponseRecorder) string {
|
||||
for _, cookie := range resp.Result().Cookies() {
|
||||
if cookie.Name == setting.SessionConfig.CookieName {
|
||||
sessionID = cookie.Value
|
||||
found = true
|
||||
return cookie.Value
|
||||
}
|
||||
}
|
||||
assert.True(t, found)
|
||||
assert.NotEmpty(t, sessionID)
|
||||
return sessionID
|
||||
}
|
||||
|
||||
func sessionFile(tmpDir, sessionID string) string {
|
||||
return filepath.Join(tmpDir, sessionID[0:1], sessionID[1:2], sessionID)
|
||||
}
|
||||
|
||||
func sessionFileExist(t *testing.T, tmpDir, sessionID string) bool {
|
||||
sessionFile := sessionFile(tmpDir, sessionID)
|
||||
_, err := os.Lstat(sessionFile)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
return true
|
||||
return ""
|
||||
}
|
||||
|
||||
func TestSessionFileCreation(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
defer test.MockVariableValue(&setting.SessionConfig.ProviderConfig)()
|
||||
defer test.MockVariableValue(&testWebRoutes)()
|
||||
|
||||
var config session.Options
|
||||
err := json.Unmarshal([]byte(setting.SessionConfig.ProviderConfig), &config)
|
||||
assert.NoError(t, err)
|
||||
|
||||
config.Provider = "file"
|
||||
|
||||
// Now create a temporaryDirectory
|
||||
tmpDir := t.TempDir()
|
||||
config.ProviderConfig = tmpDir
|
||||
|
||||
newConfigBytes, err := json.Marshal(config)
|
||||
assert.NoError(t, err)
|
||||
|
||||
setting.SessionConfig.ProviderConfig = string(newConfigBytes)
|
||||
|
||||
testWebRoutes = routers.NormalRoutes()
|
||||
defer test.MockVariableValue(&setting.SessionConfig.Provider, "file")()
|
||||
defer test.MockVariableValue(&setting.SessionConfig.ProviderConfig, tmpDir)()
|
||||
defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
|
||||
|
||||
t.Run("NoSessionOnViewIssue", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user2/repo1/issues/1")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
sessionID := getSessionID(t, resp)
|
||||
|
||||
// We're not logged in so there should be no session
|
||||
assert.False(t, sessionFileExist(t, tmpDir, sessionID))
|
||||
resp := MakeRequest(t, NewRequest(t, "GET", "/user2/repo1/issues/1"), http.StatusOK)
|
||||
assert.Empty(t, getSessionID(resp))
|
||||
})
|
||||
t.Run("CreateSessionOnLogin", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", "/user/login")
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
sessionID := getSessionID(t, resp)
|
||||
resp := MakeRequest(t, NewRequest(t, "GET", "/user/login"), http.StatusOK)
|
||||
assert.Empty(t, getSessionID(resp))
|
||||
|
||||
// We're not logged in so there should be no session
|
||||
assert.False(t, sessionFileExist(t, tmpDir, sessionID))
|
||||
|
||||
req = NewRequestWithValues(t, "POST", "/user/login", map[string]string{
|
||||
req := NewRequestWithValues(t, "POST", "/user/login", map[string]string{
|
||||
"user_name": "user2",
|
||||
"password": userPassword,
|
||||
})
|
||||
resp = MakeRequest(t, req, http.StatusSeeOther)
|
||||
sessionID = getSessionID(t, resp)
|
||||
|
||||
assert.FileExists(t, sessionFile(tmpDir, sessionID))
|
||||
sessionID := getSessionID(MakeRequest(t, req, http.StatusSeeOther))
|
||||
require.Len(t, sessionID, 16)
|
||||
assert.FileExists(t, filepath.Join(tmpDir, sessionID[0:1], sessionID[1:2], sessionID))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -68,8 +68,7 @@ func testViewRepoPublic(t *testing.T) {
|
||||
req = NewRequest(t, "GET", "/org3/repo3")
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
session = loginUser(t, "user1")
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
loginUser(t, "user1").MakeRequest(t, NewRequest(t, "GET", "/org3/repo3"), http.StatusOK)
|
||||
}
|
||||
|
||||
func testViewRepoWithCache(t *testing.T) {
|
||||
|
||||
@@ -5,32 +5,31 @@ package integration
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gitea.dev/models/auth"
|
||||
"gitea.dev/models/unittest"
|
||||
"gitea.dev/modules/timeutil"
|
||||
"gitea.dev/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_RegenerateSession(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
func TestUpdateSession(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
defer timeutil.MockSet(time.Now())()
|
||||
key := "0123456789abcdef"
|
||||
for _, create := range []bool{true, true, false} {
|
||||
require.NoError(t, auth.UpdateSession(t.Context(), key, []byte("data"), create))
|
||||
}
|
||||
sess, exist, err := auth.GetSession(t.Context(), key)
|
||||
require.NoError(t, err)
|
||||
require.True(t, exist)
|
||||
assert.Equal(t, []byte("data"), sess.Data)
|
||||
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
key := "new_key890123456" // it must be 16 characters long
|
||||
key2 := "new_key890123457" // it must be 16 characters
|
||||
exist, err := auth.ExistSession(t.Context(), key)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, auth.DestroySession(t.Context(), key))
|
||||
require.NoError(t, auth.UpdateSession(t.Context(), key, []byte("data"), false))
|
||||
_, exist, err = auth.GetSession(t.Context(), key)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, exist)
|
||||
|
||||
sess, err := auth.RegenerateSession(t.Context(), "", key)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, key, sess.Key)
|
||||
assert.Empty(t, sess.Data)
|
||||
|
||||
sess, err = auth.ReadSession(t.Context(), key2)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, key2, sess.Key)
|
||||
assert.Empty(t, sess.Data)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user