diff --git a/server/config/config.go b/server/config/config.go index f2f8159fdbe7c7a0808f3401455ec4bb54d47aa5..0766cce59bf89eb8cc742e54aa808d036cc4e9f2 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -23,6 +23,8 @@ type Callbacks interface { // SSHConfig is the SSH configuration for the server. type SSHConfig struct { + Key string `env:"KEY"` + KeyPath string `env:"KEY_PATH" envDefault:"soft_serve"` Port int `env:"PORT" envDefault:"23231"` AllowKeyless bool `env:"ALLOW_KEYLESS" envDefault:"true"` AllowPassword bool `env:"ALLOW_PASSWORD" envDefault:"false"` @@ -115,7 +117,12 @@ func (c *Config) SSHPath() string { // PrivateKeyPath returns the path to the SSH key. func (c *Config) PrivateKeyPath() string { - return filepath.Join(c.SSHPath(), "soft_serve") + return filepath.Join(c.SSHPath(), c.SSH.KeyPath) +} + +// DBPath returns the path to the database. +func (c *Config) DBPath() string { + return filepath.Join(c.DataPath, "db", "soft-serve.db") } // DefaultConfig returns a Config with the values populated with the defaults @@ -142,20 +149,27 @@ func DefaultConfig() *Config { migrateWarn = true } if migrateWarn { - log.Printf("warning: please run `soft serve --migrate` to migrate your server and configuration.") + log.Printf("warning: please run `soft serve migrate` to migrate your server and configuration.") + } + // init data path and db + if err := os.MkdirAll(cfg.RepoPath(), 0755); err != nil { + log.Fatalln(err) + } + if err := cfg.createDefaultConfigRepo(); err != nil { + log.Fatalln(err) } var db db.Store switch cfg.Db.Driver { case "sqlite": - if err := os.MkdirAll(filepath.Join(cfg.DataPath, "db"), 0755); err != nil { + if err := os.MkdirAll(filepath.Dir(cfg.DBPath()), 0755); err != nil { log.Fatalln(err) } - db, err = sqlite.New(filepath.Join(cfg.DataPath, "db", "soft-serve.db")) + db, err = sqlite.New(cfg.DBPath()) if err != nil { log.Fatalln(err) } } - return cfg.WithDB(db) + return cfg.WithDB(db).WithDataPath(cfg.DataPath) } // DB returns the database for the configuration. @@ -174,3 +188,9 @@ func (c *Config) WithDB(db db.Store) *Config { c.db = db return c } + +// WithDataPath sets the data path for the configuration. +func (c *Config) WithDataPath(path string) *Config { + c.DataPath = path + return c +} diff --git a/server/config/default.go b/server/config/default.go new file mode 100644 index 0000000000000000000000000000000000000000..a3e9633828471a9259aa87743f81f7f1c339bc77 --- /dev/null +++ b/server/config/default.go @@ -0,0 +1,69 @@ +package config + +import ( + "errors" + "path/filepath" + "time" + + "github.com/go-git/go-billy/v5/memfs" + gogit "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing/object" + "github.com/go-git/go-git/v5/plumbing/transport" + "github.com/go-git/go-git/v5/storage/memory" +) + +const ( + defaultConfigRepo = "config" + defaultReadme = "# Soft Serve\n\n Welcome! You can configure your Soft Serve server by cloning this repo and pushing changes.\n\n```\ngit clone ssh://localhost:23231/config\n```" +) + +func (cfg *Config) createDefaultConfigRepo() error { + rp := filepath.Join(cfg.RepoPath(), defaultConfigRepo) + ".git" + _, err := gogit.PlainOpen(rp) + if errors.Is(err, gogit.ErrRepositoryNotExists) { + repo, err := gogit.PlainInit(rp, true) + if err != nil { + return err + } + repo, err = gogit.Clone(memory.NewStorage(), memfs.New(), &gogit.CloneOptions{ + URL: rp, + }) + if err != nil && err != transport.ErrEmptyRemoteRepository { + return err + } + wt, err := repo.Worktree() + if err != nil { + return err + } + rm, err := wt.Filesystem.Create("README.md") + if err != nil { + return err + } + _, err = rm.Write([]byte(defaultReadme)) + if err != nil { + return err + } + _, err = wt.Add("README.md") + if err != nil { + return err + } + author := object.Signature{ + Name: "Soft Serve Server", + Email: "vt100@charm.sh", + When: time.Now(), + } + _, err = wt.Commit("Default init", &gogit.CommitOptions{ + All: true, + Author: &author, + Committer: &author, + }) + if err != nil { + return err + } + err = repo.Push(&gogit.PushOptions{}) + if err != nil { + return err + } + } + return nil +} diff --git a/server/server.go b/server/server.go index 35baac87b8653bdcd1df0dde4fc3f60735ba8b18..d17d017bde9f4b6d4cfc7db134a2d744ed005c9a 100644 --- a/server/server.go +++ b/server/server.go @@ -47,18 +47,23 @@ func NewServer(cfg *config.Config) *Server { ), } - opts := []ssh.Option{ssh.PublicKeyAuth(cfg.PublicKeyHandler)} + opts := []ssh.Option{ + wish.WithAddress(fmt.Sprintf("%s:%d", cfg.Host, cfg.SSH.Port)), + wish.WithPublicKeyAuth(cfg.PublicKeyHandler), + wish.WithMiddleware(mw...), + } if cfg.SSH.AllowKeyless { opts = append(opts, ssh.KeyboardInteractiveAuth(cfg.KeyboardInteractiveHandler)) } if cfg.SSH.AllowPassword { opts = append(opts, ssh.PasswordAuth(cfg.PasswordHandler)) } - opts = append(opts, - wish.WithAddress(fmt.Sprintf("%s:%d", cfg.Host, cfg.SSH.Port)), - wish.WithHostKeyPath(cfg.PrivateKeyPath()), - wish.WithMiddleware(mw...), - ) + if cfg.SSH.Key != "" { + opts = append(opts, wish.WithHostKeyPEM([]byte(cfg.SSH.Key))) + } else { + opts = append(opts, wish.WithHostKeyPath(cfg.PrivateKeyPath())) + } + opts = append(opts) sh, err := wish.NewServer(opts...) if err != nil { log.Fatalln(err)