-
Notifications
You must be signed in to change notification settings - Fork 1
/
report.go
152 lines (124 loc) · 3.1 KB
/
report.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
// report.go
/*
This file contains func for generating the report
*/
package main
import (
"fmt"
"io"
"io/ioutil"
"os"
"sort"
"sync"
"time"
"github.com/atotto/encoding/csv"
"github.com/ivpusic/grpool"
"github.com/keltia/ssllabs"
"github.com/pkg/errors"
)
var (
// this is to protect the Sites array
lock sync.Mutex
)
// Private functions
// getResults read the JSON array generated and gone through jq
func getResults(file string) (res []byte, err error) {
fh, err := os.Open(file)
if err != nil {
return res, errors.Wrapf(err, "can not open %s", file)
}
defer fh.Close()
res, err = ioutil.ReadAll(fh)
return res, errors.Wrapf(err, "can not read json %s", file)
}
func getSSLablsVersion(site ssllabs.Host) string {
debug("%#v", site)
return fmt.Sprintf("%s/%s", site.EngineVersion, site.CriteriaVersion)
}
// NewTLSReport generates everything we need for display/export
func NewTLSReport(reports []ssllabs.Host) (e *TLSReport, err error) {
if len(reports) == 0 {
return nil, fmt.Errorf("empty list")
}
e = &TLSReport{
Date: time.Now(),
SSLLabs: getSSLablsVersion(reports[0]),
}
verbose("%d sites found.\n", len(reports))
pool := grpool.NewPool(fJobs, len(reports))
// release resources used by pool
defer pool.Release()
pool.WaitCount(len(reports))
// Now analyze each site
for _, site := range reports {
debug("queueing %s\n", site.Host)
current := site
pool.JobQueue <- func() {
completed := NewTLSSite(current)
// Block on mutex
lock.Lock()
e.Sites = append(e.Sites, completed)
lock.Unlock()
pool.JobDone()
}
}
pool.WaitAll()
verbose("got all %d sites\n", len(e.Sites))
debug("all=%v\n", e.Sites)
sort.Sort(ByAlphabet(*e))
return e, nil
}
type Types struct {
Corrects map[string]int
Insecure int
ToFix int
}
func (r *TLSReport) ColourMap(criteria string) Types {
var (
insecure, tofix int
)
t := Types{Corrects: map[string]int{}}
for _, site := range r.Sites {
switch site.Type {
case TypeHTTPSok:
t.Corrects[selectColours(criteria)]++
case TypeHTTPSnok:
tofix++
case TypeHTTP:
insecure++
}
}
return t
}
// ToCSV output a CSV file from a report
func (r *TLSReport) ToCSV(w io.Writer) (err error) {
wh := csv.NewWriter(w)
debug("%v\n", r.Sites)
if err = wh.WriteStructHeader(r.Sites[0]); err != nil {
return errors.Wrap(err, "can not write csv header")
}
err = wh.WriteStructAll(r.Sites)
return errors.Wrap(err, "can not write csv file")
}
func WriteCSV(fh *os.File, final *TLSReport, cntrs, https map[string]int) error {
var err error
debug("WriteCSV")
if final == nil {
return fmt.Errorf("nil final")
}
if len(final.Sites) == 0 {
return fmt.Errorf("empty final")
}
if err = final.ToCSV(fh); err != nil {
return errors.Wrap(err, "Error can not generate CSV")
}
fmt.Fprintf(fh, "\nTLS Summary\n")
if err := writeSummary(os.Stdout, tlsKeys, cntrs); err != nil {
fmt.Fprintf(os.Stderr, "can not generate TLS summary: %v", err)
}
fmt.Fprintf(fh, "\nHTTP Summary\n")
if err := writeSummary(os.Stdout, httpKeys, https); err != nil {
fmt.Fprintf(os.Stderr, "can not generate HTTP summary: %v", err)
}
return nil
}