aboutsummaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorMax Resnick <max@ofmax.li>2020-11-08 11:45:16 -0800
committerMax Resnick <max@ofmax.li>2021-01-01 10:50:14 -0800
commita397341ad471cc761f7fb930d77e53cf7eb40a2a (patch)
tree76fb8318269569687fdd30467dc61ecba3499d09 /internal
parent689a57ec4a444f8233fe2e5ec7ceb0903218218d (diff)
downloadiserv-a397341ad471cc761f7fb930d77e53cf7eb40a2a.tar.gz
adds casbin and accounts
Diffstat (limited to '')
-rw-r--r--internal/acct/acct.go106
-rw-r--r--internal/auth/handler.go35
-rw-r--r--internal/auth/middleware.go45
-rw-r--r--internal/auth/model.go15
-rw-r--r--internal/auth/repo.go13
-rw-r--r--internal/auth/service.go36
-rw-r--r--internal/auth/service_test.go3
-rw-r--r--internal/db/redis/acct.go44
-rw-r--r--internal/db/redis/auth.go51
-rw-r--r--internal/db/redis/image.go2
-rw-r--r--internal/goog/goog.go89
-rw-r--r--internal/image/handler.go5
-rw-r--r--internal/image/service.go1
13 files changed, 381 insertions, 64 deletions
diff --git a/internal/acct/acct.go b/internal/acct/acct.go
new file mode 100644
index 0000000..48a71e6
--- /dev/null
+++ b/internal/acct/acct.go
@@ -0,0 +1,106 @@
+package acct
+
+import (
+ "context"
+ "net/http"
+
+ "git.ofmax.li/iserv/internal/auth"
+ "git.ofmax.li/iserv/internal/goog"
+ "github.com/alexedwards/scs/v2"
+ "golang.org/x/oauth2"
+)
+
+// handler
+
+// Handler interface to http handler
+type Handler interface {
+ Register(w http.ResponseWriter, r *http.Request)
+}
+
+type acctHandler struct {
+ svc Servicer
+ ses *scs.SessionManager
+}
+
+func (h *acctHandler) Register(w http.ResponseWriter, r *http.Request) {
+ userID := h.ses.GetString(r.Context(), "profid")
+ if userID == "" {
+ http.Redirect(w, r, "/l", http.StatusFound)
+ }
+ h.svc.GetGoogProfile(r.Context(), userID)
+ return
+}
+
+// NewHandler create new instance of handler
+// Servicer, session, and oauth client required
+func NewHandler(service Servicer, session *scs.SessionManager) Handler {
+ return &acctHandler{
+ service,
+ session,
+ }
+}
+
+// endhandler
+
+// model
+
+// Profile application account profile
+type Profile interface {
+ ProfileKeyValues() (string, []string)
+}
+
+// endmodel
+
+// repo
+// Repo storage interface
+
+type Repo interface {
+ UpdateAcctProfile(p Profile) error
+}
+
+// endrepo
+
+// service
+
+type Servicer interface {
+ UpdateProfile(p *Profile) error
+ GetGoogProfile(ctx context.Context, id string) error
+}
+
+func NewService(repo Repo, authRepo auth.Repo, goog goog.Servicer) *service {
+ return &service{
+ repo,
+ authRepo,
+ goog,
+ }
+}
+
+type service struct {
+ repo Repo
+ authRepo auth.Repo
+ goog goog.Servicer
+}
+
+func (s *service) UpdateProfile(p *Profile) error {
+ return nil
+}
+
+func (s *service) GetGoogProfile(ctx context.Context, id string) error {
+ token, err := s.authRepo.GetProfileToken(id)
+ if err != nil {
+ return err
+ }
+ client := s.goog.UserClient(ctx, token)
+ gp, _, err := s.goog.Profile(client)
+ if err != nil {
+ return err
+ }
+ s.repo.UpdateAcctProfile(gp)
+ return nil
+}
+
+func (s *service) GetProfileToken(id string) (*oauth2.Token, error) {
+ return s.authRepo.GetProfileToken(id)
+}
+
+// endservice
diff --git a/internal/auth/handler.go b/internal/auth/handler.go
index 992608c..d57d47e 100644
--- a/internal/auth/handler.go
+++ b/internal/auth/handler.go
@@ -3,15 +3,12 @@ package auth
import (
"encoding/json"
"io/ioutil"
- "log"
"net/http"
"github.com/alexedwards/scs/v2"
"golang.org/x/oauth2"
-)
-var (
- profileURL = "https://www.googleapis.com/oauth2/v3/userinfo"
+ "git.ofmax.li/iserv/internal/goog"
)
// Handler authentication handler
@@ -22,30 +19,28 @@ type Handler interface {
}
type authHandler struct {
- service Servicer
- ses *scs.SessionManager
- oclient *oauth2.Config
+ svc Servicer
+ ses *scs.SessionManager
}
+// TODO migrate to Goog
// NewHandler create new instance of handler
// Servicer, session, and oauth client required
func NewHandler(service Servicer,
- session *scs.SessionManager,
- oclient *oauth2.Config) Handler {
+ session *scs.SessionManager) Handler {
return &authHandler{
service,
session,
- oclient,
}
}
func (h *authHandler) Login(w http.ResponseWriter, r *http.Request) {
- stateValue, err := h.service.GenerateStateToken()
+ stateValue, err := h.svc.GenerateStateToken()
if err != nil {
return
}
h.ses.Put(r.Context(), "state", stateValue)
- url := h.oclient.AuthCodeURL(stateValue, oauth2.AccessTypeOnline)
+ url := h.svc.Goog().Config().AuthCodeURL(stateValue, oauth2.AccessTypeOnline)
http.Redirect(w, r, url, 302)
}
@@ -58,7 +53,7 @@ func (h *authHandler) OauthCallback(w http.ResponseWriter, r *http.Request) {
http.Error(w, "state value miss match bad data", 400)
return
}
- stateValid, err := h.service.ValidateStateToken(stateFromCallback, stateFromSession)
+ stateValid, err := h.svc.ValidateStateToken(stateFromCallback, stateFromSession)
if err != nil {
http.Error(w, "error validating", 400)
return
@@ -69,15 +64,14 @@ func (h *authHandler) OauthCallback(w http.ResponseWriter, r *http.Request) {
}
// valid and same as state
code := r.FormValue("code")
- token, err := h.oclient.Exchange(r.Context(), code)
+ token, err := h.svc.Goog().Config().Exchange(r.Context(), code)
if err != nil {
http.Error(w, err.Error(), 400)
return
}
- log.Printf("returned token %v", token)
// google profile
- client := h.oclient.Client(r.Context(), token)
- resp, err := client.Get(profileURL)
+ client := h.svc.Goog().UserClient(r.Context(), token)
+ resp, err := client.Get(goog.ProfileURL)
if err != nil {
http.Error(w, err.Error(), 400)
return
@@ -88,9 +82,9 @@ func (h *authHandler) OauthCallback(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), 400)
return
}
- gp := &GoogleAuthProfile{}
+ gp := &goog.GoogleProfile{}
err = json.Unmarshal(data, &gp)
- profileID, newProfile, err := h.service.LoginOrRegisterSessionID(token, gp)
+ profileID, newProfile, err := h.svc.LoginOrRegisterSessionID(token, gp)
if err != nil {
http.Error(w, err.Error(), 400)
return
@@ -98,8 +92,9 @@ func (h *authHandler) OauthCallback(w http.ResponseWriter, r *http.Request) {
h.ses.Put(r.Context(), "profid", profileID)
// send to registration
if newProfile == true {
- http.Redirect(w, r, "/account/register", 302)
+ http.Redirect(w, r, "/u/register", 302)
return
}
http.Redirect(w, r, "/", 302)
+ return
}
diff --git a/internal/auth/middleware.go b/internal/auth/middleware.go
new file mode 100644
index 0000000..0be033c
--- /dev/null
+++ b/internal/auth/middleware.go
@@ -0,0 +1,45 @@
+package auth
+
+import (
+ "net/http"
+
+ "github.com/alexedwards/scs/v2"
+ "github.com/apex/log"
+)
+
+const (
+ loginURL = "/login"
+)
+
+func AuthOnly(s Servicer, ses *scs.SessionManager) func(next http.Handler) http.Handler {
+ return func(next http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ userID := ses.GetString(r.Context(), "profid")
+ if userID == "" {
+ userID = "anon"
+ }
+ resource := r.URL.Path
+ // set the action to something that will never match
+ action := "forbidden"
+ switch r.Method {
+ case "POST", "PUT", "PATCH":
+ action = "write"
+ case "HEAD", "GET":
+ action = "read"
+ }
+ // TODO determine action
+ enforced, err := s.Enf().EnforceSafe(userID, resource, action)
+ if err != nil {
+ log.Errorf("%s", err)
+ return
+ }
+ if !enforced {
+ // TODO probably need to do something about suggesting to login
+ http.Error(w, "not found, are you signed in?", http.StatusNotFound)
+ return
+ }
+ next.ServeHTTP(w, r)
+ }
+ return http.HandlerFunc(fn)
+ }
+}
diff --git a/internal/auth/model.go b/internal/auth/model.go
index c51ff05..240b11b 100644
--- a/internal/auth/model.go
+++ b/internal/auth/model.go
@@ -6,20 +6,10 @@ import (
"golang.org/x/oauth2"
)
-// GoogleAuthProfile auth'd user profile
-// ProfileId, Email, Name, PictureURL
-type GoogleAuthProfile struct {
- ProfileID string `json:"sub"`
- Email string `json:"email"`
- Name string `json:"name"`
- PictureURL string `json:"picture"`
-}
-
// Profile profile and token
// Identifier + Token
type Profile struct {
ID string `json:"sub"`
- Email string `json:"email"`
AccessToken string `json:"access_token"`
TokenType string `json:"token_type,omitempty"`
RefreshToken string `json:"refresh_token,omitempty"`
@@ -37,10 +27,9 @@ func (ap *Profile) Token() (*oauth2.Token, error) {
}
// NewAuthProfile merge token and profile
-func NewAuthProfile(t *oauth2.Token, u *GoogleAuthProfile) *Profile {
+func NewAuthProfile(t *oauth2.Token, id string) *Profile {
return &Profile{
- u.ProfileID,
- u.Email,
+ id,
t.AccessToken,
t.TokenType,
t.RefreshToken,
diff --git a/internal/auth/repo.go b/internal/auth/repo.go
index f404c94..9a0420e 100644
--- a/internal/auth/repo.go
+++ b/internal/auth/repo.go
@@ -1,8 +1,15 @@
package auth
+import (
+ "git.ofmax.li/iserv/internal/goog"
+ "golang.org/x/oauth2"
+)
+
// Repo storage interface
type Repo interface {
- IsAuthorized(gp *GoogleAuthProfile) (bool, error)
- LookUpAuthProfileID(gp *GoogleAuthProfile) (string, error)
- SaveAuthProfile(ap *Profile) error
+ IsAuthorized(gp *goog.GoogleProfile) (bool, error)
+ LookUpAuthProfileID(gp *goog.GoogleProfile) (string, error)
+ SaveAuthProfile(email string, ap *Profile) error
+ CheckProfileID(id string) (bool, error)
+ GetProfileToken(id string) (*oauth2.Token, error)
}
diff --git a/internal/auth/service.go b/internal/auth/service.go
index 9997264..e85c705 100644
--- a/internal/auth/service.go
+++ b/internal/auth/service.go
@@ -2,11 +2,14 @@ package auth
import (
"errors"
+ "fmt"
"log"
"time"
+ "git.ofmax.li/iserv/internal/goog"
"golang.org/x/oauth2"
+ "github.com/casbin/casbin"
"github.com/gbrlsnchs/jwt/v3"
)
@@ -22,23 +25,40 @@ var (
// Servicer access to auth functionality
type Servicer interface {
- LoginOrRegisterSessionID(t *oauth2.Token, gp *GoogleAuthProfile) (string, bool, error)
+ Goog() goog.Servicer
+ LoginOrRegisterSessionID(t *oauth2.Token, gp *goog.GoogleProfile) (string, bool, error)
GenerateStateToken() (string, error)
ValidateStateToken(token string, sessionToken string) (bool, error)
+ CheckProfileID(id string) (bool, error)
+ Enf() *casbin.Enforcer
}
// Service a container for auth deps
type Service struct {
repo Repo
+ goog goog.Servicer
+ enf *casbin.Enforcer
}
// NewService create auth service
-func NewService(repo Repo) *Service {
+func NewService(repo Repo, goog goog.Servicer, enf *casbin.Enforcer) *Service {
return &Service{
repo,
+ goog,
+ enf,
}
}
+// Goog get google interface
+func (a *Service) Goog() goog.Servicer {
+ return a.goog
+}
+
+// Enf enforcer instance
+func (a *Service) Enf() *casbin.Enforcer {
+ return a.enf
+}
+
// GenerateStateToken create a random token for oauth exchange
func (a *Service) GenerateStateToken() (string, error) {
now := time.Now()
@@ -67,8 +87,13 @@ func (a *Service) ValidateStateToken(token string, sessionToken string) (bool, e
return false, ErrInvalidToken
}
+// CheckProfileID check if a profileid exists
+func (a *Service) CheckProfileID(id string) (bool, error) {
+ return a.repo.CheckProfileID(id)
+}
+
// LoginOrRegisterSessionID create a login
-func (a *Service) LoginOrRegisterSessionID(t *oauth2.Token, gp *GoogleAuthProfile) (string, bool, error) {
+func (a *Service) LoginOrRegisterSessionID(t *oauth2.Token, gp *goog.GoogleProfile) (string, bool, error) {
isAuthorized, err := a.repo.IsAuthorized(gp)
newRegistration := false
if err != nil {
@@ -84,10 +109,9 @@ func (a *Service) LoginOrRegisterSessionID(t *oauth2.Token, gp *GoogleAuthProfil
if profileID == "" {
// create profile
log.Printf("creating new profile")
- profile := NewAuthProfile(t, gp)
+ profile := NewAuthProfile(t, fmt.Sprintf("goog:%s", gp.ProfileID))
profileID = profile.ID
- log.Printf("new profile %+v", profile)
- err = a.repo.SaveAuthProfile(profile)
+ err = a.repo.SaveAuthProfile(gp.Email, profile)
if err != nil {
return "", newRegistration, err
}
diff --git a/internal/auth/service_test.go b/internal/auth/service_test.go
index 72ff709..b992696 100644
--- a/internal/auth/service_test.go
+++ b/internal/auth/service_test.go
@@ -11,6 +11,7 @@ import (
"github.com/golang/mock/gomock"
"git.ofmax.li/iserv/internal/auth"
+ "git.ofmax.li/iserv/internal/goog"
"git.ofmax.li/iserv/internal/mock/mock_auth"
)
@@ -77,7 +78,7 @@ func (s *serviceSuite) testValidateStateToken() func(t *testing.T) {
func (s *serviceSuite) testLoginOrRegsiterSessionId() func(t *testing.T) {
return func(t *testing.T) {
// is authorized err
- gp := &auth.GoogleAuthProfile{}
+ gp := &goog.GoogleProfile{}
token := &oauth2.Token{}
gofakeit.Struct(token)
gofakeit.Struct(gp)
diff --git a/internal/db/redis/acct.go b/internal/db/redis/acct.go
new file mode 100644
index 0000000..72df741
--- /dev/null
+++ b/internal/db/redis/acct.go
@@ -0,0 +1,44 @@
+package redis
+
+import (
+ "fmt"
+
+ "github.com/gomodule/redigo/redis"
+ "github.com/pkg/errors"
+
+ "git.ofmax.li/iserv/internal/acct"
+)
+
+// AcctRepo account
+type AcctRepo struct {
+ db *redis.Pool
+}
+
+var (
+ acctProfileKey string = "acct:email:%s"
+)
+
+// NewAcctRepo account repo
+func NewAcctRepo(conn *redis.Pool) *AcctRepo {
+ return &AcctRepo{
+ conn,
+ }
+}
+
+// UpdateAcctProfile write profile to redis
+func (db *AcctRepo) UpdateAcctProfile(p acct.Profile) error {
+ conn := db.db.Get()
+ defer conn.Close()
+ profileID, profileKeyValues := p.ProfileKeyValues()
+ acctProfileKey := fmt.Sprintf(acctProfileKey, profileID)
+ profileArgs := redis.Args{}.Add(acctProfileKey).AddFlat(profileKeyValues)
+ res, err := redis.String(conn.Do("HMSET", profileArgs...))
+ if err != nil {
+ fmt.Print(err)
+ return err
+ }
+ if res != "OK" {
+ return errors.Errorf("%s acct was not saved", acctProfileKey)
+ }
+ return nil
+}
diff --git a/internal/db/redis/auth.go b/internal/db/redis/auth.go
index 0c5246c..1f99fac 100644
--- a/internal/db/redis/auth.go
+++ b/internal/db/redis/auth.go
@@ -1,12 +1,14 @@
package redis
import (
+ "fmt"
"log"
"github.com/gomodule/redigo/redis"
"golang.org/x/oauth2"
"git.ofmax.li/iserv/internal/auth"
+ "git.ofmax.li/iserv/internal/goog"
)
var (
@@ -16,6 +18,14 @@ var (
end
return nil
`)
+ checkActiveAuthLua = redis.NewScript(1, `
+ local email = redis.call("HMGET",KEYS[1],"email")
+ if email == nil then
+ return false
+ end
+ return redis.call("SISMEMBER",email)
+ `)
+ authProfileKey = func(id string) string { return fmt.Sprintf("auth:%s") }
)
// AuthRepo supporting auth
@@ -32,11 +42,11 @@ func NewRedisAuthRepo(conn *redis.Pool) *AuthRepo {
}
// IsAuthorized is member of invites
-func (db *AuthRepo) IsAuthorized(gp *auth.GoogleAuthProfile) (bool, error) {
+func (db *AuthRepo) IsAuthorized(gp *goog.GoogleProfile) (bool, error) {
conn := db.db.Get()
defer conn.Close()
- authProfileKey := "auth:goog:" + gp.Email
- reply, err := redis.Bool(conn.Do("SISMEMBER", "invites", authProfileKey))
+ inviteKey := "goog:" + gp.Email
+ reply, err := redis.Bool(conn.Do("SISMEMBER", "invites", inviteKey))
if err != nil {
return reply, err
}
@@ -44,16 +54,12 @@ func (db *AuthRepo) IsAuthorized(gp *auth.GoogleAuthProfile) (bool, error) {
}
// LookUpAuthProfileID get internal profileid
-func (db *AuthRepo) LookUpAuthProfileID(gp *auth.GoogleAuthProfile) (string, error) {
+func (db *AuthRepo) LookUpAuthProfileID(gp *goog.GoogleProfile) (string, error) {
conn := db.db.Get()
var id string
defer conn.Close()
- authProfileKey := "auth:goog:" + gp.ProfileID
- reply, err := redis.Values(conn.Do("HMGET", authProfileKey, "id"))
- if err == redis.ErrNil {
- // no profile
- return "", nil
- } else if err != nil {
+ reply, err := redis.Values(conn.Do("HMGET", authProfileKey(gp.ProfileID), "id"))
+ if err != nil {
// some other error
return "", err
}
@@ -64,24 +70,35 @@ func (db *AuthRepo) LookUpAuthProfileID(gp *auth.GoogleAuthProfile) (string, err
}
// SaveAuthProfile save profile, validate against invites
-func (db *AuthRepo) SaveAuthProfile(ap *auth.Profile) error {
+func (db *AuthRepo) SaveAuthProfile(email string, ap *auth.Profile) error {
// TODO this will over-write refresh tokens
conn := db.db.Get()
defer conn.Close()
- authProfileKey := "auth:goog:" + ap.ID
- prof := redis.Args{}.Add(ap.Email).Add(authProfileKey).AddFlat(ap)
- res, err := createAuthLua.Do(conn, prof...)
- log.Printf("auth save response %+v", res)
+ prof := redis.Args{}.Add(email).Add(ap.ID).AddFlat(ap)
+ _, err := createAuthLua.Do(conn, prof...)
conn.Flush()
return err
}
+// CheckProfileID return true if the profile exists and authorized
+func (db *AuthRepo) CheckProfileID(id string) (bool, error) {
+ conn := db.db.Get()
+ defer conn.Close()
+ res, err := redis.Int(checkActiveAuthLua.Do(conn, authProfileKey(id)))
+ if err == redis.ErrNil {
+ return false, nil
+ } else if err != nil {
+ return false, err
+ }
+ // there could be profile created but later revoked authorization
+ return res == 1, nil
+}
+
func (db *AuthRepo) getAuthProfile(id string) (*auth.Profile, error) {
conn := db.db.Get()
defer conn.Close()
- authProfileKey := "auth:goog:" + id
authProfile := auth.Profile{}
- res, err := redis.Values(conn.Do("HGETALL", authProfileKey))
+ res, err := redis.Values(conn.Do("HGETALL", authProfileKey(id)))
if err != nil {
log.Fatal(err)
}
diff --git a/internal/db/redis/image.go b/internal/db/redis/image.go
index f216531..3622728 100644
--- a/internal/db/redis/image.go
+++ b/internal/db/redis/image.go
@@ -48,7 +48,7 @@ func (r *ImageRepo) GetFile(fileUrl string) (*image.PostMeta, error) {
key := fileKey(fileUrl, V1FilePathFmt)
res, err := redis.Values(conn.Do("HGETALL", key))
if err != nil {
- return &image.PostMeta{}, ErrNotFound
+ return &image.PostMeta{}, err
}
err = redis.ScanStruct(res, imageMeta)
if imageMeta.FilePath == "" {
diff --git a/internal/goog/goog.go b/internal/goog/goog.go
new file mode 100644
index 0000000..5102a95
--- /dev/null
+++ b/internal/goog/goog.go
@@ -0,0 +1,89 @@
+package goog
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+
+ "golang.org/x/oauth2"
+)
+
+var (
+ ProfileURL = "https://www.googleapis.com/oauth2/v3/userinfo"
+ ProfileKeyFmt = "goog:%s"
+)
+
+// GoogleProfile auth'd user profile
+// ProfileId, Email, Name, PictureURL
+type GoogleProfile struct {
+ ProfileID string `json:"sub"`
+ Email string `json:"email"`
+ Name string `json:"name"`
+ PictureURL string `json:"picture"`
+}
+
+// ProfileKeys conform to ProfileKeys
+func (gp *GoogleProfile) ProfileKeyValues() (string, []string) {
+ return fmt.Sprintf(ProfileKeyFmt, gp.Email), []string{
+ "profile_id", gp.ProfileID,
+ "email", gp.Email,
+ "name", gp.Name,
+ "picture_url", gp.PictureURL,
+ }
+}
+
+type Servicer interface {
+ Config() *oauth2.Config
+ Profile(client *http.Client) (*GoogleProfile, *oauth2.Token, error)
+ UserClient(ctx context.Context, token *oauth2.Token) *http.Client
+}
+
+// NewService container for interacting with Google
+func NewService(o *oauth2.Config) Servicer {
+ return &Goog{
+ o,
+ }
+
+}
+
+type Goog struct {
+ oauthConfig *oauth2.Config
+}
+
+func (g *Goog) Config() *oauth2.Config {
+ return g.oauthConfig
+}
+
+// UserCient just calls oauth2.Client
+func (g *Goog) UserClient(ctx context.Context, token *oauth2.Token) *http.Client {
+ return g.oauthConfig.Client(ctx, token)
+}
+
+// Profile get profile from google
+func (g *Goog) Profile(client *http.Client) (*GoogleProfile, *oauth2.Token, error) {
+ client.Get(ProfileURL)
+ resp, err := client.Get(ProfileURL)
+ if err != nil {
+ return &GoogleProfile{}, &oauth2.Token{}, err
+ }
+ defer resp.Body.Close()
+ data, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return &GoogleProfile{}, &oauth2.Token{}, err
+ }
+ // Google Profile
+ gp := &GoogleProfile{}
+ err = json.Unmarshal(data, gp)
+ if err != nil {
+ return &GoogleProfile{}, &oauth2.Token{}, err
+ }
+ // Token
+ token := &oauth2.Token{}
+ err = json.Unmarshal(data, token)
+ if err != nil {
+ return &GoogleProfile{}, &oauth2.Token{}, err
+ }
+ return gp, token, nil
+}
diff --git a/internal/image/handler.go b/internal/image/handler.go
index f41ed4d..71a5383 100644
--- a/internal/image/handler.go
+++ b/internal/image/handler.go
@@ -35,9 +35,8 @@ func (h *imageHandler) GetImage(w http.ResponseWriter, r *http.Request) {
fileID := chi.URLParam(r, "fileName")
fileMeta, err := h.service.GetFile(fileID)
if err != nil {
- w.WriteHeader(400)
- log.Printf("error: %+v", err)
- w.Write([]byte("WTF Incorrect Content Type"))
+ http.Error(w, "an error has occured", http.StatusBadRequest)
+ return
}
fileUrl := fmt.Sprintf("/f/%s", fileMeta.FilePath)
data := struct {
diff --git a/internal/image/service.go b/internal/image/service.go
index 10f4148..2a60c67 100644
--- a/internal/image/service.go
+++ b/internal/image/service.go
@@ -78,6 +78,7 @@ func (is *Service) AddFile(extension string, postMeta *PostMeta, fileBytes []byt
func (is *Service) GetFile(fileUrl string) (*PostMeta, error) {
result, err := is.db.GetFile(fileUrl)
if err != nil {
+ return &PostMeta{}, err
}
return result, err
}