io.minio.PostPolicy.java Source code

Java tutorial

Introduction

Here is the source code for io.minio.PostPolicy.java

Source

/*
 * Minio Java Library for Amazon S3 Compatible Cloud Storage, (C) 2015 Minio, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.minio;

import io.minio.errors.*;

import com.google.common.io.BaseEncoding;
import com.google.common.base.Strings;
import com.google.common.base.Joiner;
import org.joda.time.DateTime;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * Post policy information to be used to generate presigned post policy form-data.
 */
public class PostPolicy {
    private static final String ALGORITHM = "AWS4-HMAC-SHA256";

    private String bucketName;
    private String objectName;
    private boolean startsWith;
    private DateTime expirationDate;
    private String contentType;
    private long contentRangeStart;
    private long contentRangeEnd;

    public PostPolicy(String bucketName, String objectName, DateTime expirationDate)
            throws InvalidArgumentException {
        this(bucketName, objectName, false, expirationDate);
    }

    /**
     * Creates PostPolicy for given bucket name, object name, string to match object name starting with
     * and expiration time.
     */
    public PostPolicy(String bucketName, String objectName, boolean startsWith, DateTime expirationDate)
            throws InvalidArgumentException {
        if (bucketName == null) {
            throw new InvalidArgumentException("null bucket name");
        }
        this.bucketName = bucketName;

        if (objectName == null) {
            throw new InvalidArgumentException("null object name or prefix");
        }
        this.objectName = objectName;

        this.startsWith = startsWith;

        if (expirationDate == null) {
            throw new InvalidArgumentException("null expiration date");
        }
        this.expirationDate = expirationDate;
    }

    /**
     * Sets content type.
     */
    public void setContentType(String contentType) throws InvalidArgumentException {
        if (Strings.isNullOrEmpty(contentType)) {
            throw new InvalidArgumentException("empty content type");
        }

        this.contentType = contentType;
    }

    /**
     * Sets content length.
     */
    public void setContentLength(long contentLength) throws InvalidArgumentException {
        if (contentLength <= 0) {
            throw new InvalidArgumentException("negative content length");
        }

        this.setContentRange(contentLength, contentLength);
    }

    /**
     * Sets content range.
     */
    public void setContentRange(long startRange, long endRange) throws InvalidArgumentException {
        if (startRange <= 0 || endRange <= 0) {
            throw new InvalidArgumentException("negative start/end range");
        }

        if (startRange > endRange) {
            throw new InvalidArgumentException("start range is higher than end range");
        }

        this.contentRangeStart = startRange;
        this.contentRangeEnd = endRange;
    }

    /**
     * Returns bucket name.
     */
    public String bucketName() {
        return this.bucketName;
    }

    private byte[] marshalJson(ArrayList<String[]> conditions) {
        StringBuilder sb = new StringBuilder();
        Joiner joiner = Joiner.on("\",\"");

        sb.append("{");

        if (expirationDate != null) {
            sb.append("\"expiration\":" + "\"" + expirationDate.toString(DateFormat.EXPIRATION_DATE_FORMAT) + "\"");
        }

        if (!conditions.isEmpty()) {
            sb.append(",\"conditions\":[");

            ListIterator<String[]> iterator = conditions.listIterator();
            while (iterator.hasNext()) {
                sb.append("[\"" + joiner.join(iterator.next()) + "\"]");
                if (iterator.hasNext()) {
                    sb.append(",");
                }
            }

            sb.append("]");
        }

        sb.append("}");

        return sb.toString().getBytes(StandardCharsets.UTF_8);
    }

    /**
     * Returns form data of this post policy.
     */
    public Map<String, String> formData(String accessKey, String secretKey)
            throws NoSuchAlgorithmException, InvalidKeyException {
        ArrayList<String[]> conditions = new ArrayList<>();
        Map<String, String> formData = new HashMap<>();

        conditions.add(new String[] { "eq", "$bucket", this.bucketName });
        formData.put("bucket", this.bucketName);

        if (this.startsWith) {
            conditions.add(new String[] { "starts-with", "$key", this.objectName });
            formData.put("key", this.objectName);
        } else {
            conditions.add(new String[] { "eq", "$key", this.objectName });
            formData.put("key", this.objectName);
        }

        if (this.contentType != null) {
            conditions.add(new String[] { "eq", "$Content-Type", this.contentType });
            formData.put("Content-Type", this.contentType);
        }

        if (this.contentRangeStart > 0 && this.contentRangeEnd > 0) {
            conditions.add(new String[] { "content-length-range", Long.toString(this.contentRangeStart),
                    Long.toString(this.contentRangeEnd) });
        }

        conditions.add(new String[] { "eq", "$x-amz-algorithm", ALGORITHM });
        formData.put("x-amz-algorithm", ALGORITHM);

        DateTime date = new DateTime();
        String region = BucketRegionCache.INSTANCE.region(this.bucketName);
        String credential = Signer.credential(accessKey, date, region);
        conditions.add(new String[] { "eq", "$x-amz-credential", credential });
        formData.put("x-amz-credential", credential);

        String amzDate = date.toString(DateFormat.AMZ_DATE_FORMAT);
        conditions.add(new String[] { "eq", "$x-amz-date", amzDate });
        formData.put("x-amz-date", amzDate);

        String policybase64 = BaseEncoding.base64().encode(this.marshalJson(conditions));
        String signature = Signer.postPresignV4(policybase64, secretKey, date, region);

        formData.put("policy", policybase64);
        formData.put("x-amz-signature", signature);

        return formData;
    }
}