Files
flutter-picgo/lib/api/tcyun_api.dart
2021-04-23 16:58:04 +08:00

175 lines
6.2 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:dio/dio.dart';
import 'package:flutter_picgo/utils/net.dart';
import 'package:flutter_picgo/utils/strings.dart';
class TcyunApi {
static const String BASE_URL = 'myqcloud.com';
static const String secretKey = 'secretKey';
static const String secretId = 'secretId';
static Future postObject(String secretId, String secretKey, String bucket,
String area, String ext, FormData formData) async {
Response res = await NetUtils.getInstance().post(
'https://$bucket.cos.$area.$BASE_URL/',
data: formData,
options: Options(
extra: {TcyunApi.secretId: secretId, TcyunApi.secretKey: secretKey},
contentType: 'image/$ext'));
return res.headers;
}
static Future deleteobject(String secretId, String secretKey, String bucket,
String area, String key) async {
Response res = await NetUtils.getInstance().delete(
'https://$bucket.cos.$area.$BASE_URL/$key',
options: Options(
extra: {TcyunApi.secretId: secretId, TcyunApi.secretKey: secretKey},
));
return res.headers;
}
/// 构造“策略”Policy
/// 经过 Base64 编码的“策略”Policy内容
static String buildPolicy(
String bucket, String key, String secretId, String keyTime) {
Map<String, dynamic> map = {
"expiration": "2030-01-01T00:00:00.000Z",
"conditions": [
{"bucket": bucket},
{"key": key},
{"q-sign-algorithm": "sha1"},
{"q-ak": secretId},
{"q-sign-time": keyTime}
]
};
return json.encode(map);
}
/// post Signature
static String buildSignature(
String secretKey, String keyTime, String policy) {
/// signkey
var hmacsha1Signkey = Hmac(sha1, utf8.encode(secretKey));
var signKey = hmacsha1Signkey.convert(utf8.encode(keyTime));
// string to sign
var stringToSign = sha1.convert(utf8.encode(policy));
// signature
var hmacsha1Signature = Hmac(sha1, utf8.encode('$signKey'));
var signature = hmacsha1Signature.convert(utf8.encode('$stringToSign'));
return '$signature';
}
/// 生成 KeyTime
/// 获取当前时间对应的 Unix 时间戳 StartTimestampUnix 时间戳是从 UTC协调世界时
/// 或 GMT 格林威治时间1970年1月1日0时0分0秒北京时间 1970年1月1日8时0分0秒起至现在的总秒数。
/// 根据上述时间戳和期望的签名有效时长算出签名过期时间对应的 Unix 时间戳 EndTimestamp。
/// 拼接签名有效时间格式为StartTimestamp;EndTimestamp即为 KeyTime。
/// 示例1557902800;1557910000
static String buildKeyTime() {
int startTime = (new DateTime.now().millisecondsSinceEpoch) ~/ 1000;
int endTime = startTime + 99999;
return '$startTime;$endTime';
}
/// 生成 SignKey
/// 使用 HMAC-SHA1 以 SecretKey 为密钥,以 KeyTime 为消息,计算消息摘要(哈希值),即为 SignKey。
static String buildSignKey(String secretKey, String keyTime) {
// 使用SecertKey对上一步生成的原始字符串计算HMAC-SHA1签名
var hmacsha1 = Hmac(sha1, utf8.encode(secretKey));
var sign = hmacsha1.convert(utf8.encode(keyTime));
return '$sign';
}
}
/// TcYun验签拦截器
class TcyunInterceptor extends InterceptorsWrapper {
@override
Future onRequest(
RequestOptions options,
RequestInterceptorHandler handler,
) async {
if (options.path.contains(TcyunApi.BASE_URL)) {
/// 生成 KeyTime
var keytime = TcyunApi.buildKeyTime();
/// 生成 SignKey
var signKey = TcyunApi.buildSignKey(
'${options.extra[TcyunApi.secretKey]}', keytime);
/// 生成 UrlParamList 和 HttpParameters
String urlParamList = '';
String httpParameters = '';
if (options.queryParameters != null) {
options.queryParameters.forEach((key, value) {
urlParamList += '${key.toLowerCase()};';
httpParameters +=
'${key.toLowerCase()}=${isBlank(value) ? '' : value}&';
});
}
if (urlParamList.length > 0) {
urlParamList = urlParamList.substring(0, urlParamList.length - 1);
}
if (httpParameters.length > 0) {
httpParameters = httpParameters.substring(0, httpParameters.length - 1);
}
/// 生成 HeaderList 和 HttpHeaders
String headerList = '';
String httpHeaders = '';
Map<String, dynamic> headers = {
// 'Date': HttpDate.format(new DateTime.now()),
'Host': options.uri.host
};
headers.addAll(options.headers);
if (options.method.toUpperCase() == 'GET' ||
options.method.toUpperCase() == 'HEAD' ||
options.method.toUpperCase() == 'DELETE' ||
options.method.toUpperCase() == 'OPTIONS') {
headers.remove('content-type');
}
if (headers != null) {
headers.forEach((key, value) {
headerList += '${Uri.encodeComponent(key).toLowerCase()};';
httpHeaders +=
'${Uri.encodeComponent(key).toLowerCase()}=${Uri.encodeComponent(value)}&';
});
}
if (headerList.length > 0) {
headerList = headerList.substring(0, headerList.length - 1);
}
if (httpHeaders.length > 0) {
httpHeaders = httpHeaders.substring(0, httpHeaders.length - 1);
}
/// 生成 HttpString
String method = options.method.toLowerCase();
String httpString =
'$method\n${options.uri.path}\n$httpParameters\n$httpHeaders\n';
/// 生成 StringToSign
String stringtoSign =
'sha1\n$keytime\n${sha1.convert(utf8.encode(httpString))}\n';
/// 生成 Signature
var hmacsha1 = Hmac(sha1, utf8.encode(signKey));
var sign = hmacsha1.convert(utf8.encode(stringtoSign));
/// 生成签名
var realSign = 'q-sign-algorithm=sha1' +
'&q-ak=${options.extra[TcyunApi.secretId]}' +
'&q-sign-time=$keytime' +
'&q-key-time=$keytime' +
'&q-header-list=$headerList' +
'&q-url-param-list=$urlParamList' +
'&q-signature=$sign';
headers.addAll({'Authorization': realSign});
options.headers = headers;
}
return handler.next(options);
}
}