Detailed changes
@@ -31,9 +31,10 @@ type User struct {
}
type Repo struct {
- Name string `yaml:"name"`
- Repo string `yaml:"repo"`
- Note string `yaml:"note"`
+ Name string `yaml:"name"`
+ Repo string `yaml:"repo"`
+ Note string `yaml:"note"`
+ Private bool `yaml:"private"`
}
func NewConfig(host string, port int, pk string, rs *git.RepoSource) (*Config, error) {
@@ -155,3 +156,12 @@ func (cfg *Config) createDefaultConfigRepo(yaml string) error {
}
return cfg.reload()
}
+
+func (cfg *Config) isPrivate(repo string) bool {
+ for _, r := range cfg.Repos {
+ if r.Repo == repo {
+ return r.Private
+ }
+ }
+ return false
+}
@@ -1,6 +1,6 @@
package config
-const defaultReadme = "# Soft Serve\n\n Welcome! You can configure your Soft Serve server by cloning this repo and pushing changes.\n\n## Repos\n\n{{ range .Repos }}* {{ .Name }}{{ if .Note }} - {{ .Note }} {{ end }}\n - `git clone ssh://{{$.Host}}:{{$.Port}}/{{.Repo}}`\n{{ end }}"
+const 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://{{.Host}}:{{.Port}}/config\n```"
const defaultConfig = `name: Soft Serve
host: %s
@@ -16,6 +16,7 @@ allow-no-keys: false
repos:
- name: Home
repo: config
+ private: true
note: "Configuration and content repo for this server"`
const hasKeyUserConfig = `
@@ -35,6 +35,10 @@ func (cfg *Config) PublicKeyHandler(ctx ssh.Context, pk ssh.PublicKey) bool {
}
func (cfg *Config) accessForKey(repo string, pk ssh.PublicKey) gm.AccessLevel {
+ private := cfg.isPrivate(repo)
+ if repo == "config" {
+ private = true
+ }
for _, u := range cfg.Users {
apk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(u.PublicKey))
if err != nil {
@@ -50,12 +54,12 @@ func (cfg *Config) accessForKey(repo string, pk ssh.PublicKey) gm.AccessLevel {
return gm.ReadWriteAccess
}
}
- if repo != "config" {
+ if !private {
return gm.ReadOnlyAccess
}
}
}
- if repo == "config" && (cfg.AnonAccess != "read-write") {
+ if private && (cfg.AnonAccess != "read-write") {
return gm.NoAccess
}
switch cfg.AnonAccess {
@@ -11,6 +11,7 @@ import (
"github.com/charmbracelet/soft/tui/bubbles/repo"
"github.com/charmbracelet/soft/tui/bubbles/selection"
"github.com/charmbracelet/soft/tui/style"
+ "github.com/gliderlabs/ssh"
)
type sessionState int
@@ -27,6 +28,7 @@ type SessionConfig struct {
Width int
Height int
InitialRepo string
+ Session ssh.Session
}
type MenuEntry struct {
@@ -49,6 +51,7 @@ type Bubble struct {
boxes []tea.Model
activeBox int
repoSelect *selection.Bubble
+ session ssh.Session
}
func NewBubble(cfg *config.Config, sCfg *SessionConfig) *Bubble {
@@ -60,6 +63,7 @@ func NewBubble(cfg *config.Config, sCfg *SessionConfig) *Bubble {
repoMenu: make([]MenuEntry, 0),
boxes: make([]tea.Model, 2),
initialRepo: sCfg.InitialRepo,
+ session: sCfg.Session,
}
b.state = startState
return b
@@ -8,6 +8,7 @@ import (
"github.com/charmbracelet/soft/config"
br "github.com/charmbracelet/soft/tui/bubbles/repo"
"github.com/charmbracelet/soft/tui/bubbles/selection"
+ gm "github.com/charmbracelet/wish/git"
"github.com/muesli/termenv"
)
@@ -61,18 +62,20 @@ func (b *Bubble) setupCmd() tea.Msg {
func (b *Bubble) menuEntriesFromSource() ([]MenuEntry, error) {
mes := make([]MenuEntry, 0)
- for _, r := range b.config.Repos {
- me, err := b.newMenuEntry(r.Name, r.Repo)
- if err != nil {
- return nil, err
- }
- mes = append(mes, me)
- }
rs := b.config.Source.AllRepos()
OUTER:
for _, r := range rs {
- for _, me := range mes {
- if r.Name == me.Repo {
+ acc := b.config.AuthRepo(r.Name, b.session.PublicKey())
+ if acc == gm.NoAccess && r.Name != "config" {
+ continue
+ }
+ for _, cr := range b.config.Repos {
+ if r.Name == cr.Repo {
+ me, err := b.newMenuEntry(cr.Name, cr.Repo)
+ if err != nil {
+ return nil, err
+ }
+ mes = append(mes, me)
continue OUTER
}
}
@@ -87,6 +90,9 @@ OUTER:
func (b *Bubble) newMenuEntry(name string, repo string) (MenuEntry, error) {
var tmplConfig *config.Config
+ if repo == "config" {
+ tmplConfig = b.config
+ }
me := MenuEntry{Name: name, Repo: repo}
width := b.width
boxLeftWidth := b.styles.Menu.GetWidth() + b.styles.Menu.GetHorizontalFrameSize()
@@ -95,9 +101,6 @@ func (b *Bubble) newMenuEntry(name string, repo string) (MenuEntry, error) {
lipgloss.Height(b.footerView()) +
b.styles.RepoBody.GetVerticalFrameSize() +
b.styles.App.GetVerticalMargins()
- if repo == "config" {
- tmplConfig = b.config
- }
rb := br.NewBubble(
b.config.Source,
me.Repo,
@@ -11,7 +11,7 @@ import (
func SessionHandler(cfg *config.Config) func(ssh.Session) (tea.Model, []tea.ProgramOption) {
return func(s ssh.Session) (tea.Model, []tea.ProgramOption) {
cmd := s.Command()
- scfg := &SessionConfig{}
+ scfg := &SessionConfig{Session: s}
switch len(cmd) {
case 0:
scfg.InitialRepo = ""