Skip to content

Commit

Permalink
ref(config): clarify repo auth for key
Browse files Browse the repository at this point in the history
Fix edge cases when anonAccess is greater than collab
  • Loading branch information
aymanbagabas committed Nov 9, 2022
1 parent 17bf584 commit d88ccb9
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 61 deletions.
88 changes: 62 additions & 26 deletions config/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,43 +59,79 @@ func (cfg *Config) PublicKeyHandler(ctx ssh.Context, pk ssh.PublicKey) bool {
return cfg.accessForKey("", pk) != gm.NoAccess
}

func (cfg *Config) anonAccessLevel() gm.AccessLevel {
switch cfg.AnonAccess {
case "no-access":
return gm.NoAccess
case "read-only":
return gm.ReadOnlyAccess
case "read-write":
return gm.ReadWriteAccess
case "admin-access":
return gm.AdminAccess
default:
return gm.NoAccess
}
}

// accessForKey returns the access level for the given repo.
//
// If repo doesn't exist, then access is based on user's admin privileges, or
// config.AnonAccess.
// If repo exists, and private, then admins and collabs are allowed access.
// If repo exists, and not private, then access is based on config.AnonAccess.
func (cfg *Config) accessForKey(repo string, pk ssh.PublicKey) gm.AccessLevel {
private := cfg.isPrivate(repo)
for _, u := range cfg.Users {
for _, k := range u.PublicKeys {
var u *User
var r *RepoConfig
anon := cfg.anonAccessLevel()
OUT:
// Find user
for _, user := range cfg.Users {
for _, k := range user.PublicKeys {
apk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(strings.TrimSpace(k)))
if err != nil {
log.Printf("error: malformed authorized key: '%s'", k)
return gm.NoAccess
}
if ssh.KeysEqual(pk, apk) {
if u.Admin {
return gm.AdminAccess
}
for _, r := range u.CollabRepos {
if repo == r {
return gm.ReadWriteAccess
}
}
if !private {
return gm.ReadOnlyAccess
}
us := user
u = &us
break OUT
}
}
}
if private && len(cfg.Users) > 0 {
return gm.NoAccess
// Find repo
for _, rp := range cfg.Repos {
if rp.Repo == repo {
rr := rp
r = &rr
break
}
}
switch cfg.AnonAccess {
case "no-access":
return gm.NoAccess
case "read-only":
return gm.ReadOnlyAccess
case "read-write":
return gm.ReadWriteAccess
case "admin-access":
if u != nil && u.Admin {
return gm.AdminAccess
default:
return gm.NoAccess
}
if r == nil || len(cfg.Users) == 0 {
return anon
}
// Collabs default access is read-write
if u != nil {
ac := gm.ReadWriteAccess
if anon > ac {
ac = anon
}
for _, rr := range u.CollabRepos {
if rr == r.Repo {
return ac
}
}
}
// Users default access is read-only
if !r.Private {
if anon > gm.ReadOnlyAccess {
return anon
}
return gm.ReadOnlyAccess
}
return gm.NoAccess
}
63 changes: 28 additions & 35 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,6 @@ import (
"github.com/go-git/go-git/v5/storage/memory"
)

var (
// ErrNoConfig is returned when no config file is found.
ErrNoConfig = errors.New("no config file found")
)

// Config is the Soft Serve configuration.
type Config struct {
Name string `yaml:"name" json:"name"`
Expand All @@ -40,7 +35,7 @@ type Config struct {
AnonAccess string `yaml:"anon-access" json:"anon-access"`
AllowKeyless bool `yaml:"allow-keyless" json:"allow-keyless"`
Users []User `yaml:"users" json:"users"`
Repos []MenuRepo `yaml:"repos" json:"repos"`
Repos []RepoConfig `yaml:"repos" json:"repos"`
Source *RepoSource `yaml:"-" json:"-"`
Cfg *config.Config `yaml:"-" json:"-"`
mtx sync.Mutex
Expand All @@ -54,8 +49,8 @@ type User struct {
CollabRepos []string `yaml:"collab-repos" json:"collab-repos"`
}

// Repo contains repository configuration information.
type MenuRepo struct {
// RepoConfig is a repository configuration.
type RepoConfig struct {
Name string `yaml:"name" json:"name"`
Repo string `yaml:"repo" json:"repo"`
Note string `yaml:"note" json:"note"`
Expand Down Expand Up @@ -128,38 +123,45 @@ func NewConfig(cfg *config.Config) (*Config, error) {
return c, nil
}

// Reload reloads the configuration.
func (cfg *Config) Reload() error {
cfg.mtx.Lock()
defer cfg.mtx.Unlock()
err := cfg.Source.LoadRepos()
func (cfg *Config) readConfig(repo string, v interface{}) error {
cr, err := cfg.Source.GetRepo(repo)
if err != nil {
return err
}
cr, err := cfg.Source.GetRepo("config")
if err != nil {
return err
}
cy, _, err := cr.LatestFile("config.yaml")
cy, _, err := cr.LatestFile(repo + ".yaml")
if err != nil && !errors.Is(err, git.ErrFileNotFound) {
return fmt.Errorf("error reading config.yaml: %w", err)
return fmt.Errorf("error reading %s.yaml: %w", repo, err)
}
cj, _, err := cr.LatestFile("config.json")
cj, _, err := cr.LatestFile(repo + ".json")
if err != nil && !errors.Is(err, git.ErrFileNotFound) {
return fmt.Errorf("error reading config.json: %w", err)
return fmt.Errorf("error reading %s.json: %w", repo, err)
}
if cy != "" {
err = yaml.Unmarshal([]byte(cy), cfg)
err = yaml.Unmarshal([]byte(cy), v)
if err != nil {
return fmt.Errorf("bad yaml in config.yaml: %s", err)
return fmt.Errorf("bad yaml in %s.yaml: %s", repo, err)
}
} else if cj != "" {
err = json.Unmarshal([]byte(cj), cfg)
err = json.Unmarshal([]byte(cj), v)
if err != nil {
return fmt.Errorf("bad json in config.json: %s", err)
return fmt.Errorf("bad json in %s.json: %s", repo, err)
}
} else {
return ErrNoConfig
return fmt.Errorf("no config file found for %q", repo)
}
return nil
}

// Reload reloads the configuration.
func (cfg *Config) Reload() error {
cfg.mtx.Lock()
defer cfg.mtx.Unlock()
err := cfg.Source.LoadRepos()
if err != nil {
return err
}
if err := cfg.readConfig("config", cfg); err != nil {
return fmt.Errorf("error reading config: %w", err)
}
for _, r := range cfg.Source.AllRepos() {
name := r.Name()
Expand Down Expand Up @@ -276,15 +278,6 @@ 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
}

func templatize(mdt string, tmpl interface{}) (string, error) {
t, err := template.New("readme").Parse(mdt)
if err != nil {
Expand Down

0 comments on commit d88ccb9

Please sign in to comment.