Skip to content
This repository has been archived by the owner on May 24, 2024. It is now read-only.

Commit

Permalink
Merge branch 'master' into memo-length-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
fracek committed Oct 20, 2020
2 parents da6056f + 33dc4e3 commit 75fb76b
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 54 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ You can use that version of xdrgen to regenerate the XDR files from the .x files

## Contributors

- Eric Malamisura (Twitter: [@emalamisura](https://twitter.com/emalamisura), Keybase: [elucidsoft](https://keybase.io/elucidsoft))
- Eric Malamisura (Twitter: [@EricDaCoder](https://twitter.com/EricDaCoder), Keybase: [elucidsoft](https://keybase.io/elucidsoft))
- Kirbyrawr (Keybase: [Kirbyrawr](https://keybase.io/Kirbyrawr))
- Michael Monte
- Francesco Ceccon
Expand Down
4 changes: 2 additions & 2 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: 5.0.{build}
version: 5.1.{build}
pull_requests:
do_not_increment_build_number: true
os: Visual Studio 2017
Expand Down Expand Up @@ -32,6 +32,6 @@ deploy:
APPVEYOR_REPO_TAG: true
provider: NuGet
api_key:
secure: vm+rrsWiV8YUExTehIEf2ACt0R0xDzYJ0OoHvNlu7hGZfvnop/tpbuamDm16uArT
secure: J6pqB7e0Vjm9sIZcetbLlCF+HLYemSm3GMBogOg4kbCMJ1AqyjjmflxZnAdxZAL2
skip_symbols: false
artifact: nuget
112 changes: 76 additions & 36 deletions stellar-dotnet-sdk-test/WebAuthenticationTest.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using stellar_dotnet_sdk;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using stellar_dotnet_sdk;

namespace stellar_dotnet_sdk_test
{
Expand Down Expand Up @@ -522,38 +522,6 @@ public void TestReadChallengeTransactionInvalidSequenceNoNotZero()
}
}

[TestMethod]
public void TestReadChallengeTransactionInvalidTooManyOperations()
{
Network.Use(Network.Test());

var serverKeypair = KeyPair.Random();
var clientKeypair = KeyPair.Random();

var txSource = new Account(serverKeypair.Address, -1);
var opSource = new Account(clientKeypair.Address, 0);

var plainTextBytes = Encoding.UTF8.GetBytes(new string(' ', 48));
var base64Data = Encoding.ASCII.GetBytes(Convert.ToBase64String(plainTextBytes));

var operation = new ManageDataOperation.Builder(ManageDataOperationName, base64Data).SetSourceAccount(opSource.KeyPair).Build();
var transaction = new TransactionBuilder(txSource)
.AddOperation(operation).AddOperation(operation)
.AddTimeBounds(new TimeBounds(DateTimeOffset.Now, DateTimeOffset.Now.AddSeconds(1000)))
.Build();

transaction.Sign(serverKeypair);

try
{
var readTransactionID = WebAuthentication.ReadChallengeTransaction(transaction, serverKeypair.AccountId, HomeDomain, Network.Test());
}
catch (Exception exception)
{
Assert.IsTrue(exception.Message.Contains("Challenge transaction must contain one operation"));
}
}

[TestMethod]
public void TestReadChallengeTransactionInvalidOperationWrongType()
{
Expand Down Expand Up @@ -855,7 +823,7 @@ public void TestVerifyChallengeTransactionThresholdInvalidServerAndMultipleClien
{
var signersFound = WebAuthentication.VerifyChallengeTransactionThreshold(transaction, serverKeypair.AccountId, threshold, signerSummary, HomeDomain, Network.Test()).ToList();
}
catch(Exception exception)
catch (Exception exception)
{
Assert.IsTrue(exception.Message.Contains("Signers with weight 3 do not meet threshold 10"));
}
Expand Down Expand Up @@ -1522,5 +1490,77 @@ public void TestVerifyChallengeTransactionSignersInvalidNoSigners()
Assert.IsTrue(exception.Message.Contains("signers must be non-empty"));
}
}

[TestMethod]
public void TestVerifyChallengeTransactionNotValidSubsequentOperation()
{
Network.Use(Network.Test());

var serverKeypair = KeyPair.Random();
var clientKeypair = KeyPair.Random();

var txSource = new Account(serverKeypair.Address, -1);
var opSource = new Account(clientKeypair.Address, 0);

var plainTextBytes = Encoding.UTF8.GetBytes(new string(' ', 48));
var base64Data = Encoding.ASCII.GetBytes(Convert.ToBase64String(plainTextBytes));

var operation = new ManageDataOperation.Builder(ManageDataOperationName, base64Data).SetSourceAccount(opSource.KeyPair).Build();
var notValidOperation = new PaymentOperation.Builder(KeyPair.Random(), new AssetTypeNative(), "50").SetSourceAccount(opSource.KeyPair).Build();

var transaction = new TransactionBuilder(txSource)
.AddOperation(operation)
.AddOperation(notValidOperation)
.AddTimeBounds(new TimeBounds(DateTimeOffset.Now, DateTimeOffset.Now.AddSeconds(1000)))
.Build();

transaction.Sign(serverKeypair);
transaction.Sign(clientKeypair);

try
{
WebAuthentication.ReadChallengeTransaction(transaction, serverKeypair.AccountId, HomeDomain, Network.Test());
}
catch (Exception exception)
{
Assert.IsTrue(exception.Message.Contains("The transaction has operations that are not of type 'manageData'"));
}
}

[TestMethod]
public void TestVerifyChallengeTransactionNotValidSubsequentDataOperation()
{
Network.Use(Network.Test());

var serverKeypair = KeyPair.Random();
var clientKeypair = KeyPair.Random();

var txSource = new Account(serverKeypair.Address, -1);
var opSource = new Account(clientKeypair.Address, 0);

var plainTextBytes = Encoding.UTF8.GetBytes(new string(' ', 48));
var base64Data = Encoding.ASCII.GetBytes(Convert.ToBase64String(plainTextBytes));

var operation = new ManageDataOperation.Builder(ManageDataOperationName, base64Data).SetSourceAccount(opSource.KeyPair).Build();
var notValidOperation = new ManageDataOperation.Builder(ManageDataOperationName, base64Data).SetSourceAccount(KeyPair.Random()).Build();

var transaction = new TransactionBuilder(txSource)
.AddOperation(operation)
.AddOperation(notValidOperation)
.AddTimeBounds(new TimeBounds(DateTimeOffset.Now, DateTimeOffset.Now.AddSeconds(1000)))
.Build();

transaction.Sign(serverKeypair);
transaction.Sign(clientKeypair);

try
{
WebAuthentication.ReadChallengeTransaction(transaction, serverKeypair.AccountId, HomeDomain, Network.Test());
}
catch (Exception exception)
{
Assert.IsTrue(exception.Message.Contains("The transaction has operations that are unrecognized"));
}
}
}
}
}
41 changes: 26 additions & 15 deletions stellar-dotnet-sdk/WebAuthentication.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
Expand All @@ -16,7 +16,7 @@ public static class WebAuthentication
/// </summary>
/// <param name="serverKeypair">Server signing keypair</param>
/// <param name="clientAccountId">The client account id that needs authentication</param>
/// <param name="anchorName">The anchor name</param>
/// <param name="domainName">The domain name</param>
/// <param name="nonce">48 bytes long cryptographic-quality random data</param>
/// <param name="now">The datetime from which the transaction is valid</param>
/// <param name="timeout">The transaction lifespan</param>
Expand All @@ -25,15 +25,15 @@ public static class WebAuthentication
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
public static Transaction BuildChallengeTransaction(KeyPair serverKeypair, string clientAccountId,
string anchorName, byte[] nonce = null, DateTimeOffset? now = null, TimeSpan? timeout = null,
string domainName, byte[] nonce = null, DateTimeOffset? now = null, TimeSpan? timeout = null,
Network network = null)
{
if (string.IsNullOrEmpty(clientAccountId)) throw new ArgumentNullException(nameof(clientAccountId));

if (StrKey.DecodeVersionByte(clientAccountId) != StrKey.VersionByte.ACCOUNT_ID)
throw new InvalidWebAuthenticationException($"{nameof(clientAccountId)} is not a valid account id");
var clientAccountKeypair = KeyPair.FromAccountId(clientAccountId);
return BuildChallengeTransaction(serverKeypair, clientAccountKeypair, anchorName, nonce, now, timeout,
return BuildChallengeTransaction(serverKeypair, clientAccountKeypair, domainName, nonce, now, timeout,
network);
}

Expand All @@ -42,7 +42,7 @@ public static class WebAuthentication
/// </summary>
/// <param name="serverKeypair">Server signing keypair</param>
/// <param name="clientAccountId">The client account id that needs authentication</param>
/// <param name="anchorName">The anchor name</param>
/// <param name="domainName">The domain name</param>
/// <param name="nonce">48 bytes long cryptographic-quality random data</param>
/// <param name="now">The datetime from which the transaction is valid</param>
/// <param name="timeout">The transaction lifespan</param>
Expand All @@ -51,12 +51,12 @@ public static class WebAuthentication
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
public static Transaction BuildChallengeTransaction(KeyPair serverKeypair, KeyPair clientAccountId,
string anchorName, byte[] nonce = null, DateTimeOffset? now = null, TimeSpan? timeout = null,
string domainName, byte[] nonce = null, DateTimeOffset? now = null, TimeSpan? timeout = null,
Network network = null)
{
if (serverKeypair is null) throw new ArgumentNullException(nameof(serverKeypair));
if (clientAccountId is null) throw new ArgumentNullException(nameof(clientAccountId));
if (string.IsNullOrEmpty(anchorName)) throw new ArgumentNullException(nameof(anchorName));
if (string.IsNullOrEmpty(domainName)) throw new ArgumentNullException(nameof(domainName));

if (nonce is null)
{
Expand All @@ -78,7 +78,7 @@ public static class WebAuthentication
// Sequence number is incremented by 1 before building the transaction, set it to -1 to have 0
var serverAccount = new Account(serverKeypair, -1);

var manageDataKey = $"{anchorName} auth";
var manageDataKey = $"{domainName} auth";
var manageDataValue = Encoding.UTF8.GetBytes(Convert.ToBase64String(nonce));

var timeBounds = new TimeBounds(validFrom, validFor);
Expand Down Expand Up @@ -133,8 +133,8 @@ public static class WebAuthentication
if (transaction.SourceAccount.AccountId != serverAccountId)
throw new InvalidWebAuthenticationException("Challenge transaction source must be serverAccountId");

if (transaction.Operations.Length != 1)
throw new InvalidWebAuthenticationException("Challenge transaction must contain one operation");
if (transaction.Operations.Length < 1)
throw new InvalidWebAuthenticationException("Challenge transaction must contain atleast one operation");

var operation = transaction.Operations[0] as ManageDataOperation;

Expand All @@ -145,6 +145,20 @@ public static class WebAuthentication
if (operation.SourceAccount is null)
throw new InvalidWebAuthenticationException("Challenge transaction operation must have source account");

var subsequentOperations = transaction.Operations;
foreach (var op in subsequentOperations.Skip(1))
{
if (!(op is ManageDataOperation))
{
throw new InvalidWebAuthenticationException("The transaction has operations that are not of type 'manageData'");
}

if (op.SourceAccount.AccountId != serverAccountId)
{
throw new InvalidWebAuthenticationException("The transaction has operations that are unrecognized");
}
}

var clientAccountKeypair = operation.SourceAccount;

if (clientAccountKeypair.IsMuxedAccount)
Expand All @@ -157,9 +171,6 @@ public static class WebAuthentication
throw new InvalidWebAuthenticationException(
"Challenge transaction operation data must be 64 bytes long");

if (operation.Name != $"{homeDomain} auth")
throw new InvalidWebAuthenticationException("Challenge transaction operation data must have home domain key");

try
{
// There is no need to check for decoded value length since we know it's valid base64 and 64 bytes long.
Expand Down Expand Up @@ -276,7 +287,7 @@ public static class WebAuthentication

private static bool ValidateSignedBy(Transaction transaction, string accountId, Network network)
{
var signaturesUsed = VerifyTransactionSignatures(transaction, new[] {accountId}, network);
var signaturesUsed = VerifyTransactionSignatures(transaction, new[] { accountId }, network);
return signaturesUsed.Count == 1;
}

Expand Down Expand Up @@ -318,4 +329,4 @@ private static bool ValidateTimeBounds(TimeBounds timeBounds, DateTimeOffset now
return signersFound.ToArray();
}
}
}
}

0 comments on commit 75fb76b

Please sign in to comment.