diff options
author | crupest <crupest@outlook.com> | 2019-04-23 00:14:35 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2019-04-23 00:14:35 +0800 |
commit | 797b1da15c76f6598dcc48f675c1b82cb27a17ed (patch) | |
tree | 99754727d79f8ae27c96f35e2541d51be780deb4 /Timeline/Services/TencentCloudCosService.cs | |
parent | 752850049301290b991f748816c66352f578c057 (diff) | |
download | timeline-797b1da15c76f6598dcc48f675c1b82cb27a17ed.tar.gz timeline-797b1da15c76f6598dcc48f675c1b82cb27a17ed.tar.bz2 timeline-797b1da15c76f6598dcc48f675c1b82cb27a17ed.zip |
Remove qcloud cs sdk. I will write one by myself.
Develop signature algorithm.
Diffstat (limited to 'Timeline/Services/TencentCloudCosService.cs')
-rw-r--r-- | Timeline/Services/TencentCloudCosService.cs | 174 |
1 files changed, 109 insertions, 65 deletions
diff --git a/Timeline/Services/TencentCloudCosService.cs b/Timeline/Services/TencentCloudCosService.cs index 9ab9d54d..1bfcf745 100644 --- a/Timeline/Services/TencentCloudCosService.cs +++ b/Timeline/Services/TencentCloudCosService.cs @@ -1,99 +1,143 @@ -using COSXML; -using COSXML.Auth; -using COSXML.CosException; -using COSXML.Model; -using COSXML.Model.Object; -using COSXML.Model.Tag; -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Net; +using System.Security.Cryptography; +using System.Text; using System.Threading.Tasks; using Timeline.Configs; namespace Timeline.Services { - public interface ITencentCloudCosService + public interface IQCloudCosService { - Task<bool> Exists(string bucket, string key); + Task<bool> ObjectExists(string bucket, string key); string GetObjectUrl(string bucket, string key); } - public class TencentCloudCosService : ITencentCloudCosService + public class QCloudCosService : IQCloudCosService { - private readonly TencentCosConfig _config; - private readonly CosXmlServer _server; - private readonly ILogger<TencentCloudCosService> _logger; + private readonly QCloudCosConfig _config; + private readonly ILogger<QCloudCosService> _logger; - public TencentCloudCosService(IOptions<TencentCosConfig> config, ILogger<TencentCloudCosService> logger) + public QCloudCosService(IOptions<QCloudCosConfig> config, ILogger<QCloudCosService> logger) { _config = config.Value; _logger = logger; + } - var cosConfig = new CosXmlConfig.Builder() - .IsHttps(true) - .SetAppid(config.Value.AppId) - .SetRegion(config.Value.Region) - .SetDebugLog(true) - .Build(); + public class QCloudCredentials + { + public string SecretId { get; set; } + public string SecretKey { get; set; } + } - var credentialProvider = new DefaultQCloudCredentialProvider(config.Value.SecretId, config.Value.SecretKey, 3600); + public class RequestInfo + { + public string Method { get; set; } + public string Uri { get; set; } + public IEnumerable<KeyValuePair<string, string>> Parameters { get; set; } + public IEnumerable<KeyValuePair<string, string>> Headers { get; set; } + } - _server = new CosXmlServer(cosConfig, credentialProvider); + public class TimeDuration + { + public DateTimeOffset Start { get; set; } + public DateTimeOffset End { get; set; } } - public Task<bool> Exists(string bucket, string key) + public static string GenerateSign(QCloudCredentials credentials, RequestInfo request, TimeDuration signValidTime) { - bucket = bucket + "-" + _config.AppId; + Debug.Assert(credentials != null); + Debug.Assert(credentials.SecretId != null); + Debug.Assert(credentials.SecretKey != null); + Debug.Assert(request != null); + Debug.Assert(request.Method != null); + Debug.Assert(request.Uri != null); + Debug.Assert(request.Parameters != null); + Debug.Assert(request.Headers != null); + Debug.Assert(signValidTime != null); + Debug.Assert(signValidTime.Start < signValidTime.End, "Start must be before End in sign valid time."); + + List<(string key, string value)> Transform(IEnumerable<KeyValuePair<string, string>> raw) + { + var sorted= raw.Select(p => (key: p.Key.ToLower(), value: WebUtility.UrlEncode(p.Value))).ToList(); + sorted.Sort((left, right) => string.CompareOrdinal(left.key, right.key)); + return sorted; + } + + var transformedParameters = Transform(request.Parameters); + var transformedHeaders = Transform(request.Headers); + + List<(string, string)> result = new List<(string, string)>(); + + const string signAlgorithm = "sha1"; + result.Add(("q-sign-algorithm", signAlgorithm)); + + result.Add(("q-ak", credentials.SecretId)); + + var signTime = $"{signValidTime.Start.ToUnixTimeSeconds().ToString()};{signValidTime.End.ToUnixTimeSeconds().ToString()}"; + var keyTime = signTime; + result.Add(("q-sign-time", signTime)); + result.Add(("q-key-time", keyTime)); - var request = new HeadObjectRequest(bucket, key); + result.Add(("q-header-list", string.Join(';', transformedHeaders.Select(h => h.key)))); + result.Add(("q-url-param-list", string.Join(';', transformedParameters.Select(p => p.key)))); - var t = new TaskCompletionSource<bool>(); + HMACSHA1 hmac = new HMACSHA1(); - _server.HeadObject(request, delegate (CosResult result) + string ByteArrayToString(byte[] bytes) { - if (result.httpCode >= 200 && result.httpCode < 300) - t.TrySetResult(true); - else - t.TrySetResult(false); - }, - delegate (CosClientException clientException, CosServerException serverException) + return BitConverter.ToString(bytes).Replace("-", "").ToLower(); + } + + hmac.Key = Encoding.UTF8.GetBytes(credentials.SecretKey); + var signKey = ByteArrayToString(hmac.ComputeHash(Encoding.UTF8.GetBytes(keyTime))); + + string Join(IEnumerable<(string key, string value)> raw) { - if (clientException != null) - { - _logger.LogError(clientException, "An client error occured when test cos object existence. Bucket : {} . Key : {} .", bucket, key); - t.TrySetException(clientException); - return; - } - if (serverException != null) - { - if (serverException.statusCode == 404) - { - t.TrySetResult(false); - return; - } - _logger.LogError(serverException, "An server error occured when test cos object existence. Bucket : {} . Key : {} .", bucket, key); - t.TrySetException(serverException); - return; - } - _logger.LogError("An unknown error occured when test cos object existence. Bucket : {} . Key : {} .", bucket, key); - t.TrySetException(new Exception("Unknown exception when test cos object existence.")); - }); - - return t.Task; + return string.Join('&', raw.Select(p => string.Concat(p.key, "=", p.value))); + } + + var httpString = new StringBuilder() + .Append(request.Method).Append('\n') + .Append(request.Uri).Append('\n') + .Append(Join(transformedParameters)).Append('\n') + .Append(Join(transformedHeaders)).Append('\n') + .ToString(); + + string Sha1(string data) + { + var sha1 = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(data)); + return ByteArrayToString(sha1); + } + + var stringToSign = new StringBuilder() + .Append(signAlgorithm).Append('\n') + .Append(signTime).Append('\n') + .Append(Sha1(httpString)).Append('\n') + .ToString(); + + hmac.Key = Encoding.UTF8.GetBytes(signKey); + var signature = ByteArrayToString(hmac.ComputeHash( + Encoding.UTF8.GetBytes(stringToSign))); + + result.Add(("q-signature", signature)); + + return Join(result); + } + + public Task<bool> ObjectExists(string bucket, string key) + { + throw new NotImplementedException(); } public string GetObjectUrl(string bucket, string key) { - return _server.GenerateSignURL(new PreSignatureStruct() - { - appid = _config.AppId, - region = _config.Region, - bucket = bucket + "-" + _config.AppId, - key = key, - httpMethod = "GET", - isHttps = true, - signDurationSecond = 300 - }); + throw new NotImplementedException(); } } } |