1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package submission
16
17 import (
18 "context"
19 "encoding/json"
20 "fmt"
21 "html/template"
22 "net/http"
23 "os"
24 "strings"
25 "time"
26
27 ct "github.com/google/certificate-transparency-go"
28 "github.com/google/certificate-transparency-go/trillian/ctfe"
29 "github.com/google/trillian/monitoring"
30 )
31
32
33 type ProxyServer struct {
34 p *Proxy
35 addTimeout time.Duration
36 loadPendingLogs bool
37 }
38
39
40 func NewProxyServer(logListPath string, dBuilder DistributorBuilder, reqTimeout time.Duration, mf monitoring.MetricFactory) *ProxyServer {
41 s := &ProxyServer{addTimeout: reqTimeout}
42 s.p = NewProxy(NewLogListManager(NewLogListRefresher(logListPath), mf), dBuilder, mf)
43 return s
44 }
45
46
47
48 func (s *ProxyServer) Run(ctx context.Context, logListRefreshInterval time.Duration, rootsRefreshInterval time.Duration, loadPendingLogs bool) {
49 s.loadPendingLogs = loadPendingLogs
50 s.p.Run(ctx, logListRefreshInterval, rootsRefreshInterval)
51
52 <-s.p.Init
53 }
54
55
56 type SCTBatch struct {
57 SCTs []ct.SignedCertificateTimestamp `json:"scts"`
58 }
59
60 func marshalSCTs(scts []*AssignedSCT) ([]byte, error) {
61 var jsonSCTsObj SCTBatch
62 jsonSCTsObj.SCTs = make([]ct.SignedCertificateTimestamp, 0, len(scts))
63 for _, sct := range scts {
64 jsonSCTsObj.SCTs = append(jsonSCTsObj.SCTs, *sct.SCT)
65 }
66 return json.Marshal(jsonSCTsObj)
67 }
68
69
70
71 func (s *ProxyServer) handleAddSomeChain(w http.ResponseWriter, r *http.Request, asPreChain bool) {
72 if r.Method != http.MethodPost {
73 http.NotFound(w, r)
74 return
75 }
76 addChainReq, err := ctfe.ParseBodyAsJSONChain(r)
77 if err != nil {
78 rc := http.StatusBadRequest
79 pre := ""
80 if asPreChain {
81 pre = "pre-"
82 }
83 http.Error(w, fmt.Sprintf("proxy: failed to parse add-%schain body: %s", pre, err), rc)
84 return
85 }
86 ctx, cancel := context.WithTimeout(r.Context(), s.addTimeout)
87 defer cancel()
88
89 var scts []*AssignedSCT
90 if asPreChain {
91 scts, err = s.p.AddPreChain(ctx, addChainReq.Chain, s.loadPendingLogs)
92 } else {
93 scts, err = s.p.AddChain(ctx, addChainReq.Chain, s.loadPendingLogs)
94 }
95 if err != nil {
96 http.Error(w, err.Error(), http.StatusBadGateway)
97 return
98 }
99
100 data, err := marshalSCTs(scts)
101 if err != nil {
102 http.Error(w, err.Error(), http.StatusInternalServerError)
103 return
104 }
105 w.WriteHeader(http.StatusOK)
106 fmt.Fprint(w, string(data))
107 }
108
109
110 func (s *ProxyServer) HandleAddPreChain(w http.ResponseWriter, r *http.Request) {
111 s.handleAddSomeChain(w, r, true )
112 }
113
114
115 func (s *ProxyServer) HandleAddChain(w http.ResponseWriter, r *http.Request) {
116 s.handleAddSomeChain(w, r, false )
117 }
118
119 func stringToHTML(s string) template.HTML {
120 return template.HTML(strings.Replace(template.HTMLEscapeString(string(s)), "\n", "<br>", -1))
121 }
122
123
124 type InfoData struct {
125 PolicyName string
126 LogListPath template.HTML
127 LogListJSON template.HTML
128 }
129
130
131 func (s *ProxyServer) HandleInfo(w http.ResponseWriter, r *http.Request) {
132 data := InfoData{
133 s.p.dist.policy.Name(),
134 stringToHTML(s.p.llWatcher.Source()),
135 stringToHTML(string(s.p.llWatcher.LastJSON())),
136 }
137 wd, err := os.Getwd()
138 if err != nil {
139 http.Error(w, err.Error(), http.StatusInternalServerError)
140 return
141 }
142 t, err := template.ParseFiles(wd + "/submission/view/info.html")
143 if err != nil {
144 http.Error(w, err.Error(), http.StatusInternalServerError)
145 return
146 }
147
148 if err := t.Execute(w, data); err != nil {
149 http.Error(w, err.Error(), http.StatusInternalServerError)
150 return
151 }
152 }
153
View as plain text