Skip to content

Commit

Permalink
Allow to define secret key & move the secret key file to parent direc…
Browse files Browse the repository at this point in the history
…tory (#358)
  • Loading branch information
thomiceli authored Oct 31, 2024
1 parent 20372f4 commit 4fd0832
Show file tree
Hide file tree
Showing 11 changed files with 98 additions and 43 deletions.
3 changes: 3 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ external-url:
# Directory where Opengist will store its data. Default: ~/.opengist/
opengist-home:

# Secret key used for session store & encrypt MFA data on database. Default: <randomized 32 bytes>
secret-key:

# URI of the database. Default: opengist.db (SQLite)
# SQLite: file name
# PostgreSQL: postgres://user:password@host:port/database
Expand Down
1 change: 1 addition & 0 deletions docs/configuration/cheat-sheet.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ aside: false
| log-output | OG_LOG_OUTPUT | `stdout,file` | Set the log output to one or more of the following: `stdout`, `file`. |
| external-url | OG_EXTERNAL_URL | none | Public URL to access to Opengist. |
| opengist-home | OG_OPENGIST_HOME | home directory | Path to the directory where Opengist stores its data. |
| secret-key | OG_SECRET_KEY | randomized 32 bytes | Secret key used for session store & encrypt MFA data on database. |
| db-filename | OG_DB_FILENAME | `opengist.db` | Name of the SQLite database file. |
| index.enabled | OG_INDEX_ENABLED | `true` | Enable or disable the code search index (`true` or `false`) |
| index.dirname | OG_INDEX_DIRNAME | `opengist.index` | Name of the directory where the code search index is stored. |
Expand Down
2 changes: 2 additions & 0 deletions internal/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ func Initialize(ctx *cli.Context) {
panic(err)
}

config.SetupSecretKey()

config.InitLog()

gitVersion, err := git.GetGitVersion()
Expand Down
17 changes: 16 additions & 1 deletion internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ var SecretKey []byte
// Not using nested structs because the library
// doesn't support dot notation in this case sadly
type config struct {
SecretKey string `yaml:"secret-key" env:"OG_SECRET_KEY"`

LogLevel string `yaml:"log-level" env:"OG_LOG_LEVEL"`
LogOutput string `yaml:"log-output" env:"OG_LOG_OUTPUT"`
ExternalUrl string `yaml:"external-url" env:"OG_EXTERNAL_URL"`
Expand Down Expand Up @@ -82,6 +84,8 @@ type StaticLink struct {
func configWithDefaults() (*config, error) {
c := &config{}

c.SecretKey = ""

c.LogLevel = "warn"
c.LogOutput = "stdout,file"
c.OpengistHome = ""
Expand Down Expand Up @@ -138,7 +142,9 @@ func InitConfig(configPath string, out io.Writer) error {

C = c

// SecretKey = utils.GenerateSecretKey(filepath.Join(GetHomeDir(), "opengist-secret.key"))
if err = migrateConfig(); err != nil {
return err
}

if err = os.Setenv("OG_OPENGIST_HOME_INTERNAL", GetHomeDir()); err != nil {
return err
Expand Down Expand Up @@ -235,6 +241,15 @@ func GetHomeDir() string {
return filepath.Clean(absolutePath)
}

func SetupSecretKey() {
if C.SecretKey == "" {
path := filepath.Join(GetHomeDir(), "opengist-secret.key")
SecretKey, _ = utils.GenerateSecretKey(path)
} else {
SecretKey = []byte(C.SecretKey)
}
}

func loadConfigFromYaml(c *config, configPath string, out io.Writer) error {
if configPath != "" {
absolutePath, _ := filepath.Abs(configPath)
Expand Down
42 changes: 42 additions & 0 deletions internal/config/migrate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package config

import (
"fmt"
"os"
"path/filepath"
)

// auto migration for newer versions of Opengist
func migrateConfig() error {
configMigrations := []struct {
Version string
Func func() error
}{
{"1.8.0", v1_8_0},
}

for _, fn := range configMigrations {
err := fn.Func()
if err != nil {
return err
}
}

return nil
}

func v1_8_0() error {
homeDir := GetHomeDir()
moveFile(filepath.Join(filepath.Join(homeDir, "sessions"), "session-auth.key"), filepath.Join(homeDir, "opengist-secret.key"))
return nil
}

func moveFile(oldPath, newPath string) {
if _, err := os.Stat(oldPath); err != nil {
return
}

if err := os.Rename(oldPath, newPath); err == nil {
fmt.Printf("Automatically moved %s to %s\n", oldPath, newPath)
}
}
5 changes: 3 additions & 2 deletions internal/db/totp.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"encoding/json"
"fmt"
ogtotp "github.com/thomiceli/opengist/internal/auth/totp"
"github.com/thomiceli/opengist/internal/config"
"github.com/thomiceli/opengist/internal/utils"
"slices"
)
Expand All @@ -29,7 +30,7 @@ func GetTOTPByUserID(userID uint) (*TOTP, error) {

func (totp *TOTP) StoreSecret(secret string) error {
secretBytes := []byte(secret)
encrypted, err := utils.AESEncrypt([]byte("tmp"), secretBytes)
encrypted, err := utils.AESEncrypt(config.SecretKey, secretBytes)
if err != nil {
return err
}
Expand All @@ -44,7 +45,7 @@ func (totp *TOTP) ValidateCode(code string) (bool, error) {
return false, err
}

secretBytes, err := utils.AESDecrypt([]byte("tmp"), ciphertext)
secretBytes, err := utils.AESDecrypt(config.SecretKey, ciphertext)
if err != nil {
return false, err
}
Expand Down
8 changes: 5 additions & 3 deletions internal/utils/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import (
"os"
)

func GenerateSecretKey(filePath string) []byte {
// GenerateSecretKey generates a new secret key for sessions
// Returns the key and a boolean indicating if the key was generated
func GenerateSecretKey(filePath string) ([]byte, bool) {
key, err := os.ReadFile(filePath)
if err == nil {
return key
return key, false
}

key = securecookie.GenerateRandomKey(32)
Expand All @@ -22,5 +24,5 @@ func GenerateSecretKey(filePath string) []byte {
log.Fatal().Err(err).Msgf("Failed to save the key to %s", filePath)
}

return key
return key, true
}
6 changes: 2 additions & 4 deletions internal/web/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,8 @@ type Server struct {
func NewServer(isDev bool, sessionsPath string) *Server {
dev = isDev
flashStore = sessions.NewCookieStore([]byte("opengist"))
userStore = sessions.NewFilesystemStore(sessionsPath,
utils.GenerateSecretKey(path.Join(sessionsPath, "session-auth.key")),
utils.GenerateSecretKey(path.Join(sessionsPath, "session-encrypt.key")),
)
encryptKey, _ := utils.GenerateSecretKey(filepath.Join(sessionsPath, "session-encrypt.key"))
userStore = sessions.NewFilesystemStore(sessionsPath, config.SecretKey, encryptKey)
userStore.MaxLength(10 * 1024)
gothic.Store = userStore

Expand Down
24 changes: 8 additions & 16 deletions internal/web/test/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,10 @@ import (
)

func TestRegister(t *testing.T) {
setup(t)
s, err := newTestServer()
require.NoError(t, err, "Failed to create test server")
s := setup(t)
defer teardown(t, s)

err = s.request("GET", "/", nil, 302)
err := s.request("GET", "/", nil, 302)
require.NoError(t, err)

err = s.request("GET", "/register", nil, 200)
Expand Down Expand Up @@ -55,12 +53,10 @@ func TestRegister(t *testing.T) {
}

func TestLogin(t *testing.T) {
setup(t)
s, err := newTestServer()
require.NoError(t, err, "Failed to create test server")
s := setup(t)
defer teardown(t, s)

err = s.request("GET", "/login", nil, 200)
err := s.request("GET", "/login", nil, 200)
require.NoError(t, err)

user1 := db.UserDTO{Username: "thomas", Password: "thomas"}
Expand Down Expand Up @@ -101,15 +97,13 @@ type settingSet struct {
}

func TestAnonymous(t *testing.T) {
setup(t)
s, err := newTestServer()
require.NoError(t, err, "Failed to create test server")
s := setup(t)
defer teardown(t, s)

user := db.UserDTO{Username: "thomas", Password: "azeaze"}
register(t, s, user)

err = s.request("PUT", "/admin-panel/set-config", settingSet{"require-login", "1"}, 200)
err := s.request("PUT", "/admin-panel/set-config", settingSet{"require-login", "1"}, 200)
require.NoError(t, err)

gist1 := db.GistDTO{
Expand Down Expand Up @@ -154,9 +148,7 @@ func TestAnonymous(t *testing.T) {
}

func TestGitOperations(t *testing.T) {
setup(t)
s, err := newTestServer()
require.NoError(t, err, "Failed to create test server")
s := setup(t)
defer teardown(t, s)

admin := db.UserDTO{Username: "thomas", Password: "thomas"}
Expand All @@ -178,7 +170,7 @@ func TestGitOperations(t *testing.T) {
"yeah",
},
}
err = s.request("POST", "/", gist1, 302)
err := s.request("POST", "/", gist1, 302)
require.NoError(t, err)

gist2 := db.GistDTO{
Expand Down
24 changes: 8 additions & 16 deletions internal/web/test/gist_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ import (
)

func TestGists(t *testing.T) {
setup(t)
s, err := newTestServer()
require.NoError(t, err, "Failed to create test server")
s := setup(t)
defer teardown(t, s)

err = s.request("GET", "/", nil, 302)
err := s.request("GET", "/", nil, 302)
require.NoError(t, err)

user1 := db.UserDTO{Username: "thomas", Password: "thomas"}
Expand Down Expand Up @@ -106,9 +104,7 @@ func TestGists(t *testing.T) {
}

func TestVisibility(t *testing.T) {
setup(t)
s, err := newTestServer()
require.NoError(t, err, "Failed to create test server")
s := setup(t)
defer teardown(t, s)

user1 := db.UserDTO{Username: "thomas", Password: "thomas"}
Expand All @@ -123,7 +119,7 @@ func TestVisibility(t *testing.T) {
Name: []string{""},
Content: []string{"yeah"},
}
err = s.request("POST", "/", gist1, 302)
err := s.request("POST", "/", gist1, 302)
require.NoError(t, err)

gist1db, err := db.GetGistByID("1")
Expand All @@ -150,9 +146,7 @@ func TestVisibility(t *testing.T) {
}

func TestLikeFork(t *testing.T) {
setup(t)
s, err := newTestServer()
require.NoError(t, err, "Failed to create test server")
s := setup(t)
defer teardown(t, s)

user1 := db.UserDTO{Username: "thomas", Password: "thomas"}
Expand All @@ -167,7 +161,7 @@ func TestLikeFork(t *testing.T) {
Name: []string{""},
Content: []string{"yeah"},
}
err = s.request("POST", "/", gist1, 302)
err := s.request("POST", "/", gist1, 302)
require.NoError(t, err)

s.sessionCookie = ""
Expand Down Expand Up @@ -211,9 +205,7 @@ func TestLikeFork(t *testing.T) {
}

func TestCustomUrl(t *testing.T) {
setup(t)
s, err := newTestServer()
require.NoError(t, err, "Failed to create test server")
s := setup(t)
defer teardown(t, s)

user1 := db.UserDTO{Username: "thomas", Password: "thomas"}
Expand All @@ -229,7 +221,7 @@ func TestCustomUrl(t *testing.T) {
Name: []string{"gist1.txt", "gist2.txt", "gist3.txt"},
Content: []string{"yeah", "yeah\ncool", "yeah\ncool gist actually"},
}
err = s.request("POST", "/", gist1, 302)
err := s.request("POST", "/", gist1, 302)
require.NoError(t, err)

gist1db, err := db.GetGistByID("1")
Expand Down
9 changes: 8 additions & 1 deletion internal/web/test/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func structToURLValues(s interface{}) url.Values {
return v
}

func setup(t *testing.T) {
func setup(t *testing.T) *testServer {
var databaseDsn string
databaseType = os.Getenv("OPENGIST_TEST_DB")
switch databaseType {
Expand All @@ -153,6 +153,8 @@ func setup(t *testing.T) {
err = os.MkdirAll(filepath.Join(config.GetHomeDir()), 0755)
require.NoError(t, err, "Could not create Opengist home directory")

config.SetupSecretKey()

git.ReposDirectory = path.Join("tests")

config.C.IndexEnabled = false
Expand Down Expand Up @@ -180,6 +182,11 @@ func setup(t *testing.T) {

// err = index.Open(filepath.Join(homePath, "testsindex", "opengist.index"))
// require.NoError(t, err, "Could not open index")

s, err := newTestServer()
require.NoError(t, err, "Failed to create test server")

return s
}

func teardown(t *testing.T, s *testServer) {
Expand Down

0 comments on commit 4fd0832

Please sign in to comment.