From 4fbc56b08f53d480871806d113d6db499b4e7e93 Mon Sep 17 00:00:00 2001
From: meskio <meskio@sindominio.net>
Date: Tue, 29 Sep 2020 11:09:54 +0200
Subject: [PATCH] Renew token API

---
 api/api.go         |  1 +
 api/auth.go        | 36 ++++++++++++++++++++++++++++++++++++
 api/auth_test.go   | 42 +++++++++++++++++++++++++-----------------
 api/member_test.go | 17 ++++++++++++-----
 4 files changed, 74 insertions(+), 22 deletions(-)

diff --git a/api/api.go b/api/api.go
index 065d611..91d8705 100644
--- a/api/api.go
+++ b/api/api.go
@@ -35,6 +35,7 @@ func Init(dbPath string, signKey string, r *mux.Router) error {
 	log.Print(token)
 
 	r.HandleFunc("/signin", a.SignIn).Methods("POST")
+	r.HandleFunc("/token", a.GetToken).Methods("GET")
 
 	r.HandleFunc("/member", a.authAdmin(a.ListMembers)).Methods("GET")
 	r.HandleFunc("/member", a.authAdmin(a.AddMember)).Methods("POST")
diff --git a/api/auth.go b/api/auth.go
index b8c747b..94eba5a 100644
--- a/api/auth.go
+++ b/api/auth.go
@@ -59,6 +59,42 @@ func (a *api) SignIn(w http.ResponseWriter, req *http.Request) {
 	}
 }
 
+func (a *api) GetToken(w http.ResponseWriter, req *http.Request) {
+	token := req.Header.Get("x-authentication")
+	ok, claims := a.validateToken(token)
+	if !ok {
+		w.WriteHeader(http.StatusUnauthorized)
+		return
+	}
+	num, ok := claims["num"].(float64)
+	if !ok {
+		w.WriteHeader(http.StatusUnauthorized)
+		return
+	}
+	role, ok := claims["role"].(string)
+	if !ok {
+		w.WriteHeader(http.StatusUnauthorized)
+		return
+	}
+
+	w.Header().Set("Content-Type", "application/json")
+	w.WriteHeader(http.StatusOK)
+
+	token, err := a.newToken(int(num), role)
+	if err != nil {
+		log.Printf("Can't create a token: %v", err)
+		w.WriteHeader(http.StatusInternalServerError)
+		return
+	}
+	err = json.NewEncoder(w).Encode(map[string]interface{}{
+		"token": token,
+	})
+	if err != nil {
+		log.Printf("Can't encode token: %v", err)
+		w.WriteHeader(http.StatusInternalServerError)
+	}
+}
+
 func (a *api) auth(fn func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
 	return func(w http.ResponseWriter, req *http.Request) {
 		token := req.Header.Get("x-authentication")
diff --git a/api/auth_test.go b/api/auth_test.go
index 3f5dbef..a7a9d36 100644
--- a/api/auth_test.go
+++ b/api/auth_test.go
@@ -8,22 +8,10 @@ import (
 func TestSignIn(t *testing.T) {
 	tapi := newTestAPI(t)
 	defer tapi.close()
-
-	var member struct {
-		Member
-		Password string `json:"password"`
-	}
-	member.Num = 10
-	member.Name = "foo"
-	member.Role = "admin"
-	member.Password = "password"
-	resp := tapi.do("POST", "/member", member, nil)
-	if resp.StatusCode != http.StatusCreated {
-		t.Fatal("Can't create member:", resp.Status)
-	}
+	tapi.addTestMember()
 
 	tapi.token = ""
-	resp = tapi.do("GET", "/member", nil, nil)
+	resp := tapi.do("GET", "/member", nil, nil)
 	if resp.StatusCode != http.StatusUnauthorized {
 		t.Error("Got members without auth")
 	}
@@ -33,14 +21,14 @@ func TestSignIn(t *testing.T) {
 		Member Member `json:"member"`
 	}
 	jsonAuth := creds{
-		Name:     member.Name,
-		Password: member.Password,
+		Name:     testMember.Name,
+		Password: testMember.Password,
 	}
 	resp = tapi.do("POST", "/signin", jsonAuth, &respMember)
 	if resp.StatusCode != http.StatusOK {
 		t.Fatal("Can't sign in:", resp.Status)
 	}
-	if respMember.Member.Name != member.Name {
+	if respMember.Member.Name != testMember.Name {
 		t.Fatal("Unexpected member:", respMember)
 	}
 	tapi.token = respMember.Token
@@ -49,3 +37,23 @@ func TestSignIn(t *testing.T) {
 		t.Fatal("Can't get members:", resp.Status)
 	}
 }
+
+func TestGetToken(t *testing.T) {
+	tapi := newTestAPI(t)
+	defer tapi.close()
+	tapi.addTestMember()
+
+	var body struct {
+		Token string `json:"token"`
+	}
+	resp := tapi.do("GET", "/token", nil, &body)
+	if resp.StatusCode != http.StatusOK {
+		t.Fatal("Can't get token:", resp.Status)
+	}
+
+	tapi.token = body.Token
+	resp = tapi.do("GET", "/member", nil, nil)
+	if resp.StatusCode != http.StatusOK {
+		t.Fatal("Can't get members:", resp.Status)
+	}
+}
diff --git a/api/member_test.go b/api/member_test.go
index 679970c..7ef260d 100644
--- a/api/member_test.go
+++ b/api/member_test.go
@@ -5,11 +5,18 @@ import (
 	"testing"
 )
 
-var testMember = Member{
-	Num:     10,
-	Name:    "foo",
-	Email:   "foo@example.com",
-	Balance: 10000,
+var testMember = struct {
+	Member
+	Password string `json:"password"`
+}{
+	Member: Member{
+		Num:     10,
+		Name:    "foo",
+		Email:   "foo@example.com",
+		Role:    "admin",
+		Balance: 10000,
+	},
+	Password: "password",
 }
 
 func TestMemberAddList(t *testing.T) {
-- 
GitLab