diff --git a/.air.toml b/.air.toml index 4bcce6e..331f110 100644 --- a/.air.toml +++ b/.air.toml @@ -7,7 +7,7 @@ tmp_dir = "tmp" bin = "./_output/howmuch" cmd = "make build" delay = 1000 - exclude_dir = ["assets", "tmp", "vendor", "testdata", "_output"] + exclude_dir = ["assets", "tmp", "vendor", "testdata", "_output", "internal/howmuch/adapter/repo/sqlc"] exclude_file = [] exclude_regex = ["_test.go"] exclude_unchanged = false diff --git a/configs/howmuch.yml b/configs/howmuch.yml index 55ac09a..373c208 100644 --- a/configs/howmuch.yml +++ b/configs/howmuch.yml @@ -3,6 +3,8 @@ dev-mode: true web: addr: :8000 shutdown-timeout: 10 + token-secret: nzMC12IJBMiiV2AAktTFpZP4BbGAf09lFPV_sATKcwI + token-expiry-time: 24h db: # DB host diff --git a/internal/howmuch/howmuch.go b/internal/howmuch/howmuch.go index 3ba6fbd..6376cf1 100644 --- a/internal/howmuch/howmuch.go +++ b/internal/howmuch/howmuch.go @@ -35,6 +35,7 @@ import ( "git.vinchent.xyz/vinchent/howmuch/internal/howmuch/infra/router" "git.vinchent.xyz/vinchent/howmuch/internal/howmuch/registry" "git.vinchent.xyz/vinchent/howmuch/internal/pkg/log" + "git.vinchent.xyz/vinchent/howmuch/internal/pkg/token" "git.vinchent.xyz/vinchent/howmuch/pkg/version/verflag" "github.com/gin-gonic/gin" "github.com/jackc/pgx/v5" @@ -125,6 +126,9 @@ func run() error { } defer dbConn.Close(context.Background()) + // Init token + token.Init(viper.GetString("web.token-secret"), viper.GetDuration("web.token-expiry-time")) + // Register the core service r := registry.NewRegistry(dbConn) diff --git a/internal/howmuch/infra/router/router.go b/internal/howmuch/infra/router/router.go index 2020403..41ec1c5 100644 --- a/internal/howmuch/infra/router/router.go +++ b/internal/howmuch/infra/router/router.go @@ -23,6 +23,8 @@ package router import ( + "net/http" + "git.vinchent.xyz/vinchent/howmuch/internal/howmuch/adapter/controller" "git.vinchent.xyz/vinchent/howmuch/internal/pkg/core" "git.vinchent.xyz/vinchent/howmuch/internal/pkg/errno" @@ -53,6 +55,12 @@ func Routes(engine *gin.Engine, c controller.AppController) *gin.Engine { userV1 := v1.Group("/user") { userV1.POST("/create", func(ctx *gin.Context) { c.User.Create(ctx) }) + + userV1.Use(middleware.Authn()) + userV1.GET( + ":id/info", + func(ctx *gin.Context) { ctx.JSON(http.StatusOK, "Hello world") }, + ) } v1.POST("/session/create", func(ctx *gin.Context) { c.Session.Create(ctx) }) diff --git a/internal/pkg/log/log.go b/internal/pkg/log/log.go index ea9e49b..fa95cc8 100644 --- a/internal/pkg/log/log.go +++ b/internal/pkg/log/log.go @@ -27,7 +27,7 @@ import ( "sync" "git.vinchent.xyz/vinchent/howmuch/internal/pkg/core" - "git.vinchent.xyz/vinchent/howmuch/internal/pkg/middleware" + "git.vinchent.xyz/vinchent/howmuch/internal/pkg/shared" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) @@ -110,8 +110,12 @@ func CtxLog(ctx core.Context) *zapLogger { func (z *zapLogger) CtxLog(ctx core.Context) *zapLogger { zz := z.clone() - if rid := ctx.GetHeader(middleware.XRequestID); rid != "" { - zz.z = zz.z.With(zap.Any(middleware.XRequestID, rid)) + if rid := ctx.GetHeader(shared.XRequestID); rid != "" { + zz.z = zz.z.With(zap.Any(shared.XRequestID, rid)) + } + + if user := ctx.GetHeader(shared.XUserName); user != "" { + zz.z = zz.z.With(zap.Any(shared.XUserName, user)) } return zz diff --git a/internal/pkg/middleware/authn.go b/internal/pkg/middleware/authn.go index 6605759..539c76a 100644 --- a/internal/pkg/middleware/authn.go +++ b/internal/pkg/middleware/authn.go @@ -27,6 +27,7 @@ import ( "git.vinchent.xyz/vinchent/howmuch/internal/pkg/core" "git.vinchent.xyz/vinchent/howmuch/internal/pkg/errno" + "git.vinchent.xyz/vinchent/howmuch/internal/pkg/shared" "git.vinchent.xyz/vinchent/howmuch/internal/pkg/token" "github.com/gin-gonic/gin" ) @@ -37,8 +38,6 @@ var ErrTokenInvalid = &errno.Errno{ Message: "invalid token", } -const XUserName = "X-Username" - // Authn authenticates a user's access by validating their token. func Authn() gin.HandlerFunc { return func(ctx *gin.Context) { @@ -46,11 +45,12 @@ func Authn() gin.HandlerFunc { if err != nil || tk == nil { core.WriteResponse(ctx, ErrTokenInvalid, nil) ctx.Abort() + return } // TODO: check if the key is on logout blacklist. - ctx.Header(XUserName, tk.Identity) + ctx.Header(shared.XUserName, tk.Identity) ctx.Next() } } diff --git a/internal/pkg/middleware/requestid.go b/internal/pkg/middleware/requestid.go index a6cc349..919414a 100644 --- a/internal/pkg/middleware/requestid.go +++ b/internal/pkg/middleware/requestid.go @@ -23,24 +23,23 @@ package middleware import ( + "git.vinchent.xyz/vinchent/howmuch/internal/pkg/shared" "github.com/gin-gonic/gin" "github.com/google/uuid" ) -const XRequestID = "X-Request-Id" - func RequestID() gin.HandlerFunc { return func(ctx *gin.Context) { var rid string - if rid = ctx.GetHeader(XRequestID); rid != "" { - ctx.Request.Header.Add(XRequestID, rid) + if rid = ctx.GetHeader(shared.XRequestID); rid != "" { + ctx.Request.Header.Add(shared.XRequestID, rid) ctx.Next() } rid = uuid.NewString() - ctx.Request.Header.Add(XRequestID, rid) - ctx.Header(XRequestID, rid) + ctx.Request.Header.Add(shared.XRequestID, rid) + ctx.Header(shared.XRequestID, rid) ctx.Next() } } diff --git a/internal/pkg/middleware/requestid_test.go b/internal/pkg/middleware/requestid_test.go index 29a0fd6..cb0ccd5 100644 --- a/internal/pkg/middleware/requestid_test.go +++ b/internal/pkg/middleware/requestid_test.go @@ -26,6 +26,7 @@ import ( "net/http" "testing" + "git.vinchent.xyz/vinchent/howmuch/internal/pkg/shared" "git.vinchent.xyz/vinchent/howmuch/internal/pkg/test" "github.com/gin-gonic/gin" "github.com/google/uuid" @@ -39,12 +40,12 @@ func TestRequestID(t *testing.T) { wanted := "123" r.GET("/example", func(c *gin.Context) { - got = c.GetHeader(XRequestID) + got = c.GetHeader(shared.XRequestID) c.Status(http.StatusOK) }) r.POST("/example", func(c *gin.Context) { - got = c.GetHeader(XRequestID) + got = c.GetHeader(shared.XRequestID) c.String(http.StatusAccepted, "ok") }) @@ -55,12 +56,12 @@ func TestRequestID(t *testing.T) { "GET", "/example?a=100", nil, - test.Header{Key: XRequestID, Value: wanted}, + test.Header{Key: shared.XRequestID, Value: wanted}, ) assert.Equal(t, "123", got) res := test.PerformRequest(t, r, "GET", "/example?a=100", nil) assert.NotEqual(t, "", got) assert.NoError(t, uuid.Validate(got)) - assert.Equal(t, res.Header()[XRequestID][0], got) + assert.Equal(t, res.Header()[shared.XRequestID][0], got) } diff --git a/internal/pkg/shared/const.go b/internal/pkg/shared/const.go new file mode 100644 index 0000000..bdb9d3d --- /dev/null +++ b/internal/pkg/shared/const.go @@ -0,0 +1,6 @@ +package shared + +const ( + XRequestID = "X-Request-Id" + XUserName = "X-Username" +)