From f4dec10e8f097e79b4bba3187431ecf3c4899083 Mon Sep 17 00:00:00 2001
From: ale <ale@incal.net>
Date: Fri, 6 Dec 2019 10:49:33 +0000
Subject: [PATCH] Use a response field instead of a 404 when no keys are found

This makes it easier to detect unexpected errors.
---
 client/client.go | 15 ++++++++++++---
 protocol.go      |  3 ++-
 server/server.go | 14 +++++++++-----
 3 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/client/client.go b/client/client.go
index 307f3eeb..5ffa3951 100644
--- a/client/client.go
+++ b/client/client.go
@@ -2,12 +2,16 @@ package client
 
 import (
 	"context"
+	"errors"
 
 	"git.autistici.org/ai3/go-common/clientutil"
 
 	"git.autistici.org/id/keystore"
 )
 
+// ErrNoKeys indicates that the user has no encryption keys.
+var ErrNoKeys = errors.New("no keys available")
+
 // Client for the keystore API.
 type Client interface {
 	Open(context.Context, string, string, string, int) error
@@ -19,9 +23,8 @@ type ksClient struct {
 	be clientutil.Backend
 }
 
-// New returns a new Client with the given Config. Use this when the
-// keystore service runs on a single global instance.
-func New(config *clientutil.BackendConfig) (*ksClient, error) {
+// New returns a new Client with the given backend Config.
+func New(config *clientutil.BackendConfig) (Client, error) {
 	be, err := clientutil.NewBackend(config)
 	if err != nil {
 		return nil, err
@@ -46,6 +49,12 @@ func (c *ksClient) Get(ctx context.Context, shard, username, ssoTicket string) (
 	}
 	var resp keystore.GetResponse
 	err := c.be.Call(ctx, shard, "/api/get_key", &req, &resp)
+	if err != nil {
+		return nil, err
+	}
+	if !resp.HasKey {
+		return nil, ErrNoKeys
+	}
 	return resp.Key, err
 }
 
diff --git a/protocol.go b/protocol.go
index 0e65499f..fc6113e3 100644
--- a/protocol.go
+++ b/protocol.go
@@ -14,7 +14,8 @@ type GetRequest struct {
 }
 
 type GetResponse struct {
-	Key []byte `json:"key"`
+	HasKey bool   `json:"has_key"`
+	Key    []byte `json:"key"`
 }
 
 type CloseRequest struct {
diff --git a/server/server.go b/server/server.go
index ba17efd1..71a3eb22 100644
--- a/server/server.go
+++ b/server/server.go
@@ -41,22 +41,26 @@ func (s *keyStoreServer) handleGet(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
+	var resp keystore.GetResponse
 	key, err := s.KeyStore.Get(req.Username, req.SSOTicket)
-	if err != nil {
-		log.Printf("Get(%s) error: %v", req.Username, err)
+	if err == errNoKeys {
+		log.Printf("no keys for %s", req.Username)
+	} else if err != nil {
 		// Return an appropriate error code.
 		switch err {
 		case errUnauthorized, errBadUser:
 			http.Error(w, err.Error(), http.StatusForbidden)
-		case errNoKeys:
-			http.NotFound(w, r)
 		default:
+			log.Printf("Get(%s) error: %v", req.Username, err)
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 		}
 		return
+	} else {
+		resp.HasKey = true
+		resp.Key = key
 	}
 
-	serverutil.EncodeJSONResponse(w, &keystore.GetResponse{Key: key})
+	serverutil.EncodeJSONResponse(w, &resp)
 }
 
 func (s *keyStoreServer) handleClose(w http.ResponseWriter, r *http.Request) {
-- 
GitLab