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 时间戳 StartTimestamp,Unix 时间戳是从 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);
}
}