aboutsummaryrefslogtreecommitdiffstats
path: root/internal/utils
diff options
context:
space:
mode:
authorLibravatar Mo Tarbin <mhed.t91@gmail.com>2024-06-30 21:41:41 -0400
committerLibravatar Mo Tarbin <mhed.t91@gmail.com>2024-06-30 21:41:41 -0400
commitc13dd9addbf89f716e4ef5cfdf1d673139ffcb68 (patch)
treebc09646ce1d6d3a402abb4694e19da51b57204f6 /internal/utils
downloaddonetick-c13dd9addbf89f716e4ef5cfdf1d673139ffcb68.tar.gz
donetick-c13dd9addbf89f716e4ef5cfdf1d673139ffcb68.tar.bz2
donetick-c13dd9addbf89f716e4ef5cfdf1d673139ffcb68.zip
Move to Donetick Org, first commit
Diffstat (limited to '')
-rw-r--r--internal/utils/key_generator.go28
-rw-r--r--internal/utils/middleware.go72
2 files changed, 100 insertions, 0 deletions
diff --git a/internal/utils/key_generator.go b/internal/utils/key_generator.go
new file mode 100644
index 0000000..1f88be9
--- /dev/null
+++ b/internal/utils/key_generator.go
@@ -0,0 +1,28 @@
+package utils
+
+import (
+ "encoding/base64"
+
+ crand "crypto/rand"
+
+ "donetick.com/core/logging"
+ "github.com/gin-gonic/gin"
+)
+
+func GenerateInviteCode(c *gin.Context) string {
+ logger := logging.FromContext(c)
+ // Define the length of the token (in bytes). For example, 32 bytes will result in a 44-character base64-encoded token.
+ tokenLength := 12
+
+ // Generate a random byte slice.
+ tokenBytes := make([]byte, tokenLength)
+ _, err := crand.Read(tokenBytes)
+ if err != nil {
+ logger.Errorw("utility.GenerateEmailResetToken failed to generate random bytes", "err", err)
+ }
+
+ // Encode the byte slice to a base64 string.
+ token := base64.URLEncoding.EncodeToString(tokenBytes)
+
+ return token
+}
diff --git a/internal/utils/middleware.go b/internal/utils/middleware.go
new file mode 100644
index 0000000..f31184b
--- /dev/null
+++ b/internal/utils/middleware.go
@@ -0,0 +1,72 @@
+package utils
+
+import (
+ "context"
+ "net/http"
+ "strconv"
+ "time"
+
+ "donetick.com/core/config"
+ "github.com/gin-gonic/gin"
+ "github.com/ulule/limiter/v3"
+ "github.com/ulule/limiter/v3/drivers/store/memory"
+)
+
+const (
+ XRequestIdKey = "X-Request-ID" // request id header key
+)
+
+func NewRateLimiter(cfg *config.Config) *limiter.Limiter {
+
+ store := memory.NewStore()
+
+ // rate, err := limiter.NewRateFromFormatted("10-H")
+ rate := limiter.Rate{
+ Period: cfg.Server.RatePeriod,
+ Limit: int64(cfg.Server.RateLimit),
+ }
+
+ // Then, create the limiter instance which takes the store and the rate as arguments.
+ // Now, you can give this instance to any supported middleware.
+ return limiter.New(store, rate)
+
+}
+
+// wrapper ratelimiter and have it as a middkewatr function:
+func RateLimitMiddleware(limiter *limiter.Limiter) gin.HandlerFunc {
+ return func(c *gin.Context) {
+ // Use the IP as the key, which is the client IP.
+ // And set the expiration time to 10 seconds.
+ context, err := limiter.Get(c.Request.Context(), c.ClientIP())
+ if err != nil {
+ panic(err) // perhaps handle this nicer
+ }
+ // Check if the client is ratelimited.
+ if context.Reached {
+ c.AbortWithStatusJSON(http.StatusTooManyRequests, gin.H{"message": "Too many requests"})
+ return
+ }
+ // Add a header in response to inform the current quota.
+ c.Header("X-RateLimit-Limit", strconv.FormatInt(context.Limit, 10))
+ // Add a header in response to inform the remaining quota.
+ c.Header("X-RateLimit-Remaining", strconv.FormatInt(context.Remaining, 10))
+ // Add a header in response to inform the time to wait before retry.
+ c.Header("X-RateLimit-Reset", strconv.FormatInt(context.Reset, 10))
+ c.Next()
+ }
+}
+
+func TimeoutMiddleware(timeout time.Duration) gin.HandlerFunc {
+ return func(c *gin.Context) {
+ ctx, cancel := context.WithTimeout(c.Request.Context(), timeout)
+
+ defer func() {
+ if ctx.Err() == context.DeadlineExceeded {
+ c.AbortWithStatus(http.StatusGatewayTimeout)
+ }
+ cancel()
+ }()
+ c.Request = c.Request.WithContext(ctx)
+ c.Next()
+ }
+}