2022-09-02 21:18:23 +02:00
// Copyright 2019 The Gitea Authors. All rights reserved.
2022-11-27 19:20:29 +01:00
// SPDX-License-Identifier: MIT
2022-09-02 21:18:23 +02:00
package e2e
import (
"context"
2025-01-05 06:17:04 +01:00
"crypto/rand"
"encoding/hex"
"fmt"
2022-09-02 21:18:23 +02:00
"net"
"net/http"
"net/url"
2024-11-15 14:02:16 +01:00
"os"
2025-01-05 06:17:04 +01:00
"path/filepath"
2024-11-15 14:02:16 +01:00
"regexp"
2025-01-05 06:17:04 +01:00
"strings"
2022-09-02 21:18:23 +02:00
"testing"
"time"
2025-01-05 06:17:04 +01:00
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/json"
modules_session "code.gitea.io/gitea/modules/session"
2022-09-02 21:18:23 +02:00
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/tests"
2025-01-05 06:17:04 +01:00
"code.forgejo.org/go-chi/session"
2024-07-30 21:41:10 +02:00
"github.com/stretchr/testify/require"
2022-09-02 21:18:23 +02:00
)
2024-11-15 14:02:16 +01:00
var rootPathRe = regexp . MustCompile ( "\\[repository\\]\nROOT\\s=\\s.*" )
2024-08-25 14:52:21 +02:00
func onForgejoRunTB ( t testing . TB , callback func ( testing . TB , * url . URL ) , prepare ... bool ) {
2022-09-02 21:18:23 +02:00
if len ( prepare ) == 0 || prepare [ 0 ] {
defer tests . PrepareTestEnv ( t , 1 ) ( )
}
2025-01-05 06:17:04 +01:00
createSessions ( t )
2022-09-02 21:18:23 +02:00
s := http . Server {
2023-08-12 18:30:16 +02:00
Handler : testE2eWebRoutes ,
2022-09-02 21:18:23 +02:00
}
u , err := url . Parse ( setting . AppURL )
2024-07-30 21:41:10 +02:00
require . NoError ( t , err )
2022-09-02 21:18:23 +02:00
listener , err := net . Listen ( "tcp" , u . Host )
i := 0
for err != nil && i <= 10 {
time . Sleep ( 100 * time . Millisecond )
listener , err = net . Listen ( "tcp" , u . Host )
i ++
}
2024-07-30 21:41:10 +02:00
require . NoError ( t , err )
2022-09-02 21:18:23 +02:00
u . Host = listener . Addr ( ) . String ( )
2024-11-15 14:02:16 +01:00
// Override repository root in config.
conf , err := os . ReadFile ( setting . CustomConf )
require . NoError ( t , err )
require . NoError ( t , os . WriteFile ( setting . CustomConf , rootPathRe . ReplaceAll ( conf , [ ] byte ( "[repository]\nROOT = " + setting . RepoRootPath ) ) , 0 o644 ) )
2022-09-02 21:18:23 +02:00
defer func ( ) {
2024-11-15 14:02:16 +01:00
require . NoError ( t , os . WriteFile ( setting . CustomConf , conf , 0 o644 ) )
2022-09-02 21:18:23 +02:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , 2 * time . Minute )
s . Shutdown ( ctx )
cancel ( )
} ( )
go s . Serve ( listener )
// Started by config go ssh.Listen(setting.SSH.ListenHost, setting.SSH.ListenPort, setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs)
callback ( t , u )
}
2024-08-25 14:52:21 +02:00
func onForgejoRun ( t * testing . T , callback func ( * testing . T , * url . URL ) , prepare ... bool ) {
onForgejoRunTB ( t , func ( t testing . TB , u * url . URL ) {
2022-09-02 21:18:23 +02:00
callback ( t . ( * testing . T ) , u )
} , prepare ... )
}
2025-01-05 06:17:04 +01:00
func createSessions ( t testing . TB ) {
t . Helper ( )
// copied from playwright.config.ts
browsers := [ ] string {
"chromium" ,
"firefox" ,
"webkit" ,
"Mobile Chrome" ,
"Mobile Safari" ,
}
scopes := [ ] string {
"shared" ,
}
users := [ ] string {
"user1" ,
"user2" ,
"user12" ,
"user40" ,
}
authState := filepath . Join ( filepath . Dir ( setting . AppPath ) , "tests" , "e2e" , ".auth" )
err := os . RemoveAll ( authState )
require . NoError ( t , err )
err = os . MkdirAll ( authState , os . ModePerm )
require . NoError ( t , err )
createSessionCookie := stateHelper ( t )
for _ , user := range users {
u := unittest . AssertExistsAndLoadBean ( t , & user_model . User { LowerName : strings . ToLower ( user ) } )
for _ , browser := range browsers {
for _ , scope := range scopes {
stateFile := strings . ReplaceAll ( strings . ToLower ( fmt . Sprintf ( "state-%s-%s-%s.json" , browser , user , scope ) ) , " " , "-" )
createSessionCookie ( filepath . Join ( authState , stateFile ) , u )
}
}
}
}
func stateHelper ( t testing . TB ) func ( stateFile string , user * user_model . User ) {
type Cookie struct {
Name string ` json:"name" `
Value string ` json:"value" `
Domain string ` json:"domain" `
Path string ` json:"path" `
Expires int ` json:"expires" `
HTTPOnly bool ` json:"httpOnly" `
Secure bool ` json:"secure" `
SameSite string ` json:"sameSite" `
}
type BrowserState struct {
Cookies [ ] Cookie ` json:"cookies" `
Origins [ ] string ` json:"origins" `
}
options := session . Options {
Provider : setting . SessionConfig . Provider ,
ProviderConfig : setting . SessionConfig . ProviderConfig ,
CookieName : setting . SessionConfig . CookieName ,
CookiePath : setting . SessionConfig . CookiePath ,
Gclifetime : setting . SessionConfig . Gclifetime ,
Maxlifetime : setting . SessionConfig . Maxlifetime ,
Secure : setting . SessionConfig . Secure ,
SameSite : setting . SessionConfig . SameSite ,
Domain : setting . SessionConfig . Domain ,
}
opt := session . PrepareOptions ( [ ] session . Options { options } )
vsp := modules_session . VirtualSessionProvider { }
err := vsp . Init ( opt . Maxlifetime , opt . ProviderConfig )
require . NoError ( t , err )
return func ( stateFile string , user * user_model . User ) {
buf := make ( [ ] byte , opt . IDLength / 2 )
_ , err = rand . Read ( buf )
require . NoError ( t , err )
sessionID := hex . EncodeToString ( buf )
s , err := vsp . Read ( sessionID )
require . NoError ( t , err )
err = s . Set ( "uid" , user . ID )
require . NoError ( t , err )
err = s . Release ( )
require . NoError ( t , err )
state := BrowserState {
Cookies : [ ] Cookie {
{
Name : opt . CookieName ,
Value : sessionID ,
Domain : setting . Domain ,
Path : "/" ,
Expires : - 1 ,
HTTPOnly : true ,
Secure : false ,
SameSite : "Lax" ,
} ,
} ,
Origins : [ ] string { } ,
}
jsonData , err := json . Marshal ( state )
require . NoError ( t , err )
err = os . WriteFile ( stateFile , jsonData , 0 o644 )
require . NoError ( t , err )
}
}