Skip to content

Commit

Permalink
rest api
Browse files Browse the repository at this point in the history
  • Loading branch information
Peter committed Jul 10, 2024
1 parent 1a2271b commit 2eb6782
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 33 deletions.
9 changes: 9 additions & 0 deletions http/http.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package http

import (
"encoding/json"
"errors"
"net/http"
"reflect"
Expand Down Expand Up @@ -46,6 +47,14 @@ func getClientOrErr(r *http.Request, w http.ResponseWriter, clients *ClientsStru
return cl
}

func httpError(err string, w http.ResponseWriter, status int) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(map[string]string{
"error": err,
})
}

func normalizeHttpPathPrefix(config *Config) {
if len(config.HttpPathPrefix) > 0 && config.HttpPathPrefix[0] != byte('/') {
config.HttpPathPrefix = "/" + config.HttpPathPrefix
Expand Down
11 changes: 8 additions & 3 deletions http/insert_log.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,24 @@ type LogRequest struct {
func handleLog(messageChannel chan models.Message) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {

if r.Method != http.MethodPost {
httpError("This endpoint accepts only POST method", w, http.StatusMethodNotAllowed)
return
}

var p LogRequest
err := json.NewDecoder(r.Body).Decode(&p)

if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
httpError(err.Error(), w, http.StatusInternalServerError)
return
}

utils.Logger.Debugf("Inserting a batch of log messages (%d)", len(p.Logs))
for _, el := range p.Logs {
modes.ProduceMessageString(messageChannel, el.Log.String, models.MessageTypeStdout, &models.MessageOrigin{
modes.ProduceMessageStringTimestamped(messageChannel, el.Log.String, models.MessageTypeStdout, &models.MessageOrigin{
ApiSource: p.Source,
})
}, el.Ts.Time)
}

w.WriteHeader(http.StatusAccepted)
Expand Down
33 changes: 13 additions & 20 deletions http/middleware_api_key.go
Original file line number Diff line number Diff line change
@@ -1,43 +1,36 @@
package http

import (
"encoding/json"
"net/http"
"strings"

"github.com/logdyhq/logdy-core/utils"
)

const API_KEY_HEADER_NAME = "logdy-api-key"
const API_KEY_HEADER_NAME = "Authorization"

func apiKeyMiddleware(apiKey string, f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if apiKey == "" {
httpError("Configure api key to access this endpoint", w, http.StatusUnauthorized)
return
}

key := r.Header.Get(API_KEY_HEADER_NAME)

if apiKey == "" {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(map[string]string{
"error": "Api key not set in the headers (" + API_KEY_HEADER_NAME + ")",
})
if !strings.HasPrefix(key, "Bearer ") {
httpError("The Authorization token should be prefixed with `Bearer`", w, http.StatusBadRequest)
return
}

if apiKey != "" && key == "" {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(map[string]string{
"error": "Missing '" + API_KEY_HEADER_NAME + "' header with the api key",
})
if key == "" {
httpError("Missing '"+API_KEY_HEADER_NAME+"' header with the api key", w, http.StatusUnauthorized)
return
}

if apiKey != "" && apiKey != key {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(map[string]string{
"error": "Invalid api key",
})
key, _ = strings.CutPrefix(key, "Bearer ")
if apiKey != key {
httpError("Invalid api key", w, http.StatusUnauthorized)
return
}

Expand Down
16 changes: 8 additions & 8 deletions http/middleware_api_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,30 @@ func TestApiKeyMiddleware(t *testing.T) {
{
name: "Valid API Key",
apiKey: "valid-key",
headerKey: "valid-key",
headerKey: "Bearer valid-key",
expectedStatus: http.StatusOK,
expectedBody: nil,
},
{
name: "Invalid API Key",
apiKey: "valid-key",
headerKey: "invalid-key",
headerKey: "Bearer invalid-key",
expectedStatus: http.StatusUnauthorized,
expectedBody: map[string]string{"error": "Invalid api key"},
},
{
name: "Missing API Key",
name: "Invalid API Key",
apiKey: "valid-key",
headerKey: "",
expectedStatus: http.StatusUnauthorized,
expectedBody: map[string]string{"error": "Missing '" + API_KEY_HEADER_NAME + "' header with the api key"},
headerKey: "valid-key",
expectedStatus: http.StatusBadRequest,
expectedBody: map[string]string{"error": "The Authorization token should be prefixed with `Bearer`"},
},
{
name: "No API Key Set",
apiKey: "",
headerKey: "",
headerKey: "Bearer ",
expectedStatus: http.StatusUnauthorized,
expectedBody: map[string]string{"error": "Api key not set in the headers (" + API_KEY_HEADER_NAME + ")"},
expectedBody: map[string]string{"error": "Configure api key to access this endpoint"},
},
}

Expand Down
4 changes: 4 additions & 0 deletions logdy/logdy.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ type Config struct {
// A function to be invoked when a Logdy internal log message is produced
// If not nil then LogLevel is ignored
LogInterceptor LogInterceptor

// Key to be used when communicating with the REST API
ApiKey string
}

type LOG_LEVEL = utils.LOG_LEVEL
Expand Down Expand Up @@ -93,6 +96,7 @@ func translateToConfig(c *Config) http.Config {
MaxMessageCount: c.MaxMessageCount,
LogLevel: c.LogLevel,
LogInterceptor: c.LogInterceptor,
ApiKey: c.ApiKey,
}
}

Expand Down
8 changes: 6 additions & 2 deletions modes/producer.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
var FallthroughGlobal = false
var DisableANSICodeStripping = false

func ProduceMessageString(ch chan models.Message, line string, mt models.LogType, mo *models.MessageOrigin) {
func ProduceMessageStringTimestamped(ch chan models.Message, line string, mt models.LogType, mo *models.MessageOrigin, ts time.Time) {

if !DisableANSICodeStripping {
line = utils.StripAnsi(line)
Expand Down Expand Up @@ -59,6 +59,10 @@ func ProduceMessageString(ch chan models.Message, line string, mt models.LogType
IsJson: validJson == nil,
BaseMessage: models.BaseMessage{MessageType: "log"},
Origin: mo,
Ts: time.Now().UnixMilli(),
Ts: ts.UnixMilli(),
}
}

func ProduceMessageString(ch chan models.Message, line string, mt models.LogType, mo *models.MessageOrigin) {
ProduceMessageStringTimestamped(ch, line, mt, mo, time.Now())
}

0 comments on commit 2eb6782

Please sign in to comment.