cleaner check for mkdir errors

This commit is contained in:
Umputun
2018-02-14 23:52:32 -06:00
parent 481f4f4fee
commit b347dfd749
3 changed files with 24 additions and 12 deletions
+1
View File
@@ -238,3 +238,4 @@ _all calls require auth and admin_
- User can vote for the comment multiple times but only to change his/her vote. Double-voting not allowed.
- User can edit comments in 5 mins window after creation.
- User ID prefixed by oauth provider name in order to avoid collisions and potential abuse.
- All avatars cached locally in order to prevent rate limiters from google/github/facebook.
+5 -5
View File
@@ -32,9 +32,9 @@ type Provider struct {
Endpoint oauth2.Endpoint
Scopes []string
MapUser func(userData, []byte) store.User
AvatarProxy *avatar.Proxy
conf *oauth2.Config
avatarProxy *avatar.Proxy
conf *oauth2.Config
}
// Params to make initialized and ready to use provider
@@ -69,7 +69,7 @@ func initProvider(p Params, provider Provider) Provider {
provider.conf = &conf
provider.Store = p.SessionStore
provider.AvatarProxy = p.AvatarProxy
provider.avatarProxy = p.AvatarProxy
return provider
}
@@ -166,8 +166,8 @@ func (p Provider) authHandler(w http.ResponseWriter, r *http.Request) {
log.Printf("[DEBUG] got raw user info %+v", jData)
u := p.MapUser(jData, data)
if p.AvatarProxy != nil {
if avatarURL, e := p.AvatarProxy.Put(u); e == nil {
if p.avatarProxy != nil {
if avatarURL, e := p.avatarProxy.Put(u); e == nil {
u.Picture = avatarURL
} else {
log.Printf("[WARN] failed to proxy avatar, %s", e)
+18 -7
View File
@@ -29,6 +29,8 @@ type Proxy struct {
RoutePath string
}
const imgSfx = ".image"
// Put gets original avatar url from user info and returns proxied url
func (p *Proxy) Put(u store.User) (avatarURL string, err error) {
@@ -39,6 +41,7 @@ func (p *Proxy) Put(u store.User) (avatarURL string, err error) {
return "", errors.Errorf("no picture for %s", u.ID)
}
// load avatar from remote location
client := http.Client{Timeout: 10 * time.Second}
resp, err := client.Get(u.Picture)
if err != nil {
@@ -49,13 +52,18 @@ func (p *Proxy) Put(u store.User) (avatarURL string, err error) {
log.Printf("[WARN] can't close response body, %s", e)
}
}()
// get ID and location of locally cached avatar
encID := p.encodeID(u.ID)
location := p.location(encID)
if err = os.Mkdir(location, 0700); err != nil && !strings.Contains(err.Error(), "file exists") {
return "", errors.Wrapf(err, "failed to make avatar location %s", location)
location := p.location(encID) // location adds partion to path
if _, err = os.Stat(location); os.IsNotExist(err) {
if e := os.Mkdir(location, 0700); e != nil {
return "", errors.Wrapf(e, "failed to mkdir avatar location %s", location)
}
}
avFile := path.Join(location, encID+".image")
avFile := path.Join(location, encID+imgSfx)
fh, err := os.Create(avFile)
if err != nil {
return "", errors.Wrapf(err, "can't create file %s", avFile)
@@ -71,15 +79,17 @@ func (p *Proxy) Put(u store.User) (avatarURL string, err error) {
}
log.Printf("[DEBUG] saved avatar from %s to %s, user %q", u.Picture, avFile, u.Name)
return p.RoutePath + "/" + encID + ".image", nil
return p.RoutePath + "/" + encID + imgSfx, nil
}
// Routes returns auth routes for given provider
func (p *Proxy) Routes() chi.Router {
router := chi.NewRouter()
// GET /123456789.image
router.Get("/{avatar}", func(w http.ResponseWriter, r *http.Request) {
avatar := chi.URLParam(r, "avatar")
location := p.location(strings.TrimSuffix(avatar, ".image"))
location := p.location(strings.TrimSuffix(avatar, imgSfx))
avFile := path.Join(location, avatar)
fh, err := os.Open(avFile)
if err != nil {
@@ -111,6 +121,7 @@ func (p *Proxy) Routes() chi.Router {
return router
}
// encodeID hashes user id to sha1
func (p *Proxy) encodeID(id string) string {
h := sha1.New()
_, err := h.Write([]byte(id))
@@ -121,7 +132,7 @@ func (p *Proxy) encodeID(id string) string {
}
// get location for user id by adding partion to final path
// the end result is a full path like this - /tmp/avatars.test/992
// the end result is a full path like this - /tmp/avatars.test/92
func (p *Proxy) location(id string) string {
checksum64 := crc64.Checksum([]byte(id), crc64.MakeTable(crc64.ECMA))
partition := checksum64 % 100