Commit 1eca32e

mo khan <mo@mokhan.ca>
2025-05-06 18:37:11
feat: add option to generate an HMAC SHA256 signature
1 parent 3a0c247
Changed files (3)
pkg/cookie/option.go
@@ -1,9 +1,11 @@
 package cookie
 
 import (
+	"fmt"
 	"net/http"
 	"time"
 
+	"github.com/xlgmokha/x/pkg/pls"
 	"github.com/xlgmokha/x/pkg/x"
 )
 
@@ -61,3 +63,9 @@ func WithExpiration(expires time.Time) x.Option[*http.Cookie] {
 		}
 	})
 }
+
+func WithSignedValue(value string, secret string) x.Option[*http.Cookie] {
+	signature := pls.GenerateHMAC256([]byte(secret), []byte(value))
+	expected := fmt.Sprintf("%v--%v", value, string(signature))
+	return WithValue(expected)
+}
pkg/cookie/option_test.go
@@ -1,11 +1,15 @@
 package cookie
 
 import (
+	"crypto/hmac"
+	"fmt"
 	"net/http"
 	"testing"
 	"time"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	"github.com/xlgmokha/x/pkg/pls"
 )
 
 func TestOption(t *testing.T) {
@@ -50,4 +54,20 @@ func TestOption(t *testing.T) {
 			assert.Equal(t, -1, cookie.MaxAge)
 		})
 	})
+
+	t.Run("WithSignedValue", func(t *testing.T) {
+		value := "1"
+		secret := "secret"
+		cookie := New("session", WithSignedValue(value, secret))
+
+		require.NotNil(t, cookie)
+		assert.NotEqual(t, "1", cookie.Value)
+		assert.NotEmpty(t, cookie.Value)
+
+		signature := pls.GenerateHMAC256([]byte(secret), []byte(value))
+		expected := fmt.Sprintf("%v--%v", value, string(signature))
+
+		assert.Equal(t, expected, cookie.Value)
+		assert.True(t, hmac.Equal([]byte(expected), []byte(cookie.Value)))
+	})
 }
pkg/pls/hmac.go
@@ -0,0 +1,12 @@
+package pls
+
+import (
+	"crypto/hmac"
+	"crypto/sha256"
+)
+
+func GenerateHMAC256(key, value []byte) []byte {
+	mac := hmac.New(sha256.New, key)
+	mac.Write(value)
+	return mac.Sum(nil)
+}