-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathurl_safe.go
126 lines (104 loc) · 2.63 KB
/
url_safe.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package itsdangerous
import (
"bytes"
"compress/zlib"
"encoding/json"
"fmt"
"io"
"time"
)
type URLSafeSerializer struct {
Signer
}
func NewURLSafeSerializer(secret, salt string) *URLSafeSerializer {
s := NewSigner(secret, salt)
return &URLSafeSerializer{Signer: *s}
}
func (s *URLSafeSerializer) Marshal(value interface{}) (string, error) {
encoded, err := urlSafeSerialize(value)
if err != nil {
return "", err
}
return s.Signer.Sign(encoded), nil
}
func (s *URLSafeSerializer) Unmarshal(signed string, value interface{}) error {
encoded, err := s.Signer.Unsign(signed)
if err != nil {
return err
}
return urlSafeDeserialize(encoded, value)
}
type URLSafeTimedSerializer struct {
TimestampSigner
}
func NewURLSafeTimedSerializer(secret, salt string) *URLSafeTimedSerializer {
s := NewTimestampSigner(secret, salt)
return &URLSafeTimedSerializer{TimestampSigner: *s}
}
func (s *URLSafeTimedSerializer) Marshal(value interface{}) (string, error) {
encoded, err := urlSafeSerialize(value)
if err != nil {
return "", err
}
return s.TimestampSigner.Sign(encoded), nil
}
func (s *URLSafeTimedSerializer) Unmarshal(signed string, value interface{}, maxAge time.Duration) error {
encoded, err := s.TimestampSigner.Unsign(signed, maxAge)
if err != nil {
return err
}
return urlSafeDeserialize(encoded, value)
}
func urlSafeSerialize(value interface{}) (string, error) {
jsonEncoded, err := json.Marshal(value)
if err != nil {
return "", fmt.Errorf("error JSON marshalling payload: %w", err)
}
compressed := false
var buf bytes.Buffer
zw := zlib.NewWriter(&buf)
_, err = zw.Write(jsonEncoded)
if err != nil {
return "", fmt.Errorf("error compressing payload: %w", err)
}
err = zw.Close()
if err != nil {
return "", fmt.Errorf("error compressing payload: %w", err)
}
if buf.Len() < len(jsonEncoded) {
jsonEncoded = buf.Bytes()
compressed = true
}
encoded := base64Encode(jsonEncoded)
if compressed {
encoded = "." + encoded
}
return encoded, nil
}
func urlSafeDeserialize(encoded string, value interface{}) error {
decompress := false
if encoded[0] == '.' {
decompress = true
encoded = encoded[1:]
}
decoded, err := base64Decode(encoded)
if err != nil {
return err
}
if decompress {
zr, err := zlib.NewReader(bytes.NewReader(decoded))
if err != nil {
return fmt.Errorf("Error decompressing payload: %w", err)
}
defer zr.Close()
decoded, err = io.ReadAll(zr)
if err != nil {
return fmt.Errorf("Error decompressing payload: %w", err)
}
}
err = json.Unmarshal([]byte(decoded), value)
if err != nil {
return fmt.Errorf("error JSON unmarshalling payload: %w", err)
}
return nil
}