diff options
| author | Shulhan <ms@kilabit.info> | 2026-03-30 16:03:49 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2026-03-30 16:27:50 +0700 |
| commit | 4110657def17a00fa715bc1c5c0d9b728c4085d0 (patch) | |
| tree | 8e0199e61d5de0fbc826a4fbb637e1e0c36c3ad5 /lib | |
| parent | cf94a6045d5e06b53101dac4a36d7b26be163b0b (diff) | |
| download | pakakeh.go-4110657def17a00fa715bc1c5c0d9b728c4085d0.tar.xz | |
paseto/v4: improve examples by splitting example and package
By not using the same package name in example, we can see how the package
actually used in real code.
For instance, we can know that constant publicHeader should be exported
so it could be used by Unpack method.
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/paseto/v4/local_mode_example_test.go | 6 | ||||
| -rw-r--r-- | lib/paseto/v4/public_mode.go | 17 | ||||
| -rw-r--r-- | lib/paseto/v4/public_mode_example_test.go | 110 |
3 files changed, 72 insertions, 61 deletions
diff --git a/lib/paseto/v4/local_mode_example_test.go b/lib/paseto/v4/local_mode_example_test.go index a9708935..af3b1e60 100644 --- a/lib/paseto/v4/local_mode_example_test.go +++ b/lib/paseto/v4/local_mode_example_test.go @@ -1,12 +1,14 @@ // SPDX-License-Identifier: BSD-3-Clause // SPDX-FileCopyrightText: 2026 M. Shulhan <ms@kilabit.info> -package pasetov4 +package pasetov4_test import ( "encoding/hex" "fmt" "log" + + pasetov4 "git.sr.ht/~shulhan/pakakeh.go/lib/paseto/v4" ) func ExampleLocalMode() { @@ -15,7 +17,7 @@ func ExampleLocalMode() { if err != nil { log.Fatal(err) } - lmode := NewLocalMode([32]byte(key)) + lmode := pasetov4.NewLocalMode([32]byte(key)) plain := []byte(`{"data":"Hello, secret!"}`) footer := []byte(`{"kid":1000}`) token, err := lmode.Encrypt(plain, footer, nil) diff --git a/lib/paseto/v4/public_mode.go b/lib/paseto/v4/public_mode.go index 776a8f06..10e19cd6 100644 --- a/lib/paseto/v4/public_mode.go +++ b/lib/paseto/v4/public_mode.go @@ -16,7 +16,8 @@ import ( "git.sr.ht/~shulhan/pakakeh.go/lib/paseto" ) -const publicHeader = `v4.public.` +// PublicHeader defines the public header in generated token. +const PublicHeader = `v4.public.` // List of errors for [PublicMode.Unpack] and [PublicMode.Verify]. var ( @@ -25,8 +26,10 @@ var ( ErrPublicKey = errors.New(`invalid or empty public key`) ) -// PublicMode contains ed25519 private and public key for signing and -// verifying message. +// PublicMode represents paseto v4 public protocol. +// It contains ed25519 private and public key for signing and +// verifying message, and list of known peers for verifying the peer's +// message. type PublicMode struct { peers map[string]paseto.Peer @@ -112,7 +115,7 @@ func (pmode *PublicMode) Sign(payload, footer, implicit []byte) ( logp := `Sign` // Step 3: pack header, message, footer, and implicit. - pae, err := paseto.PreAuthEncode([]byte(publicHeader), + pae, err := paseto.PreAuthEncode([]byte(PublicHeader), payload, footer, implicit) if err != nil { return ``, fmt.Errorf(`%s: %w`, logp, err) @@ -124,7 +127,7 @@ func (pmode *PublicMode) Sign(payload, footer, implicit []byte) ( // Step 5: Pack all into token, var buf bytes.Buffer - buf.WriteString(publicHeader) + buf.WriteString(PublicHeader) paysig := slices.Concat(payload, sig) n := base64.RawURLEncoding.EncodedLen(len(paysig)) @@ -153,7 +156,7 @@ func (pmode *PublicMode) Unpack(token string, implicit []byte, msg *paseto.Messa ) { logp := `Unpack` - err = msg.Unpack(publicHeader, token, implicit) + err = msg.Unpack(PublicHeader, token, implicit) if err != nil { return fmt.Errorf(`%s: %w`, logp, err) } @@ -188,7 +191,7 @@ func (pmode *PublicMode) Verify(token string, implicit []byte) ( logp := `Verify` msg := &paseto.Message{} - err = msg.Unpack(publicHeader, token, implicit) + err = msg.Unpack(PublicHeader, token, implicit) if err != nil { return nil, nil, fmt.Errorf(`%s: %w`, logp, err) } diff --git a/lib/paseto/v4/public_mode_example_test.go b/lib/paseto/v4/public_mode_example_test.go index 8ca3536e..49f98ce0 100644 --- a/lib/paseto/v4/public_mode_example_test.go +++ b/lib/paseto/v4/public_mode_example_test.go @@ -1,34 +1,55 @@ // SPDX-License-Identifier: BSD-3-Clause // SPDX-FileCopyrightText: 2026 M. Shulhan <ms@kilabit.info> -package pasetov4 +package pasetov4_test import ( - "encoding/base64" "encoding/hex" "encoding/json" "fmt" "log" - "strings" "git.sr.ht/~shulhan/pakakeh.go/lib/paseto" + pasetov4 "git.sr.ht/~shulhan/pakakeh.go/lib/paseto/v4" ) -func ExamplePublicMode() { +func ExamplePublicMode_Sign() { secret := `b4cbfb43df4ce210727d953e4a713307fa19bb7d9f85041438d9e11b942a3774` seed, err := hex.DecodeString(secret) if err != nil { log.Fatal(err) } - pmode := NewPublicMode([32]byte(seed)) + pmode := pasetov4.NewPublicMode([32]byte(seed)) - plain := []byte(`{"data":"signed message!"}`) - footer := []byte(`{"kid":1000}`) - token, err := pmode.Sign(plain, footer, nil) + payload := []byte(`{"data":"signed message!"}`) + footer := []byte(`{"peer_id":1000}`) + + token, err := pmode.Sign(payload, footer, nil) if err != nil { log.Fatal(err) } + msg := paseto.Message{} + msg.Unpack(pasetov4.PublicHeader, token, nil) + + fmt.Printf("Payload: %s\n", msg.RawPayload) + fmt.Printf("Footer: %s\n", msg.RawFooter) + + // Output: + // Payload: {"data":"signed message!"} + // Footer: {"peer_id":1000} +} + +func ExamplePublicMode_Verify() { + secret := `b4cbfb43df4ce210727d953e4a713307fa19bb7d9f85041438d9e11b942a3774` + seed, err := hex.DecodeString(secret) + if err != nil { + log.Fatal(err) + } + pmode := pasetov4.NewPublicMode([32]byte(seed)) + + token := `v4.public.eyJkYXRhIjoic2lnbmVkIG1lc3NhZ2UhIn0kqxCoccpjcXj3jNt6Q8cafIIF2JpapJrFNWi0mBJKS-Q3IU4dXZx-_Qx3P7LtSPnHyu6deqdeg72jb6hTCz4E.eyJwZWVyX2lkIjoxMDAwfQ` + gotPlain, gotFooter, err := pmode.Verify(token, nil) if err != nil { log.Fatal(err) @@ -38,23 +59,18 @@ func ExamplePublicMode() { // Output: // {"data":"signed message!"} - // {"kid":1000} -} - -type DummyData struct { - Email string `json:"email"` -} -type DummyFooterData struct { - Quote string `json:"quote"` + // {"peer_id":1000} } func ExamplePublicMode_Pack() { - createPeer := func(id, secret string) (peer paseto.Peer, pmode *PublicMode) { + createPeer := func(id, secret string) ( + peer paseto.Peer, pmode *pasetov4.PublicMode, + ) { seed, err := hex.DecodeString(secret) if err != nil { log.Fatal(err) } - pmode = NewPublicMode([32]byte(seed)) + pmode = pasetov4.NewPublicMode([32]byte(seed)) peer = paseto.Peer{ ID: id, Private: pmode.PrivateKey, @@ -72,11 +88,11 @@ func ExamplePublicMode_Pack() { ) sendMsg := paseto.NewMessage(sender, receiver, `hello`) - sendMsg.Payload.Data = DummyData{ - Email: `hello@example.com`, + sendMsg.Payload.Data = map[string]string{ + `email`: `hello@example.com`, } - sendMsg.Footer.Data = DummyFooterData{ - Quote: `Live to eat`, + sendMsg.Footer.Data = map[string]string{ + `quote`: `Live to eat`, } token, err := senderpm.Pack(*sendMsg, nil) @@ -84,33 +100,28 @@ func ExamplePublicMode_Pack() { log.Fatal(err) } - pieces := strings.Split(token, `.`) - fmt.Printf("Header: %s.%s\n", pieces[0], pieces[1]) + msg := paseto.Message{} + msg.Unpack(pasetov4.PublicHeader, token, nil) - paysig, _ := base64.RawURLEncoding.DecodeString(pieces[2]) - payload := paysig[:len(paysig)-64] - pdata := paseto.Payload{ - Data: &DummyData{}, - } - _ = json.Unmarshal(payload, &pdata) + pdata := paseto.Payload{} + _ = json.Unmarshal(msg.RawPayload, &pdata) fmt.Printf("Payload.Data: %+v\n", pdata.Data) - - footer, _ := base64.RawURLEncoding.DecodeString(pieces[3]) - fmt.Printf("Footer: %s", footer) + fmt.Printf("Footer: %s", msg.RawFooter) // Output: - // Header: v4.public - // Payload.Data: &{Email:hello@example.com} + // Payload.Data: map[email:hello@example.com] // Footer: {"data":{"quote":"Live to eat"},"peer_id":"john@example.com"} } func ExamplePublicMode_Unpack() { - createPeer := func(id, secret string) (peer paseto.Peer, pmode *PublicMode) { + createPeer := func(id, secret string) ( + peer paseto.Peer, pmode *pasetov4.PublicMode, + ) { seed, err := hex.DecodeString(secret) if err != nil { log.Fatal(err) } - pmode = NewPublicMode([32]byte(seed)) + pmode = pasetov4.NewPublicMode([32]byte(seed)) peer = paseto.Peer{ ID: id, Private: pmode.PrivateKey, @@ -126,27 +137,22 @@ func ExamplePublicMode_Unpack() { `jane@example.org`, `2222222222222222222222222222222222222222222222222222222222222222`, ) + + // Add the sender to list of receiver's peer. recvpm.AddPeer(sender) - token := `v4.public.eyJpc3MiOiJqb2huQGV4YW1wbGUuY29tIiwic3ViIjoiaGVsbG8iLCJhdWQiOiJqYW5lQGV4YW1wbGUub3JnIiwiZXhwIjoxNzc0ODE5NzYzLCJuYmYiOjE3NzQ4MTk3MDMsImlhdCI6MTc3NDgxOTcwMywiZGF0YSI6eyJlbWFpbCI6ImhlbGxvQGV4YW1wbGUuY29tIn19Ui741xeDUhQE2w31smKyAJ_d-fhMH20SRLkIY3lDbIBfj_tq7es9-H2wQR3q6EZZRPrlAPxEug712IEgomTnBA.eyJkYXRhIjp7InF1b3RlIjoiTGlmZSBpcyBmb3IgZWF0aW5nIn0sInBlZXJfaWQiOiJqb2huQGV4YW1wbGUuY29tIn0` - pdata := DummyData{} - fdata := DummyFooterData{} - recvMsg := paseto.Message{ - Payload: paseto.Payload{ - Data: &pdata, - }, - Footer: paseto.Footer{ - Data: &fdata, - }, - } + // This is the token send by sender. + token := `v4.public.eyJkYXRhIjp7ImVtYWlsIjoiaGVsbG9AZXhhbXBsZS5jb20ifSwiaXNzIjoiam9obkBleGFtcGxlLmNvbSIsInN1YiI6ImhlbGxvIiwiYXVkIjoiamFuZUBleGFtcGxlLm9yZyIsImV4cCI6MTc3NDg1OTg4OSwibmJmIjoxNzc0ODU5ODI5LCJpYXQiOjE3NzQ4NTk4Mjl9eGHMkOlYiVchKl1GqQwSMyTC8eWCpXhNJHGHq_MEJNqlKur-kPpHqY-hWHoh4I1RaBq68MN_TNveqwPIbk9iBQ.eyJkYXRhIjp7InF1b3RlIjoiTGl2ZSB0byBlYXQifSwicGVlcl9pZCI6ImpvaG5AZXhhbXBsZS5jb20ifQ` + + recvMsg := paseto.Message{} err := recvpm.Unpack(token, nil, &recvMsg) if err != nil { log.Fatal(err) } - fmt.Printf("%+v\n", recvMsg.Payload.Data) - fmt.Printf("%+v\n", recvMsg.Footer.Data) + fmt.Printf("Payload.Data: %+v\n", recvMsg.Payload.Data) + fmt.Printf("Footer: %+v\n", recvMsg.Footer) // Output: - // &{Email:hello@example.com} - // &{Quote:Life is for eating} + // Payload.Data: map[email:hello@example.com] + // Footer: {Data:map[quote:Live to eat] PeerID:john@example.com} } |
