forked from sensepost/gowitness
/
processor.go
170 lines (138 loc) 路 3.58 KB
/
processor.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package lib
import (
"bytes"
"image/png"
"io/ioutil"
"net/http"
"net/url"
"github.com/corona10/goimagehash"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/sensepost/gowitness/chrome"
"github.com/sensepost/gowitness/storage"
"gorm.io/gorm"
)
// Processor is a URL processing helper
type Processor struct {
Logger *zerolog.Logger
Db *gorm.DB
Chrome *chrome.Chrome
URL *url.URL
ScreenshotPath string
ScreenshotFileName string
// file name & file path
fn string
fp string
// preflight response
response *http.Response
title string
// persistence id
urlid uint
// screenshot
screenshot *[]byte
}
// Gowitness processes a URL by:
// - preflighting
// - storing
// - screenshotting
// - calculating a perception hash
// - writing a screenshot to disk
func (p *Processor) Gowitness() (err error) {
p.init()
if err = p.preflight(); err != nil {
log.Error().Err(err).Msg("preflight request failed")
return
}
if err = p.persistPreflight(); err != nil {
log.Error().Err(err).Msg("failed to store preflight information")
return
}
if err = p.takeScreenshot(); err != nil {
log.Error().Err(err).Msg("failed to take screenshot")
return
}
if err = p.storePerceptionHash(); err != nil {
log.Error().Err(err).Msg("failed to calculate and save a perception hash")
return
}
if err = p.writeScreenshot(); err != nil {
log.Error().Err(err).Msg("failed to save screenshot buffer")
return
}
return
}
// init initialises the Processor
func (p *Processor) init() {
if p.ScreenshotFileName != "" {
p.fn = p.ScreenshotFileName
} else {
p.fn = SafeFileName(p.URL.String())
}
p.fp = ScreenshotPath(p.fn, p.URL, p.ScreenshotPath)
}
// preflight invokes the Chrome preflight helper
func (p *Processor) preflight() (err error) {
p.Logger.Debug().Str("url", p.URL.String()).Msg("preflighting")
p.response, p.title, err = p.Chrome.Preflight(p.URL)
if err != nil {
return
}
var l *zerolog.Event
if p.response.StatusCode == 200 {
l = p.Logger.Info()
} else {
l = p.Logger.Warn()
}
l.Str("url", p.URL.String()).Int("statuscode", p.response.StatusCode).
Str("title", p.title).Msg("preflight result")
return
}
// persistPreflight dispatches the StorePreflight function
func (p *Processor) persistPreflight() (err error) {
if p.Db == nil {
return
}
p.Logger.Debug().Str("url", p.URL.String()).Msg("storing preflight data")
if p.urlid, err = p.Chrome.StorePreflight(p.URL, p.Db, p.response, p.title, p.fn); err != nil {
return
}
return
}
// takeScreenshot dispatches the takeScreenshot function
func (p *Processor) takeScreenshot() (err error) {
p.Logger.Debug().Str("url", p.URL.String()).Msg("screenshotting")
buf, err := p.Chrome.Screenshot(p.URL)
if err != nil {
return
}
p.screenshot = &buf
return
}
// storePerceptionHash calculates and stores a perception hash
func (p *Processor) storePerceptionHash() (err error) {
if p.Db == nil {
return
}
p.Logger.Debug().Str("url", p.URL.String()).Msg("calculating perception hash")
img, err := png.Decode(bytes.NewReader(*p.screenshot))
if err != nil {
return
}
comp, err := goimagehash.PerceptionHash(img)
if err != nil {
return
}
var dburl storage.URL
p.Db.First(&dburl, p.urlid)
dburl.PerceptionHash = comp.ToString()
p.Db.Save(&dburl)
return
}
// writeScreenshot writes the screenshot buffer to disk
func (p *Processor) writeScreenshot() (err error) {
p.Logger.Debug().Str("url", p.URL.String()).Str("path", p.fn).Msg("saving screenshot buffer")
if err = ioutil.WriteFile(p.fp, *p.screenshot, 0644); err != nil {
return
}
return
}