// Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package install import ( "bytes" "mime/multipart" "net/http" "net/http/httptest" "os" "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/services/forms" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestRoutes(t *testing.T) { defer test.MockVariableValue(&setting.InstallLock, false)() r := Routes() assert.NotNil(t, r) w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/", nil) r.ServeHTTP(w, req) assert.Equal(t, 200, w.Code) assert.Contains(t, w.Body.String(), `class="page-content install`) assert.Contains(t, w.Body.String(), `name="default_language"`) assert.Contains(t, w.Body.String(), `name="app_ini_file"`) w = httptest.NewRecorder() req = httptest.NewRequest(http.MethodGet, "/no-such", nil) r.ServeHTTP(w, req) assert.Equal(t, 404, w.Code) w = httptest.NewRecorder() req = httptest.NewRequest(http.MethodGet, "/assets/img/gitea.svg", nil) r.ServeHTTP(w, req) assert.Equal(t, 200, w.Code) } func TestReorderInstallLanguages(t *testing.T) { defer test.MockVariableValue(&setting.Langs, []string{"en-US", "de-DE", "fr-FR"})() assert.Equal(t, "en-US", resolveInstallDefaultLanguage("")) assert.Equal(t, "en-US", resolveInstallDefaultLanguage("invalid")) assert.Equal(t, "fr-FR", resolveInstallDefaultLanguage("fr-FR")) assert.Equal(t, []string{"fr-FR", "en-US", "de-DE"}, reorderInstallLanguages("fr-FR")) assert.Equal(t, []string{"en-US", "de-DE", "fr-FR"}, reorderInstallLanguages("invalid")) } func TestPopulateInstallFormFromConfig(t *testing.T) { defer test.MockVariableValue(&setting.SupportedDatabaseTypes, []string{"mysql", "postgres", "sqlite3"})() defer test.MockVariableValue(&setting.Langs, []string{"en-US", "de-DE", "fr-FR"})() cfg, err := setting.NewConfigProviderFromData(` APP_NAME = Imported Gitea RUN_USER = imported-user [database] DB_TYPE = postgres HOST = db.example.com:5432 USER = gitea PASSWD = secret NAME = giteadb SCHEMA = custom SSL_MODE = require [repository] ROOT = /srv/gitea/repos [server] DOMAIN = gitea.example.com SSH_PORT = 2222 HTTP_PORT = 4000 ROOT_URL = https://gitea.example.com/ [lfs] PATH = /srv/gitea/lfs [log] ROOT_PATH = /srv/gitea/log [mailer] ENABLED = true SMTP_ADDR = smtp.example.com SMTP_PORT = 587 FROM = Gitea USER = smtp-user PASSWD = smtp-pass [service] REGISTER_EMAIL_CONFIRM = true REGISTER_MANUAL_CONFIRM = false ENABLE_NOTIFY_MAIL = true ADMIN_CREATED_ACCOUNT_MODE = invite DISABLE_REGISTRATION = false ALLOW_ONLY_INTERNAL_REGISTRATION = true ALLOW_ONLY_EXTERNAL_REGISTRATION = false ENABLE_CAPTCHA = true REQUIRE_SIGNIN_VIEW = true DEFAULT_KEEP_EMAIL_PRIVATE = true DEFAULT_ALLOW_CREATE_ORGANIZATION = false DEFAULT_ENABLE_TIMETRACKING = false NO_REPLY_ADDRESS = noreply.example.com [openid] ENABLE_OPENID_SIGNIN = true ENABLE_OPENID_SIGNUP = true [security] ENABLE_UPDATE_CHECKER = true PASSWORD_HASH_ALGO = pbkdf2 [admin] ADMIN_MANAGEMENT_POLICY = super_admin_only [i18n] LANGS = de-DE,en-US `) require.NoError(t, err) form, curDBType := newInstallFormFromSettings() curDBType = populateInstallFormFromConfig(&form, cfg, curDBType) assert.Equal(t, "postgres", curDBType) assert.Equal(t, "postgres", form.DbType) assert.Equal(t, "Imported Gitea", form.AppName) assert.Equal(t, "imported-user", form.RunUser) assert.Equal(t, "db.example.com:5432", form.DbHost) assert.Equal(t, "gitea", form.DbUser) assert.Equal(t, "secret", form.DbPasswd) assert.Equal(t, "giteadb", form.DbName) assert.Equal(t, "custom", form.DbSchema) assert.Equal(t, "require", form.SSLMode) assert.Equal(t, "/srv/gitea/repos", form.RepoRootPath) assert.Equal(t, "/srv/gitea/lfs", form.LFSRootPath) assert.Equal(t, "gitea.example.com", form.Domain) assert.Equal(t, 2222, form.SSHPort) assert.Equal(t, "4000", form.HTTPPort) assert.Equal(t, "https://gitea.example.com/", form.AppURL) assert.Equal(t, "/srv/gitea/log", form.LogRootPath) assert.Equal(t, "smtp.example.com", form.SMTPAddr) assert.Equal(t, "587", form.SMTPPort) assert.Equal(t, "Gitea ", form.SMTPFrom) assert.Equal(t, "smtp-user", form.SMTPUser) assert.Equal(t, "smtp-pass", form.SMTPPasswd) assert.Equal(t, "de-DE", form.DefaultLanguage) assert.True(t, form.RegisterConfirm) assert.False(t, form.RegisterManualConfirm) assert.True(t, form.MailNotify) assert.Equal(t, "invite", form.AdminCreatedAccountMode) assert.Equal(t, "local_only", form.RegistrationMode) assert.False(t, form.EnableOpenIDSignIn) assert.False(t, form.EnableOpenIDSignUp) assert.True(t, form.EnableCaptcha) assert.True(t, form.RequireSignInView) assert.True(t, form.DefaultKeepEmailPrivate) assert.False(t, form.DefaultAllowCreateOrganization) assert.False(t, form.DefaultEnableTimetracking) assert.Equal(t, "noreply.example.com", form.NoReplyAddress) assert.True(t, form.EnableUpdateChecker) assert.Equal(t, "pbkdf2", form.PasswordAlgorithm) assert.Equal(t, "super_admin_only", form.AdminManagementPolicy) } func TestPopulateInstallFormFromConfigWithSensitiveSecrets(t *testing.T) { cfg, err := setting.NewConfigProviderFromData(` [server] LFS_JWT_SECRET = lfs-secret [security] INTERNAL_TOKEN = internal-secret [oauth2] JWT_SECRET = oauth-secret `) require.NoError(t, err) form, curDBType := newInstallFormFromSettings() form.ImportSensitiveSecrets = true populateInstallFormFromConfig(&form, cfg, curDBType) assert.Equal(t, "lfs-secret", form.ImportedLFSJWTSecret) assert.Equal(t, "internal-secret", form.ImportedInternalToken) assert.Equal(t, "oauth-secret", form.ImportedOAuth2JWTSecret) } func TestPopulateInstallFormFromConfigWithSensitiveSecretURIs(t *testing.T) { tmpDir := t.TempDir() lfsSecretPath := filepath.Join(tmpDir, "lfs_secret") internalTokenPath := filepath.Join(tmpDir, "internal_token") oauthSecretPath := filepath.Join(tmpDir, "oauth_secret") require.NoError(t, os.WriteFile(lfsSecretPath, []byte("lfs-secret-uri\n"), 0o644)) require.NoError(t, os.WriteFile(internalTokenPath, []byte("internal-secret-uri\n"), 0o644)) require.NoError(t, os.WriteFile(oauthSecretPath, []byte("oauth-secret-uri\n"), 0o644)) cfg, err := setting.NewConfigProviderFromData(` [server] LFS_JWT_SECRET_URI = file:` + filepath.ToSlash(lfsSecretPath) + ` [security] INTERNAL_TOKEN_URI = file:` + filepath.ToSlash(internalTokenPath) + ` [oauth2] JWT_SECRET_URI = file:` + filepath.ToSlash(oauthSecretPath) + ` `) require.NoError(t, err) form, curDBType := newInstallFormFromSettings() form.ImportSensitiveSecrets = true populateInstallFormFromConfig(&form, cfg, curDBType) assert.Equal(t, "lfs-secret-uri", form.ImportedLFSJWTSecret) assert.Equal(t, "internal-secret-uri", form.ImportedInternalToken) assert.Equal(t, "oauth-secret-uri", form.ImportedOAuth2JWTSecret) } func TestPopulateInstallSensitiveSecretsFromConfigFillsMissingValuesOnly(t *testing.T) { tmpDir := t.TempDir() internalTokenPath := filepath.Join(tmpDir, "internal_token") require.NoError(t, os.WriteFile(internalTokenPath, []byte("internal-secret-uri\n"), 0o644)) cfg, err := setting.NewConfigProviderFromData(` [server] LFS_JWT_SECRET = lfs-secret [security] INTERNAL_TOKEN_URI = file:` + filepath.ToSlash(internalTokenPath) + ` [oauth2] JWT_SECRET = oauth-secret `) require.NoError(t, err) form := forms.InstallForm{ ImportSensitiveSecrets: true, ImportedLFSJWTSecret: "", ImportedInternalToken: "", ImportedOAuth2JWTSecret: "already-set", } populateInstallSensitiveSecretsFromConfig(&form, cfg) assert.Equal(t, "lfs-secret", form.ImportedLFSJWTSecret) assert.Equal(t, "internal-secret-uri", form.ImportedInternalToken) assert.Equal(t, "already-set", form.ImportedOAuth2JWTSecret) } func TestImportAppINIWithSensitiveSecrets(t *testing.T) { defer test.MockVariableValue(&setting.InstallLock, false)() var body bytes.Buffer writer := multipart.NewWriter(&body) require.NoError(t, writer.WriteField("import_sensitive_secrets", "on")) fileWriter, err := writer.CreateFormFile("app_ini_file", "app.ini") require.NoError(t, err) _, err = fileWriter.Write([]byte(` [server] LFS_JWT_SECRET = lfs-secret [security] INTERNAL_TOKEN = internal-secret [oauth2] JWT_SECRET = oauth-secret `)) require.NoError(t, err) require.NoError(t, writer.Close()) r := Routes() w := httptest.NewRecorder() req := httptest.NewRequest(http.MethodPost, "/import_app_ini", &body) req.Header.Set("Content-Type", writer.FormDataContentType()) r.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) assert.Contains(t, w.Body.String(), `name="imported_lfs_jwt_secret" value="lfs-secret"`) assert.Contains(t, w.Body.String(), `name="imported_internal_token" value="internal-secret"`) assert.Contains(t, w.Body.String(), `name="imported_o_auth2_jwt_secret" value="oauth-secret"`) } func TestApplyInstallSensitiveSecretsToConfigPersistsImportedValues(t *testing.T) { tmpDir := t.TempDir() configPath := filepath.Join(tmpDir, "app.ini") defer test.MockVariableValue(&setting.InternalToken, "")() cfg, err := setting.NewConfigProviderFromData("") require.NoError(t, err) form := forms.InstallForm{ LFSRootPath: filepath.Join(tmpDir, "lfs"), ImportSensitiveSecrets: true, ImportedLFSJWTSecret: "lfs-secret", ImportedInternalToken: "internal-secret", ImportedOAuth2JWTSecret: "oauth-secret", } require.NoError(t, applyInstallSensitiveSecretsToConfig(cfg, &form)) require.NoError(t, cfg.SaveTo(configPath)) data, err := os.ReadFile(configPath) require.NoError(t, err) content := string(data) assert.Contains(t, content, "LFS_JWT_SECRET = lfs-secret") assert.Contains(t, content, "INTERNAL_TOKEN = internal-secret") assert.Contains(t, content, "JWT_SECRET = oauth-secret") } func TestMain(m *testing.M) { unittest.MainTest(m) }