aboutsummaryrefslogtreecommitdiff
path: root/Timeline/Services/TencentCloudCosService.cs
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2019-04-23 00:14:35 +0800
committercrupest <crupest@outlook.com>2019-04-23 00:14:35 +0800
commit797b1da15c76f6598dcc48f675c1b82cb27a17ed (patch)
tree99754727d79f8ae27c96f35e2541d51be780deb4 /Timeline/Services/TencentCloudCosService.cs
parent752850049301290b991f748816c66352f578c057 (diff)
downloadtimeline-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.cs174
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();
}
}
}