解决 minio 桶中的文件的内容类型 Content-Type 不能正确保存的问题。

This commit is contained in:
刘小平 2024-12-04 16:16:50 +08:00
parent e016db9936
commit 73fff94968
8 changed files with 16 additions and 2898 deletions

View File

@ -802,6 +802,8 @@ public class StorageEngineServiceImpl implements StorageEngineService {
fileKey = IdUtil.fastSimpleUUID(); fileKey = IdUtil.fastSimpleUUID();
// 存储路径 // 存储路径
storagePath = CommonUtil.getPathByDate(); storagePath = CommonUtil.getPathByDate();
// MIME类型
String fileMimeType = FileUtil.getMimeType(bo.getFullFileName());
// 存储桶 // 存储桶
bucketName = StorageBucketEnums.getBucketByFileSuffix(suffix); bucketName = StorageBucketEnums.getBucketByFileSuffix(suffix);
@ -809,7 +811,7 @@ public class StorageEngineServiceImpl implements StorageEngineService {
minioS3Client.makeBucket(bucketName); minioS3Client.makeBucket(bucketName);
// 创建分片请求,获取uploadId // 创建分片请求,获取uploadId
uploadId = minioS3Client.createMultipartUpload(bucketName, CommonUtil.getObjectName(bo.getFileMd5())); uploadId = minioS3Client.createMultipartUpload(bucketName, CommonUtil.getObjectName(bo.getFileMd5()),fileMimeType);
long start = 0; long start = 0;
for (Integer partNumber = 1; partNumber <= chunkNum; partNumber++) { for (Integer partNumber = 1; partNumber <= chunkNum; partNumber++) {
FileCheckResultVo.Part part = this.buildResultPart(bucketName, CommonUtil.getObjectName(bo.getFileMd5()), uploadId, bo.getFileSize(), start, partNumber); FileCheckResultVo.Part part = this.buildResultPart(bucketName, CommonUtil.getObjectName(bo.getFileMd5()), uploadId, bo.getFileSize(), start, partNumber);

View File

@ -29,9 +29,10 @@ public interface MinioS3Client {
* 创建上传任务 * 创建上传任务
* @param bucketName 桶名称 * @param bucketName 桶名称
* @param objectName 对象名称含路径 * @param objectName 对象名称含路径
* @param contentType 内容类型
* @return UploadId 上传任务编号 * @return UploadId 上传任务编号
*/ */
String createMultipartUpload(String bucketName, String objectName); String createMultipartUpload(String bucketName, String objectName,String contentType);
/** /**
* 合并分片 * 合并分片

View File

@ -1,7 +1,10 @@
package org.liuxp.minioplus.s3.official; package org.liuxp.minioplus.s3.official;
import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.IoUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import io.minio.*; import io.minio.*;
import io.minio.errors.InsufficientDataException; import io.minio.errors.InsufficientDataException;
import io.minio.errors.InternalException; import io.minio.errors.InternalException;
@ -107,9 +110,15 @@ public class MinioS3ClientImpl implements MinioS3Client {
} }
@Override @Override
public String createMultipartUpload(String bucketName, String objectName) { public String createMultipartUpload(String bucketName, String objectName, String contentType) {
Multimap<String, String> reqParams = HashMultimap.create();
if(CharSequenceUtil.isNotBlank(contentType)){
reqParams.put("Content-Type", contentType);
}
try { try {
CreateMultipartUploadResponse createMultipartUploadResponse = this.getClient().createMultipartUpload(bucketName, null, objectName, null, null); CreateMultipartUploadResponse createMultipartUploadResponse = this.getClient().createMultipartUpload(bucketName, null, objectName, reqParams,null );
return createMultipartUploadResponse.result().uploadId(); return createMultipartUploadResponse.result().uploadId();
} catch (Exception e) { } catch (Exception e) {
log.error(LOG_TEMPLATE, MinioPlusErrorCode.CREATE_MULTIPART_UPLOAD_FAILED.getMessage(), e.getMessage(), e); log.error(LOG_TEMPLATE, MinioPlusErrorCode.CREATE_MULTIPART_UPLOAD_FAILED.getMessage(), e.getMessage(), e);

View File

@ -1,154 +0,0 @@
/*
* MinIO Java SDK 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.
*/
import com.google.common.io.BaseEncoding;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Locale;
/** Various global static functions used. */
public class Digest {
// MD5 hash of zero length byte array.
public static final String ZERO_MD5_HASH = "1B2M2Y8AsgTpgAmY7PhCfg==";
// SHA-256 hash of zero length byte array.
public static final String ZERO_SHA256_HASH =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
/** Private constructor. */
private Digest() {}
/** Returns MD5 hash of byte array. */
public static String md5Hash(byte[] data, int length) throws NoSuchAlgorithmException {
MessageDigest md5Digest = MessageDigest.getInstance("MD5");
md5Digest.update(data, 0, length);
return Base64.getEncoder().encodeToString(md5Digest.digest());
}
/** Returns SHA-256 hash of byte array. */
public static String sha256Hash(byte[] data, int length) throws NoSuchAlgorithmException {
MessageDigest sha256Digest = MessageDigest.getInstance("SHA-256");
sha256Digest.update((byte[]) data, 0, length);
return BaseEncoding.base16().encode(sha256Digest.digest()).toLowerCase(Locale.US);
}
/** Returns SHA-256 hash of given string. */
public static String sha256Hash(String string) throws NoSuchAlgorithmException {
byte[] data = string.getBytes(StandardCharsets.UTF_8);
return sha256Hash(data, data.length);
}
/**
* Returns SHA-256 and MD5 hashes of given data and it's length.
*
* @param data must be {@link RandomAccessFile}, {@link BufferedInputStream} or byte array.
* @param len length of data to be read for hash calculation.
* @deprecated This method is no longer supported.
*/
@Deprecated
public static String[] sha256Md5Hashes(Object data, int len)
throws NoSuchAlgorithmException, IOException, RuntimeException {
MessageDigest sha256Digest = MessageDigest.getInstance("SHA-256");
MessageDigest md5Digest = MessageDigest.getInstance("MD5");
if (data instanceof BufferedInputStream || data instanceof RandomAccessFile) {
updateDigests(data, len, sha256Digest, md5Digest);
} else if (data instanceof byte[]) {
sha256Digest.update((byte[]) data, 0, len);
md5Digest.update((byte[]) data, 0, len);
} else {
throw new RuntimeException(
"Unknown data source to calculate SHA-256 hash. This should not happen, "
+ "please report this issue at https://github.com/minio/minio-java/issues",
null);
}
return new String[] {
BaseEncoding.base16().encode(sha256Digest.digest()).toLowerCase(Locale.US),
BaseEncoding.base64().encode(md5Digest.digest())
};
}
/** Updated MessageDigest with bytes read from file and stream. */
private static int updateDigests(
Object inputStream, int len, MessageDigest sha256Digest, MessageDigest md5Digest)
throws IOException, RuntimeException {
RandomAccessFile file = null;
BufferedInputStream stream = null;
if (inputStream instanceof RandomAccessFile) {
file = (RandomAccessFile) inputStream;
} else if (inputStream instanceof BufferedInputStream) {
stream = (BufferedInputStream) inputStream;
}
// hold current position of file/stream to reset back to this position.
long pos = 0;
if (file != null) {
pos = file.getFilePointer();
} else {
stream.mark(len);
}
// 16KiB buffer for optimization
byte[] buf = new byte[16384];
int bytesToRead = buf.length;
int bytesRead = 0;
int totalBytesRead = 0;
while (totalBytesRead < len) {
if ((len - totalBytesRead) < bytesToRead) {
bytesToRead = len - totalBytesRead;
}
if (file != null) {
bytesRead = file.read(buf, 0, bytesToRead);
} else {
bytesRead = stream.read(buf, 0, bytesToRead);
}
if (bytesRead < 0) {
// reached EOF
throw new RuntimeException(
"Insufficient data. bytes read " + totalBytesRead + " expected " + len);
}
if (bytesRead > 0) {
if (sha256Digest != null) {
sha256Digest.update(buf, 0, bytesRead);
}
if (md5Digest != null) {
md5Digest.update(buf, 0, bytesRead);
}
totalBytesRead += bytesRead;
}
}
// reset back to saved position.
if (file != null) {
file.seek(pos);
} else {
stream.reset();
}
return totalBytesRead;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,70 +0,0 @@
/*
* MinIO Java SDK for Amazon S3 Compatible Cloud Storage, (C) 2016 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.
*/
import com.google.common.escape.Escaper;
import com.google.common.net.UrlEscapers;
public class S3Escaper {
private static final Escaper ESCAPER = UrlEscapers.urlPathSegmentEscaper();
/** Returns S3 encoded string. */
public static String encode(String str) {
if (str == null) {
return "";
}
return ESCAPER
.escape(str)
.replaceAll("\\!", "%21")
.replaceAll("\\$", "%24")
.replaceAll("\\&", "%26")
.replaceAll("\\'", "%27")
.replaceAll("\\(", "%28")
.replaceAll("\\)", "%29")
.replaceAll("\\*", "%2A")
.replaceAll("\\+", "%2B")
.replaceAll("\\,", "%2C")
.replaceAll("\\/", "%2F")
.replaceAll("\\:", "%3A")
.replaceAll("\\;", "%3B")
.replaceAll("\\=", "%3D")
.replaceAll("\\@", "%40")
.replaceAll("\\[", "%5B")
.replaceAll("\\]", "%5D");
}
/** Returns S3 encoded string of given path where multiple '/' are trimmed. */
public static String encodePath(String path) {
final StringBuilder encodedPath = new StringBuilder();
for (String pathSegment : path.split("/")) {
if (!pathSegment.isEmpty()) {
if (encodedPath.length() > 0) {
encodedPath.append("/");
}
encodedPath.append(S3Escaper.encode(pathSegment));
}
}
if (path.startsWith("/")) {
encodedPath.insert(0, "/");
}
if (path.endsWith("/")) {
encodedPath.append("/");
}
return encodedPath.toString();
}
}

View File

@ -1,420 +0,0 @@
/*
* MinIO Java SDK 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.
*/
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;
import com.google.common.io.BaseEncoding;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.Request;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.ZonedDateTime;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
/** Amazon AWS S3 signature V4 signer. */
public class Signer {
//
// Excerpts from @lsegal - https://github.com/aws/aws-sdk-js/issues/659#issuecomment-120477258
//
// * User-Agent
// This is ignored from signing because signing this causes problems with generating pre-signed
// URLs (that are executed by other agents) or when customers pass requests through proxies, which
// may modify the user-agent.
//
// * Content-Length
// This is ignored from signing because generating a pre-signed URL should not provide a
// content-length constraint, specifically when vending a S3 pre-signed PUT URL. The corollary to
// this is that when sending regular requests (non-pre-signed), the signature contains a checksum
// of the body, which implicitly validates the payload length (since changing the number of bytes
// would change the checksum) and therefore this header is not valuable in the signature.
//
// * Content-Type
// Signing this header causes quite a number of problems in browser environments, where browsers
// like to modify and normalize the content-type header in different ways. There is more
// information on this in https://github.com/aws/aws-sdk-js/issues/244. Avoiding this field
// simplifies logic and reduces the possibility of future bugs.
//
// * Authorization
// Is skipped for obvious reasons.
//
// * Accept-Encoding
// Some S3 servers like Hitachi Content Platform do not honour this header for signature
// calculation.
//
private static final Set<String> IGNORED_HEADERS =
ImmutableSet.of(
"accept-encoding", "authorization", "content-type", "content-length", "user-agent");
private static final Set<String> PRESIGN_IGNORED_HEADERS =
ImmutableSet.of(
"accept-encoding",
"authorization",
"content-type",
"content-length",
"user-agent",
"content-md5",
"x-amz-content-sha256",
"x-amz-date",
"x-amz-security-token");
private Request request;
private String contentSha256;
private ZonedDateTime date;
private String region;
private String accessKey;
private String secretKey;
private String prevSignature;
private String scope;
private Map<String, String> canonicalHeaders;
private String signedHeaders;
private HttpUrl url;
private String canonicalQueryString;
private String canonicalRequest;
private String canonicalRequestHash;
private String stringToSign;
private byte[] signingKey;
private String signature;
private String authorization;
/**
* Create new Signer object for V4.
*
* @param request HTTP Request object.
* @param contentSha256 SHA-256 hash of request payload.
* @param date Date to be used to sign the request.
* @param region Amazon AWS region for the request.
* @param accessKey Access Key string.
* @param secretKey Secret Key string.
* @param prevSignature Previous signature of chunk upload.
*/
private Signer(
Request request,
String contentSha256,
ZonedDateTime date,
String region,
String accessKey,
String secretKey,
String prevSignature) {
this.request = request;
this.contentSha256 = contentSha256;
this.date = date;
this.region = region;
this.accessKey = accessKey;
this.secretKey = secretKey;
this.prevSignature = prevSignature;
}
private void setScope(String serviceName) {
this.scope =
this.date.format(Time.SIGNER_DATE_FORMAT)
+ "/"
+ this.region
+ "/"
+ serviceName
+ "/aws4_request";
}
private void setCanonicalHeaders(Set<String> ignored_headers) {
this.canonicalHeaders = new TreeMap<>();
Headers headers = this.request.headers();
for (String name : headers.names()) {
String signedHeader = name.toLowerCase(Locale.US);
if (!ignored_headers.contains(signedHeader)) {
// Convert and add header values as per
// https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
// * Header having multiple values should be converted to comma separated values.
// * Multi-spaced value of header should be trimmed to single spaced value.
this.canonicalHeaders.put(
signedHeader,
headers.values(name).stream()
.map(
value -> {
return value.replaceAll("( +)", " ");
})
.collect(Collectors.joining(",")));
}
}
this.signedHeaders = Joiner.on(";").join(this.canonicalHeaders.keySet());
}
private void setCanonicalQueryString() {
String encodedQuery = this.url.encodedQuery();
if (encodedQuery == null) {
this.canonicalQueryString = "";
return;
}
// Building a multimap which only order keys, ordering values is not performed
// until MinIO server supports it.
Multimap<String, String> signedQueryParams =
MultimapBuilder.treeKeys().arrayListValues().build();
for (String queryParam : encodedQuery.split("&")) {
String[] tokens = queryParam.split("=");
if (tokens.length > 1) {
signedQueryParams.put(tokens[0], tokens[1]);
} else {
signedQueryParams.put(tokens[0], "");
}
}
this.canonicalQueryString =
Joiner.on("&").withKeyValueSeparator("=").join(signedQueryParams.entries());
}
private void setCanonicalRequest() throws NoSuchAlgorithmException {
setCanonicalHeaders(IGNORED_HEADERS);
this.url = this.request.url();
setCanonicalQueryString();
// CanonicalRequest =
// HTTPRequestMethod + '\n' +
// CanonicalURI + '\n' +
// CanonicalQueryString + '\n' +
// CanonicalHeaders + '\n' +
// SignedHeaders + '\n' +
// HexEncode(Hash(RequestPayload))
this.canonicalRequest =
this.request.method()
+ "\n"
+ this.url.encodedPath()
+ "\n"
+ this.canonicalQueryString
+ "\n"
+ Joiner.on("\n").withKeyValueSeparator(":").join(this.canonicalHeaders)
+ "\n\n"
+ this.signedHeaders
+ "\n"
+ this.contentSha256;
this.canonicalRequestHash = Digest.sha256Hash(this.canonicalRequest);
}
private void setStringToSign() {
this.stringToSign =
"AWS4-HMAC-SHA256"
+ "\n"
+ this.date.format(Time.AMZ_DATE_FORMAT)
+ "\n"
+ this.scope
+ "\n"
+ this.canonicalRequestHash;
}
private void setChunkStringToSign() throws NoSuchAlgorithmException {
this.stringToSign =
"AWS4-HMAC-SHA256-PAYLOAD"
+ "\n"
+ this.date.format(Time.AMZ_DATE_FORMAT)
+ "\n"
+ this.scope
+ "\n"
+ this.prevSignature
+ "\n"
+ Digest.sha256Hash("")
+ "\n"
+ this.contentSha256;
}
private void setSigningKey(String serviceName)
throws NoSuchAlgorithmException, InvalidKeyException {
String aws4SecretKey = "AWS4" + this.secretKey;
byte[] dateKey =
sumHmac(
aws4SecretKey.getBytes(StandardCharsets.UTF_8),
this.date.format(Time.SIGNER_DATE_FORMAT).getBytes(StandardCharsets.UTF_8));
byte[] dateRegionKey = sumHmac(dateKey, this.region.getBytes(StandardCharsets.UTF_8));
byte[] dateRegionServiceKey =
sumHmac(dateRegionKey, serviceName.getBytes(StandardCharsets.UTF_8));
this.signingKey =
sumHmac(dateRegionServiceKey, "aws4_request".getBytes(StandardCharsets.UTF_8));
}
private void setSignature() throws NoSuchAlgorithmException, InvalidKeyException {
byte[] digest = sumHmac(this.signingKey, this.stringToSign.getBytes(StandardCharsets.UTF_8));
this.signature = BaseEncoding.base16().encode(digest).toLowerCase(Locale.US);
}
private void setAuthorization() {
this.authorization =
"AWS4-HMAC-SHA256 Credential="
+ this.accessKey
+ "/"
+ this.scope
+ ", SignedHeaders="
+ this.signedHeaders
+ ", Signature="
+ this.signature;
}
/** Returns chunk signature calculated using given arguments. */
public static String getChunkSignature(
String chunkSha256, ZonedDateTime date, String region, String secretKey, String prevSignature)
throws NoSuchAlgorithmException, InvalidKeyException {
Signer signer = new Signer(null, chunkSha256, date, region, null, secretKey, prevSignature);
signer.setScope("s3");
signer.setChunkStringToSign();
signer.setSigningKey("s3");
signer.setSignature();
return signer.signature;
}
/** Returns signed request object for given request, region, access key and secret key. */
private static Request signV4(
String serviceName,
Request request,
String region,
String accessKey,
String secretKey,
String contentSha256)
throws NoSuchAlgorithmException, InvalidKeyException {
ZonedDateTime date = ZonedDateTime.parse(request.header("x-amz-date"), Time.AMZ_DATE_FORMAT);
Signer signer = new Signer(request, contentSha256, date, region, accessKey, secretKey, null);
signer.setScope(serviceName);
signer.setCanonicalRequest();
signer.setStringToSign();
signer.setSigningKey(serviceName);
signer.setSignature();
signer.setAuthorization();
return request.newBuilder().header("Authorization", signer.authorization).build();
}
/** Returns signed request of given request for S3 service. */
public static Request signV4S3(
Request request, String region, String accessKey, String secretKey, String contentSha256)
throws NoSuchAlgorithmException, InvalidKeyException {
return signV4("s3", request, region, accessKey, secretKey, contentSha256);
}
/** Returns signed request of given request for STS service. */
public static Request signV4Sts(
Request request, String region, String accessKey, String secretKey, String contentSha256)
throws NoSuchAlgorithmException, InvalidKeyException {
return signV4("sts", request, region, accessKey, secretKey, contentSha256);
}
private void setPresignCanonicalRequest(int expires) throws NoSuchAlgorithmException {
setCanonicalHeaders(PRESIGN_IGNORED_HEADERS);
HttpUrl.Builder urlBuilder = this.request.url().newBuilder();
urlBuilder.addEncodedQueryParameter(
S3Escaper.encode("X-Amz-Algorithm"), S3Escaper.encode("AWS4-HMAC-SHA256"));
urlBuilder.addEncodedQueryParameter(
S3Escaper.encode("X-Amz-Credential"), S3Escaper.encode(this.accessKey + "/" + this.scope));
urlBuilder.addEncodedQueryParameter(
S3Escaper.encode("X-Amz-Date"), S3Escaper.encode(this.date.format(Time.AMZ_DATE_FORMAT)));
urlBuilder.addEncodedQueryParameter(
S3Escaper.encode("X-Amz-Expires"), S3Escaper.encode(Integer.toString(expires)));
urlBuilder.addEncodedQueryParameter(
S3Escaper.encode("X-Amz-SignedHeaders"), S3Escaper.encode(this.signedHeaders));
this.url = urlBuilder.build();
setCanonicalQueryString();
this.canonicalRequest =
this.request.method()
+ "\n"
+ this.url.encodedPath()
+ "\n"
+ this.canonicalQueryString
+ "\n"
+ Joiner.on("\n").withKeyValueSeparator(":").join(this.canonicalHeaders)
+ "\n\n"
+ this.signedHeaders
+ "\n"
+ this.contentSha256;
this.canonicalRequestHash = Digest.sha256Hash(this.canonicalRequest);
}
/**
* Returns pre-signed HttpUrl object for given request, region, access key, secret key and expires
* time.
*/
public static HttpUrl presignV4(
Request request, String region, String accessKey, String secretKey, int expires)
throws NoSuchAlgorithmException, InvalidKeyException {
String contentSha256 = "UNSIGNED-PAYLOAD";
ZonedDateTime date = ZonedDateTime.parse(request.header("x-amz-date"), Time.AMZ_DATE_FORMAT);
Signer signer = new Signer(request, contentSha256, date, region, accessKey, secretKey, null);
signer.setScope("s3");
signer.setPresignCanonicalRequest(expires);
signer.setStringToSign();
signer.setSigningKey("s3");
signer.setSignature();
return signer
.url
.newBuilder()
.addEncodedQueryParameter(
S3Escaper.encode("X-Amz-Signature"), S3Escaper.encode(signer.signature))
.build();
}
/** Returns credential string of given access key, date and region. */
public static String credential(String accessKey, ZonedDateTime date, String region) {
return accessKey
+ "/"
+ date.format(Time.SIGNER_DATE_FORMAT)
+ "/"
+ region
+ "/s3/aws4_request";
}
/** Returns pre-signed post policy string for given stringToSign, secret key, date and region. */
public static String postPresignV4(
String stringToSign, String secretKey, ZonedDateTime date, String region)
throws NoSuchAlgorithmException, InvalidKeyException {
Signer signer = new Signer(null, null, date, region, null, secretKey, null);
signer.stringToSign = stringToSign;
signer.setSigningKey("s3");
signer.setSignature();
return signer.signature;
}
/** Returns HMacSHA256 digest of given key and data. */
public static byte[] sumHmac(byte[] key, byte[] data)
throws NoSuchAlgorithmException, InvalidKeyException {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(key, "HmacSHA256"));
mac.update(data);
return mac.doFinal();
}
}

View File

@ -1,44 +0,0 @@
/*
* MinIO Java SDK for Amazon S3 Compatible Cloud Storage,
* (C) 2020 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.
*/
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
/** Time formatters for S3 APIs. */
public class Time {
public static final ZoneId UTC = ZoneId.of("Z");
public static final DateTimeFormatter AMZ_DATE_FORMAT =
DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'", Locale.US).withZone(UTC);
public static final DateTimeFormatter RESPONSE_DATE_FORMAT =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH':'mm':'ss'.'SSS'Z'", Locale.US).withZone(UTC);
// Formatted string is convertible to LocalDate only, not to LocalDateTime or ZonedDateTime.
// Below example shows how to use this to get ZonedDateTime.
// LocalDate.parse("20200225", SIGNER_DATE_FORMAT).atStartOfDay(UTC);
public static final DateTimeFormatter SIGNER_DATE_FORMAT =
DateTimeFormatter.ofPattern("yyyyMMdd", Locale.US).withZone(UTC);
public static final DateTimeFormatter HTTP_HEADER_DATE_FORMAT =
DateTimeFormatter.ofPattern("EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'", Locale.US).withZone(UTC);
public static final DateTimeFormatter EXPIRATION_DATE_FORMAT = RESPONSE_DATE_FORMAT;
private Time() {}
}