summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.nix25
-rw-r--r--srv/default.nix3
-rw-r--r--srv/src/api/api.go17
-rw-r--r--srv/src/api/auth.go10
-rw-r--r--srv/src/cmd/hash-password/main.go23
-rw-r--r--srv/src/cmd/mediocre-blog/main.go9
6 files changed, 70 insertions, 17 deletions
diff --git a/config.nix b/config.nix
index 95b2b0e..1e3726c 100644
--- a/config.nix
+++ b/config.nix
@@ -1,14 +1,19 @@
{
- runDir = "/tmp/mediocre-blog/run";
- dataDir = "/tmp/mediocre-blog/data";
+ runDir = "/tmp/mediocre-blog/run";
+ dataDir = "/tmp/mediocre-blog/data";
- powSecret = "ssshhh";
- mlSMTPAddr = "";
- mlSMTPAuth = "";
- mlPublicURL = "http://localhost:4000";
- listenProto = "tcp";
- listenAddr = ":4000";
+ powSecret = "ssshhh";
+ mlSMTPAddr = "";
+ mlSMTPAuth = "";
+ mlPublicURL = "http://localhost:4000";
+ listenProto = "tcp";
+ listenAddr = ":4000";
- # If empty then a derived static directory is used
- staticProxyURL = "http://127.0.0.1:4002";
+ # If empty then a derived static directory is used
+ staticProxyURL = "http://127.0.0.1:4002";
+
+ # password is "bar". This should definitely be changed for prod.
+ apiAuthUsers = {
+ "foo" = "$2a$13$0JdWlUfHc.3XimEMpEu1cuu6RodhUvzD9l7iiAqa4YkM3mcFV5Pxi";
+ };
}
diff --git a/srv/default.nix b/srv/default.nix
index 7067e1e..e7286b6 100644
--- a/srv/default.nix
+++ b/srv/default.nix
@@ -32,6 +32,9 @@
# listening
export MEDIOCRE_BLOG_LISTEN_PROTO="${config.listenProto}"
export MEDIOCRE_BLOG_LISTEN_ADDR="${config.listenAddr}"
+
+ # api
+ export MEDIOCRE_BLOG_API_AUTH_USERS='${builtins.toJSON config.apiAuthUsers}'
'';
build = buildGoModule {
diff --git a/srv/src/api/api.go b/srv/src/api/api.go
index a5ada2d..7538662 100644
--- a/srv/src/api/api.go
+++ b/srv/src/api/api.go
@@ -54,6 +54,11 @@ type Params struct {
// reverse-proxied there.
StaticDir string
StaticProxy *url.URL
+
+ // AuthUsers keys are usernames which are allowed to edit server-side data,
+ // and the values are the password hash which accompanies those users. The
+ // password hash must have been produced by NewPasswordHash.
+ AuthUsers map[string]string
}
// SetupCfg implement the cfg.Cfger interface.
@@ -176,6 +181,8 @@ func (a *api) handler() http.Handler {
return h
}
+ auther := NewAuther(a.params.AuthUsers)
+
mux := http.NewServeMux()
mux.Handle("/", staticHandler)
@@ -208,9 +215,13 @@ func (a *api) handler() http.Handler {
v2Mux.Handle("/posts/", a.renderPostHandler())
v2Mux.Handle("/assets/", http.StripPrefix("/assets",
apiutil.MethodMux(map[string]http.Handler{
- "GET": a.getPostAssetHandler(),
- "POST": formMiddleware(a.postPostAssetHandler()),
- "DELETE": formMiddleware(a.deletePostAssetHandler()),
+ "GET": a.getPostAssetHandler(),
+ "POST": authMiddleware(auther,
+ formMiddleware(a.postPostAssetHandler()),
+ ),
+ "DELETE": authMiddleware(auther,
+ formMiddleware(a.deletePostAssetHandler()),
+ ),
}),
))
v2Mux.Handle("/", a.renderIndexHandler())
diff --git a/srv/src/api/auth.go b/srv/src/api/auth.go
index e668d7b..0d946a3 100644
--- a/srv/src/api/auth.go
+++ b/srv/src/api/auth.go
@@ -3,13 +3,14 @@ package api
import (
"net/http"
+ "github.com/mediocregopher/blog.mediocregopher.com/srv/api/apiutil"
"golang.org/x/crypto/bcrypt"
)
// NewPasswordHash returns the hash of the given plaintext password, for use
// with Auther.
func NewPasswordHash(plaintext string) string {
- hashedPassword, err := bcrypt.GenerateFromPassword([]byte(plaintext), 12)
+ hashedPassword, err := bcrypt.GenerateFromPassword([]byte(plaintext), 13)
if err != nil {
panic(err)
}
@@ -48,9 +49,10 @@ func (a *auther) Allowed(username, password string) bool {
func authMiddleware(auther Auther, h http.Handler) http.Handler {
- respondUnauthorized := func(rw http.ResponseWriter) {
+ respondUnauthorized := func(rw http.ResponseWriter, r *http.Request) {
rw.Header().Set("WWW-Authenticate", `Basic realm="NOPE"`)
rw.WriteHeader(http.StatusUnauthorized)
+ apiutil.GetRequestLogger(r).WarnString(r.Context(), "unauthorized")
}
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
@@ -58,12 +60,12 @@ func authMiddleware(auther Auther, h http.Handler) http.Handler {
username, password, ok := r.BasicAuth()
if !ok {
- respondUnauthorized(rw)
+ respondUnauthorized(rw, r)
return
}
if !auther.Allowed(username, password) {
- respondUnauthorized(rw)
+ respondUnauthorized(rw, r)
return
}
diff --git a/srv/src/cmd/hash-password/main.go b/srv/src/cmd/hash-password/main.go
new file mode 100644
index 0000000..b787a4d
--- /dev/null
+++ b/srv/src/cmd/hash-password/main.go
@@ -0,0 +1,23 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strings"
+
+ "github.com/mediocregopher/blog.mediocregopher.com/srv/api"
+)
+
+func main() {
+
+ fmt.Fprint(os.Stderr, "Password: ")
+
+ line, err := bufio.NewReader(os.Stdin).ReadString('\n')
+
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Println(api.NewPasswordHash(strings.TrimSpace(line)))
+}
diff --git a/srv/src/cmd/mediocre-blog/main.go b/srv/src/cmd/mediocre-blog/main.go
index 092c4da..5cb4d5f 100644
--- a/srv/src/cmd/mediocre-blog/main.go
+++ b/srv/src/cmd/mediocre-blog/main.go
@@ -2,6 +2,7 @@ package main
import (
"context"
+ "encoding/json"
"os"
"os/signal"
"syscall"
@@ -55,6 +56,8 @@ func main() {
pathPrefix := cfg.String("path-prefix", "", "Prefix which is optionally applied to all URL paths rendered by the blog")
+ apiAuthUsersStr := cfg.String("api-auth-users", "{}", "JSON object with usernames as values and password hashes (produced by the hash-password binary) as values. Denotes users which are able to edit server-side data")
+
// initialization
err := cfg.Init(ctx)
@@ -128,6 +131,11 @@ func main() {
postStore := post.NewStore(postSQLDB)
postAssetStore := post.NewAssetStore(postSQLDB)
+ var apiAuthUsers map[string]string
+ if err := json.Unmarshal([]byte(*apiAuthUsersStr), &apiAuthUsers); err != nil {
+ logger.Fatal(ctx, "unmarshaling -api-auth-users", err)
+ }
+
apiParams.Logger = logger.WithNamespace("api")
apiParams.PowManager = powMgr
apiParams.PathPrefix = *pathPrefix
@@ -136,6 +144,7 @@ func main() {
apiParams.MailingList = ml
apiParams.GlobalRoom = chatGlobalRoom
apiParams.UserIDCalculator = chatUserIDCalc
+ apiParams.AuthUsers = apiAuthUsers
logger.Info(ctx, "listening")
a, err := api.New(apiParams)