in backend/server/api/middlewares.go [98:202]
func RestAuthentication(router *gin.Engine, basicRes context.BasicRes) gin.HandlerFunc {
type ApiBody struct {
Success bool `json:"success"`
Message string `json:"message"`
}
db := basicRes.GetDal()
logger := basicRes.GetLogger()
if db == nil {
panic(fmt.Errorf("db is not initialised"))
}
apiKeyHelper := apikeyhelper.NewApiKeyHelper(basicRes, logger)
return func(c *gin.Context) {
path := c.Request.URL.Path
// Only open api needs to check api key
if !strings.HasPrefix(path, "/rest") {
logger.Info("path %s will continue", path)
c.Next()
return
}
path = strings.TrimPrefix(path, "/rest")
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.Abort()
c.JSON(http.StatusUnauthorized, &ApiBody{
Success: false,
Message: "token is missing",
})
return
}
apiKeyStr := strings.TrimPrefix(authHeader, "Bearer ")
if apiKeyStr == authHeader || apiKeyStr == "" {
c.Abort()
c.JSON(http.StatusUnauthorized, &ApiBody{
Success: false,
Message: "token is not present or malformed",
})
return
}
hashedApiKey, err := apiKeyHelper.DigestToken(apiKeyStr)
if err != nil {
logger.Error(err, "DigestToken")
c.Abort()
c.JSON(http.StatusInternalServerError, &ApiBody{
Success: false,
Message: err.Error(),
})
return
}
apiKey, err := apiKeyHelper.GetApiKey(nil, dal.Where("api_key = ?", hashedApiKey))
if err != nil {
c.Abort()
if db.IsErrorNotFound(err) {
c.JSON(http.StatusForbidden, &ApiBody{
Success: false,
Message: "api key is invalid",
})
} else {
logger.Error(err, "query api key from db")
c.JSON(http.StatusInternalServerError, &ApiBody{
Success: false,
Message: err.Error(),
})
}
return
}
if apiKey.ExpiredAt != nil && time.Until(*apiKey.ExpiredAt) < 0 {
c.Abort()
c.JSON(http.StatusForbidden, &ApiBody{
Success: false,
Message: "api key has expired",
})
return
}
matched, matchErr := regexp.MatchString(apiKey.AllowedPath, path)
if matchErr != nil {
logger.Error(err, "regexp match path error")
c.Abort()
c.JSON(http.StatusInternalServerError, &ApiBody{
Success: false,
Message: matchErr.Error(),
})
return
}
if !matched {
c.JSON(http.StatusForbidden, &ApiBody{
Success: false,
Message: "path doesn't match api key's scope",
})
return
}
logger.Info("redirect path: %s to: %s", c.Request.URL.Path, path)
c.Request.URL.Path = path
c.Set(common.USER, &common.User{
Name: apiKey.Creator.Creator,
Email: apiKey.Creator.CreatorEmail,
})
router.HandleContext(c)
c.Abort()
}
}