github.com/decred/politeia@v1.4.0/politeiawww/server.go (about) 1 // Copyright (c) 2021-2022 The Decred developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "fmt" 9 "net/http" 10 "os" 11 "path/filepath" 12 13 v3 "github.com/decred/politeia/politeiawww/api/http/v3" 14 "github.com/decred/politeia/util" 15 "github.com/gorilla/csrf" 16 "github.com/gorilla/mux" 17 ) 18 19 const ( 20 csrfKeyLength = 32 // In bytes 21 csrfCookieMaxAge = 86400 // 1 day in seconds 22 ) 23 24 // setupRouter sets up the router for the politeiawww http API. 25 func (p *politeiawww) setupRouter() error { 26 // Setup the router 27 p.router = mux.NewRouter() 28 p.router.StrictSlash(true) // Ignore trailing slashes 29 30 // Add a 404 handler 31 p.router.NotFoundHandler = http.HandlerFunc(p.handleNotFound) 32 33 // Add router middleware. Middleware is executed 34 // in the same order that they are registered in. 35 m := middleware{ 36 reqBodySizeLimit: p.cfg.ReqBodySizeLimit, 37 } 38 p.router.Use(closeBodyMiddleware) // MUST be registered first 39 p.router.Use(m.reqBodySizeLimitMiddleware) 40 p.router.Use(loggingMiddleware) 41 p.router.Use(recoverMiddleware) 42 43 // Setup a subrouter that is CSRF protected. Authenticated routes are 44 // required to use the protected router. The subrouter takes on the 45 // configuration of the router that it was spawned from, including all 46 // of the middleware that has already been registered. 47 p.protected = p.router.NewRoute().Subrouter() 48 49 // The CSRF middleware uses the double submit cookie method. The server 50 // provides clients with two CSRF tokens: a cookie token and a header 51 // token. The cookie token is set automatically by the CSRF protected 52 // subrouter anytime one of the protected routes it hit. The header token 53 // must be set manually by a request handler. Clients MUST provide both 54 // tokens in their request if they want to access a CSRF protected route. 55 // The CSRF protected subrouter returns a 403 HTTP status code if a client 56 // attempts to access a protected route without providing the proper CSRF 57 // tokens. 58 csrfKey, err := p.loadCSRFKey() 59 if err != nil { 60 return err 61 } 62 csrfMiddleware := csrf.Protect( 63 csrfKey, 64 // Set the CSRF cookie on all auth router paths and subpaths. 65 csrf.Path("/"), 66 csrf.MaxAge(csrfCookieMaxAge), 67 ) 68 p.protected.Use(csrfMiddleware) 69 70 return nil 71 } 72 73 // setupPluginRoutes set ups the http API routes for the plugin API. 74 func (p *politeiawww) setupPluginRoutes() { 75 // NOTE: This will override the legacy version route. 76 // Disable it until we are ready to switch over. 77 // addRoute(p.protected, http.MethodGet, "", "/", p.handleVersion) 78 79 // The version routes set the CSRF header token and thus needs 80 // to be part of the CSRF protected auth router so that the 81 // cookie CSRF is set too. The CSRF cookie is set on all auth 82 // routes. The header token is only set on the version route. 83 addRoute(p.protected, http.MethodGet, v3.APIVersionPrefix, 84 v3.VersionRoute, p.handleVersion) 85 86 // Unprotected routes 87 addRoute(p.router, http.MethodGet, v3.APIVersionPrefix, 88 v3.PolicyRoute, p.handlePolicy) 89 addRoute(p.router, http.MethodPost, v3.APIVersionPrefix, 90 v3.ReadRoute, p.handleRead) 91 addRoute(p.router, http.MethodPost, v3.APIVersionPrefix, 92 v3.ReadBatchRoute, p.handleReadBatch) 93 94 // CSRF protected routes 95 addRoute(p.protected, http.MethodPost, v3.APIVersionPrefix, 96 v3.NewUserRoute, p.handleNewUser) 97 addRoute(p.protected, http.MethodPost, v3.APIVersionPrefix, 98 v3.WriteRoute, p.handleWrite) 99 } 100 101 // addRoute adds a route to the provided router. 102 func addRoute(router *mux.Router, method string, routePrefix, route string, handler http.HandlerFunc) { 103 router.HandleFunc(routePrefix+route, handler).Methods(method) 104 } 105 106 // loadCSRFKey loads the CSRF key from disk. If a CSRF key does not exist then 107 // one is created and saved to disk for future use. 108 func (p *politeiawww) loadCSRFKey() ([]byte, error) { 109 log.Infof("Load CSRF key") 110 111 // Open the CSRF key file 112 fp := filepath.Join(p.cfg.DataDir, "csrf.key") 113 fCSRF, err := os.Open(fp) 114 switch { 115 case err == nil: 116 // CSRF key exists; continue 117 118 case os.IsNotExist(err): 119 // CSRF key does not exist. Create one 120 // and save it to disk. 121 key, err := util.Random(csrfKeyLength) 122 if err != nil { 123 return nil, err 124 } 125 126 fCSRF, err = os.OpenFile(fp, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) 127 if err != nil { 128 return nil, err 129 } 130 _, err = fCSRF.Write(key) 131 if err != nil { 132 return nil, err 133 } 134 _, err = fCSRF.Seek(0, 0) 135 if err != nil { 136 return nil, err 137 } 138 139 log.Infof("CSRF key created and saved to %v", fp) 140 141 default: 142 // All other errors 143 return nil, err 144 } 145 146 // Read the CSRF key from the file 147 csrfKey := make([]byte, csrfKeyLength) 148 r, err := fCSRF.Read(csrfKey) 149 if err != nil { 150 return nil, err 151 } 152 fCSRF.Close() 153 154 if r != csrfKeyLength { 155 return nil, fmt.Errorf("CSRF key corrupt") 156 } 157 158 return csrfKey, nil 159 }