diff --git a/CryptoExchange.Net/Authentication/ApiCredentials.cs b/CryptoExchange.Net/Authentication/ApiCredentials.cs
index 416b57f..9098eef 100644
--- a/CryptoExchange.Net/Authentication/ApiCredentials.cs
+++ b/CryptoExchange.Net/Authentication/ApiCredentials.cs
@@ -5,6 +5,11 @@
///
public abstract class ApiCredentials
{
+ ///
+ /// Validate the API credentials
+ ///
+ public abstract void Validate();
+
///
/// Copy the credentials
///
diff --git a/CryptoExchange.Net/Authentication/AuthenticationProvider.cs b/CryptoExchange.Net/Authentication/AuthenticationProvider.cs
index 0d26a47..a78e091 100644
--- a/CryptoExchange.Net/Authentication/AuthenticationProvider.cs
+++ b/CryptoExchange.Net/Authentication/AuthenticationProvider.cs
@@ -453,43 +453,33 @@ namespace CryptoExchange.Net.Authentication
///
public abstract class AuthenticationProvider : AuthenticationProvider
+ where TApiCredentials: ApiCredentials
{
///
/// API credentials used for signing requests
///
public TApiCredentials ApiCredentials { get; set; }
- public CredentialPair? Credential { get; set; }
-
///
/// ctor
///
protected AuthenticationProvider(TApiCredentials credentials)
{
- ApiCredentials = credentials;
- }
-
- ///
- /// ctor
- ///
- protected AuthenticationProvider(TApiCredentials credentials, CredentialPair? credentialPair)
- {
- if (credentialPair == null)
- throw new ArgumentNullException(nameof(credentialPair), $"Credential pair needed but not provided");
+ credentials.Validate();
ApiCredentials = credentials;
- Credential = credentialPair;
}
}
///
public abstract class AuthenticationProvider : AuthenticationProvider
+ where TApiCredentials : ApiCredentials
where TCredentialType : CredentialPair
{
///
/// The specific credential type used for signing requests.
///
- public new TCredentialType Credential => (TCredentialType)base.Credential!;
+ public TCredentialType Credential { get; }
///
public override string Key => Credential.Key;
@@ -497,8 +487,12 @@ namespace CryptoExchange.Net.Authentication
///
/// ctor
///
- protected AuthenticationProvider(TApiCredentials credentials, TCredentialType? credential) : base(credentials, credential)
+ protected AuthenticationProvider(TApiCredentials credentials, TCredentialType? credential) : base(credentials)
{
+ if (credential == null)
+ throw new ArgumentException("Missing required credentials");
+
+ Credential = credential;
}
///
diff --git a/CryptoExchange.Net/Authentication/CredentialPair.cs b/CryptoExchange.Net/Authentication/CredentialPair.cs
index 26f6228..e7b135a 100644
--- a/CryptoExchange.Net/Authentication/CredentialPair.cs
+++ b/CryptoExchange.Net/Authentication/CredentialPair.cs
@@ -2,6 +2,8 @@
using System.Security.Cryptography;
using System.Text;
+#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
+
namespace CryptoExchange.Net.Authentication
{
///
@@ -14,6 +16,11 @@ namespace CryptoExchange.Net.Authentication
///
public string Key { get; set; }
+ ///
+ /// ctor
+ ///
+ public CredentialPair() { }
+
///
/// ctor
///
@@ -21,6 +28,15 @@ namespace CryptoExchange.Net.Authentication
{
Key = key;
}
+
+ ///
+ /// Validate the API credential
+ ///
+ public override void Validate()
+ {
+ if (string.IsNullOrEmpty(Key))
+ throw new ArgumentException("Key unset", nameof(Key));
+ }
}
///
@@ -34,12 +50,11 @@ namespace CryptoExchange.Net.Authentication
/// Api key
public ApiKeyCredential(string key) : base(key)
{
- if (string.IsNullOrEmpty(key))
- throw new ArgumentException("Key can't be null/empty");
}
///
public override ApiCredentials Copy() => new ApiKeyCredential(Key);
+
}
///
@@ -53,24 +68,22 @@ namespace CryptoExchange.Net.Authentication
/// API secret
///
public string Secret { get; set; }
+
///
- /// Passphrase, not needed on all exchanges
+ /// ctor
///
- public string? Pass { get; set; }
+ public HMACCredential()
+ {
+ }
///
/// ctor
///
/// Api key/label
/// Api secret
- /// Optional passphrase
- public HMACCredential(string key, string secret, string? pass = null) : base(key)
+ public HMACCredential(string key, string secret) : base(key)
{
- if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(secret))
- throw new ArgumentException("Key and secret can't be null/empty");
-
Secret = secret;
- Pass = pass;
}
///
@@ -83,7 +96,56 @@ namespace CryptoExchange.Net.Authentication
}
///
- public override ApiCredentials Copy() => new HMACCredential(Key, Secret, Pass);
+ public override ApiCredentials Copy() => new HMACCredential(Key, Secret);
+
+ ///
+ public override void Validate()
+ {
+ base.Validate();
+ if (string.IsNullOrEmpty(Secret))
+ throw new ArgumentException("Secret unset", nameof(Secret));
+ }
+ }
+
+ ///
+ /// HMAC credentials
+ ///
+ public class HMACPassCredential : HMACCredential
+ {
+ ///
+ /// Passphrase
+ ///
+ public string Pass { get; set; }
+
+ ///
+ /// ctor
+ ///
+ public HMACPassCredential()
+ {
+ }
+
+ ///
+ /// ctor
+ ///
+ /// Api key/label
+ /// Api secret
+ /// Passphrase
+ public HMACPassCredential(string key, string secret, string pass) : base(key, secret)
+ {
+ Pass = pass;
+ }
+
+
+ ///
+ public override ApiCredentials Copy() => new HMACPassCredential(Key, Secret, Pass);
+
+ ///
+ public override void Validate()
+ {
+ base.Validate();
+ if (string.IsNullOrEmpty(Pass))
+ throw new ArgumentException("Pass unset", nameof(Pass));
+ }
}
///
@@ -95,10 +157,54 @@ namespace CryptoExchange.Net.Authentication
/// Private key
///
public string PrivateKey { get; set; }
+
+ ///
+ /// ctor
+ ///
+ public RSACredential()
+ {
+ }
+
+ ///
+ /// ctor
+ ///
+ /// Public key
+ /// Private key
+ public RSACredential(string key, string privateKey) : base(key)
+ {
+ PrivateKey = privateKey;
+ }
+
+ ///
+ /// Get RSA signer
+ ///
+ public abstract RSA GetSigner();
+
+ ///
+ public override void Validate()
+ {
+ base.Validate();
+ if (string.IsNullOrEmpty(PrivateKey))
+ throw new ArgumentException("PrivateKey unset", nameof(PrivateKey));
+ }
+ }
+
+ ///
+ /// RSA credentials
+ ///
+ public abstract class RSAPassCredential : RSACredential
+ {
///
/// Passphrase
///
- public string? Pass { get; set; }
+ public string Pass { get; set; }
+
+ ///
+ /// ctor
+ ///
+ public RSAPassCredential()
+ {
+ }
///
/// ctor
@@ -106,19 +212,19 @@ namespace CryptoExchange.Net.Authentication
/// Public key
/// Private key
/// Passphrase
- public RSACredential(string key, string privateKey, string? pass = null) : base(key)
+ public RSAPassCredential(string key, string privateKey, string pass) : base(key, privateKey)
{
- if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(privateKey))
- throw new ArgumentException("Public and private key can't be null/empty");
-
PrivateKey = privateKey;
Pass = pass;
}
- ///
- /// Get RSA signer
- ///
- public abstract RSA GetSigner();
+ ///
+ public override void Validate()
+ {
+ base.Validate();
+ if (string.IsNullOrEmpty(Pass))
+ throw new ArgumentException("Pass unset", nameof(Pass));
+ }
}
#if NETSTANDARD2_1_OR_GREATER || NET7_0_OR_GREATER
@@ -127,13 +233,19 @@ namespace CryptoExchange.Net.Authentication
///
public class RSAPemCredential : RSACredential
{
+ ///
+ /// ctor
+ ///
+ public RSAPemCredential()
+ {
+ }
+
///
/// ctor
///
/// Public key
/// Private key
- /// Passphrase
- public RSAPemCredential(string key, string privateKey, string? passphrase = null) : base(key, privateKey, passphrase)
+ public RSAPemCredential(string key, string privateKey) : base(key, privateKey)
{
}
@@ -156,7 +268,59 @@ namespace CryptoExchange.Net.Authentication
}
///
- public override ApiCredentials Copy() => new RSAPemCredential(Key, PrivateKey, Pass);
+ public override ApiCredentials Copy() => new RSAPemCredential(Key, PrivateKey);
+
+ ///
+ public override void Validate()
+ {
+ base.Validate();
+ if (string.IsNullOrEmpty(PrivateKey))
+ throw new ArgumentException("PrivateKey unset", nameof(PrivateKey));
+ }
+ }
+
+ ///
+ /// RSA PEM/Base64 credentials
+ ///
+ public class RSAPemPassCredential : RSAPassCredential
+ {
+ ///
+ /// ctor
+ ///
+ public RSAPemPassCredential()
+ {
+ }
+
+ ///
+ /// ctor
+ ///
+ /// Api key/label
+ /// Api secret
+ /// Passphrase
+ public RSAPemPassCredential(string key, string privateKey, string pass) : base(key, privateKey, pass)
+ {
+ }
+
+ ///
+ /// Get RSA signer
+ ///
+ public override RSA GetSigner()
+ {
+ var rsa = RSA.Create();
+ var key = PrivateKey!
+ .Replace("\n", "")
+ .Replace("-----BEGIN PRIVATE KEY-----", "")
+ .Replace("-----END PRIVATE KEY-----", "")
+ .Trim();
+ rsa.ImportPkcs8PrivateKey(Convert.FromBase64String(
+ key)
+ , out _);
+
+ return rsa;
+ }
+
+ ///
+ public override ApiCredentials Copy() => new RSAPemPassCredential(Key, PrivateKey, Pass);
}
#endif
@@ -165,13 +329,19 @@ namespace CryptoExchange.Net.Authentication
///
public class RSAXmlCredential : RSACredential
{
+ ///
+ /// ctor
+ ///
+ public RSAXmlCredential()
+ {
+ }
+
///
/// ctor
///
/// Public key
/// Private key
- /// Passphrase
- public RSAXmlCredential(string key, string privateKey, string? passphrase = null) : base(key, privateKey, passphrase)
+ public RSAXmlCredential(string key, string privateKey) : base(key, privateKey)
{
}
@@ -186,7 +356,43 @@ namespace CryptoExchange.Net.Authentication
}
///
- public override ApiCredentials Copy() => new RSAXmlCredential(Key, PrivateKey, Pass);
+ public override ApiCredentials Copy() => new RSAXmlCredential(Key, PrivateKey);
+ }
+
+ ///
+ /// RSA XML credentials
+ ///
+ public class RSAXmlPassCredential : RSAPassCredential
+ {
+ ///
+ /// ctor
+ ///
+ public RSAXmlPassCredential()
+ {
+ }
+
+ ///
+ /// ctor
+ ///
+ /// Api key/label
+ /// Api secret
+ /// Passphrase
+ public RSAXmlPassCredential(string key, string privateKey, string pass) : base(key, privateKey, pass)
+ {
+ }
+
+ ///
+ /// Get RSA signer
+ ///
+ public override RSA GetSigner()
+ {
+ var rsa = RSA.Create();
+ rsa.FromXmlString(PrivateKey);
+ return rsa;
+ }
+
+ ///
+ public override ApiCredentials Copy() => new RSAXmlPassCredential(Key, PrivateKey, Pass);
}
#if NET8_0_OR_GREATER
@@ -201,21 +407,22 @@ namespace CryptoExchange.Net.Authentication
/// Private key
///
public string PrivateKey { get; set; }
+
///
- /// Passphrase
+ /// ctor
///
- public string? Pass { get; set; }
+ public Ed25519Credential()
+ {
+ }
///
/// ctor
///
/// Public key
/// Private key
- /// Passphrase
- public Ed25519Credential(string key, string privateKey, string? pass = null) : base(key)
+ public Ed25519Credential(string key, string privateKey) : base(key)
{
PrivateKey = privateKey;
- Pass = pass;
}
///
@@ -237,7 +444,55 @@ namespace CryptoExchange.Net.Authentication
}
///
- public override ApiCredentials Copy() => new Ed25519Credential(Key, PrivateKey, Pass);
+ public override ApiCredentials Copy() => new Ed25519Credential(Key, PrivateKey);
+
+ ///
+ public override void Validate()
+ {
+ base.Validate();
+ if (string.IsNullOrEmpty(PrivateKey))
+ throw new ArgumentException("PrivateKey unset", nameof(PrivateKey));
+ }
+ }
+
+ ///
+ /// Ed25519 credentials
+ ///
+ public class Ed25519PassCredential : Ed25519Credential
+ {
+ ///
+ /// Passphrase
+ ///
+ public string Pass { get; set; }
+
+ ///
+ /// ctor
+ ///
+ public Ed25519PassCredential()
+ {
+ }
+
+ ///
+ /// ctor
+ ///
+ /// Api key/label
+ /// Private key
+ /// Passphrase
+ public Ed25519PassCredential(string key, string privateKey, string pass) : base(key, privateKey)
+ {
+ Pass = pass;
+ }
+
+ ///
+ public override ApiCredentials Copy() => new Ed25519PassCredential(Key, PrivateKey, Pass);
+
+ ///
+ public override void Validate()
+ {
+ base.Validate();
+ if (string.IsNullOrEmpty(Pass))
+ throw new ArgumentException("Pass unset", nameof(Pass));
+ }
}
#endif
@@ -250,24 +505,73 @@ namespace CryptoExchange.Net.Authentication
/// Private key
///
public string PrivateKey { get; set; }
+
///
- /// Passphrase
+ /// ctor
///
- public string? Pass { get; set; }
+ public ECDsaCredential()
+ {
+ }
///
/// ctor
///
/// Public key
/// Private key
- /// Passphrase
- public ECDsaCredential(string key, string privateKey, string? pass = null) : base(key)
+ public ECDsaCredential(string key, string privateKey) : base(key)
{
PrivateKey = privateKey;
+ }
+
+ ///
+ public override ApiCredentials Copy() => new ECDsaCredential(Key, PrivateKey);
+
+ ///
+ public override void Validate()
+ {
+ base.Validate();
+ if (string.IsNullOrEmpty(PrivateKey))
+ throw new ArgumentException("PrivateKey unset", nameof(PrivateKey));
+ }
+ }
+
+ ///
+ /// ECDsa credentials
+ ///
+ public class ECDsaPassCredential : ECDsaCredential
+ {
+ ///
+ /// Passphrase
+ ///
+ public string Pass { get; set; }
+
+ ///
+ /// ctor
+ ///
+ public ECDsaPassCredential()
+ {
+ }
+
+ ///
+ /// ctor
+ ///
+ /// Api key/label
+ /// Private key
+ /// Passphrase
+ public ECDsaPassCredential(string key, string privateKey, string pass) : base(key, privateKey)
+ {
Pass = pass;
}
///
- public override ApiCredentials Copy() => new ECDsaCredential(Key, PrivateKey, Pass);
+ public override ApiCredentials Copy() => new ECDsaPassCredential(Key, PrivateKey, Pass);
+
+ ///
+ public override void Validate()
+ {
+ base.Validate();
+ if (string.IsNullOrEmpty(Pass))
+ throw new ArgumentException("Pass unset", nameof(Pass));
+ }
}
}