/ api / api.go
api.go
 1  package api
 2  
 3  import (
 4  	"encoding/base64"
 5  	"strings"
 6  
 7  	"context"
 8  
 9  	"github.com/gofiber/fiber/v2"
10  	"github.com/gofiber/fiber/v2/middleware/cors"
11  	"github.com/gofiber/fiber/v2/utils"
12  	v1 "github.com/mrusme/journalist/api/v1"
13  	"github.com/mrusme/journalist/ent"
14  	"github.com/mrusme/journalist/ent/user"
15  	"github.com/mrusme/journalist/lib"
16  )
17  
18  // @title Journalist API
19  // @version 1.0
20  // @description The Journalist REST API v1
21  
22  // @contact.name Marius
23  // @contact.url https://xn--gckvb8fzb.com
24  // @contact.email marius@xn--gckvb8fzb.com
25  
26  // @license.name GPL-3.0
27  // @license.url https://github.com/mrusme/journalist/blob/master/LICENSE
28  
29  // @host localhost:8000
30  // @BasePath /api/v1
31  // @accept json
32  // @produce json
33  // @schemes http
34  // @securityDefinitions.basic  BasicAuth
35  func Register(
36  	jctx *lib.JournalistContext,
37  	fiberApp *fiber.App,
38  ) {
39  	api := fiberApp.Group("/api")
40  	api.Use(cors.New())
41  	api.Use(authorizer(jctx.EntClient))
42  
43  	v1.Register(
44  		jctx,
45  		&api,
46  	)
47  }
48  
49  // TODO: Move to `middlewares`
50  func authorizer(entClient *ent.Client) fiber.Handler {
51  	return func(ctx *fiber.Ctx) error {
52  		auth := ctx.Get(fiber.HeaderAuthorization)
53  
54  		if len(auth) <= 6 || strings.ToLower(auth[:5]) != "basic" {
55  			return ctx.SendStatus(fiber.StatusUnauthorized)
56  		}
57  
58  		raw, err := base64.StdEncoding.DecodeString(auth[6:])
59  		if err != nil {
60  			return ctx.SendStatus(fiber.StatusUnauthorized)
61  		}
62  
63  		creds := utils.UnsafeString(raw)
64  
65  		index := strings.Index(creds, ":")
66  		if index == -1 {
67  			return ctx.SendStatus(fiber.StatusUnauthorized)
68  		}
69  
70  		username := creds[:index]
71  		password := creds[index+1:]
72  
73  		u, err := entClient.User.
74  			Query().
75  			Where(user.Username(username)).
76  			Only(context.Background())
77  		if err != nil {
78  			return ctx.SendStatus(fiber.StatusUnauthorized)
79  		}
80  
81  		if u.Password != password {
82  			return ctx.SendStatus(fiber.StatusUnauthorized)
83  		}
84  
85  		ctx.Locals("user_id", u.ID.String())
86  		ctx.Locals("username", u.Username)
87  		// ctx.Locals("password", u.Password)
88  		ctx.Locals("role", u.Role)
89  		return ctx.Next()
90  	}
91  }