Skip to content

Commit a9ebbb3

Browse files
committed
feat: Initial code for web dashboard
1 parent daf640e commit a9ebbb3

File tree

11 files changed

+697
-0
lines changed

11 files changed

+697
-0
lines changed

cmd/rdctl-bot/main.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import (
1111

1212
"github.com/crazyuploader/rdctl-bot/internal/bot"
1313
"github.com/crazyuploader/rdctl-bot/internal/config"
14+
"github.com/crazyuploader/rdctl-bot/internal/db"
15+
"github.com/crazyuploader/rdctl-bot/internal/realdebrid"
16+
"github.com/crazyuploader/rdctl-bot/internal/web"
1417
"github.com/spf13/cobra"
1518
"github.com/spf13/viper"
1619
)
@@ -152,6 +155,12 @@ func runBot(cmd *cobra.Command, args []string) {
152155
return
153156
}
154157

158+
// Initialize database
159+
database, err := db.Init(cfg.Database.GetDSN())
160+
if err != nil {
161+
log.Fatalf("Failed to initialize database: %v", err)
162+
}
163+
155164
// Log configuration details
156165
log.Printf("Allowed chat IDs: %v", cfg.Telegram.AllowedChatIDs)
157166
log.Printf("Super admin IDs: %v", cfg.Telegram.SuperAdminIDs)
@@ -169,6 +178,20 @@ func runBot(cmd *cobra.Command, args []string) {
169178
log.Fatalf("Failed to create bot: %v", err)
170179
}
171180

181+
go func() {
182+
// Create dependencies for web handlers
183+
deps := web.Dependencies{
184+
RDClient: realdebrid.NewClient(cfg.RealDebrid.BaseURL, cfg.RealDebrid.APIToken, cfg.RealDebrid.Proxy, time.Duration(cfg.RealDebrid.Timeout)*time.Second),
185+
UserRepo: db.NewUserRepository(database),
186+
ActivityRepo: db.NewActivityRepository(database),
187+
TorrentRepo: db.NewTorrentRepository(database),
188+
DownloadRepo: db.NewDownloadRepository(database),
189+
CommandRepo: db.NewCommandRepository(database),
190+
Config: cfg,
191+
}
192+
web.Start(deps)
193+
}()
194+
172195
// Setup graceful shutdown using context with signal notification
173196
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
174197
defer stop()

example-config.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,7 @@ database:
4040
dbname: "rdctl_bot"
4141
# SSL mode for database connection (e.g., "disable", "require")
4242
sslmode: "disable"
43+
44+
web:
45+
listen_addr: ":8082"
46+
api_key: "random_key"

go.mod

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.25.3
44

55
require (
66
github.com/go-telegram/bot v1.17.0
7+
github.com/gofiber/fiber/v2 v2.52.9
78
github.com/spf13/cobra v1.10.1
89
github.com/spf13/viper v1.21.0
910
golang.org/x/text v0.30.0
@@ -13,22 +14,32 @@ require (
1314
)
1415

1516
require (
17+
github.com/andybalholm/brotli v1.1.0 // indirect
1618
github.com/fsnotify/fsnotify v1.9.0 // indirect
1719
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
20+
github.com/google/uuid v1.6.0 // indirect
1821
github.com/inconshreveable/mousetrap v1.1.0 // indirect
1922
github.com/jackc/pgpassfile v1.0.0 // indirect
2023
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
2124
github.com/jackc/pgx/v5 v5.6.0 // indirect
2225
github.com/jackc/puddle/v2 v2.2.2 // indirect
2326
github.com/jinzhu/inflection v1.0.0 // indirect
2427
github.com/jinzhu/now v1.1.5 // indirect
28+
github.com/klauspost/compress v1.17.9 // indirect
29+
github.com/mattn/go-colorable v0.1.13 // indirect
30+
github.com/mattn/go-isatty v0.0.20 // indirect
31+
github.com/mattn/go-runewidth v0.0.16 // indirect
2532
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
33+
github.com/rivo/uniseg v0.2.0 // indirect
2634
github.com/sagikazarmark/locafero v0.11.0 // indirect
2735
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
2836
github.com/spf13/afero v1.15.0 // indirect
2937
github.com/spf13/cast v1.10.0 // indirect
3038
github.com/spf13/pflag v1.0.10 // indirect
3139
github.com/subosito/gotenv v1.6.0 // indirect
40+
github.com/valyala/bytebufferpool v1.0.0 // indirect
41+
github.com/valyala/fasthttp v1.51.0 // indirect
42+
github.com/valyala/tcplisten v1.0.0 // indirect
3243
go.yaml.in/yaml/v3 v3.0.4 // indirect
3344
golang.org/x/crypto v0.35.0 // indirect
3445
golang.org/x/sync v0.17.0 // indirect

go.sum

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
2+
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
13
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
24
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
35
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -10,8 +12,12 @@ github.com/go-telegram/bot v1.17.0 h1:Hs0kGxSj97QFqOQP0zxduY/4tSx8QDzvNI9uVRS+zm
1012
github.com/go-telegram/bot v1.17.0/go.mod h1:i2TRs7fXWIeaceF3z7KzsMt/he0TwkVC680mvdTFYeM=
1113
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
1214
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
15+
github.com/gofiber/fiber/v2 v2.52.9 h1:YjKl5DOiyP3j0mO61u3NTmK7or8GzzWzCFzkboyP5cw=
16+
github.com/gofiber/fiber/v2 v2.52.9/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
1317
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
1418
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
19+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
20+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
1521
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
1622
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
1723
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
@@ -26,14 +32,25 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
2632
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
2733
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
2834
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
35+
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
36+
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
2937
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
3038
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
3139
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
3240
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
41+
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
42+
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
43+
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
44+
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
45+
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
46+
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
47+
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
3348
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
3449
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
3550
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
3651
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
52+
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
53+
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
3754
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
3855
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
3956
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -59,12 +76,20 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
5976
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
6077
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
6178
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
79+
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
80+
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
81+
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
82+
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
83+
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
84+
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
6285
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
6386
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
6487
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
6588
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
6689
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
6790
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
91+
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
92+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
6893
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
6994
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
7095
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=

internal/config/config.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ type Config struct {
1515
RealDebrid RealDebridConfig `mapstructure:"realdebrid"`
1616
App AppConfig `mapstructure:"app"`
1717
Database DatabaseConfig `mapstructure:"database"`
18+
Web WebConfig `mapstructure:"web"`
19+
}
20+
21+
// WebConfig holds all web server configuration
22+
type WebConfig struct {
23+
ListenAddr string `mapstructure:"listen_addr"`
24+
APIKey string `mapstructure:"api_key"`
1825
}
1926

2027
// TelegramConfig holds Telegram bot settings
@@ -189,6 +196,13 @@ func (c *Config) Validate() error {
189196
c.Database.SSLMode = "disable"
190197
}
191198

199+
if c.Web.ListenAddr == "" {
200+
c.Web.ListenAddr = ":8080"
201+
}
202+
if c.Web.APIKey == "" {
203+
return fmt.Errorf("web api_key is required for dashboard access")
204+
}
205+
192206
return nil
193207
}
194208

internal/web/handlers.go

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package web
2+
3+
import (
4+
"log"
5+
"strconv"
6+
7+
"github.com/crazyuploader/rdctl-bot/internal/realdebrid"
8+
"github.com/gofiber/fiber/v2"
9+
)
10+
11+
// GetStatus retrieves the Real-Debrid account status
12+
func (d *Dependencies) GetStatus(c *fiber.Ctx) error {
13+
user, err := d.RDClient.GetUser()
14+
if err != nil {
15+
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"success": false, "error": err.Error()})
16+
}
17+
return c.JSON(fiber.Map{"success": true, "data": user})
18+
}
19+
20+
// GetTorrents retrieves the list of active torrents
21+
func (d *Dependencies) GetTorrents(c *fiber.Ctx) error {
22+
limit, _ := strconv.Atoi(c.Query("limit", "50"))
23+
offset, _ := strconv.Atoi(c.Query("offset", "0"))
24+
25+
torrents, err := d.RDClient.GetTorrents(limit, offset)
26+
if err != nil {
27+
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"success": false, "error": err.Error()})
28+
}
29+
30+
// Format status and size for frontend convenience
31+
for i := range torrents {
32+
torrents[i].Status = realdebrid.FormatStatus(torrents[i].Status)
33+
}
34+
35+
return c.JSON(fiber.Map{"success": true, "data": torrents})
36+
}
37+
38+
// GetTorrentInfo retrieves detailed information about a single torrent
39+
func (d *Dependencies) GetTorrentInfo(c *fiber.Ctx) error {
40+
id := c.Params("id")
41+
torrent, err := d.RDClient.GetTorrentInfo(id)
42+
if err != nil {
43+
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"success": false, "error": err.Error()})
44+
}
45+
torrent.Status = realdebrid.FormatStatus(torrent.Status)
46+
return c.JSON(fiber.Map{"success": true, "data": torrent})
47+
}
48+
49+
// AddTorrent adds a new torrent from a magnet link
50+
func (d *Dependencies) AddTorrent(c *fiber.Ctx) error {
51+
var body struct {
52+
Magnet string `json:"magnet"`
53+
}
54+
if err := c.BodyParser(&body); err != nil {
55+
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"success": false, "error": "Invalid request body"})
56+
}
57+
58+
if body.Magnet == "" {
59+
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"success": false, "error": "Magnet link is required"})
60+
}
61+
62+
resp, err := d.RDClient.AddMagnet(body.Magnet)
63+
if err != nil {
64+
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"success": false, "error": err.Error()})
65+
}
66+
67+
// Automatically select all files
68+
if err := d.RDClient.SelectAllFiles(resp.ID); err != nil {
69+
log.Printf("Failed to select files for torrent %s: %v", resp.ID, err)
70+
// Non-fatal, just log it
71+
}
72+
73+
return c.Status(fiber.StatusCreated).JSON(fiber.Map{"success": true, "data": resp})
74+
}
75+
76+
// DeleteTorrent deletes a torrent
77+
func (d *Dependencies) DeleteTorrent(c *fiber.Ctx) error {
78+
id := c.Params("id")
79+
if err := d.RDClient.DeleteTorrent(id); err != nil {
80+
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"success": false, "error": err.Error()})
81+
}
82+
return c.Status(fiber.StatusOK).JSON(fiber.Map{"success": true, "message": "Torrent deleted successfully"})
83+
}
84+
85+
// GetDownloads retrieves the download history
86+
func (d *Dependencies) GetDownloads(c *fiber.Ctx) error {
87+
limit, _ := strconv.Atoi(c.Query("limit", "50"))
88+
offset, _ := strconv.Atoi(c.Query("offset", "0"))
89+
90+
downloads, err := d.RDClient.GetDownloads(limit, offset)
91+
if err != nil {
92+
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"success": false, "error": err.Error()})
93+
}
94+
return c.JSON(fiber.Map{"success": true, "data": downloads})
95+
}
96+
97+
// UnrestrictLink unrestricts a hoster link
98+
func (d *Dependencies) UnrestrictLink(c *fiber.Ctx) error {
99+
var body struct {
100+
Link string `json:"link"`
101+
}
102+
if err := c.BodyParser(&body); err != nil {
103+
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"success": false, "error": "Invalid request body"})
104+
}
105+
106+
if body.Link == "" {
107+
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"success": false, "error": "Link is required"})
108+
}
109+
110+
unrestricted, err := d.RDClient.UnrestrictLink(body.Link)
111+
if err != nil {
112+
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"success": false, "error": err.Error()})
113+
}
114+
115+
return c.JSON(fiber.Map{"success": true, "data": unrestricted})
116+
}
117+
118+
// DeleteDownload deletes a download from history
119+
func (d *Dependencies) DeleteDownload(c *fiber.Ctx) error {
120+
id := c.Params("id")
121+
if err := d.RDClient.DeleteDownload(id); err != nil {
122+
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"success": false, "error": err.Error()})
123+
}
124+
return c.Status(fiber.StatusOK).JSON(fiber.Map{"success": true, "message": "Download link removed successfully"})
125+
}
126+
127+
// GetUserStats retrieves statistics for a user
128+
func (d *Dependencies) GetUserStats(c *fiber.Ctx) error {
129+
userID, err := strconv.ParseUint(c.Params("id"), 10, 64)
130+
if err != nil {
131+
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"success": false, "error": "Invalid user ID"})
132+
}
133+
134+
stats, err := d.CommandRepo.GetUserStats(uint(userID))
135+
if err != nil {
136+
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"success": false, "error": err.Error()})
137+
}
138+
return c.JSON(fiber.Map{"success": true, "data": stats})
139+
}

internal/web/middleware.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package web
2+
3+
import (
4+
"github.com/gofiber/fiber/v2"
5+
)
6+
7+
// APIKeyAuth is a middleware for simple API key authentication
8+
func APIKeyAuth(apiKey string) fiber.Handler {
9+
return func(c *fiber.Ctx) error {
10+
providedKey := c.Get("X-API-Key")
11+
if providedKey == "" {
12+
providedKey = c.Query("api_key")
13+
}
14+
15+
if providedKey != apiKey {
16+
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
17+
"success": false,
18+
"message": "Unauthorized: Invalid or missing API Key",
19+
})
20+
}
21+
return c.Next()
22+
}
23+
}

0 commit comments

Comments
 (0)