Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions authHandlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,13 @@ func GitSignupAction(w http.ResponseWriter, r *http.Request) error {
log.Printf("git signup create user error for %s: %v", user, err)
return err
}
if err := prov.CreateRepo(r.Context(), user, nil, RepoName); err != nil {
log.Printf("git signup create repo error for %s: %v", user, err)
if exists, err := prov.RepoExists(r.Context(), user, nil, RepoName); err == nil && !exists {
if err := prov.CreateRepo(r.Context(), user, nil, RepoName); err != nil {
log.Printf("git signup create repo error for %s: %v", user, err)
return err
}
} else if err != nil {
log.Printf("git signup repo check error for %s: %v", user, err)
return err
}
if err := prov.CreateBookmarks(r.Context(), user, nil, "main", defaultBookmarks); err != nil {
Expand Down
3 changes: 3 additions & 0 deletions bookmarkActionHandlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ func BookmarksEditSaveAction(w http.ResponseWriter, r *http.Request) error {

_, curSha, err := GetBookmarks(r.Context(), login, ref, token)
if err != nil {
if errors.Is(err, ErrSignedOut) {
return ErrSignedOut
}
if errors.Is(err, ErrRepoNotFound) {
if p := providerFromContext(r.Context()); p != nil {
if err := p.CreateRepo(r.Context(), login, token, repoName); err == nil {
Expand Down
1 change: 1 addition & 0 deletions provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type Provider interface {
UpdateBookmarks(ctx context.Context, user string, token *oauth2.Token, sourceRef, branch, text, expectSHA string) error
CreateBookmarks(ctx context.Context, user string, token *oauth2.Token, branch, text string) error
CreateRepo(ctx context.Context, user string, token *oauth2.Token, name string) error
RepoExists(ctx context.Context, user string, token *oauth2.Token, name string) (bool, error)
DefaultServer() string
}

Expand Down
29 changes: 25 additions & 4 deletions provider_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package gobookmarks

import (
"context"
"errors"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -91,23 +92,35 @@ func GetTags(ctx context.Context, user string, token *oauth2.Token) ([]*Tag, err
if p == nil {
return nil, ErrNoProvider
}
return p.GetTags(ctx, user, token)
tags, err := p.GetTags(ctx, user, token)
if errors.Is(err, ErrRepoNotFound) && p.Name() == "git" {
return nil, ErrSignedOut
}
return tags, err
}

func GetBranches(ctx context.Context, user string, token *oauth2.Token) ([]*Branch, error) {
p := providerFromContext(ctx)
if p == nil {
return nil, ErrNoProvider
}
return p.GetBranches(ctx, user, token)
bs, err := p.GetBranches(ctx, user, token)
if errors.Is(err, ErrRepoNotFound) && p.Name() == "git" {
return nil, ErrSignedOut
}
return bs, err
}

func GetCommits(ctx context.Context, user string, token *oauth2.Token) ([]*Commit, error) {
p := providerFromContext(ctx)
if p == nil {
return nil, ErrNoProvider
}
return p.GetCommits(ctx, user, token)
cs, err := p.GetCommits(ctx, user, token)
if errors.Is(err, ErrRepoNotFound) && p.Name() == "git" {
return nil, ErrSignedOut
}
return cs, err
}

func GetBookmarks(ctx context.Context, user, ref string, token *oauth2.Token) (string, string, error) {
Expand All @@ -118,7 +131,11 @@ func GetBookmarks(ctx context.Context, user, ref string, token *oauth2.Token) (s
if p == nil {
return "", "", ErrNoProvider
}
return p.GetBookmarks(ctx, user, ref, token)
b, sha, err := p.GetBookmarks(ctx, user, ref, token)
if errors.Is(err, ErrRepoNotFound) && p.Name() == "git" {
return "", "", ErrSignedOut
}
return b, sha, err
}

func UpdateBookmarks(ctx context.Context, user string, token *oauth2.Token, sourceRef, branch, text, expectSHA string) error {
Expand All @@ -129,6 +146,8 @@ func UpdateBookmarks(ctx context.Context, user string, token *oauth2.Token, sour
err := p.UpdateBookmarks(ctx, user, token, sourceRef, branch, text, expectSHA)
if err == nil {
invalidateBookmarkCache(user)
} else if errors.Is(err, ErrRepoNotFound) && p.Name() == "git" {
return ErrSignedOut
}
return err
}
Expand All @@ -141,6 +160,8 @@ func CreateBookmarks(ctx context.Context, user string, token *oauth2.Token, bran
err := p.CreateBookmarks(ctx, user, token, branch, text)
if err == nil {
invalidateBookmarkCache(user)
} else if errors.Is(err, ErrRepoNotFound) && p.Name() == "git" {
return ErrSignedOut
}
return err
}
64 changes: 48 additions & 16 deletions provider_git.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,31 +226,59 @@ func (GitProvider) CreateRepo(ctx context.Context, user string, token *oauth2.To
if err := os.MkdirAll(path, 0700); err != nil {
return err
}
if _, err := git.PlainOpen(path); err == nil {
// repo already exists
return nil
} else if !errors.Is(err, git.ErrRepositoryNotExists) {
return err
}
r, err := git.PlainInit(path, false)
if err != nil {
if errors.Is(err, git.ErrRepositoryAlreadyExists) {
r, err = git.PlainOpen(path)
if err != nil {
return err
}
} else {
return err
}
return err
}
wt, err := r.Worktree()
if err != nil {
return err
}
if err := os.WriteFile(filepath.Join(path, "readme.md"), []byte("# bookmarks"), 0600); err != nil {
return err
added := false
if _, err := os.Stat(filepath.Join(path, "readme.md")); os.IsNotExist(err) {
if err := os.WriteFile(filepath.Join(path, "readme.md"), []byte("# bookmarks"), 0600); err != nil {
return err
}
if _, err := wt.Add("readme.md"); err != nil {
return err
}
added = true
}
if _, err := wt.Add("readme.md"); err != nil {
return err
if _, err := os.Stat(filepath.Join(path, ".gitignore")); os.IsNotExist(err) {
if err := os.WriteFile(filepath.Join(path, ".gitignore"), []byte(".password\n"), 0600); err != nil {
return err
}
if _, err := wt.Add(".gitignore"); err != nil {
return err
}
added = true
}
if added {
_, err = wt.Commit("init", &git.CommitOptions{
Author: &object.Signature{Name: "Gobookmarks", Email: "Gobookmarks@arran.net.au", When: time.Now()},
})
if err != nil {
return err
}
}
return nil
}

func (GitProvider) RepoExists(ctx context.Context, user string, token *oauth2.Token, name string) (bool, error) {
path := userDir(user)
if _, err := git.PlainOpen(path); err == nil {
return true, nil
} else if errors.Is(err, git.ErrRepositoryNotExists) {
return false, nil
} else {
return false, err
}
_, err = wt.Commit("init", &git.CommitOptions{
Author: &object.Signature{Name: "Gobookmarks", Email: "Gobookmarks@arran.net.au", When: time.Now()},
})
return err
}

func passwordPath(user string) string {
Expand All @@ -261,6 +289,10 @@ func passwordPath(user string) string {
// CreateUser writes a bcrypt hash for the given user. It returns ErrUserExists
// if the password file already exists.
func (GitProvider) CreateUser(ctx context.Context, user, password string) error {
gp := GitProvider{}
if err := gp.CreateRepo(ctx, user, nil, RepoName); err != nil {
return err
}
p := passwordPath(user)
if _, err := os.Stat(p); err == nil {
return ErrUserExists
Expand Down
41 changes: 40 additions & 1 deletion provider_git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package gobookmarks
import (
"context"
"errors"
"os"
"path/filepath"
"strings"
"testing"
)

Expand All @@ -16,6 +18,13 @@ func TestGitProviderCreateAndGet(t *testing.T) {
if err := p.CreateRepo(context.Background(), user, nil, RepoName); err != nil {
t.Fatalf("CreateRepo: %v", err)
}
gi, err := os.ReadFile(filepath.Join(userDir(user), ".gitignore"))
if err != nil {
t.Fatalf("gitignore missing: %v", err)
}
if !strings.Contains(string(gi), ".password") {
t.Fatalf(".password not ignored")
}
if err := p.CreateBookmarks(context.Background(), user, nil, "main", text); err != nil {
t.Fatalf("CreateBookmarks: %v", err)
}
Expand All @@ -31,6 +40,27 @@ func TestGitProviderCreateAndGet(t *testing.T) {
}
}

func TestGitRepoExists(t *testing.T) {
tmp := t.TempDir()
LocalGitPath = tmp
p := GitProvider{}
user := "carol"
exists, err := p.RepoExists(context.Background(), user, nil, RepoName)
if err != nil {
t.Fatalf("RepoExists before create: %v", err)
}
if exists {
t.Fatalf("repo should not exist")
}
if err := p.CreateRepo(context.Background(), user, nil, RepoName); err != nil {
t.Fatalf("CreateRepo: %v", err)
}
exists, err = p.RepoExists(context.Background(), user, nil, RepoName)
if err != nil || !exists {
t.Fatalf("repo should exist, got %v %v", exists, err)
}
}

func TestGitPasswordLifecycle(t *testing.T) {
tmp := t.TempDir()
LocalGitPath = tmp
Expand All @@ -39,10 +69,19 @@ func TestGitPasswordLifecycle(t *testing.T) {
user := "bob"
pass := "secret"

// create user
if err := p.CreateUser(ctx, user, pass); err != nil {
t.Fatalf("CreateUser: %v", err)
}
if _, err := os.Stat(filepath.Join(userDir(user), ".git")); err != nil {
t.Fatalf("repo missing after CreateUser: %v", err)
}
gi, err := os.ReadFile(filepath.Join(userDir(user), ".gitignore"))
if err != nil {
t.Fatalf("gitignore missing: %v", err)
}
if !strings.Contains(string(gi), ".password") {
t.Fatalf(".password not ignored")
}
// creating again should fail
if err := p.CreateUser(ctx, user, pass); !errors.Is(err, ErrUserExists) {
t.Fatalf("expected ErrUserExists, got %v", err)
Expand Down
15 changes: 15 additions & 0 deletions provider_github.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,21 @@ See . https://github.com/arran4/gobookmarks `),
return nil
}

func (p GitHubProvider) RepoExists(ctx context.Context, user string, token *oauth2.Token, name string) (bool, error) {
client := p.client(ctx, token)
_, resp, err := client.Repositories.Get(ctx, user, name)
if err != nil {
if resp != nil && resp.StatusCode == http.StatusNotFound {
return false, nil
}
if resp != nil && resp.StatusCode == http.StatusUnauthorized {
return false, ErrSignedOut
}
return false, err
}
return true, nil
}

func (p GitHubProvider) createRef(ctx context.Context, user string, client *github.Client, sourceRef, branchRef string) error {
gsref, resp, err := client.Git.GetRef(ctx, user, RepoName, sourceRef)
if resp != nil && resp.StatusCode == 404 {
Expand Down
18 changes: 18 additions & 0 deletions provider_gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,3 +312,21 @@ func (p GitLabProvider) CreateRepo(ctx context.Context, user string, token *oaut
}
return err
}

func (p GitLabProvider) RepoExists(ctx context.Context, user string, token *oauth2.Token, name string) (bool, error) {
c, err := GitLabProvider{}.client(token)
if err != nil {
return false, err
}
_, resp, err := c.Projects.GetProject(user+"/"+name, nil)
if err != nil {
if resp != nil && resp.StatusCode == http.StatusNotFound {
return false, nil
}
if gitlabUnauthorized(err) {
return false, ErrSignedOut
}
return false, err
}
return true, nil
}
Loading