|
|
|
@ -101,8 +101,9 @@ type contentLengthRange struct { |
|
|
|
|
type PostPolicyForm struct { |
|
|
|
|
Expiration time.Time // Expiration date and time of the POST policy.
|
|
|
|
|
Conditions struct { // Conditional policy structure.
|
|
|
|
|
Policies map[string]struct { |
|
|
|
|
Policies []struct { |
|
|
|
|
Operator string |
|
|
|
|
Key string |
|
|
|
|
Value string |
|
|
|
|
} |
|
|
|
|
ContentLengthRange contentLengthRange |
|
|
|
@ -130,10 +131,6 @@ func parsePostPolicyForm(policy string) (ppf PostPolicyForm, e error) { |
|
|
|
|
if err != nil { |
|
|
|
|
return ppf, err |
|
|
|
|
} |
|
|
|
|
parsedPolicy.Conditions.Policies = make(map[string]struct { |
|
|
|
|
Operator string |
|
|
|
|
Value string |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
// Parse conditions.
|
|
|
|
|
for _, val := range rawPolicy.Conditions { |
|
|
|
@ -146,13 +143,13 @@ func parsePostPolicyForm(policy string) (ppf PostPolicyForm, e error) { |
|
|
|
|
} |
|
|
|
|
// {"acl": "public-read" } is an alternate way to indicate - [ "eq", "$acl", "public-read" ]
|
|
|
|
|
// In this case we will just collapse this into "eq" for all use cases.
|
|
|
|
|
parsedPolicy.Conditions.Policies["$"+strings.ToLower(k)] = struct { |
|
|
|
|
parsedPolicy.Conditions.Policies = append(parsedPolicy.Conditions.Policies, struct { |
|
|
|
|
Operator string |
|
|
|
|
Key string |
|
|
|
|
Value string |
|
|
|
|
}{ |
|
|
|
|
Operator: policyCondEqual, |
|
|
|
|
Value: toString(v), |
|
|
|
|
} |
|
|
|
|
policyCondEqual, "$" + strings.ToLower(k), toString(v), |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
case []interface{}: // Handle array types.
|
|
|
|
|
if len(condt) != 3 { // Return error if we have insufficient elements.
|
|
|
|
@ -167,13 +164,16 @@ func parsePostPolicyForm(policy string) (ppf PostPolicyForm, e error) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
operator, matchType, value := toLowerString(condt[0]), toLowerString(condt[1]), toString(condt[2]) |
|
|
|
|
parsedPolicy.Conditions.Policies[matchType] = struct { |
|
|
|
|
if !strings.HasPrefix(matchType, "$") { |
|
|
|
|
return parsedPolicy, fmt.Errorf("Invalid according to Policy: Policy Condition failed: [%s, %s, %s]", operator, matchType, value) |
|
|
|
|
} |
|
|
|
|
parsedPolicy.Conditions.Policies = append(parsedPolicy.Conditions.Policies, struct { |
|
|
|
|
Operator string |
|
|
|
|
Key string |
|
|
|
|
Value string |
|
|
|
|
}{ |
|
|
|
|
Operator: operator, |
|
|
|
|
Value: value, |
|
|
|
|
} |
|
|
|
|
operator, matchType, value, |
|
|
|
|
}) |
|
|
|
|
case policyCondContentLength: |
|
|
|
|
min, err := toInteger(condt[1]) |
|
|
|
|
if err != nil { |
|
|
|
@ -224,10 +224,10 @@ func checkPostPolicy(formValues http.Header, postPolicyForm PostPolicyForm) erro |
|
|
|
|
} |
|
|
|
|
// map to store the metadata
|
|
|
|
|
metaMap := make(map[string]string) |
|
|
|
|
for cond, v := range postPolicyForm.Conditions.Policies { |
|
|
|
|
if strings.HasPrefix(cond, "$x-amz-meta-") { |
|
|
|
|
formCanonicalName := http.CanonicalHeaderKey(strings.TrimPrefix(cond, "$")) |
|
|
|
|
metaMap[formCanonicalName] = v.Value |
|
|
|
|
for _, policy := range postPolicyForm.Conditions.Policies { |
|
|
|
|
if strings.HasPrefix(policy.Key, "$x-amz-meta-") { |
|
|
|
|
formCanonicalName := http.CanonicalHeaderKey(strings.TrimPrefix(policy.Key, "$")) |
|
|
|
|
metaMap[formCanonicalName] = policy.Value |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Check if any extra metadata field is passed as input
|
|
|
|
@ -243,30 +243,30 @@ func checkPostPolicy(formValues http.Header, postPolicyForm PostPolicyForm) erro |
|
|
|
|
condPassed := true |
|
|
|
|
|
|
|
|
|
// Iterate over policy conditions and check them against received form fields
|
|
|
|
|
for cond, v := range postPolicyForm.Conditions.Policies { |
|
|
|
|
for _, policy := range postPolicyForm.Conditions.Policies { |
|
|
|
|
// Form fields names are in canonical format, convert conditions names
|
|
|
|
|
// to canonical for simplification purpose, so `$key` will become `Key`
|
|
|
|
|
formCanonicalName := http.CanonicalHeaderKey(strings.TrimPrefix(cond, "$")) |
|
|
|
|
formCanonicalName := http.CanonicalHeaderKey(strings.TrimPrefix(policy.Key, "$")) |
|
|
|
|
// Operator for the current policy condition
|
|
|
|
|
op := v.Operator |
|
|
|
|
op := policy.Operator |
|
|
|
|
// If the current policy condition is known
|
|
|
|
|
if startsWithSupported, condFound := startsWithConds[cond]; condFound { |
|
|
|
|
if startsWithSupported, condFound := startsWithConds[policy.Key]; condFound { |
|
|
|
|
// Check if the current condition supports starts-with operator
|
|
|
|
|
if op == policyCondStartsWith && !startsWithSupported { |
|
|
|
|
return fmt.Errorf("Invalid according to Policy: Policy Condition failed") |
|
|
|
|
} |
|
|
|
|
// Check if current policy condition is satisfied
|
|
|
|
|
condPassed = checkPolicyCond(op, formValues.Get(formCanonicalName), v.Value) |
|
|
|
|
condPassed = checkPolicyCond(op, formValues.Get(formCanonicalName), policy.Value) |
|
|
|
|
if !condPassed { |
|
|
|
|
return fmt.Errorf("Invalid according to Policy: Policy Condition failed") |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// This covers all conditions X-Amz-Meta-* and X-Amz-*
|
|
|
|
|
if strings.HasPrefix(cond, "$x-amz-meta-") || strings.HasPrefix(cond, "$x-amz-") { |
|
|
|
|
if strings.HasPrefix(policy.Key, "$x-amz-meta-") || strings.HasPrefix(policy.Key, "$x-amz-") { |
|
|
|
|
// Check if policy condition is satisfied
|
|
|
|
|
condPassed = checkPolicyCond(op, formValues.Get(formCanonicalName), v.Value) |
|
|
|
|
condPassed = checkPolicyCond(op, formValues.Get(formCanonicalName), policy.Value) |
|
|
|
|
if !condPassed { |
|
|
|
|
return fmt.Errorf("Invalid according to Policy: Policy Condition failed: [%s, %s, %s]", op, cond, v.Value) |
|
|
|
|
return fmt.Errorf("Invalid according to Policy: Policy Condition failed: [%s, %s, %s]", op, policy.Key, policy.Value) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|