...

Source file src/github.com/google/certificate-transparency-go/submission/proxy_server.go

Documentation: github.com/google/certificate-transparency-go/submission

     1  // Copyright 2019 Google LLC. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    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  // ProxyServer wraps Proxy and handles HTTP-requests for it.
    33  type ProxyServer struct {
    34  	p               *Proxy
    35  	addTimeout      time.Duration
    36  	loadPendingLogs bool
    37  }
    38  
    39  // NewProxyServer creates ProxyServer instance. Call Run() to init.
    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  // Run starts regular Log list updates in the background, running until the
    47  // context is canceled. Blocks until initialization happens.
    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  // SCTBatch represents JSON response to add-pre-chain method of proxy.
    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  // handleAddSomeChain is helper func choosing between AddChain and AddPreChain
    70  // based on asPreChain value
    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  // HandleAddPreChain handles multiplexed add-pre-chain HTTP request.
   110  func (s *ProxyServer) HandleAddPreChain(w http.ResponseWriter, r *http.Request) {
   111  	s.handleAddSomeChain(w, r, true /* asPreChain*/)
   112  }
   113  
   114  // HandleAddChain handles multiplexed add-chain HTTP request.
   115  func (s *ProxyServer) HandleAddChain(w http.ResponseWriter, r *http.Request) {
   116  	s.handleAddSomeChain(w, r, false /* asPreChain*/)
   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  // InfoData wraps data field required for info-page.
   124  type InfoData struct {
   125  	PolicyName  string
   126  	LogListPath template.HTML
   127  	LogListJSON template.HTML
   128  }
   129  
   130  // HandleInfo handles info-page request.
   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