/
instream.go
109 lines (89 loc) · 2.66 KB
/
instream.go
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
package controllers
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"github.com/lescactus/clamav-api-go/internal/clamav"
"github.com/rs/zerolog/hlog"
)
// InStreamResponse represents the json response of a /scan endpoint.
type InStreamResponse struct {
Status string `json:"status"`
Msg string `json:"msg"`
Signature string `json:"signature"`
VirusFound bool `json:"virus_found"`
}
var (
ErrFormFile = errors.New("failed to parse file")
ErrOpenFileHeaders = errors.New("failed to open multipart file headers")
)
func (h *Handler) InStream(w http.ResponseWriter, r *http.Request) {
// Get request id for logging purposes
req_id, _ := hlog.IDFromCtx(r.Context())
// Parsing the Multipart file
_, hd, err := r.FormFile("file")
if err != nil {
e := fmt.Errorf("%w: %v", ErrFormFile, err)
h.Logger.Debug().Str("req_id", req_id.String()).Msgf("%v", e)
SetErrorResponse(w, e)
return
}
f, err := hd.Open()
if err != nil {
e := fmt.Errorf("%w: %v", ErrOpenFileHeaders, err)
h.Logger.Debug().Str("req_id", req_id.String()).Msgf("%v", e)
SetErrorResponse(w, e)
return
}
defer f.Close()
size := hd.Size
h.Logger.Debug().
Str("req_id", req_id.String()).
Str("file_name", hd.Filename).
Int64("file_size", hd.Size).
Msg("multipart file read successfully")
var inStreamResp InStreamResponse
var ctx = r.Context()
inStream, err := h.Clamav.InStream(ctx, f, size)
if err != nil {
if errors.Is(err, clamav.ErrVirusFound) {
h.Logger.Debug().Str("req_id", req_id.String()).Msg(err.Error())
inStreamResp = InStreamResponse{
Status: "error",
Msg: clamav.ErrVirusFound.Error(),
Signature: h.parseSignature(string(inStream)),
VirusFound: true,
}
} else {
h.Logger.Debug().Str("req_id", req_id.String()).Err(err).Msg("error while scanning file")
SetErrorResponse(w, err)
return
}
} else {
inStreamResp = InStreamResponse{
Status: "noerror",
Msg: string(clamav.RespScan),
Signature: "",
VirusFound: false,
}
}
h.Logger.Debug().Str("req_id", req_id.String()).Msg("file scanned successfully")
resp, err := json.Marshal(inStreamResp)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", ContentTypeApplicationJSON)
w.WriteHeader(http.StatusOK)
w.Write(resp)
}
// parseSignature will extract the name of the virus signature
// from Clamd response when a potential virus is found.
//
// An example of such response from the Clamd daemon is:
// "stream: Eicar-Signature FOUND"
func (h *Handler) parseSignature(msg string) string {
return strings.TrimLeft(strings.TrimRight(msg, " FOUND"), "stream: ")
}