diff --git a/Cmd b/Cmd
index 3458b86..b015649 100755
Binary files a/Cmd and b/Cmd differ
diff --git a/Gateway.go b/Gateway.go
index 678bda1..b705b90 100644
--- a/Gateway.go
+++ b/Gateway.go
@@ -7,198 +7,208 @@ Author: Peter Kleissner
package main
import (
- "crypto/tls"
- "encoding/hex"
- "fmt"
- "io"
- "net"
- "net/http"
- "path"
- "strings"
- "time"
+ "crypto/tls"
+ "encoding/hex"
+ "fmt"
+ "io"
+ "net"
+ "net/http"
+ "path"
+ "strings"
+ "time"
- "github.com/PeernetOfficial/core"
- "github.com/PeernetOfficial/core/btcec"
- "github.com/PeernetOfficial/core/webapi"
- "github.com/gorilla/mux"
+ "github.com/PeernetOfficial/core"
+ "github.com/PeernetOfficial/core/btcec"
+ "github.com/PeernetOfficial/core/webapi"
+ "github.com/gorilla/mux"
)
func startWebGateway(backend *core.Backend) {
- router := mux.NewRouter()
- router.PathPrefix("/").Handler(http.HandlerFunc(webGatewayHandler(backend))).Methods("GET")
+ router := mux.NewRouter()
+ router.PathPrefix("/").Handler(http.HandlerFunc(webGatewayHandler(backend))).Methods("GET")
- for _, listen := range config.WebListen {
- go startWebServer(backend, listen, config.WebUseSSL, config.WebCertificateFile, config.WebCertificateKey, router, "Web Listen", parseDuration(config.WebTimeoutRead), parseDuration(config.WebTimeoutWrite))
- }
+ for _, listen := range config.WebListen {
+ go startWebServer(backend, listen, config.WebUseSSL, config.WebCertificateFile, config.WebCertificateKey, router, "Web Listen", parseDuration(config.WebTimeoutRead), parseDuration(config.WebTimeoutWrite))
+ }
- if config.Redirect80 != "" {
- go webRedirect80(config.Redirect80)
- }
+ if config.Redirect80 != "" {
+ go webRedirect80(config.Redirect80)
+ }
- // wait forever
- select {}
+ // wait forever
+ select {}
}
// startWebServer starts the web-server and may block forever
func startWebServer(backend *core.Backend, WebListen string, UseSSL bool, CertificateFile, CertificateKey string, Handler http.Handler, Info string, ReadTimeout, WriteTimeout time.Duration) {
- //func startWebServer(backend *core.Backend, webListen string, useSSL bool, certificateFile, certificateKey string, server *http.Server) {
- backend.LogError("startWebServer", "Web Gateway to listen on '%s'", WebListen)
+ //func startWebServer(backend *core.Backend, webListen string, useSSL bool, certificateFile, certificateKey string, server *http.Server) {
+ backend.LogError("startWebServer", "Web Gateway to listen on '%s'", WebListen)
- tlsConfig := &tls.Config{MinVersion: tls.VersionTLS12} // for security reasons disable TLS 1.0/1.1
+ tlsConfig := &tls.Config{MinVersion: tls.VersionTLS12} // for security reasons disable TLS 1.0/1.1
- server := &http.Server{
- Addr: WebListen,
- Handler: Handler,
- ReadTimeout: ReadTimeout, // ReadTimeout is the maximum duration for reading the entire request, including the body.
- WriteTimeout: WriteTimeout, // WriteTimeout is the maximum duration before timing out writes of the response. This includes processing time and is therefore the max time any HTTP function may take.
- //IdleTimeout: IdleTimeout, // IdleTimeout is the maximum amount of time to wait for the next request when keep-alives are enabled.
- TLSConfig: tlsConfig,
- }
+ server := &http.Server{
+ Addr: WebListen,
+ Handler: Handler,
+ ReadTimeout: ReadTimeout, // ReadTimeout is the maximum duration for reading the entire request, including the body.
+ WriteTimeout: WriteTimeout, // WriteTimeout is the maximum duration before timing out writes of the response. This includes processing time and is therefore the max time any HTTP function may take.
+ //IdleTimeout: IdleTimeout, // IdleTimeout is the maximum amount of time to wait for the next request when keep-alives are enabled.
+ TLSConfig: tlsConfig,
+ }
- if UseSSL {
- // HTTPS
- if err := server.ListenAndServeTLS(CertificateFile, CertificateKey); err != nil {
- backend.LogError("startWebServer", "Error listening on '%s': %v\n", WebListen, err)
- }
- } else {
- // HTTP
- if err := server.ListenAndServe(); err != nil {
- backend.LogError("startWebServer", "Error listening on '%s': %v\n", WebListen, err)
- }
- }
+ if UseSSL {
+ // HTTPS
+ if err := server.ListenAndServeTLS(CertificateFile, CertificateKey); err != nil {
+ backend.LogError("startWebServer", "Error listening on '%s': %v\n", WebListen, err)
+ }
+ } else {
+ // HTTP
+ if err := server.ListenAndServe(); err != nil {
+ backend.LogError("startWebServer", "Error listening on '%s': %v\n", WebListen, err)
+ }
+ }
}
// parseDuration is the same as time.ParseDuration without returning an error. Valid units are ms, s, m, h. For example "10s".
func parseDuration(input string) (result time.Duration) {
- result, _ = time.ParseDuration(input)
- return
+ result, _ = time.ParseDuration(input)
+ return
}
func redirect(w http.ResponseWriter, r *http.Request) {
- http.Redirect(w, r, "https://"+r.Host+r.URL.String(), http.StatusMovedPermanently)
+ http.Redirect(w, r, "https://"+r.Host+r.URL.String(), http.StatusMovedPermanently)
}
func webRedirect80(listen80 string) {
- // redirect HTTP -> HTTPS
- http.ListenAndServe(net.JoinHostPort(listen80, "80"), http.HandlerFunc(redirect))
+ // redirect HTTP -> HTTPS
+ http.ListenAndServe(net.JoinHostPort(listen80, "80"), http.HandlerFunc(redirect))
}
func webGatewayHandler(backend *core.Backend) func(w http.ResponseWriter, r *http.Request) {
- return func(w http.ResponseWriter, r *http.Request) {
- // For security and simplicity reasons, below paths are hard-coded.
- // Using arbitrary user input is an avoidable security risk here.
- switch r.URL.Path {
- case "/", "/index.html":
- http.ServeFile(w, r, path.Join(config.WebFiles, "index.html"))
- return
- case "/favicon.ico":
- http.ServeFile(w, r, path.Join(config.WebFiles, "favicon.ico"))
- return
- }
+ return func(w http.ResponseWriter, r *http.Request) {
+ // For security and simplicity reasons, below paths are hard-coded.
+ // Using arbitrary user input is an avoidable security risk here.
+ switch r.URL.Path {
+ case "/", "/index.html":
+ http.ServeFile(w, r, path.Join(config.WebFiles, "index.html"))
+ return
+ case "/favicon.ico":
+ http.ServeFile(w, r, path.Join(config.WebFiles, "favicon.ico"))
+ return
+ }
- // Assume it is in the format "/[blockchain public key]/[file hash]".
+ // Assume it is in the format "/[blockchain public key]/[file hash]".
- // Remove slash prefix and suffix.
- pathA := strings.TrimPrefix(strings.TrimSuffix(r.URL.Path, "/"), "/")
+ // Remove slash prefix and suffix.
+ pathA := strings.TrimPrefix(strings.TrimSuffix(r.URL.Path, "/"), "/")
- pathParts := strings.Split(pathA, "/")
- if len(pathParts) != 1 && len(pathParts) != 2 {
- http.Error(w, "404 not found", http.StatusNotFound)
- return
- }
+ pathParts := strings.Split(pathA, "/")
+ if len(pathParts) != 1 && len(pathParts) != 2 {
+ http.Error(w, "404 not found", http.StatusNotFound)
+ return
+ }
- // Default timeout for connection is 10 seconds. This will be an optional parameter in the future.
- timeout := 10 * time.Second
+ // Default timeout for connection is 10 seconds. This will be an optional parameter in the future.
+ timeout := 10 * time.Second
- // First part must be the public key as peer ID or node ID, hex encoded. Form: "/[blockchain public key]"
- nodeIDA := pathParts[0]
- nodeID, validNodeID := webapi.DecodeBlake3Hash(nodeIDA)
- publicKey, errPK := core.PublicKeyFromPeerID(nodeIDA)
+ // First part must be the public key as peer ID or node ID, hex encoded. Form: "/[blockchain public key]"
+ nodeIDA := pathParts[0]
+ nodeID, validNodeID := webapi.DecodeBlake3Hash(nodeIDA)
+ publicKey, errPK := core.PublicKeyFromPeerID(nodeIDA)
- if !validNodeID && errPK != nil {
- http.Error(w, "404 not found", http.StatusNotFound)
- return
- }
- if !validNodeID {
- nodeID = []byte{}
- }
+ if !validNodeID && errPK != nil {
+ http.Error(w, "404 not found", http.StatusNotFound)
+ return
+ }
+ if !validNodeID {
+ nodeID = []byte{}
+ }
- // Check if a blockchain is requested.
- // The format must be "/[blockchain public key]". Part 1 = hex encoding, peer ID or node ID.
- if len(pathParts) == 1 {
- webGatewayShowBlockchain(backend, w, r, nodeID, publicKey, timeout)
- } else if len(pathParts) == 2 {
- // Check if a specific file on a specific blockchain is requested.
- // The format must be "/[blockchain public key]/[file hash]". Part 2 = hex encoding, blake3 hash.
- hash, valid := webapi.DecodeBlake3Hash(pathParts[1])
- if !valid {
- http.Error(w, "Invalid file hash.", http.StatusBadRequest)
- return
- }
+ // Check if a blockchain is requested.
+ // The format must be "/[blockchain public key]". Part 1 = hex encoding, peer ID or node ID.
+ if len(pathParts) == 1 {
+ webGatewayShowBlockchain(backend, w, r, nodeID, publicKey, timeout)
+ } else if len(pathParts) == 2 {
+ // Check if a specific file on a specific blockchain is requested.
+ // The format must be "/[blockchain public key]/[file hash]". Part 2 = hex encoding, blake3 hash.
+ hash, valid := webapi.DecodeBlake3Hash(pathParts[1])
+ if !valid {
+ http.Error(w, "Invalid file hash.", http.StatusBadRequest)
+ return
+ }
- webGatewayShowFile(backend, w, r, nodeID, publicKey, hash, timeout)
- }
+ webGatewayShowFile(backend, w, r, nodeID, publicKey, hash, timeout)
+ }
- // Check if an arbitrary directory on a specific blockchain is requested.
- // Directories are identified by name.
- // TODO
+ // Check if an arbitrary directory on a specific blockchain is requested.
+ // Directories are identified by name.
+ // TODO
- //http.Error(w, "test handler", http.StatusOK)
- }
+ //http.Error(w, "test handler", http.StatusOK)
+ }
}
func webGatewayShowBlockchain(backend *core.Backend, w http.ResponseWriter, r *http.Request, nodeID []byte, publicKey *btcec.PublicKey, timeout time.Duration) {
- var err error
- var peer *core.PeerInfo
- if len(nodeID) != 0 {
- peer, err = webapi.PeerConnectNode(backend, nodeID, timeout)
- } else {
- peer, err = webapi.PeerConnectPublicKey(backend, publicKey, timeout)
- }
- if err != nil {
- http.Error(w, "Could not connect to remote peer. 😢", http.StatusNotFound)
- return
- }
+ var err error
+ var peer *core.PeerInfo
+ if len(nodeID) != 0 {
+ peer, err = webapi.PeerConnectNode(backend, nodeID, timeout)
+ } else {
+ peer, err = webapi.PeerConnectPublicKey(backend, publicKey, timeout)
+ }
+ if err != nil {
+ http.Error(w, "Could not connect to remote peer. 😢", http.StatusNotFound)
+ return
+ }
- // connection established!
- text := fmt.Sprintf("Peer %s blockchain height %d version %d\nUser Agent: %s\n", hex.EncodeToString(peer.NodeID), peer.BlockchainHeight, peer.BlockchainVersion, peer.UserAgent)
- http.Error(w, text, http.StatusOK)
+ // connection established!
+ text := fmt.Sprintf("Peer %s blockchain height %d version %d\nUser Agent: %s\n", hex.EncodeToString(peer.NodeID), peer.BlockchainHeight, peer.BlockchainVersion, peer.UserAgent)
+ http.Error(w, text, http.StatusOK)
}
func webGatewayShowFile(backend *core.Backend, w http.ResponseWriter, r *http.Request, nodeID []byte, publicKey *btcec.PublicKey, fileHash []byte, timeout time.Duration) {
- var err error
- var peer *core.PeerInfo
- if len(nodeID) != 0 {
- peer, err = webapi.PeerConnectNode(backend, nodeID, timeout)
- } else {
- peer, err = webapi.PeerConnectPublicKey(backend, publicKey, timeout)
- }
- if err != nil {
- http.Error(w, "Could not connect to remote peer. 😢", http.StatusNotFound)
- return
- }
+ var err error
+ var peer *core.PeerInfo
+ if len(nodeID) != 0 {
+ peer, err = webapi.PeerConnectNode(backend, nodeID, timeout)
+ } else {
+ peer, err = webapi.PeerConnectPublicKey(backend, publicKey, timeout)
+ }
+ if err != nil {
+ http.Error(w, "Could not connect to remote peer. 😢", http.StatusNotFound)
+ return
+ }
- // Todo: Try webapi.serveFileFromWarehouse
+ // Todo: Try webapi.serveFileFromWarehouse
- // Todo: Cache.
+ // Todo: Cache.
- offset := 0
- limit := 0
+ offset := 0
+ limit := 0
- // start the reader
- //reader, fileSize, transferSize, err := webapi.FileStartReader(peer, fileHash, uint64(offset), uint64(limit), r.Context().Done())
- reader, _, transferSize, err := webapi.FileStartReader(peer, fileHash, uint64(offset), uint64(limit), r.Context().Done())
- if reader != nil {
- defer reader.Close()
- }
- if err != nil || reader == nil {
- http.Error(w, "File not found.", http.StatusNotFound)
- return
- }
+ // start the reader
+ //reader, fileSize, transferSize, err := webapi.FileStartReader(peer, fileHash, uint64(offset), uint64(limit), r.Context().Done())
+ reader, _, transferSize, err := webapi.FileStartReader(peer, fileHash, uint64(offset), uint64(limit), r.Context().Done())
+ if reader != nil {
+ defer reader.Close()
+ }
+ if err != nil || reader == nil {
+ http.Error(w, "File not found.", http.StatusNotFound)
+ return
+ }
- // set the right headers
- //webapi.setContentLengthRangeHeader(w, uint64(offset), transferSize, fileSize, ranges)
+ // if get request ?download=true
+ // trigger download of the file
+ download := r.URL.Query().Get("download")
+ if download == "true" {
+ io.Copy(w, io.LimitReader(reader, int64(transferSize)))
+ return
+ } else {
- // Start sending the data!
- io.Copy(w, io.LimitReader(reader, int64(transferSize)))
+ }
+
+ // set the right headers
+ //webapi.setContentLengthRangeHeader(w, uint64(offset), transferSize, fileSize, ranges)
+
+ // Start sending the data!
+ io.Copy(w, io.LimitReader(reader, int64(transferSize)))
}
diff --git a/html/download.html b/html/download.html
index ff66550..809c6b8 100644
--- a/html/download.html
+++ b/html/download.html
@@ -10,7 +10,7 @@
-
+
@@ -78,10 +78,10 @@
-
-
-
-
+
+
+
+