summaryrefslogtreecommitdiff
path: root/internal/api/handlers.go
blob: 45354aab6f26c19db096622304b4d893ddefaf72 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package api

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net"
	"strings"
	"regexp"
	"time"
)

var fs http.Handler

func init() {
	fs = http.FileServer(http.Dir("static"))
}

const LogLength = 100

type accessLog struct {
	ClientAddr    string    `json:"clientAddr"`
	RequestedPath string    `json:"requestedPath"`
	RequestTime   time.Time `json:"requestTime"`
	HttpMethod    string    `json:"httpMethod"`
}

func CreateFilesHandler(logs *[LogLength]string, n *int, logChan chan string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		jsonData, _ := json.Marshal(accessLog{
			ClientAddr:    redactIP(r.RemoteAddr),
			RequestedPath: r.URL.Path,
			RequestTime:   time.Now().UTC(),
			HttpMethod:    r.Method,
		})
		addRotLog(logs, n, logChan, string(jsonData))
		// Serve the index.html file from the static directory
		http.StripPrefix("/", fs).ServeHTTP(w, r)
	}
}

func CreateGetLogs(logs *[LogLength]string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		for _, s := range logs {
			fmt.Fprintln(w, s)
		}
	}
}

func CreateLoginHandler(logs *[LogLength]string, n *int, logChan chan string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		body, err := io.ReadAll(r.Body)
		if err != nil {
			http.Error(w, "Bad Request", http.StatusBadRequest)
			return
		}
		defer r.Body.Close()

		var data map[string]any
		if json.Unmarshal(body, &data) != nil {
			addRotLog(logs, n, logChan, fmt.Sprintf(`{"authRequest": %s}`, string(body)))
			http.Error(w, `{"message": "Unauthorized"}`, http.StatusUnauthorized)
			return
		}

		if email, ok := data["email"].(string); ok {
			if rememberMe, ok := data["rememberMe"].(bool); ok {
				addRotLog(logs, n, logChan, fmt.Sprintf(`{"authRequest": {"email": "%s", "password": "XXXXXXXX", "loginTime": "%s", "success": false, "rememberMe": %t}}`, email, time.Now().UTC(), rememberMe))
			}
		}
		http.Error(w, `{"message": "Unauthorized"}`, http.StatusUnauthorized)
	}
}

func redactIP(input string) string {
	ipRegex := `\b(?:\d{1,3}\.){3}\d{1,3}\b`
	re := regexp.MustCompile(ipRegex)

	return re.ReplaceAllStringFunc(input, func(match string) string {
		if ip := net.ParseIP(match); ip != nil {
			parts := strings.Split(match, ".")
			if len(parts) == 4 {
				parts[3] = "XXX"
				return strings.Join(parts, ".")
			}
		}
		return match
	})
}

func addRotLog(logs *[LogLength]string, last *int, parser chan string, value string) {
	if strings.Contains(value, "\n") {
		for _, v := range strings.Split(value, "\n") {
			addRotLog(logs, last, parser, v)
		}
	} else {
		if *last == LogLength {
			for i := 0; i < LogLength-1; i++ {
				logs[i] = logs[i+1]
			}
			logs[LogLength-1] = value
			parser <- value
		} else {
			logs[*last] = value
			*last++
			parser <- value
		}
	}
}