|
| 1 | +package main |
| 2 | + |
| 3 | +import ( |
| 4 | + "crypto/sha256" |
| 5 | + "encoding/base64" |
| 6 | + "fmt" |
| 7 | + "io" |
| 8 | + "math/rand" |
| 9 | + "net/http" |
| 10 | + "net/url" |
| 11 | + "time" |
| 12 | +) |
| 13 | + |
| 14 | +type application struct { |
| 15 | + config struct { |
| 16 | + port string |
| 17 | + path string |
| 18 | + cert string |
| 19 | + key string |
| 20 | + } |
| 21 | + user struct { |
| 22 | + name string |
| 23 | + pass string |
| 24 | + } |
| 25 | +} |
| 26 | + |
| 27 | +func main() { |
| 28 | + // Instantiate app with some application data |
| 29 | + app := new(application) |
| 30 | + // Setup the config data |
| 31 | + app.config.port = "8003" |
| 32 | + app.config.path = "./www" |
| 33 | + app.config.cert = "localhost.crt" |
| 34 | + app.config.key = "localhost.key" |
| 35 | + // Setup the user data |
| 36 | + app.user.name = "admin" |
| 37 | + app.user.pass = "A6xnQhbz4Vx2HuGl4lXwZ5U2I8iziLRFnhP5eNfIRvQ=" // 1234 |
| 38 | + // Setup some routes |
| 39 | + http.HandleFunc("/", app.fileHandler) |
| 40 | + http.HandleFunc("/hello", app.helloHandler) |
| 41 | + http.HandleFunc("/hash", app.hashHandler) |
| 42 | + // Start a server |
| 43 | + fmt.Printf("Server started on port %s\n", app.config.port) |
| 44 | + if err := http.ListenAndServeTLS(":"+app.config.port, app.config.cert, app.config.key, nil); err != nil { |
| 45 | + fmt.Println(err) |
| 46 | + } |
| 47 | +} |
| 48 | + |
| 49 | +// A function that authenticates the user and returns true or false |
| 50 | +func (app *application) auth(w http.ResponseWriter, r *http.Request) bool { |
| 51 | + // Grab the username, password, and a verification that they were formatted ok in the request |
| 52 | + user, pass, ok := r.BasicAuth() |
| 53 | + // If the header includes credentials |
| 54 | + if ok { |
| 55 | + // Base64 encode the recieved password |
| 56 | + sum := sha256.Sum256([]byte(pass)) |
| 57 | + encodedPass := base64.StdEncoding.EncodeToString(sum[:]) |
| 58 | + // If the passed credentials are correct |
| 59 | + if user == app.user.name && encodedPass == app.user.pass { |
| 60 | + return true |
| 61 | + } |
| 62 | + } |
| 63 | + // Sleep for some random amount of time to prevent timed attacks |
| 64 | + rand.Seed(time.Now().UnixNano()) |
| 65 | + wait := rand.Intn(2500) |
| 66 | + fmt.Printf("Waiting %d milliseconds\n", wait) |
| 67 | + time.Sleep(time.Duration(wait) * time.Millisecond) |
| 68 | + // Set a header reporting unauthorized and requesting credentials |
| 69 | + w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`) |
| 70 | + http.Error(w, "Unauthorized", http.StatusUnauthorized) |
| 71 | + return false |
| 72 | +} |
| 73 | + |
| 74 | +func (app *application) fileHandler(w http.ResponseWriter, r *http.Request) { |
| 75 | + // Authorize the user and return on failure |
| 76 | + if !app.auth(w, r) { |
| 77 | + return |
| 78 | + } |
| 79 | + // Parse the url for the path |
| 80 | + u, err := url.ParseRequestURI(r.RequestURI) |
| 81 | + if err != nil { |
| 82 | + fmt.Println("Unable to parse url.") |
| 83 | + } |
| 84 | + fmt.Println("Serving " + app.config.path + u.Path) |
| 85 | + // Serve a file from the default directory |
| 86 | + http.ServeFile(w, r, app.config.path+u.Path) |
| 87 | +} |
| 88 | + |
| 89 | +// A handler that authorizes the user and says hello |
| 90 | +func (app *application) helloHandler(w http.ResponseWriter, r *http.Request) { |
| 91 | + // Authorize the user and return on failure |
| 92 | + if !app.auth(w, r) { |
| 93 | + return |
| 94 | + } |
| 95 | + // Say hello |
| 96 | + w.Header().Add("content-type", "text/html") |
| 97 | + io.WriteString(w, "Hello World.\n") |
| 98 | +} |
| 99 | + |
| 100 | +// An example of how to hash a password and store it |
| 101 | +func (app *application) hashHandler(w http.ResponseWriter, r *http.Request) { |
| 102 | + pass := r.URL.Query().Get("pass") |
| 103 | + sum := sha256.Sum256([]byte(pass)) |
| 104 | + w.Header().Add("content-type", "text/html") |
| 105 | + io.WriteString(w, base64.StdEncoding.EncodeToString(sum[:])) |
| 106 | +} |
0 commit comments