-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathinline.go
More file actions
137 lines (126 loc) · 2.91 KB
/
inline.go
File metadata and controls
137 lines (126 loc) · 2.91 KB
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
137
package sweetcookie
import (
"encoding/base64"
"encoding/json"
"errors"
"os"
"time"
)
func inlineAny(in InlineCookies) bool {
return len(in.JSON) > 0 || in.Base64 != "" || in.File != ""
}
type inlinePayload struct {
Cookies []inlineCookie `json:"cookies"`
}
type inlineCookie struct {
Name string `json:"name"`
Value string `json:"value"`
Domain string `json:"domain"`
Path string `json:"path"`
Secure bool `json:"secure"`
HTTPOnly bool `json:"httpOnly"`
SameSite string `json:"sameSite"`
Expires interface{} `json:"expires"`
}
func readInlineCookies(in InlineCookies) ([]Cookie, []string, error) {
raw, warnings, err := readInlineBytes(in)
if err != nil {
return nil, warnings, err
}
raw = bytesTrimSpace(raw)
if len(raw) == 0 {
return nil, warnings, errors.New("sweetcookie: inline cookies empty")
}
// Support both `Cookie[]` and `{ cookies: Cookie[] }`.
var payload inlinePayload
if err := json.Unmarshal(raw, &payload); err == nil && len(payload.Cookies) > 0 {
return inlineToCookies(payload.Cookies), warnings, nil
}
var arr []inlineCookie
if err := json.Unmarshal(raw, &arr); err != nil {
return nil, warnings, err
}
return inlineToCookies(arr), warnings, nil
}
func readInlineBytes(in InlineCookies) ([]byte, []string, error) {
switch {
case len(in.JSON) > 0:
return in.JSON, nil, nil
case in.Base64 != "":
b, err := base64.StdEncoding.DecodeString(in.Base64)
if err != nil {
return nil, nil, err
}
return b, nil, nil
case in.File != "":
b, err := os.ReadFile(in.File)
if err != nil {
return nil, nil, err
}
return b, nil, nil
default:
return nil, nil, errors.New("sweetcookie: no inline cookie source provided")
}
}
func inlineToCookies(in []inlineCookie) []Cookie {
if len(in) == 0 {
return nil
}
out := make([]Cookie, 0, len(in))
for _, c := range in {
cc := Cookie{
Name: c.Name,
Value: c.Value,
Domain: c.Domain,
Path: c.Path,
Secure: c.Secure,
HTTPOnly: c.HTTPOnly,
SameSite: normalizeSameSite(c.SameSite),
Source: Source{
Browser: BrowserInline,
},
}
if expires := parseInlineExpires(c.Expires); expires != nil {
cc.Expires = expires
}
out = append(out, cc)
}
return out
}
func parseInlineExpires(v interface{}) *time.Time {
switch vv := v.(type) {
case nil:
return nil
case float64:
// JSON numbers come through as float64.
sec := int64(vv)
if sec <= 0 {
return nil
}
t := time.Unix(sec, 0).UTC()
return &t
case string:
if vv == "" {
return nil
}
if t, err := time.Parse(time.RFC3339, vv); err == nil {
tt := t.UTC()
return &tt
}
return nil
default:
return nil
}
}
func normalizeSameSite(v string) SameSite {
switch v {
case "Strict", "strict":
return SameSiteStrict
case "Lax", "lax":
return SameSiteLax
case "None", "none", "NoRestriction", "no_restriction":
return SameSiteNone
default:
return ""
}
}