Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rageshake: Add file server with basic auth #3169

Merged
merged 2 commits into from
Feb 8, 2017
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions scripts/rageshake.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// Run a web server capable of dumping bug reports sent by Riot.
// Requires Go 1.5+
// Usage: go run rageshake.go PORT
// Example: go run rageshake.go 8080
// Usage: BUGS_USER=user BUGS_PASS=password go run rageshake.go PORT
// Example: BUGS_USER=alice BUGS_PASS=secret go run rageshake.go 8080
package main

import (
"bytes"
"compress/gzip"
"crypto/subtle"
"encoding/json"
"fmt"
"io/ioutil"
Expand Down Expand Up @@ -61,6 +62,22 @@ func gzipAndSave(data []byte, dirname, fpath string) error {
return nil
}

func basicAuth(handler http.Handler, username, password, realm string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
user, pass, ok := r.BasicAuth() // pull creds from the request

// check user and pass securely
if !ok || subtle.ConstantTimeCompare([]byte(user), []byte(username)) != 1 || subtle.ConstantTimeCompare([]byte(pass), []byte(password)) != 1 {
w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`)
w.WriteHeader(401)
w.Write([]byte("Unauthorised.\n"))
return
}

handler.ServeHTTP(w, r)
})
}

func main() {
http.HandleFunc("/api/submit", func(w http.ResponseWriter, req *http.Request) {
if req.Method != "POST" && req.Method != "OPTIONS" {
Expand Down Expand Up @@ -110,6 +127,20 @@ func main() {
// Make sure bugs directory exists
_ = os.Mkdir("bugs", os.ModePerm)

// serve files under "bugs"
fs := http.FileServer(http.Dir("bugs"))
fs = http.StripPrefix("/api/listing/", fs)

// set auth if env vars exist
usr := os.Getenv("BUGS_USER")
pass := os.Getenv("BUGS_PASS")
if usr == "" || pass == "" {
fmt.Println("BUGS_USER and BUGS_PASS env vars not found. No authentication is running for /api/listing")
} else {
fs = basicAuth(fs, usr, pass, "Enter username and password")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't realm normally something like Riot bug reports?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's an arbitrary string which is sent to the client in a popup, which is usually prefixed with "This website says: REALM" hence the request to enter u/p. I don't care what this is called, so I'll change it to whatever.

Copy link
Member

@richvdh richvdh Feb 8, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's more than that. It is specifically used to identify things which should have the same u/p on a domain. Obviously if different apps with different auth all use "Enter username and password" that's no good.

Also, some clients may show "Enter the username and password for <realm>".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}
http.Handle("/api/listing/", fs)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so a link to an individual report will be /api/listing/2017-02-07/205222 ? How about /reports instead of /api/listing ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not the link that will be present for our deployment. The Apache is configured to route riot.im/bugreports/* to /api/* so the individual report is linked as https://riot.im/bugreports/listing/2017-02-07/205222. I can rename listing to reports if you want to be redundant.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh. so why /api then? Why not just /submit and /listing (or /reports).

I suddenly realise I don't actually care about this, though. Do as you see fit :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We as a team have certain conventions when it comes to Go and HTTP servers. One of them is that everything public is served under /api so that you can attach Prometheus metrics (which hook into /metrics) and pprof tooling (which hook into /debug/pprof) without making those endpoints visible to the wider internet which would be the case if we attached to /. See https://docs.google.com/document/d/1yu7qImAcr-_yN72Ndb5ht_zjyK0hxXQGZQYIKFaGBXw/edit


port := os.Args[1]
log.Fatal(http.ListenAndServe(":"+port, nil))
}