Skip to content

Commit

Permalink
Fixing issues with the signatures returned from the relay
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidGershony committed Nov 16, 2023
1 parent f005464 commit c739fd4
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 86 deletions.
83 changes: 47 additions & 36 deletions src/Angor/Client/Pages/Invest.razor
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
@using Angor.Shared
@using Angor.Client.Storage
@using Angor.Shared.Models
@using Blockcore.Consensus.TransactionInfo
@using Blockcore.NBitcoin
@using Angor.Client.Services
@using Angor.Shared.ProtocolNew
@using Blockcore.NBitcoin.DataEncoders
@using JSException = Microsoft.JSInterop.JSException
@using Money = Blockcore.NBitcoin.Money
@using Transaction = Blockcore.Consensus.TransactionInfo.Transaction

@inject IJSRuntime JS

Expand Down Expand Up @@ -160,16 +161,19 @@
}
</div>
}
@if (recoverySigs != null)
@if (recoverySigs?.Signatures.Count == project.Stages.Count)
{
<div class="modal fade show d-block" tabindex="-1" style="background: rgba(0, 0, 0, 0.5)">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">The founder has signed the recovery transaction</h5>
<button type="button" class="btn-success" @onclick="PublishSignedTransactionAsync">Invest</button>
</div>
</div>
<div class="card">
<div class="card-body">
@if (!validatingsignaturs)
{
<h5 class="modal-title">The founder has signed the recovery transaction</h5>
<button type="button" class="btn-success" @onclick="PublishSignedTransactionAsync">Invest</button>
}
else
{
<div class="loader"></div>
}
</div>
</div>
}
Expand All @@ -190,6 +194,7 @@
Transaction unSignedTransaction;

SignatureInfo recoverySigs;
bool validatingsignaturs;

private FeeData feeData = new();

Expand Down Expand Up @@ -404,31 +409,7 @@
content = encryptedContent,
NostrPubKey = project.NostrPubKey,
InvestorNostrPrivateKey = nostrPrivateKeyHex
}, async _ =>
{
var test = await javascriptNostrToolsModule.InvokeAsync<string>(
"decryptNostr",
nostrPrivateKeyHex,
project.NostrPubKey,
_);

_Logger.LogInformation("signature : " + test);

recoverySigs ??= new SignatureInfo();


recoverySigs.Signatures.Add(new SignatureInfoItem
{
Signature = test, StageIndex = recoverySigs.Signatures.Count()
});


if (recoverySigs.Signatures.Count == project.Stages.Count())
{
StateHasChanged();
}

});
}, async _ => await HandleSignatureReceivedAsync(nostrPrivateKeyHex, _));

return new OperationResult { Success = true, };
});
Expand All @@ -443,8 +424,34 @@
}
}

private async Task HandleSignatureReceivedAsync(string? nostrPrivateKeyHex, string _)
{
var signatureJson = await javascriptNostrToolsModule.InvokeAsync<string>(
"decryptNostr",
nostrPrivateKeyHex,
project.NostrPubKey,
_);

var signature = System.Text.Json.JsonSerializer.Deserialize<string>(signatureJson);

_Logger.LogInformation("signature : " + signatureJson);

recoverySigs ??= new SignatureInfo();

recoverySigs.Signatures.Add(new SignatureInfoItem
{
Signature = signature, StageIndex = recoverySigs.Signatures.Count()
});

if (recoverySigs.Signatures.Count == project.Stages.Count())
{
StateHasChanged();
}
}

public async Task PublishSignedTransactionAsync()
{
validatingsignaturs = true;
var operationResult = await notificationComponent.LongOperation(async () =>
{
var validSignatures = _InvestorTransactionActions.CheckInvestorRecoverySignatures(project, signedTransaction, recoverySigs);
Expand All @@ -461,7 +468,9 @@

var response = await _WalletOperations.PublishTransactionAsync(network, signedTransaction);

return !response.Success ? response : new OperationResult { Success = true };
//TODO David remove signatures from storage on fail?
return response.Success ? new SuccessOperationResult() : response;
});

if (operationResult.Success)
Expand All @@ -474,7 +483,9 @@
}
else
{
validatingsignaturs = false;
notificationComponent.ShowErrorMessage(operationResult.Message);
StateHasChanged();
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/Angor/Client/Pages/Settings.razor
Original file line number Diff line number Diff line change
Expand Up @@ -166,13 +166,13 @@
return;
}

if (!(uri.Scheme == "http" || uri.Scheme == "https"))
if (uri.Scheme is not ("http" or "https"))
{
notificationComponent.ShowErrorMessage($"invalid url {newIndexerLink} schema must be http or https");
return;
}

newIndexerLink = new Uri($"{uri.Scheme}://{uri.Host}/").ToString();
newIndexerLink = new Uri($"{uri.Scheme}://{uri.Host}").ToString();

if (settingsInfo.Indexers.Any(a => a.Url == newIndexerLink))
{
Expand All @@ -198,13 +198,13 @@
return;
}

if (!(uri.Scheme == "ws" || uri.Scheme == "wss"))
if (uri.Scheme is not ("ws" or "wss"))
{
notificationComponent.ShowErrorMessage($"invalid url {newRelayLink} schema must be ws or wss");
return;
}

newRelayLink = new Uri($"{uri.Scheme}://{uri.Host}/").ToString();
newRelayLink = new Uri($"{uri.Scheme}://{uri.Host}").ToString();

if (settingsInfo.Relays.Any(a => a.Url == newRelayLink))
{
Expand Down
75 changes: 37 additions & 38 deletions src/Angor/Server/TestNostrSigningFromRelay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,51 +101,18 @@ public async Task SignTransactionsFromNostrAsync(string projectIdentifier)

_nostrClient.Streams.EventStream.Where(_ => _.Subscription == nostrPubKey + "1")
.Where(_ => _.Event.Kind == NostrKind.ApplicationSpecificData)
//.Where(_ => _.Event.Pubkey == nostrPubKey)
.Subscribe(_ =>
{
_clientLogger.LogInformation("application specific data" + _.Event.Content);
_storage.Add(JsonConvert.DeserializeObject<ProjectInfo>(_.Event.Content,NostrSerializer.Settings));
_storage.Add(System.Text.Json.JsonSerializer.Deserialize<ProjectInfo>(_.Event.Content));
});

_nostrClient.Streams.EventStream.Where(_ => _.Subscription == nostrPubKey + "2")
.Where(_ => _.Event.Kind == NostrKind.EncryptedDm)
// .Where(_ => _.Event.Tags.ContainsTag("p",nostrPubKey))
.Select(_ => _.Event as NostrEncryptedEvent)
.Subscribe(nostrEvent =>
{
_clientLogger.LogInformation("encrypted direct message");
var project = (_storage.Get().GetAwaiter().GetResult()).First(_ => _.ProjectIdentifier == projectIdentifier);
var transactionHex = nostrEvent.DecryptContent(nostrPrivateKey);
_clientLogger.LogInformation(transactionHex);
var sig = signProject(transactionHex,project,projectKeys.founderSigningPrivateKey);
var stages = sig.Signatures.Select(_ => _.Signature );
foreach (var stage in sig.Signatures)
{
var sigJson = JsonConvert.SerializeObject(stage.Signature);
//JsonConvert.SerializeObject(sig.Signatures.OrderBy(_ => _.StageIndex).Select(_ => _.Signature), NostrSerializer.Settings);
_logger.LogInformation($"Signature to send for stage {stage.StageIndex}: {sigJson}");
var ev = new NostrEvent
{
Kind = NostrKind.EncryptedDm,
CreatedAt = DateTime.UtcNow,
Content = sigJson,
Tags = new NostrEventTags(new[] { NostrEventTag.Profile(nostrEvent.Pubkey) })
};
var signed = NostrEncryptedEvent.EncryptDirectMessage(ev, nostrPrivateKey)
.Sign(nostrPrivateKey);
_nostrClient.Send(new NostrEventRequest(signed));
}
SignInvestorTransactionsAsync(projectIdentifier, nostrEvent, nostrPrivateKey, projectKeys);
});

_nostrClient.Send(new NostrRequest( nostrPubKey + "1", new NostrFilter
Expand All @@ -154,15 +121,47 @@ public async Task SignTransactionsFromNostrAsync(string projectIdentifier)
Kinds = new[] { NostrKind.ApplicationSpecificData },
Limit = 1
}));

_nostrClient.Send(new NostrRequest(nostrPubKey + "2", new NostrFilter
{
P = new []{nostrPubKey},
Kinds = new[] {NostrKind.EncryptedDm },
P = new[] { nostrPubKey },
Kinds = new[] { NostrKind.EncryptedDm },
Since = DateTime.UtcNow
}));
}

private void SignInvestorTransactionsAsync(string projectIdentifier, NostrEncryptedEvent? nostrEvent,
NostrPrivateKey nostrPrivateKey, ProjectKeys projectKeys)
{
_clientLogger.LogInformation("encrypted direct message");
var project = (_storage.Get().GetAwaiter().GetResult()).First(_ => _.ProjectIdentifier == projectIdentifier);
var transactionHex = nostrEvent.DecryptContent(nostrPrivateKey);

_clientLogger.LogInformation(transactionHex);

var sig = signProject(transactionHex, project, projectKeys.founderSigningPrivateKey);

foreach (var stage in sig.Signatures)
{
var sigJson = System.Text.Json.JsonSerializer.Serialize(stage.Signature);

_logger.LogInformation($"Signature to send for stage {stage.StageIndex}: {sigJson}");

var ev = new NostrEvent
{
Kind = NostrKind.EncryptedDm,
CreatedAt = DateTime.UtcNow,
Content = sigJson,
Tags = new NostrEventTags(new[] { NostrEventTag.Profile(nostrEvent.Pubkey) })
};

var signed = NostrEncryptedEvent.EncryptDirectMessage(ev, nostrPrivateKey)
.Sign(nostrPrivateKey);

_nostrClient.Send(new NostrEventRequest(signed));
}
}

private SignatureInfo signProject(string transactionHex,ProjectInfo info, string founderSigningPrivateKey)
{
var investorTrx = _networkConfiguration.GetNetwork().CreateTransaction(transactionHex);
Expand Down
8 changes: 8 additions & 0 deletions src/Angor/Shared/Models/OperationResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ public class OperationResult
public bool Success { get; set; }
}

public class SuccessOperationResult : OperationResult
{
public SuccessOperationResult()
{
Success = true;
}
}

public class OperationResult<T> : OperationResult
{
public T? Data { get; set; }
Expand Down
24 changes: 19 additions & 5 deletions src/Angor/Shared/Services/RelayService.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using System.Reactive.Linq;
using System.Text.Json;
using Angor.Shared.Models;
using Angor.Shared.Utilities;
using Nostr.Client.Requests;
using Microsoft.Extensions.Logging;
using Nostr.Client.Client;
using Nostr.Client.Communicator;
using Nostr.Client.Json;
using Nostr.Client.Keys;
using Nostr.Client.Messages;
using Nostr.Client.Messages.Metadata;
Expand Down Expand Up @@ -74,11 +75,10 @@ public Task LookupProjectsInfoByPubKeysAsync<T>(Action<T> responseDataAction,par
{
var subscription = _nostrClient.Streams.EventStream
.Where(_ => _.Subscription == subscriptionName)
//.Where(_ => nostrPubKeys.Contains(_.Event.Pubkey))
.Select(_ => _.Event)
.Subscribe(ev =>
{
responseDataAction(Newtonsoft.Json.JsonConvert.DeserializeObject<T>(ev.Content, NostrSerializer.Settings));
responseDataAction(JsonSerializer.Deserialize<T>(ev.Content,settings));
});

subscriptions.Add(subscriptionName, subscription);
Expand Down Expand Up @@ -129,7 +129,7 @@ public Task<string> AddProjectAsync(ProjectInfo project, string hexPrivateKey)
if (!project.NostrPubKey.Contains(key.DerivePublicKey().Hex))
throw new ArgumentException($"The nostr pub key on the project does not fit the npub calculated from the nsec {project.NostrPubKey} {key.DerivePublicKey().Hex}");

var content = Newtonsoft.Json.JsonConvert.SerializeObject(project, NostrSerializer.Settings);
var content = JsonSerializer.Serialize(project,settings);

var signed = GetNip78NostrEvent(content)
.Sign(key);
Expand All @@ -146,7 +146,7 @@ public Task<string> CreateNostrProfileAsync(NostrMetadata metadata, string hexPr
{
var key = NostrPrivateKey.FromHex(hexPrivateKey);

var content = Newtonsoft.Json.JsonConvert.SerializeObject(metadata, NostrSerializer.Settings);
var content = JsonSerializer.Serialize(metadata,settings);

var signed = new NostrEvent
{
Expand Down Expand Up @@ -281,6 +281,20 @@ private void SetupNostrCommunicator()
info.Text, info.MessageType);
});
}

private JsonSerializerOptions settings => new ()
{
// Equivalent to Formatting = Formatting.None
WriteIndented = false,

// Equivalent to NullValueHandling = NullValueHandling.Ignore
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull,

// PropertyNamingPolicy equivalent to CamelCasePropertyNamesContractResolver
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,

Converters = { new UnixDateTimeConverter() }
};
}

}
7 changes: 4 additions & 3 deletions src/Angor/Shared/Services/SignService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Angor.Client.Services
public interface ISignService
{
Task AddSignKeyAsync(ProjectInfo project, string founderRecoveryPrivateKey, string nostrPrivateKey);
Task<string> RequestInvestmentSigsAsync(SignRecoveryRequest signRecoveryRequest, Action<string> action);
Task<string> RequestInvestmentSigsAsync(SignRecoveryRequest signRecoveryRequest, Func<string,Task> action);
}

public class SignService : ISignService
Expand Down Expand Up @@ -56,7 +56,7 @@ public async Task AddSignKeyAsync(ProjectInfo project, string founderRecoveryPri
response.EnsureSuccessStatusCode();
}

public Task<string> RequestInvestmentSigsAsync(SignRecoveryRequest signRecoveryRequest, Action<string> action)
public Task<string> RequestInvestmentSigsAsync(SignRecoveryRequest signRecoveryRequest, Func<string,Task> action)
{
var sender = NostrPrivateKey.FromHex(signRecoveryRequest.InvestorNostrPrivateKey);
//var receiver = NostrPublicKey.FromHex(signRecoveryRequest.NostrPubKey);
Expand Down Expand Up @@ -85,7 +85,8 @@ public Task<string> RequestInvestmentSigsAsync(SignRecoveryRequest signRecoveryR
Authors = new []{signRecoveryRequest.NostrPubKey},
P = new []{nostrPubKey},
Kinds = new[] { NostrKind.EncryptedDm},
Since = timeOfMessage
Since = timeOfMessage,
Limit = 1
}));

var subscription = _nostrClient.Streams.EventStream
Expand Down
Loading

0 comments on commit c739fd4

Please sign in to comment.