dir-server

Simple http(s) server
git clone https://www.brianlane.com/git/dir-server
Log | Files | Refs

commit 29860982d8ceb91da5d20563979e6b363eca526b
Author: Brian C. Lane <bcl@brianlane.com>
Date:   Sat, 29 Feb 2020 08:39:24 -0800

Initial commit - working dir-server with TLS support

Diffstat:
Amain.go | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 155 insertions(+), 0 deletions(-)

diff --git a/main.go b/main.go @@ -0,0 +1,155 @@ +/*dir-server - simple http or https server for current directory + + Copyright (C) 2019-2020 Brian C. Lane <bcl@brianlane.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +package main + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "flag" + "fmt" + "log" + "math/big" + "net/http" + "os" + "time" +) + +type cmdlineArgs struct { + ListenIP string + ListenPort int + TLS bool + Cert string + Key string +} + +var cfg = cmdlineArgs{ + ListenIP: "0.0.0.0", + ListenPort: 8000, + TLS: false, + Cert: "/var/tmp/cert.pem", + Key: "/var/tmp/key.pem", +} + +func init() { + flag.StringVar(&cfg.ListenIP, "ip", cfg.ListenIP, "IP Address to Listen to (0.0.0.0)") + flag.IntVar(&cfg.ListenPort, "port", cfg.ListenPort, "Port to listen to (8000)") + flag.BoolVar(&cfg.TLS, "tls", cfg.TLS, "Use https instead of http") + flag.StringVar(&cfg.Cert, "cert", cfg.Cert, "Path to temporary cert.pem") + flag.StringVar(&cfg.Key, "key", cfg.Key, "Path to temporary key.pem") + + flag.Parse() +} + +func publicKey(priv interface{}) interface{} { + switch k := priv.(type) { + case *ecdsa.PrivateKey: + return &k.PublicKey + default: + return nil + } +} + +// This generates a self-signed cert good for 6 hours using ecdsa P256 curve +func makeSelfSigned(cert, key string) { + hostname, err := os.Hostname() + if err != nil { + log.Fatalf("Error getting hostname: %s", err) + } + + // these are temporary certs, only valid for 6 hours + notBefore := time.Now() + notAfter := notBefore.Add(6 * time.Hour) + + var priv interface{} + priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + log.Fatalf("Failed to generate private key: %s", err) + } + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + if err != nil { + log.Fatalf("Failed to generate serial number: %s", err) + } + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + Organization: []string{"Random Bits UNL"}, + }, + NotBefore: notBefore, + NotAfter: notAfter, + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + DNSNames: []string{hostname}, + } + derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv) + if err != nil { + log.Fatalf("Failed to create certificate: %s", err) + } + + certOut, err := os.Create(cert) + if err != nil { + log.Fatalf("Failed to open %s for writing: %s", cert, err) + } + if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { + log.Fatalf("Failed to write data to cert.pem: %s", err) + } + if err := certOut.Close(); err != nil { + log.Fatalf("Error closing %s: %s", cert, err) + } + log.Printf("wrote %s\n", cert) + + keyOut, err := os.OpenFile(key, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + log.Fatalf("Failed to open %s for writing: %s", key, err) + } + privBytes, err := x509.MarshalPKCS8PrivateKey(priv) + if err != nil { + log.Fatalf("Unable to marshal private key: %v", err) + } + if err := pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil { + log.Fatalf("Failed to write data to %s: %s", key, err) + } + if err := keyOut.Close(); err != nil { + log.Fatalf("Error closing %s: %s", key, err) + } + log.Printf("wrote %s\n", key) +} + +func main() { + http.Handle("/", http.FileServer(http.Dir("./"))) + listen := fmt.Sprintf("%s:%d", cfg.ListenIP, cfg.ListenPort) + + if !cfg.TLS { + if err := http.ListenAndServe(listen, nil); err != nil { + panic(err) + } + } else { + makeSelfSigned(cfg.Cert, cfg.Key) + if err := http.ListenAndServeTLS(listen, cfg.Cert, cfg.Key, nil); err != nil { + panic(err) + } + + } +}