package com.lean56.andplug.image.qiniu;
import android.text.TextUtils;
import android.util.Base64;
import com.alibaba.fastjson.JSON;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
public final class Auth {
private final static Charset UTF_8 = Charset.forName("UTF-8");
/**
* 上传策略,参数规格详见
* <p/>
* http://developer.qiniu.com/docs/v6/api/reference/security/put-policy.html
*/
private static final String[] policyFields = new String[]{
"callbackUrl",
"callbackBody",
"callbackHost",
"callbackBodyType",
"callbackFetchKey",
"returnUrl",
"returnBody",
"endUser",
"saveKey",
"insertOnly",
"detectMime",
"mimeLimit",
"fsizeLimit",
"fsizeMin",
"persistentOps",
"persistentNotifyUrl",
"persistentPipeline",
};
private static final String[] deprecatedPolicyFields = new String[]{
"asyncOps",
};
private final String accessKey;
private final SecretKeySpec secretKey;
private Auth(String accessKey, SecretKeySpec secretKeySpec) {
this.accessKey = accessKey;
this.secretKey = secretKeySpec;
}
public static Auth create(String accessKey, String secretKey) {
if (TextUtils.isEmpty(accessKey) || TextUtils.isEmpty(secretKey)) {
throw new IllegalArgumentException("empty key");
}
byte[] sk = secretKey.getBytes(UTF_8);
SecretKeySpec secretKeySpec = new SecretKeySpec(sk, "HmacSHA1");
return new Auth(accessKey, secretKeySpec);
}
private static void copyPolicy(final StringMap policy, StringMap originPolicy, final boolean strict) {
if (originPolicy == null) {
return;
}
originPolicy.forEach(new StringMap.Consumer() {
@Override
public void accept(String key, Object value) {
if (inStringArray(key, deprecatedPolicyFields)) {
throw new IllegalArgumentException(key + " is deprecated!");
}
if (!strict || inStringArray(key, policyFields)) {
policy.put(key, value);
}
}
});
}
private static boolean inStringArray(String s, String[] array) {
for (String x : array) {
if (x.equals(s)) {
return true;
}
}
return false;
}
private Mac createMac() {
Mac mac;
try {
mac = Mac.getInstance("HmacSHA1");
mac.init(secretKey);
} catch (GeneralSecurityException e) {
e.printStackTrace();
throw new IllegalArgumentException(e);
}
return mac;
}
public String sign(byte[] data) {
Mac mac = createMac();
String encodedSign = Base64.encodeToString(mac.doFinal(data), Base64.URL_SAFE | Base64.NO_WRAP);
return this.accessKey + ":" + encodedSign;
}
public String sign(String data) {
return sign(data.getBytes(UTF_8));
}
public String signWithData(byte[] data) {
String s = Base64.encodeToString(data, Base64.URL_SAFE | Base64.NO_WRAP);
return sign(s.getBytes(UTF_8)) + ":" + s;
}
public String signWithData(String data) {
return signWithData(data.getBytes(UTF_8));
}
/**
* scope = bucket
* 一般情况下可通过此方法获取token
*
* @param bucket 空间名
* @return 生成的上传token
*/
public String uploadToken(String bucket) {
return uploadToken(bucket, null, 3600, null, true);
}
/**
* scope = bucket:key
* 同名文件覆盖操作、只能上传指定key的文件可以可通过此方法获取token
*
* @param bucket 空间名
* @param key key,可为 null
* @return 生成的上传token
*/
public String uploadToken(String bucket, String key) {
return uploadToken(bucket, key, 3600, null, true);
}
/**
* 生成上传token
*
* @param bucket 空间名
* @param key key,可为 null
* @param expires 有效时长,单位秒
* @param policy 上传策略的其它参数,如 new StringMap().put("endUser", "uid").putNotEmpty("returnBody", "")。
* scope通过 bucket、key间接设置,deadline 通过 expires 间接设置
* @return 生成的上传token
*/
public String uploadToken(String bucket, String key, long expires, StringMap policy) {
return uploadToken(bucket, key, expires, policy, true);
}
/**
* 生成上传token
*
* @param bucket 空间名
* @param key key,可为 null
* @param expires 有效时长,单位秒。默认3600s
* @param policy 上传策略的其它参数,如 new StringMap().put("endUser", "uid").putNotEmpty("returnBody", "")。
* scope通过 bucket、key间接设置,deadline 通过 expires 间接设置
* @param strict 是否去除非限定的策略字段,默认true
* @return 生成的上传token
*/
public String uploadToken(String bucket, String key, long expires, StringMap policy, boolean strict) {
long deadline = System.currentTimeMillis() / 1000 + expires;
return uploadTokenWithDeadline(bucket, key, deadline, policy, strict);
}
String uploadTokenWithDeadline(String bucket, String key, long deadline, StringMap policy, boolean strict) {
String scope = bucket;
if (key != null) {
scope = bucket + ":" + key;
}
StringMap x = new StringMap();
copyPolicy(x, policy, strict);
x.put("scope", scope);
x.put("deadline", deadline);
String s = JSON.toJSONString(x.map());
return signWithData(s.getBytes(UTF_8));
}
}