Detailed changes
@@ -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
+}
@@ -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
+}
@@ -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)