aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/paseto/footer.go2
-rw-r--r--lib/paseto/message_test.go1
-rw-r--r--lib/paseto/payload.go4
-rw-r--r--lib/paseto/v4/public_mode.go23
-rw-r--r--lib/paseto/v4/public_mode_test.go66
5 files changed, 85 insertions, 11 deletions
diff --git a/lib/paseto/footer.go b/lib/paseto/footer.go
index acaa3714..ae4fff09 100644
--- a/lib/paseto/footer.go
+++ b/lib/paseto/footer.go
@@ -8,5 +8,5 @@ package paseto
// MUST NOT include sensitive information.
type Footer struct {
Data any `json:"data,omitempty"`
- PeerID string `json:"peer_id"`
+ PeerID string `json:"peer_id,omitempty"`
}
diff --git a/lib/paseto/message_test.go b/lib/paseto/message_test.go
index aa4f7a23..a3d21420 100644
--- a/lib/paseto/message_test.go
+++ b/lib/paseto/message_test.go
@@ -31,7 +31,6 @@ func TestNewMessage(t *testing.T) {
"peer_id": "sender"
},
"Payload": {
- "data": null,
"iss": "sender",
"sub": "test",
"aud": "receiver",
diff --git a/lib/paseto/payload.go b/lib/paseto/payload.go
index af889d77..346356f7 100644
--- a/lib/paseto/payload.go
+++ b/lib/paseto/payload.go
@@ -29,9 +29,9 @@ var (
// The claims follow RFC 7519 that includes issuer, subject, audience,
// expiration time, not-before time, issued-at, and ID.
type Payload struct {
- // Data defines actual information to be send in message.
+ // Data defines additional information to be send in message.
// Data must be JSON encodable.
- Data any `json:"data"`
+ Data any `json:"data,omitempty"`
// Issuer defines the peer ID that issued the payload.
Issuer string `json:"iss,omitempty"`
diff --git a/lib/paseto/v4/public_mode.go b/lib/paseto/v4/public_mode.go
index e4b281d7..7e54d505 100644
--- a/lib/paseto/v4/public_mode.go
+++ b/lib/paseto/v4/public_mode.go
@@ -95,6 +95,9 @@ func (pmode *PublicMode) Pack(msg paseto.Message, implicit []byte) (
if err != nil {
return ``, fmt.Errorf(`%s: %w`, logp, err)
}
+ if bytes.Equal(msg.RawFooter, []byte(`{}`)) {
+ msg.RawFooter = nil
+ }
token, err = pmode.Sign(msg.RawPayload, msg.RawFooter, implicit)
if err != nil {
return ``, fmt.Errorf(`%s: %w`, logp, err)
@@ -166,14 +169,20 @@ func (pmode *PublicMode) Unpack(token string, implicit []byte, msg *paseto.Messa
return fmt.Errorf(`%s: %w`, logp, err)
}
- err = json.Unmarshal(msg.RawFooter, &msg.Footer)
- if err != nil {
- return fmt.Errorf(`%w: %w`, paseto.ErrTokenFooter, err)
- }
+ var sender paseto.Peer
+ if msg.RawFooter != nil {
+ err = json.Unmarshal(msg.RawFooter, &msg.Footer)
+ if err != nil {
+ return fmt.Errorf(`%w: %w`, paseto.ErrTokenFooter, err)
+ }
- sender, ok := pmode.GetPeer(msg.Footer.PeerID)
- if !ok {
- return fmt.Errorf(`%s: %w %s`, logp, ErrPeerID, msg.Footer.PeerID)
+ var ok bool
+ sender, ok = pmode.GetPeer(msg.Footer.PeerID)
+ if !ok {
+ return fmt.Errorf(`%s: %w %s`, logp, ErrPeerID, msg.Footer.PeerID)
+ }
+ } else {
+ sender = pmode.Peer
}
if !ed25519.Verify(sender.PublicKey, msg.PAE, msg.Sig) {
diff --git a/lib/paseto/v4/public_mode_test.go b/lib/paseto/v4/public_mode_test.go
index 658facb8..3e060e8a 100644
--- a/lib/paseto/v4/public_mode_test.go
+++ b/lib/paseto/v4/public_mode_test.go
@@ -9,7 +9,10 @@ import (
"log"
"os"
"testing"
+ "testing/cryptotest"
+ "testing/synctest"
+ "git.sr.ht/~shulhan/pakakeh.go/lib/paseto"
"git.sr.ht/~shulhan/pakakeh.go/lib/test"
)
@@ -36,6 +39,69 @@ func (tvp *testVectorPublic) init() {
}
}
+func TestPublicMode_Pack(t *testing.T) {
+ cryptotest.SetGlobalRandom(t, 1)
+
+ listcase := []struct {
+ msg paseto.Message
+ desc string
+ expToken string
+ expRawPayload string
+ expRawFooter string
+ }{{
+ desc: `Empty`,
+ expToken: `v4.public.e316aAoBcV59pCXGKmxwuKl050jOA9gP9F5qCFWllfEHUzzEWqRtZDK29vC07QoCJZEd-6T_65tybe4uJRuErwwE`,
+ expRawPayload: `{}`,
+ }, {
+ desc: `FooterOnly`,
+ msg: paseto.Message{
+ Footer: paseto.Footer{
+ Data: `footer.data`,
+ },
+ },
+ expToken: `v4.public.e32fZEGqzzkbqRiMbrlQnsacHTa1RjMBuE5cgciyHTEQiUIwh67S106_rGBROlkJKu71axKQURDKqjLMS1E6liQF.eyJkYXRhIjoiZm9vdGVyLmRhdGEifQ`,
+ expRawPayload: `{}`,
+ expRawFooter: `{"data":"footer.data"}`,
+ }, {
+ desc: `PayloadAndFooter`,
+ msg: paseto.Message{
+ Payload: paseto.Payload{
+ Data: []byte{0x73, 0x68, 0x75, 0x6c},
+ },
+ Footer: paseto.Footer{
+ Data: `footer.data`,
+ },
+ },
+ expToken: `v4.public.eyJkYXRhIjoiYzJoMWJBPT0ifXIYsFygQyakjTQ2j500FIxcPKrE3B3G1Sid7NAvvZ9_yqAZgIhhMu4ojqiewIPw81G-ZvX7GO321Ofgvv8_Zgw.eyJkYXRhIjoiZm9vdGVyLmRhdGEifQ`,
+ expRawPayload: `{"data":"c2h1bA=="}`,
+ expRawFooter: `{"data":"footer.data"}`,
+ }}
+
+ seed, err := hex.DecodeString(`b4cbfb43df4ce210727d953e4a713307fa19bb7d9f85041438d9e11b942a3774`)
+ if err != nil {
+ t.Fatal(err)
+ }
+ pmode := NewPublicMode(``, [32]byte(seed))
+
+ synctest.Test(t, func(t *testing.T) {
+ for _, tc := range listcase {
+ gotToken, err := pmode.Pack(tc.msg, nil)
+ if err != nil {
+ t.Fatalf(`%s: %s`, tc.desc, err)
+ }
+ test.Assert(t, tc.desc, tc.expToken, gotToken)
+
+ msg := paseto.Message{}
+ err = UnpackPublicToken(&msg, gotToken, nil)
+ if err != nil {
+ t.Fatalf(`%s: %s`, tc.desc, err)
+ }
+ test.Assert(t, `RawPayload`, tc.expRawPayload, string(msg.RawPayload))
+ test.Assert(t, `RawFooter`, tc.expRawFooter, string(msg.RawFooter))
+ }
+ })
+}
+
func TestPublicMode_Sign(t *testing.T) {
logp := `TestPublicMode_Sign`