diff options
Diffstat (limited to 'api/main.go')
-rw-r--r-- | api/main.go | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/api/main.go b/api/main.go new file mode 100644 index 0000000..ebae5d1 --- /dev/null +++ b/api/main.go | |||
@@ -0,0 +1,99 @@ | |||
1 | package main | ||
2 | |||
3 | import ( | ||
4 | "net/http" | ||
5 | "crypto/rand" | ||
6 | "encoding/base64" | ||
7 | |||
8 | "github.com/gin-gonic/gin" | ||
9 | ) | ||
10 | |||
11 | func CORSMiddleware() gin.HandlerFunc { | ||
12 | return func(c *gin.Context) { | ||
13 | c.Writer.Header().Set("Access-Control-Allow-Origin", "*") | ||
14 | c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") | ||
15 | c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With") | ||
16 | c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT") | ||
17 | |||
18 | if c.Request.Method == "OPTIONS" { | ||
19 | c.AbortWithStatus(204) | ||
20 | return | ||
21 | } | ||
22 | |||
23 | c.Next() | ||
24 | } | ||
25 | } | ||
26 | |||
27 | func generateToken() string { | ||
28 | token := make([]byte, 32) | ||
29 | rand.Read(token) | ||
30 | return base64.StdEncoding.EncodeToString(token) | ||
31 | } | ||
32 | |||
33 | type User struct { | ||
34 | Username string | ||
35 | Password string | ||
36 | } | ||
37 | |||
38 | var users = map[string]User{ | ||
39 | "user1": {"user1", "password1"}, | ||
40 | } | ||
41 | |||
42 | func setupRouter() *gin.Engine { | ||
43 | // Disable Console Color | ||
44 | // gin.DisableConsoleColor() | ||
45 | r := gin.Default() | ||
46 | r.Use(CORSMiddleware()) | ||
47 | |||
48 | api := r.Group("api/v1") | ||
49 | |||
50 | api.POST("/auth", func(c *gin.Context) { | ||
51 | username, password, ok := c.Request.BasicAuth() | ||
52 | if !ok { | ||
53 | c.Header("WWW-Authenticate", `Basic realm="Please enter your username and password."`) | ||
54 | c.AbortWithStatus(http.StatusUnauthorized) | ||
55 | return | ||
56 | } | ||
57 | |||
58 | user, exists := users[username] | ||
59 | |||
60 | if !exists || user.Password != password { | ||
61 | c.AbortWithStatus(http.StatusUnauthorized) | ||
62 | return | ||
63 | } | ||
64 | |||
65 | // Generate a simple API token | ||
66 | apiToken := generateToken() | ||
67 | c.JSON(http.StatusOK, gin.H{"token": apiToken}) | ||
68 | }) | ||
69 | |||
70 | stats := api.Group("stats") | ||
71 | |||
72 | stats.GET("/", func(c *gin.Context) { | ||
73 | c.JSON(http.StatusOK, gin.H{"status": "ok"}) | ||
74 | }) | ||
75 | |||
76 | stats.POST("/", func(c *gin.Context) { | ||
77 | c.JSON(http.StatusCreated, gin.H{"status": "created"}) | ||
78 | }) | ||
79 | |||
80 | stats.GET("/:uuid", func(c *gin.Context) { | ||
81 | c.JSON(http.StatusOK, gin.H{"status": "ok", "uuid": c.Param("uuid")}) | ||
82 | }) | ||
83 | |||
84 | stats.PATCH("/:uuid", func(c *gin.Context) { | ||
85 | c.JSON(http.StatusNoContent, gin.H{"status": "No Content"}) | ||
86 | }) | ||
87 | |||
88 | stats.DELETE("/:uuid", func(c *gin.Context) { | ||
89 | c.JSON(http.StatusNoContent, gin.H{"status": "No Content"}) | ||
90 | }) | ||
91 | |||
92 | return r | ||
93 | } | ||
94 | |||
95 | func main() { | ||
96 | r := setupRouter() | ||
97 | // Listen and Server in 0.0.0.0:8080 | ||
98 | r.Run(":8080") | ||
99 | } | ||