aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/minio/minio-go/v7/post-policy.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/minio/minio-go/v7/post-policy.go')
-rw-r--r--vendor/github.com/minio/minio-go/v7/post-policy.go349
1 files changed, 349 insertions, 0 deletions
diff --git a/vendor/github.com/minio/minio-go/v7/post-policy.go b/vendor/github.com/minio/minio-go/v7/post-policy.go
new file mode 100644
index 0000000..3f4881e
--- /dev/null
+++ b/vendor/github.com/minio/minio-go/v7/post-policy.go
@@ -0,0 +1,349 @@
1/*
2 * MinIO Go Library for Amazon S3 Compatible Cloud Storage
3 * Copyright 2015-2023 MinIO, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package minio
19
20import (
21 "encoding/base64"
22 "fmt"
23 "net/http"
24 "strings"
25 "time"
26
27 "github.com/minio/minio-go/v7/pkg/encrypt"
28)
29
30// expirationDateFormat date format for expiration key in json policy.
31const expirationDateFormat = "2006-01-02T15:04:05.000Z"
32
33// policyCondition explanation:
34// http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html
35//
36// Example:
37//
38// policyCondition {
39// matchType: "$eq",
40// key: "$Content-Type",
41// value: "image/png",
42// }
43type policyCondition struct {
44 matchType string
45 condition string
46 value string
47}
48
49// PostPolicy - Provides strict static type conversion and validation
50// for Amazon S3's POST policy JSON string.
51type PostPolicy struct {
52 // Expiration date and time of the POST policy.
53 expiration time.Time
54 // Collection of different policy conditions.
55 conditions []policyCondition
56 // ContentLengthRange minimum and maximum allowable size for the
57 // uploaded content.
58 contentLengthRange struct {
59 min int64
60 max int64
61 }
62
63 // Post form data.
64 formData map[string]string
65}
66
67// NewPostPolicy - Instantiate new post policy.
68func NewPostPolicy() *PostPolicy {
69 p := &PostPolicy{}
70 p.conditions = make([]policyCondition, 0)
71 p.formData = make(map[string]string)
72 return p
73}
74
75// SetExpires - Sets expiration time for the new policy.
76func (p *PostPolicy) SetExpires(t time.Time) error {
77 if t.IsZero() {
78 return errInvalidArgument("No expiry time set.")
79 }
80 p.expiration = t
81 return nil
82}
83
84// SetKey - Sets an object name for the policy based upload.
85func (p *PostPolicy) SetKey(key string) error {
86 if strings.TrimSpace(key) == "" || key == "" {
87 return errInvalidArgument("Object name is empty.")
88 }
89 policyCond := policyCondition{
90 matchType: "eq",
91 condition: "$key",
92 value: key,
93 }
94 if err := p.addNewPolicy(policyCond); err != nil {
95 return err
96 }
97 p.formData["key"] = key
98 return nil
99}
100
101// SetKeyStartsWith - Sets an object name that an policy based upload
102// can start with.
103// Can use an empty value ("") to allow any key.
104func (p *PostPolicy) SetKeyStartsWith(keyStartsWith string) error {
105 policyCond := policyCondition{
106 matchType: "starts-with",
107 condition: "$key",
108 value: keyStartsWith,
109 }
110 if err := p.addNewPolicy(policyCond); err != nil {
111 return err
112 }
113 p.formData["key"] = keyStartsWith
114 return nil
115}
116
117// SetBucket - Sets bucket at which objects will be uploaded to.
118func (p *PostPolicy) SetBucket(bucketName string) error {
119 if strings.TrimSpace(bucketName) == "" || bucketName == "" {
120 return errInvalidArgument("Bucket name is empty.")
121 }
122 policyCond := policyCondition{
123 matchType: "eq",
124 condition: "$bucket",
125 value: bucketName,
126 }
127 if err := p.addNewPolicy(policyCond); err != nil {
128 return err
129 }
130 p.formData["bucket"] = bucketName
131 return nil
132}
133
134// SetCondition - Sets condition for credentials, date and algorithm
135func (p *PostPolicy) SetCondition(matchType, condition, value string) error {
136 if strings.TrimSpace(value) == "" || value == "" {
137 return errInvalidArgument("No value specified for condition")
138 }
139
140 policyCond := policyCondition{
141 matchType: matchType,
142 condition: "$" + condition,
143 value: value,
144 }
145 if condition == "X-Amz-Credential" || condition == "X-Amz-Date" || condition == "X-Amz-Algorithm" {
146 if err := p.addNewPolicy(policyCond); err != nil {
147 return err
148 }
149 p.formData[condition] = value
150 return nil
151 }
152 return errInvalidArgument("Invalid condition in policy")
153}
154
155// SetContentType - Sets content-type of the object for this policy
156// based upload.
157func (p *PostPolicy) SetContentType(contentType string) error {
158 if strings.TrimSpace(contentType) == "" || contentType == "" {
159 return errInvalidArgument("No content type specified.")
160 }
161 policyCond := policyCondition{
162 matchType: "eq",
163 condition: "$Content-Type",
164 value: contentType,
165 }
166 if err := p.addNewPolicy(policyCond); err != nil {
167 return err
168 }
169 p.formData["Content-Type"] = contentType
170 return nil
171}
172
173// SetContentTypeStartsWith - Sets what content-type of the object for this policy
174// based upload can start with.
175// Can use an empty value ("") to allow any content-type.
176func (p *PostPolicy) SetContentTypeStartsWith(contentTypeStartsWith string) error {
177 policyCond := policyCondition{
178 matchType: "starts-with",
179 condition: "$Content-Type",
180 value: contentTypeStartsWith,
181 }
182 if err := p.addNewPolicy(policyCond); err != nil {
183 return err
184 }
185 p.formData["Content-Type"] = contentTypeStartsWith
186 return nil
187}
188
189// SetContentLengthRange - Set new min and max content length
190// condition for all incoming uploads.
191func (p *PostPolicy) SetContentLengthRange(min, max int64) error {
192 if min > max {
193 return errInvalidArgument("Minimum limit is larger than maximum limit.")
194 }
195 if min < 0 {
196 return errInvalidArgument("Minimum limit cannot be negative.")
197 }
198 if max <= 0 {
199 return errInvalidArgument("Maximum limit cannot be non-positive.")
200 }
201 p.contentLengthRange.min = min
202 p.contentLengthRange.max = max
203 return nil
204}
205
206// SetSuccessActionRedirect - Sets the redirect success url of the object for this policy
207// based upload.
208func (p *PostPolicy) SetSuccessActionRedirect(redirect string) error {
209 if strings.TrimSpace(redirect) == "" || redirect == "" {
210 return errInvalidArgument("Redirect is empty")
211 }
212 policyCond := policyCondition{
213 matchType: "eq",
214 condition: "$success_action_redirect",
215 value: redirect,
216 }
217 if err := p.addNewPolicy(policyCond); err != nil {
218 return err
219 }
220 p.formData["success_action_redirect"] = redirect
221 return nil
222}
223
224// SetSuccessStatusAction - Sets the status success code of the object for this policy
225// based upload.
226func (p *PostPolicy) SetSuccessStatusAction(status string) error {
227 if strings.TrimSpace(status) == "" || status == "" {
228 return errInvalidArgument("Status is empty")
229 }
230 policyCond := policyCondition{
231 matchType: "eq",
232 condition: "$success_action_status",
233 value: status,
234 }
235 if err := p.addNewPolicy(policyCond); err != nil {
236 return err
237 }
238 p.formData["success_action_status"] = status
239 return nil
240}
241
242// SetUserMetadata - Set user metadata as a key/value couple.
243// Can be retrieved through a HEAD request or an event.
244func (p *PostPolicy) SetUserMetadata(key, value string) error {
245 if strings.TrimSpace(key) == "" || key == "" {
246 return errInvalidArgument("Key is empty")
247 }
248 if strings.TrimSpace(value) == "" || value == "" {
249 return errInvalidArgument("Value is empty")
250 }
251 headerName := fmt.Sprintf("x-amz-meta-%s", key)
252 policyCond := policyCondition{
253 matchType: "eq",
254 condition: fmt.Sprintf("$%s", headerName),
255 value: value,
256 }
257 if err := p.addNewPolicy(policyCond); err != nil {
258 return err
259 }
260 p.formData[headerName] = value
261 return nil
262}
263
264// SetChecksum sets the checksum of the request.
265func (p *PostPolicy) SetChecksum(c Checksum) {
266 if c.IsSet() {
267 p.formData[amzChecksumAlgo] = c.Type.String()
268 p.formData[c.Type.Key()] = c.Encoded()
269 }
270}
271
272// SetEncryption - sets encryption headers for POST API
273func (p *PostPolicy) SetEncryption(sse encrypt.ServerSide) {
274 if sse == nil {
275 return
276 }
277 h := http.Header{}
278 sse.Marshal(h)
279 for k, v := range h {
280 p.formData[k] = v[0]
281 }
282}
283
284// SetUserData - Set user data as a key/value couple.
285// Can be retrieved through a HEAD request or an event.
286func (p *PostPolicy) SetUserData(key, value string) error {
287 if key == "" {
288 return errInvalidArgument("Key is empty")
289 }
290 if value == "" {
291 return errInvalidArgument("Value is empty")
292 }
293 headerName := fmt.Sprintf("x-amz-%s", key)
294 policyCond := policyCondition{
295 matchType: "eq",
296 condition: fmt.Sprintf("$%s", headerName),
297 value: value,
298 }
299 if err := p.addNewPolicy(policyCond); err != nil {
300 return err
301 }
302 p.formData[headerName] = value
303 return nil
304}
305
306// addNewPolicy - internal helper to validate adding new policies.
307// Can use starts-with with an empty value ("") to allow any content within a form field.
308func (p *PostPolicy) addNewPolicy(policyCond policyCondition) error {
309 if policyCond.matchType == "" || policyCond.condition == "" {
310 return errInvalidArgument("Policy fields are empty.")
311 }
312 if policyCond.matchType != "starts-with" && policyCond.value == "" {
313 return errInvalidArgument("Policy value is empty.")
314 }
315 p.conditions = append(p.conditions, policyCond)
316 return nil
317}
318
319// String function for printing policy in json formatted string.
320func (p PostPolicy) String() string {
321 return string(p.marshalJSON())
322}
323
324// marshalJSON - Provides Marshaled JSON in bytes.
325func (p PostPolicy) marshalJSON() []byte {
326 expirationStr := `"expiration":"` + p.expiration.Format(expirationDateFormat) + `"`
327 var conditionsStr string
328 conditions := []string{}
329 for _, po := range p.conditions {
330 conditions = append(conditions, fmt.Sprintf("[\"%s\",\"%s\",\"%s\"]", po.matchType, po.condition, po.value))
331 }
332 if p.contentLengthRange.min != 0 || p.contentLengthRange.max != 0 {
333 conditions = append(conditions, fmt.Sprintf("[\"content-length-range\", %d, %d]",
334 p.contentLengthRange.min, p.contentLengthRange.max))
335 }
336 if len(conditions) > 0 {
337 conditionsStr = `"conditions":[` + strings.Join(conditions, ",") + "]"
338 }
339 retStr := "{"
340 retStr = retStr + expirationStr + ","
341 retStr += conditionsStr
342 retStr += "}"
343 return []byte(retStr)
344}
345
346// base64 - Produces base64 of PostPolicy's Marshaled json.
347func (p PostPolicy) base64() string {
348 return base64.StdEncoding.EncodeToString(p.marshalJSON())
349}