-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathencoding.go
136 lines (108 loc) · 2.89 KB
/
encoding.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
127
128
129
130
131
132
133
134
135
136
package pvx
import (
"bytes"
"encoding/base64"
"encoding/binary"
"encoding/json"
"fmt"
"strings"
)
// encode performs json.Marshalling for claims and serialize footer interface (not necessary JSON) to byte slice if it is present.
func encode(claims Claims, footerObj interface{}) ([]byte, []byte, error) {
var (
payload []byte
err error
)
if claims != nil {
payload, err = json.Marshal(claims)
} else {
payload, err = json.Marshal(struct{}{})
}
if err != nil {
return nil, nil, fmt.Errorf("json.Marshal problem with claims: %w", err)
}
footer := []byte("")
if footerObj != nil {
footer, err = encodeFooter(footerObj)
if err != nil {
return nil, nil, err
}
}
return payload, footer, nil
}
func b64(src []byte) string {
b64RawURL := base64.RawURLEncoding
dst := make([]byte, b64RawURL.EncodedLen(len(src)))
b64RawURL.Encode(dst, src)
return string(dst)
}
func decodeB64ToRawBinary(token string, headerLen int) (message, footer []byte, err error) {
var (
base64EncodedPayload []byte
base64EncodedFooter []byte
)
parts := strings.Split(token[headerLen:], ".")
switch len(parts) {
case 1:
base64EncodedPayload = []byte(parts[0])
case 2:
base64EncodedPayload, base64EncodedFooter = []byte(parts[0]), []byte(parts[1])
default:
return nil, nil, ErrMalformedToken
}
base64RawURL := base64.RawURLEncoding
message = make([]byte, base64RawURL.DecodedLen(len(base64EncodedPayload)))
if _, err := base64RawURL.Decode(message, base64EncodedPayload); err != nil {
return nil, nil, fmt.Errorf("failed to decode message claims from base64: %w", err)
}
if len(base64EncodedFooter) > 0 {
footer = make([]byte, base64RawURL.DecodedLen(len(base64EncodedFooter)))
if _, err := base64RawURL.Decode(footer, base64EncodedFooter); err != nil {
return nil, nil, fmt.Errorf("failed to decode footer from base64: %w", err)
}
}
return message, footer, nil
}
func encodeFooter(i interface{}) ([]byte, error) {
switch v := i.(type) {
case nil:
return []byte(""), nil
case []byte:
return v, nil
case *[]byte:
if v != nil {
return *v, nil
}
case string:
return []byte(v), nil
case *string:
if v != nil {
return []byte(*v), nil
}
}
return json.Marshal(i)
}
func decodeFooter(data []byte, i interface{}) error {
switch f := i.(type) {
case *string:
*f = string(data)
case *[]byte:
*f = data
default:
if err := json.Unmarshal(data, i); err != nil {
return fmt.Errorf("problems while trying to unmarshal footer in JSON: %w", err)
}
}
return nil
}
// preAuthenticationEncoding is PAE(), find 2.2.1. PAE Definition of RFC
func preAuthenticationEncoding(pieces ...[]byte) []byte {
count := len(pieces)
output := &bytes.Buffer{}
_ = binary.Write(output, binary.LittleEndian, uint64(count))
for i := range pieces {
_ = binary.Write(output, binary.LittleEndian, uint64(len(pieces[i])))
output.Write(pieces[i])
}
return output.Bytes()
}