private async Task AcknowledgeMessageAsync( OpenVaspPayload payload, string symKey, string asymKey, string returnTopic = null) { var envelopeId = Guid.NewGuid().ToString("N"); var ackPayload = new OpenVaspPayload( Instruction.Ack, _vaspId, // receiver becomes a sender payload.ConnectionId, envelopeId) { EnvelopeAck = payload.EnvelopeId }; var ackEnvelope = new MessageEnvelope { Topic = returnTopic ?? payload.ReturnTopic, EncryptionKey = symKey ?? asymKey, EncryptionType = symKey != null ? EncryptionType.Symmetric : EncryptionType.Asymmetric, }; await _outboundEnvelopeService.AcknowledgeAsync(ackEnvelope, ackPayload.ToString()); _logger?.LogInformation( $"Sent ACK to {payload.Instruction} with topic {ackEnvelope.Topic} for connection {payload.ConnectionId} from {_vaspId} to {payload.SenderVaspId}"); }
private async Task HandleAcceptMessageAsync(OpenVaspPayload payload) { var connection = _connections[payload.ConnectionId]; if (connection == null) { throw new ArgumentException($"Connection with id '{payload.ConnectionId}' was not found"); } var sharedSecret = ECDH_Key.ImportKey(connection.PrivateKey).GenerateSharedSecretHex(payload.EcdhPk); (connection.Filter, connection.SymKeyId) = await RegisterConnectionAsync(connection.InboundTopic, sharedSecret); connection.SharedPrivateEncryptionKey = sharedSecret; connection.OutboundTopic = payload.ReturnTopic; await AcknowledgeMessageAsync( payload, connection.SymKeyId, null); var senderVaspCode = payload.SenderVaspId.Substring(4, 8); var signingKey = await _vaspCodesService.GetSigningKeyAsync(senderVaspCode); await TriggerAsyncEvent(TransportMessageReceived, new TransportMessageEvent { ConnectionId = payload.ConnectionId, SenderVaspId = payload.SenderVaspId, Instruction = payload.Instruction, Payload = payload.OvMessage, Timestamp = DateTime.UtcNow, SigningKey = signingKey }); }
private async Task HandleMessageAsync( OpenVaspPayload payload, bool doAcknowledge, Func <Connection, bool> connectionUpdate = null) { var connection = _connections[payload.ConnectionId]; if (connection == null) { throw new ArgumentException($"Connection with id '{payload.ConnectionId}' was not found"); } var originalConnStatus = connection.Status; connectionUpdate?.Invoke(connection);; if (doAcknowledge) { var symKeyId = originalConnStatus == ConnectionStatus.PartiallyActive ? null : connection.SymKeyId; string asymKey = null; if (symKeyId == null) { asymKey = payload.EcdhPk ?? connection.CounterPartyPublicKey ?? await _vaspCodesService.GetTransportKeyAsync(connection.CounterPartyVaspId.Substring(4)); asymKey = asymKey?.DecompressPublicKey().ToHex(true); } if (string.IsNullOrWhiteSpace(symKeyId) && string.IsNullOrWhiteSpace(asymKey)) { _logger?.LogWarning($"Can't sent ACK for {payload.Instruction} via connection {payload.ConnectionId}"); } else { await AcknowledgeMessageAsync( payload, symKeyId, asymKey, string.IsNullOrWhiteSpace(connection.SymKeyId) && string.IsNullOrWhiteSpace(payload.EcdhPk) ?connection.CounterPartyVaspId.Substring(4) : null); } } var senderVaspCode = payload.SenderVaspId.Substring(4, 8); var signingKey = await _vaspCodesService.GetSigningKeyAsync(senderVaspCode); await TriggerAsyncEvent(TransportMessageReceived, new TransportMessageEvent { ConnectionId = payload.ConnectionId, SenderVaspId = payload.SenderVaspId, Instruction = payload.Instruction, Payload = payload.OvMessage, Timestamp = DateTime.UtcNow, SigningKey = signingKey }); }
private Task HandleDenyMessageAsync(OpenVaspPayload payload) { return(HandleMessageAsync( payload, false, connectionUpdate: c => { c.Status = ConnectionStatus.Passive; return true; })); }
private Task HandleCloseMessageAsync(OpenVaspPayload payload) { return(HandleMessageAsync( payload, true, c => { c.Status = ConnectionStatus.Passive; return true; })); }
private async Task ProcessReceivedMessageAsync( string topic, string messagePayload) { var payload = OpenVaspPayload.Create(messagePayload); _logger?.LogInformation( $"Received {payload.Instruction} with topic {topic} for connection {payload.ConnectionId} from {payload.SenderVaspId} to {_vaspId}"); switch (payload.Instruction) { case Instruction.Ack: await HandleAcknowledgementMessageAsync(payload); break; case Instruction.Invite: await HandleInviteMessageAsync(payload); break; case Instruction.Accept: await HandleAcceptMessageAsync(payload); break; case Instruction.Deny: await HandleDenyMessageAsync(payload); break; case Instruction.Update: await HandleUpdateMessageAsync(payload); break; case Instruction.Close: await HandleCloseMessageAsync(payload); break; default: throw new ArgumentOutOfRangeException(); } if (!_openVaspPayloads.ContainsKey(payload.EnvelopeId)) { _openVaspPayloads[payload.EnvelopeId] = payload; } }
private Task HandleUpdateMessageAsync(OpenVaspPayload payload) { return(HandleMessageAsync( payload, true, c => { if (c.Status != ConnectionStatus.PartiallyActive) { return false; } c.Status = ConnectionStatus.Active; return true; })); }
private async Task HandleAcknowledgementMessageAsync(OpenVaspPayload payload) { await _outboundEnvelopeService.RemoveQueuedEnvelopeAsync(payload.EnvelopeAck); var ackedMessage = _openVaspPayloads[payload.EnvelopeAck]; if (ackedMessage?.Instruction == Instruction.Close) { await DeactivateAsync(payload.ConnectionId); } var connection = _connections[payload.ConnectionId]; if (connection == null) { throw new ArgumentException($"Connection with id '{payload.ConnectionId}' was not found"); } if (connection.Status == ConnectionStatus.PartiallyActive) { connection.Status = ConnectionStatus.Active; } }
private async Task HandleInviteMessageAsync(OpenVaspPayload payload) { var senderVaspCode = payload.SenderVaspId.Substring(4, 8); var vaspTransportKey = await _vaspCodesService.GetTransportKeyAsync(senderVaspCode); if (vaspTransportKey == null) { _logger?.LogError($"Transport key for vasp code {senderVaspCode} cannot be found during invitation processing"); return; } _connections.TryGetValue(payload.ConnectionId, out var connection); if (connection != null) { bool isSameData = connection.CounterPartyVaspId == payload.SenderVaspId && connection.OutboundTopic == payload.ReturnTopic; if (isSameData) { _logger?.LogWarning( $"Received invite for already existing connectionId {payload.ConnectionId} with the same data. Skipping."); await AcknowledgeMessageAsync( payload, null, payload.EcdhPk.DecompressPublicKey().ToHex(true)); } else { _logger?.LogWarning( $"Received invite for already existing connectionId {payload.ConnectionId} with the different data:{Environment.NewLine}" + $"SenderVaspId: {connection.CounterPartyVaspId} - {payload.SenderVaspId},{Environment.NewLine}" + $"Topic: {connection.OutboundTopic} - {payload.ReturnTopic},{Environment.NewLine}"); } return; } var topic = TopicGenerator.GenerateConnectionTopic(); var sessionKey = ECDH_Key.GenerateKey(); var sharedSecret = sessionKey.GenerateSharedSecretHex(payload.EcdhPk); var(filter, symKeyId) = await RegisterConnectionAsync(topic, sharedSecret); var newConnection = new Connection { Id = payload.ConnectionId, Filter = filter, InboundTopic = topic, OutboundTopic = payload.ReturnTopic, Status = ConnectionStatus.PartiallyActive, CounterPartyVaspId = payload.SenderVaspId, SymKeyId = symKeyId, SharedPrivateEncryptionKey = sharedSecret, PrivateKey = sessionKey.PrivateKey, CounterPartyPublicKey = payload.EcdhPk, }; _connections[newConnection.Id] = newConnection; await AcknowledgeMessageAsync( payload, null, payload.EcdhPk.DecompressPublicKey().ToHex(true)); var signingKey = await _vaspCodesService.GetSigningKeyAsync(senderVaspCode); await TriggerAsyncEvent(TransportMessageReceived, new TransportMessageEvent { ConnectionId = payload.ConnectionId, SenderVaspId = payload.SenderVaspId, Instruction = payload.Instruction, Payload = payload.OvMessage, Timestamp = DateTime.UtcNow, SigningKey = signingKey }); }
public async Task SendAsync(string connectionId, string message, Instruction instruction, string receiverVaspId) { var connection = _connections[connectionId]; var receiverVaspCode = (receiverVaspId ?? connection.CounterPartyVaspId).Substring(4, 8); var envelopeId = Guid.NewGuid().ToString("N"); var payload = new OpenVaspPayload( instruction, _vaspId, connection.Id, envelopeId) { ReturnTopic = connection.InboundTopic, OvMessage = message }; if (instruction == Instruction.Invite || instruction == Instruction.Accept || instruction == Instruction.Deny) { payload.EcdhPk = ECDH_Key.ImportKey(connection.PrivateKey).PublicKey; } var topic = connection.OutboundTopic ?? receiverVaspCode; if (string.IsNullOrWhiteSpace(topic)) { throw new InvalidOperationException($"Topic is empty for connection {connection.Id}"); } var envelope = new MessageEnvelope { Topic = topic, }; if (instruction == Instruction.Invite || instruction == Instruction.Close && string.IsNullOrWhiteSpace(connection.SymKeyId)) { envelope.EncryptionType = EncryptionType.Asymmetric; var vaspTransportKey = await _vaspCodesService.GetTransportKeyAsync(receiverVaspCode); if (vaspTransportKey == null) { throw new InvalidOperationException($"Transport key for vasp code {receiverVaspCode} cannot be found during message sending"); } envelope.EncryptionKey = vaspTransportKey.DecompressPublicKey().ToHex(true); } else if (instruction == Instruction.Accept || instruction == Instruction.Deny || instruction == Instruction.Close && connection.Status == ConnectionStatus.PartiallyActive) { envelope.EncryptionType = EncryptionType.Asymmetric; envelope.EncryptionKey = connection.CounterPartyPublicKey.DecompressPublicKey().ToHex(true); } else { envelope.EncryptionType = EncryptionType.Symmetric; envelope.EncryptionKey = connection.SymKeyId; } var outboundEnvelope = new OutboundEnvelope { Id = envelopeId, ConnectionId = connectionId, Envelope = envelope, TotalResents = 0, Payload = payload.ToString() }; _openVaspPayloads[payload.EnvelopeId] = payload; await _outboundEnvelopeService.SendEnvelopeAsync(outboundEnvelope, instruction != Instruction.Deny); if (instruction == Instruction.Deny) { await DeactivateAsync(connectionId); } }