1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2025-06-09 17:06:19 +00:00

Moved PrivateKey to ApiCredentials, ApiCredentials use SecureString, Refactored array param string building

This commit is contained in:
JKorf 2018-08-01 14:41:53 +02:00
parent b0cf1a899e
commit ed14082b9a
5 changed files with 107 additions and 60 deletions

View File

@ -1,27 +1,82 @@
using System; using System;
using System.Security;
namespace CryptoExchange.Net.Authentication namespace CryptoExchange.Net.Authentication
{ {
public class ApiCredentials public class ApiCredentials: IDisposable
{ {
/// <summary> /// <summary>
/// The api key /// The api key to authenticate requests
/// </summary> /// </summary>
public string Key { get; } public SecureString Key { get; }
/// <summary> /// <summary>
/// The api secret /// The api secret to authenticate requests
/// </summary> /// </summary>
public string Secret { get; } public SecureString Secret { get; }
public ApiCredentials() { } /// <summary>
/// The private key to authenticate requests
/// </summary>
public SecureString PrivateKey { get; }
public ApiCredentials(string key, string secret) /// <summary>
/// Create Api credentials providing a private key for authenication
/// </summary>
/// <param name="privateKey">The private key used for signing</param>
public ApiCredentials(SecureString privateKey)
{ {
if(string.IsNullOrEmpty(key) || string.IsNullOrEmpty(secret)) PrivateKey = Key;
throw new ArgumentException("Apikey or apisecret not provided"); }
/// <summary>
/// Create Api credentials providing a private key for authenication
/// </summary>
/// <param name="privateKey">The private key used for signing</param>
public ApiCredentials(string privateKey)
{
var securePrivateKey = new SecureString();
foreach (var c in privateKey)
securePrivateKey.AppendChar(c);
securePrivateKey.MakeReadOnly();
PrivateKey = securePrivateKey;
}
/// <summary>
/// Create Api credentials providing a api key and secret for authenciation
/// </summary>
/// <param name="key">The api key used for identification</param>
/// <param name="secret">The api secret used for signing</param>
public ApiCredentials(SecureString key, SecureString secret)
{
Key = key; Key = key;
Secret = secret; Secret = secret;
} }
/// <summary>
/// Create Api credentials providing a private key for authenication
/// </summary>
/// <param name="privateKey">The private key used for signing</param>
public ApiCredentials(string key, string secret)
{
var secureApiKey = new SecureString();
foreach (var c in key)
secureApiKey.AppendChar(c);
secureApiKey.MakeReadOnly();
Key = secureApiKey;
var secureApiSecret = new SecureString();
foreach (var c in secret)
secureApiSecret.AppendChar(c);
secureApiSecret.MakeReadOnly();
Secret = secureApiSecret;
}
public void Dispose()
{
Key?.Dispose();
Secret?.Dispose();
PrivateKey?.Dispose();
}
} }
} }

View File

@ -1,5 +1,4 @@
using CryptoExchange.Net.Interfaces; using CryptoExchange.Net.Interfaces;
using System.Security;
namespace CryptoExchange.Net.Authentication namespace CryptoExchange.Net.Authentication
{ {
@ -7,18 +6,11 @@ namespace CryptoExchange.Net.Authentication
{ {
public ApiCredentials Credentials { get; } public ApiCredentials Credentials { get; }
public SecureString PrivateKey { get; }
protected AuthenticationProvider(ApiCredentials credentials) protected AuthenticationProvider(ApiCredentials credentials)
{ {
Credentials = credentials; Credentials = credentials;
} }
protected AuthenticationProvider(SecureString privateKey)
{
PrivateKey = privateKey;
}
public virtual string AddAuthenticationToUriString(string uri, bool signed) public virtual string AddAuthenticationToUriString(string uri, bool signed)
{ {
return uri; return uri;

View File

@ -106,23 +106,12 @@ namespace CryptoExchange.Net
string paramString = null; string paramString = null;
if (parameters != null) if (parameters != null)
{ {
paramString = "with parameters "; paramString = "with parameters";
int paramCount = 1;
foreach (var param in parameters) foreach (var param in parameters)
{ paramString += $" {param.Key}={(param.Value.GetType().IsArray ? $"[{string.Join(", ", ((object[])param.Value).Select(p => p.ToString()))}]": param.Value )},";
string paramValue = param.Value.ToString();
if (param.Value.GetType().IsArray)
paramValue = string.Format("[{0}]", string.Join(", ", ((object[])param.Value).Select(p => p.ToString())));
paramString += $"{param.Key}={paramValue}"; paramString = paramString.Trim(',');
if (paramCount < parameters.Count)
paramString += ", ";
else
paramString += ".";
paramCount++;
}
} }
log.Write(LogVerbosity.Debug, $"Sending {(signed ? "signed" : "")} request to {request.Uri} {(paramString ?? "")}"); log.Write(LogVerbosity.Debug, $"Sending {(signed ? "signed" : "")} request to {request.Uri} {(paramString ?? "")}");
@ -140,25 +129,13 @@ namespace CryptoExchange.Net
uriString += "?"; uriString += "?";
var arraysParameters = parameters.Where(p => p.Value.GetType().IsArray).ToList(); var arraysParameters = parameters.Where(p => p.Value.GetType().IsArray).ToList();
if (arraysParameters != null && arraysParameters.Count() > 0) foreach(var arrayEntry in arraysParameters)
{ {
bool isFirstEntry = true; uriString += $"{string.Join("&", ((object[])arrayEntry.Value).Select(v => $"{arrayEntry.Key}[]={v}"))}&";
arraysParameters.ForEach((arrayEntry) =>
{
if (!isFirstEntry)
uriString += "&";
List<object> values = ((object[])arrayEntry.Value).ToList();
uriString += $"{string.Join("&", values.Select(v => $"{arrayEntry.Key}[]={v}"))}";
isFirstEntry = false;
});
if (parameters.Count - arraysParameters.Count > 0)
uriString += "&";
} }
uriString += $"{string.Join("&", parameters.Where(p => !p.Value.GetType().IsArray).Select(s => $"{s.Key}={s.Value}"))}"; uriString += $"{string.Join("&", parameters.Where(p => !p.Value.GetType().IsArray).Select(s => $"{s.Key}={s.Value}"))}";
uriString = uriString.TrimEnd('&');
} }
if (authProvider != null) if (authProvider != null)
@ -272,6 +249,10 @@ namespace CryptoExchange.Net
private void CheckObject(Type type, JObject obj) private void CheckObject(Type type, JObject obj)
{ {
if (type.GetCustomAttribute<JsonConverterAttribute>(true) != null)
// If type has a custom JsonConverter we assume this will handle property mapping
return;
bool isDif = false; bool isDif = false;
var properties = new List<string>(); var properties = new List<string>();
var props = type.GetProperties(); var props = type.GetProperties();
@ -291,12 +272,8 @@ namespace CryptoExchange.Net
{ {
d = properties.SingleOrDefault(p => p.ToLower() == token.Key.ToLower()); d = properties.SingleOrDefault(p => p.ToLower() == token.Key.ToLower());
if (d == null && !(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>))) if (d == null && !(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)))
{ {
// Checking if missing properties is voluntary log.Write(LogVerbosity.Warning, $"Didn't find property `{token.Key}` in object of type `{type.Name}`");
// True : If entire class is handled by a JsonConveter
bool isManuallyDeserialized = type.GetCustomAttribute<JsonConverterAttribute>(true) != null;
if (!isManuallyDeserialized)
log.Write(LogVerbosity.Warning, $"Didn't find property `{token.Key}` in object of type `{type.Name}`");
isDif = true; isDif = true;
continue; continue;
} }
@ -359,6 +336,7 @@ namespace CryptoExchange.Net
public virtual void Dispose() public virtual void Dispose()
{ {
authProvider?.Credentials?.Dispose();
log.Write(LogVerbosity.Debug, "Disposing exchange client"); log.Write(LogVerbosity.Debug, "Disposing exchange client");
} }
} }

View File

@ -1,6 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Security;
using CryptoExchange.Net.Authentication; using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.Logging; using CryptoExchange.Net.Logging;
using CryptoExchange.Net.RateLimiter; using CryptoExchange.Net.RateLimiter;
@ -18,11 +17,6 @@ namespace CryptoExchange.Net
/// </summary> /// </summary>
public ApiCredentials ApiCredentials { get; set; } public ApiCredentials ApiCredentials { get; set; }
/// <summary>
/// The private key instead of api credentials
/// </summary>
public SecureString PrivateKey { get; set; }
/// <summary> /// <summary>
/// Proxy to use /// Proxy to use
/// </summary> /// </summary>

View File

@ -1,4 +1,7 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security;
namespace CryptoExchange.Net namespace CryptoExchange.Net
{ {
@ -25,5 +28,30 @@ namespace CryptoExchange.Net
if (value != null) if (value != null)
parameters.Add(key, value); parameters.Add(key, value);
} }
public static string GetString(this SecureString source)
{
string result = null;
int length = source.Length;
IntPtr pointer = IntPtr.Zero;
char[] chars = new char[length];
try
{
pointer = Marshal.SecureStringToBSTR(source);
Marshal.Copy(pointer, chars, 0, length);
result = string.Join("", chars);
}
finally
{
if (pointer != IntPtr.Zero)
{
Marshal.ZeroFreeBSTR(pointer);
}
}
return result;
}
} }
} }