Skip to content

Commit a8f199d

Browse files
authored
Merge pull request #54 from arran4/codex/refactor-git-provider-password-file-handling
Refine repo creation during signup
2 parents 7b8352d + 174d4f1 commit a8f199d

File tree

8 files changed

+157
-23
lines changed

8 files changed

+157
-23
lines changed

authHandlers.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,13 @@ func GitSignupAction(w http.ResponseWriter, r *http.Request) error {
193193
log.Printf("git signup create user error for %s: %v", user, err)
194194
return err
195195
}
196-
if err := prov.CreateRepo(r.Context(), user, nil, RepoName); err != nil {
197-
log.Printf("git signup create repo error for %s: %v", user, err)
196+
if exists, err := prov.RepoExists(r.Context(), user, nil, RepoName); err == nil && !exists {
197+
if err := prov.CreateRepo(r.Context(), user, nil, RepoName); err != nil {
198+
log.Printf("git signup create repo error for %s: %v", user, err)
199+
return err
200+
}
201+
} else if err != nil {
202+
log.Printf("git signup repo check error for %s: %v", user, err)
198203
return err
199204
}
200205
if err := prov.CreateBookmarks(r.Context(), user, nil, "main", defaultBookmarks); err != nil {

bookmarkActionHandlers.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ func BookmarksEditSaveAction(w http.ResponseWriter, r *http.Request) error {
2626

2727
_, curSha, err := GetBookmarks(r.Context(), login, ref, token)
2828
if err != nil {
29+
if errors.Is(err, ErrSignedOut) {
30+
return ErrSignedOut
31+
}
2932
if errors.Is(err, ErrRepoNotFound) {
3033
if p := providerFromContext(r.Context()); p != nil {
3134
if err := p.CreateRepo(r.Context(), login, token, repoName); err == nil {

provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ type Provider interface {
3737
UpdateBookmarks(ctx context.Context, user string, token *oauth2.Token, sourceRef, branch, text, expectSHA string) error
3838
CreateBookmarks(ctx context.Context, user string, token *oauth2.Token, branch, text string) error
3939
CreateRepo(ctx context.Context, user string, token *oauth2.Token, name string) error
40+
RepoExists(ctx context.Context, user string, token *oauth2.Token, name string) (bool, error)
4041
DefaultServer() string
4142
}
4243

provider_access.go

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package gobookmarks
22

33
import (
44
"context"
5+
"errors"
56
"strings"
67
"sync"
78
"time"
@@ -91,23 +92,35 @@ func GetTags(ctx context.Context, user string, token *oauth2.Token) ([]*Tag, err
9192
if p == nil {
9293
return nil, ErrNoProvider
9394
}
94-
return p.GetTags(ctx, user, token)
95+
tags, err := p.GetTags(ctx, user, token)
96+
if errors.Is(err, ErrRepoNotFound) && p.Name() == "git" {
97+
return nil, ErrSignedOut
98+
}
99+
return tags, err
95100
}
96101

97102
func GetBranches(ctx context.Context, user string, token *oauth2.Token) ([]*Branch, error) {
98103
p := providerFromContext(ctx)
99104
if p == nil {
100105
return nil, ErrNoProvider
101106
}
102-
return p.GetBranches(ctx, user, token)
107+
bs, err := p.GetBranches(ctx, user, token)
108+
if errors.Is(err, ErrRepoNotFound) && p.Name() == "git" {
109+
return nil, ErrSignedOut
110+
}
111+
return bs, err
103112
}
104113

105114
func GetCommits(ctx context.Context, user string, token *oauth2.Token) ([]*Commit, error) {
106115
p := providerFromContext(ctx)
107116
if p == nil {
108117
return nil, ErrNoProvider
109118
}
110-
return p.GetCommits(ctx, user, token)
119+
cs, err := p.GetCommits(ctx, user, token)
120+
if errors.Is(err, ErrRepoNotFound) && p.Name() == "git" {
121+
return nil, ErrSignedOut
122+
}
123+
return cs, err
111124
}
112125

113126
func GetBookmarks(ctx context.Context, user, ref string, token *oauth2.Token) (string, string, error) {
@@ -118,7 +131,11 @@ func GetBookmarks(ctx context.Context, user, ref string, token *oauth2.Token) (s
118131
if p == nil {
119132
return "", "", ErrNoProvider
120133
}
121-
return p.GetBookmarks(ctx, user, ref, token)
134+
b, sha, err := p.GetBookmarks(ctx, user, ref, token)
135+
if errors.Is(err, ErrRepoNotFound) && p.Name() == "git" {
136+
return "", "", ErrSignedOut
137+
}
138+
return b, sha, err
122139
}
123140

124141
func UpdateBookmarks(ctx context.Context, user string, token *oauth2.Token, sourceRef, branch, text, expectSHA string) error {
@@ -129,6 +146,8 @@ func UpdateBookmarks(ctx context.Context, user string, token *oauth2.Token, sour
129146
err := p.UpdateBookmarks(ctx, user, token, sourceRef, branch, text, expectSHA)
130147
if err == nil {
131148
invalidateBookmarkCache(user)
149+
} else if errors.Is(err, ErrRepoNotFound) && p.Name() == "git" {
150+
return ErrSignedOut
132151
}
133152
return err
134153
}
@@ -141,6 +160,8 @@ func CreateBookmarks(ctx context.Context, user string, token *oauth2.Token, bran
141160
err := p.CreateBookmarks(ctx, user, token, branch, text)
142161
if err == nil {
143162
invalidateBookmarkCache(user)
163+
} else if errors.Is(err, ErrRepoNotFound) && p.Name() == "git" {
164+
return ErrSignedOut
144165
}
145166
return err
146167
}

provider_git.go

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -226,31 +226,59 @@ func (GitProvider) CreateRepo(ctx context.Context, user string, token *oauth2.To
226226
if err := os.MkdirAll(path, 0700); err != nil {
227227
return err
228228
}
229+
if _, err := git.PlainOpen(path); err == nil {
230+
// repo already exists
231+
return nil
232+
} else if !errors.Is(err, git.ErrRepositoryNotExists) {
233+
return err
234+
}
229235
r, err := git.PlainInit(path, false)
230236
if err != nil {
231-
if errors.Is(err, git.ErrRepositoryAlreadyExists) {
232-
r, err = git.PlainOpen(path)
233-
if err != nil {
234-
return err
235-
}
236-
} else {
237-
return err
238-
}
237+
return err
239238
}
240239
wt, err := r.Worktree()
241240
if err != nil {
242241
return err
243242
}
244-
if err := os.WriteFile(filepath.Join(path, "readme.md"), []byte("# bookmarks"), 0600); err != nil {
245-
return err
243+
added := false
244+
if _, err := os.Stat(filepath.Join(path, "readme.md")); os.IsNotExist(err) {
245+
if err := os.WriteFile(filepath.Join(path, "readme.md"), []byte("# bookmarks"), 0600); err != nil {
246+
return err
247+
}
248+
if _, err := wt.Add("readme.md"); err != nil {
249+
return err
250+
}
251+
added = true
246252
}
247-
if _, err := wt.Add("readme.md"); err != nil {
248-
return err
253+
if _, err := os.Stat(filepath.Join(path, ".gitignore")); os.IsNotExist(err) {
254+
if err := os.WriteFile(filepath.Join(path, ".gitignore"), []byte(".password\n"), 0600); err != nil {
255+
return err
256+
}
257+
if _, err := wt.Add(".gitignore"); err != nil {
258+
return err
259+
}
260+
added = true
261+
}
262+
if added {
263+
_, err = wt.Commit("init", &git.CommitOptions{
264+
Author: &object.Signature{Name: "Gobookmarks", Email: "Gobookmarks@arran.net.au", When: time.Now()},
265+
})
266+
if err != nil {
267+
return err
268+
}
269+
}
270+
return nil
271+
}
272+
273+
func (GitProvider) RepoExists(ctx context.Context, user string, token *oauth2.Token, name string) (bool, error) {
274+
path := userDir(user)
275+
if _, err := git.PlainOpen(path); err == nil {
276+
return true, nil
277+
} else if errors.Is(err, git.ErrRepositoryNotExists) {
278+
return false, nil
279+
} else {
280+
return false, err
249281
}
250-
_, err = wt.Commit("init", &git.CommitOptions{
251-
Author: &object.Signature{Name: "Gobookmarks", Email: "Gobookmarks@arran.net.au", When: time.Now()},
252-
})
253-
return err
254282
}
255283

256284
func passwordPath(user string) string {
@@ -261,6 +289,10 @@ func passwordPath(user string) string {
261289
// CreateUser writes a bcrypt hash for the given user. It returns ErrUserExists
262290
// if the password file already exists.
263291
func (GitProvider) CreateUser(ctx context.Context, user, password string) error {
292+
gp := GitProvider{}
293+
if err := gp.CreateRepo(ctx, user, nil, RepoName); err != nil {
294+
return err
295+
}
264296
p := passwordPath(user)
265297
if _, err := os.Stat(p); err == nil {
266298
return ErrUserExists

provider_git_test.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package gobookmarks
33
import (
44
"context"
55
"errors"
6+
"os"
67
"path/filepath"
8+
"strings"
79
"testing"
810
)
911

@@ -16,6 +18,13 @@ func TestGitProviderCreateAndGet(t *testing.T) {
1618
if err := p.CreateRepo(context.Background(), user, nil, RepoName); err != nil {
1719
t.Fatalf("CreateRepo: %v", err)
1820
}
21+
gi, err := os.ReadFile(filepath.Join(userDir(user), ".gitignore"))
22+
if err != nil {
23+
t.Fatalf("gitignore missing: %v", err)
24+
}
25+
if !strings.Contains(string(gi), ".password") {
26+
t.Fatalf(".password not ignored")
27+
}
1928
if err := p.CreateBookmarks(context.Background(), user, nil, "main", text); err != nil {
2029
t.Fatalf("CreateBookmarks: %v", err)
2130
}
@@ -31,6 +40,27 @@ func TestGitProviderCreateAndGet(t *testing.T) {
3140
}
3241
}
3342

43+
func TestGitRepoExists(t *testing.T) {
44+
tmp := t.TempDir()
45+
LocalGitPath = tmp
46+
p := GitProvider{}
47+
user := "carol"
48+
exists, err := p.RepoExists(context.Background(), user, nil, RepoName)
49+
if err != nil {
50+
t.Fatalf("RepoExists before create: %v", err)
51+
}
52+
if exists {
53+
t.Fatalf("repo should not exist")
54+
}
55+
if err := p.CreateRepo(context.Background(), user, nil, RepoName); err != nil {
56+
t.Fatalf("CreateRepo: %v", err)
57+
}
58+
exists, err = p.RepoExists(context.Background(), user, nil, RepoName)
59+
if err != nil || !exists {
60+
t.Fatalf("repo should exist, got %v %v", exists, err)
61+
}
62+
}
63+
3464
func TestGitPasswordLifecycle(t *testing.T) {
3565
tmp := t.TempDir()
3666
LocalGitPath = tmp
@@ -39,10 +69,19 @@ func TestGitPasswordLifecycle(t *testing.T) {
3969
user := "bob"
4070
pass := "secret"
4171

42-
// create user
4372
if err := p.CreateUser(ctx, user, pass); err != nil {
4473
t.Fatalf("CreateUser: %v", err)
4574
}
75+
if _, err := os.Stat(filepath.Join(userDir(user), ".git")); err != nil {
76+
t.Fatalf("repo missing after CreateUser: %v", err)
77+
}
78+
gi, err := os.ReadFile(filepath.Join(userDir(user), ".gitignore"))
79+
if err != nil {
80+
t.Fatalf("gitignore missing: %v", err)
81+
}
82+
if !strings.Contains(string(gi), ".password") {
83+
t.Fatalf(".password not ignored")
84+
}
4685
// creating again should fail
4786
if err := p.CreateUser(ctx, user, pass); !errors.Is(err, ErrUserExists) {
4887
t.Fatalf("expected ErrUserExists, got %v", err)

provider_github.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,21 @@ See . https://github.com/arran4/gobookmarks `),
187187
return nil
188188
}
189189

190+
func (p GitHubProvider) RepoExists(ctx context.Context, user string, token *oauth2.Token, name string) (bool, error) {
191+
client := p.client(ctx, token)
192+
_, resp, err := client.Repositories.Get(ctx, user, name)
193+
if err != nil {
194+
if resp != nil && resp.StatusCode == http.StatusNotFound {
195+
return false, nil
196+
}
197+
if resp != nil && resp.StatusCode == http.StatusUnauthorized {
198+
return false, ErrSignedOut
199+
}
200+
return false, err
201+
}
202+
return true, nil
203+
}
204+
190205
func (p GitHubProvider) createRef(ctx context.Context, user string, client *github.Client, sourceRef, branchRef string) error {
191206
gsref, resp, err := client.Git.GetRef(ctx, user, RepoName, sourceRef)
192207
if resp != nil && resp.StatusCode == 404 {

provider_gitlab.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,3 +312,21 @@ func (p GitLabProvider) CreateRepo(ctx context.Context, user string, token *oaut
312312
}
313313
return err
314314
}
315+
316+
func (p GitLabProvider) RepoExists(ctx context.Context, user string, token *oauth2.Token, name string) (bool, error) {
317+
c, err := GitLabProvider{}.client(token)
318+
if err != nil {
319+
return false, err
320+
}
321+
_, resp, err := c.Projects.GetProject(user+"/"+name, nil)
322+
if err != nil {
323+
if resp != nil && resp.StatusCode == http.StatusNotFound {
324+
return false, nil
325+
}
326+
if gitlabUnauthorized(err) {
327+
return false, ErrSignedOut
328+
}
329+
return false, err
330+
}
331+
return true, nil
332+
}

0 commit comments

Comments
 (0)