X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=app%2Fuser.go;h=63cd08676efffc3918aa2949d8c693122e01e15b;hb=d0e6c21a361171170dac75e65f9ef97e50435db2;hp=ffe65e97b6dc4f3336d0240e7e8614e17839f156;hpb=68e9c0c9f6290ef3cbf08962587ae2dbf351ad92;p=kraftakt.git diff --git a/app/user.go b/app/user.go index ffe65e9..63cd086 100644 --- a/app/user.go +++ b/app/user.go @@ -2,11 +2,15 @@ package app import ( "context" + "crypto/hmac" + "crypto/sha1" + "encoding/hex" "fmt" "net/http" "sync" "github.com/google/uuid" + "github.com/octo/retry" legacy_context "golang.org/x/net/context" "golang.org/x/oauth2" "google.golang.org/appengine/datastore" @@ -14,8 +18,10 @@ import ( ) type User struct { + key *datastore.Key + + ID string Email string - key *datastore.Key } type dbUser struct { @@ -23,14 +29,23 @@ type dbUser struct { } func NewUser(ctx context.Context, email string) (*User, error) { + var id string err := datastore.RunInTransaction(ctx, func(ctx legacy_context.Context) error { key := datastore.NewKey(ctx, "User", email, 0, nil) - if err := datastore.Get(ctx, key, &dbUser{}); err != datastore.ErrNoSuchEntity { - return err // may be nil + + var u dbUser + err := datastore.Get(ctx, key, &u) + if err != nil && err != datastore.ErrNoSuchEntity { + return err + } + if err == nil { + id = u.ID + return nil } - _, err := datastore.Put(ctx, key, &dbUser{ - ID: uuid.New().String(), + id = uuid.New().String() + _, err = datastore.Put(ctx, key, &dbUser{ + ID: id, }) return err }, nil) @@ -39,8 +54,9 @@ func NewUser(ctx context.Context, email string) (*User, error) { } return &User{ - Email: email, key: datastore.NewKey(ctx, "User", email, 0, nil), + ID: id, + Email: email, }, nil } @@ -55,20 +71,12 @@ func UserByID(ctx context.Context, id string) (*User, error) { } return &User{ - Email: keys[0].StringID(), key: keys[0], + ID: id, + Email: keys[0].StringID(), }, nil } -func (u *User) ID(ctx context.Context) (string, error) { - var db dbUser - if err := datastore.Get(ctx, u.key, &db); err != nil { - return "", err - } - - return db.ID, nil -} - func (u *User) Token(ctx context.Context, svc string) (*oauth2.Token, error) { key := datastore.NewKey(ctx, "Token", svc, 0, u.key) @@ -96,22 +104,34 @@ func (u *User) OAuthClient(ctx context.Context, svc string, cfg *oauth2.Config) var tok oauth2.Token if err := datastore.Get(ctx, key, &tok); err != nil { - return nil, err + return nil, fmt.Errorf("datastore.Get(%v) = %v", key, err) } src := cfg.TokenSource(ctx, &tok) - return oauth2.NewClient(ctx, &persistingTokenSource{ + c := oauth2.NewClient(ctx, &persistingTokenSource{ ctx: ctx, t: &tok, src: src, key: key, - }), nil + }) + c.Transport = retry.Transport{ + RoundTripper: c.Transport, + } + + return c, nil } func (u *User) String() string { return u.Email } +func (u *User) Sign(payload string) string { + mac := hmac.New(sha1.New, []byte(u.ID)) + mac.Write([]byte(payload)) + + return hex.EncodeToString(mac.Sum(nil)) +} + type persistingTokenSource struct { ctx context.Context t *oauth2.Token