public override Dialog OnCreateDialog(Bundle savedInstanceState) { base.OnCreateDialog(savedInstanceState); AlertDialog.Builder builder = new AlertDialog.Builder(Activity) .SetView(Resource.Layout.Dialog) .SetPositiveButton(Resource.String.Join, (sender, e) => { var roomName = Dialog.FindViewById <EditText>(Resource.Id.Userinput).Text; ChatRoomContext context = Globals.CampfireChatClient.ChatRoomTable.GetOrCreate(IdentityHash.GetFlyweight(CryptoUtil.GetHash(CryptoUtil.GetHash(Encoding.UTF8.GetBytes(roomName))))); context.FriendlyName = roomName; Globals.CampfireNetClient.IdentityManager.AddMulticastKey( IdentityHash.GetFlyweight(CryptoUtil.GetHash(CryptoUtil.GetHash(Encoding.UTF8.GetBytes(roomName)))), CryptoUtil.GetHash(Encoding.UTF8.GetBytes(roomName))); byte[] roomKey = CryptoUtil.GetHash(CryptoUtil.GetHash(Encoding.UTF8.GetBytes(roomName))); Globals.JoinedRooms.Add(roomKey); uiHandler.ObtainMessage(0, new ChatEntry(roomKey, context)).SendToTarget(); Dismiss(); }) .SetNegativeButton(Resource.String.Cancel, (sender, e) => { Dismiss(); }); return(builder.Create()); }
public async Task MulticastAsync(IdentityHash destinationId, byte[] payload) { byte[] symmetricKey; if (!identity.IdentityManager.TryLookupMulticastKey(destinationId, out symmetricKey)) { throw new InvalidStateException("Attempted to multicast to destination of unknown key!"); } var messageDto = identity.EncodePacket(payload, symmetricKey); var localInsertionResult = await localMerkleTree.TryInsertAsync(messageDto).ConfigureAwait(false); if (localInsertionResult.Item1) { // "Decrypt the message" MessageSent?.Invoke(new MessageReceivedEventArgs( null, new BroadcastMessage { SourceId = IdentityHash.GetFlyweight(identity.PublicIdentityHash), DestinationId = destinationId, DecryptedPayload = payload, Dto = messageDto } )); } }
private static Dictionary <IdentityHash, int> ReadLogicalClock(BinaryReader reader) { var dict = new Dictionary <IdentityHash, int>(); var count = reader.ReadInt32(); for (var i = 0; i < count; i++) { var identityHashBytes = reader.ReadBytes(CryptoUtil.HASH_SIZE); var clock = reader.ReadInt32(); var identityHash = IdentityHash.GetFlyweight(identityHashBytes); dict.Add(identityHash, clock); } return(dict); }
public async Task BroadcastAsync(byte[] payload) { var messageDto = identity.EncodePacket(payload, null); var localInsertionResult = await localMerkleTree.TryInsertAsync(messageDto).ConfigureAwait(false); if (localInsertionResult.Item1) { // "Decrypt the message" MessageSent?.Invoke(new MessageReceivedEventArgs( null, new BroadcastMessage { SourceId = IdentityHash.GetFlyweight(identity.PublicIdentityHash), DestinationId = IdentityHash.GetFlyweight(Identity.BROADCAST_ID), DecryptedPayload = payload, Dto = messageDto } )); } }
public async Task UnicastAsync(IdentityHash destinationId, byte[] payload) { var trustChainNode = identity.IdentityManager.LookupIdentity(destinationId.Bytes.ToArray()); var messageDto = identity.EncodePacket(payload, trustChainNode.ThisId); var localInsertionResult = await localMerkleTree.TryInsertAsync(messageDto).ConfigureAwait(false); if (localInsertionResult.Item1) { // "Decrypt the message" MessageSent?.Invoke(new MessageReceivedEventArgs( null, new BroadcastMessage { SourceId = IdentityHash.GetFlyweight(identity.PublicIdentityHash), DestinationId = destinationId, DecryptedPayload = payload, Dto = messageDto } )); } }
public void Setup() { Console.WriteLine("Adding data"); if (Globals.JoinedRooms == null) { Globals.CampfireChatClient.ChatRoomTable.GetOrCreate(IdentityHash.GetFlyweight(Identity.BROADCAST_ID)).FriendlyName = "Broadcast"; Globals.CampfireChatClient.ChatRoomTable.GetOrCreate(IdentityHash.GetFlyweight(CryptoUtil.GetHash(CryptoUtil.GetHash(Encoding.UTF8.GetBytes("General"))))).FriendlyName = "General"; Globals.CampfireChatClient.ChatRoomTable.GetOrCreate(IdentityHash.GetFlyweight(CryptoUtil.GetHash(CryptoUtil.GetHash(Encoding.UTF8.GetBytes("Test"))))).FriendlyName = "Test"; Globals.CampfireNetClient.IdentityManager.AddMulticastKey( IdentityHash.GetFlyweight(CryptoUtil.GetHash(CryptoUtil.GetHash(Encoding.UTF8.GetBytes("General")))), CryptoUtil.GetHash(Encoding.UTF8.GetBytes("General"))); Globals.CampfireNetClient.IdentityManager.AddMulticastKey( IdentityHash.GetFlyweight(CryptoUtil.GetHash(CryptoUtil.GetHash(Encoding.UTF8.GetBytes("Test")))), CryptoUtil.GetHash(Encoding.UTF8.GetBytes("Test"))); Globals.JoinedRooms = new HashSet <byte[]> { Identity.BROADCAST_ID, CryptoUtil.GetHash(CryptoUtil.GetHash(Encoding.UTF8.GetBytes("General"))), CryptoUtil.GetHash(CryptoUtil.GetHash(Encoding.UTF8.GetBytes("Test"))), }; } var testEntries = GetKnownRooms(); chatlistRecyclerView = (RecyclerView)FindViewById(Resource.Id.ChatList); chatlistRecyclerView.HasFixedSize = true; chatlistLayoutManager = new LinearLayoutManager(this); chatlistRecyclerView.SetLayoutManager(chatlistLayoutManager); chatlistAdapter = new ChatlistAdapter(testEntries); chatlistAdapter.ItemClick += OnItemClick; chatlistRecyclerView.SetAdapter(chatlistAdapter); }
public ChatRoomContext ConfigurePublicChatRoom(string name) { var roomHashBytes = Encoding.UTF8.GetBytes(name); return(ChatRoomTable.GetOrCreate(IdentityHash.GetFlyweight(CryptoUtil.GetHash(roomHashBytes)))); }
public ChatRoomViewModel CreateChatRoomViewModelByNameAndSubscribe(string chatroomName, ChatMessageReceivedCallback messageReceivedCallback) { var destinationHash = IdentityHash.GetFlyweight(CryptoUtil.GetHash(Encoding.UTF8.GetBytes(chatroomName))); return(CreateChatRoomViewModelByIdentityHashAndSubscribe(destinationHash, messageReceivedCallback)); }
private List <ChatEntry> GetKnownRooms() { var entries = new List <ChatEntry>(); foreach (var roomKey in Globals.JoinedRooms) { ChatRoomContext context = Globals.CampfireChatClient.ChatRoomTable.GetOrCreate(IdentityHash.GetFlyweight(roomKey)); entries.Add(new ChatEntry(roomKey, context)); } return(entries); }
protected override void OnCreate(Bundle savedInstanceState) { // testMessages = new List<MessageEntry> { // new MessageEntry("Name 1", "This is a test message 1"), // new MessageEntry("Name 2", "This is a test message 2"), // new MessageEntry("Name 3", "This is a test message 3"), // new MessageEntry("Name 2", "This is a test message 4 really long message here one that is sure to overflow. How about some more text here and see if we can get it to three lines - or even more! How far can we go?"), // new MessageEntry("Name 3", "This is a test message 5"), // new MessageEntry("Name 1", "These are yet more messages designed to be long and take up space."), // new MessageEntry("Name 2", "These are yet more messages designed to be long and take up space."), // new MessageEntry("Name 3", "These are yet more messages designed to be long and take up space."), // new MessageEntry("Name 1", "These are yet more messages designed to be long and take up space."), // new MessageEntry("Name 2", "These are yet more messages designed to be long and take up space.") // }; base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.Chat); var toolbar = FindViewById <Android.Widget.Toolbar>(Resource.Id.Toolbar); SetActionBar(toolbar); ActionBar.SetDisplayHomeAsUpEnabled(true); chatRecyclerView = (RecyclerView)FindViewById(Resource.Id.Messages); chatRecyclerView.HasFixedSize = true; chatLayoutManager = new LinearLayoutManager(this); chatRecyclerView.SetLayoutManager(chatLayoutManager); chatAdapter = new ChatAdapter(); chatAdapter.ItemClick += OnItemClick; chatRecyclerView.SetAdapter(chatAdapter); var chatId = Intent.GetByteArrayExtra("chatId"); chatRoomContext = Globals.CampfireChatClient.ChatRoomTable.GetOrCreate(IdentityHash.GetFlyweight(chatId)); Title = chatRoomContext.FriendlyName; viewModel = chatRoomContext.CreateViewModelAndSubscribe((sender, e) => { Console.WriteLine(" ######## hitting add entry time"); var message = e.Message; if (message.ContentType != ChatMessageContentType.Text) { throw new NotImplementedException(); } chatAdapter.AddEntry(new MessageEntry(message, message.FriendlySenderName, Encoding.UTF8.GetString(message.ContentRaw))); uiHandler.ObtainMessage(UPDATE_VIEW, -1, 0).SendToTarget(); }); foreach (var message in viewModel.InitialMessages) { chatAdapter.AddEntry(new MessageEntry(message, message.FriendlySenderName, Encoding.UTF8.GetString(message.ContentRaw))); } var sendButton = FindViewById <Button>(Resource.Id.SendMessage); sendButton.Click += HandleSendButtonClicked; uiHandler = new LambdaHandler(msg => { if (msg.What == UPDATE_VIEW) { var index = msg.Arg1 == -1 ? chatAdapter.Entries.Count - 1 : msg.Arg1; Console.WriteLine($"Updating item view at {index}"); // chatAdapter.NotifyItemChanged(index); chatAdapter.NotifyDataSetChanged(); chatRecyclerView.GetLayoutManager().ScrollToPosition(chatAdapter.Entries.Count - 1); } }); }
private async Task SynchronizeRemoteToLocalAsync() { DebugPrint("Enter Remote to Local"); var have = await ChannelsExtensions.ReadAsync(haveChannel).ConfigureAwait(false); DebugPrint("Have is {0}", have.MerkleRootHash); var isRemoteRootSyncedLocally = await IsRemoteObjectHeldLocally(have.MerkleRootHash).ConfigureAwait(false); DebugPrint("IRRSL {0}", isRemoteRootSyncedLocally); if (!isRemoteRootSyncedLocally) { var nodesToImport = new List <Tuple <string, MerkleNode> >(); var neededHashes = new LinkedList <string>(); neededHashes.AddLast(have.MerkleRootHash); while (neededHashes.Count != 0) { var hashesReadLocally = new HashSet <string>(); foreach (var hash in neededHashes) { var localNode = await localMerkleTree.GetNodeAsync(hash).ConfigureAwait(false); if (localNode != null) { nodesToImport.Add(Tuple.Create(hash, localNode)); hashesReadLocally.Add(hash); continue; } var need = new NeedPacket { MerkleRootHash = hash }; DebugPrint("SEND NEED {0}", need.MerkleRootHash); neighbor.SendAsync(serializer.ToByteArray(need)).Forget(); } Console.WriteLine($"Found {neededHashes.Count} messages to sync"); foreach (var i in Enumerable.Range(0, neededHashes.Count)) { var hash = neededHashes.First(); neededHashes.RemoveFirst(); if (hashesReadLocally.Contains(hash)) { continue; } var give = await ChannelsExtensions.ReadAsync(giveChannel).ConfigureAwait(false); Console.WriteLine($"Got hash {give.NodeHash}"); nodesToImport.Add(Tuple.Create(give.NodeHash, give.Node)); if (!await IsRemoteObjectHeldLocally(give.Node.LeftHash).ConfigureAwait(false)) { neededHashes.AddLast(give.Node.LeftHash); } if (!await IsRemoteObjectHeldLocally(give.Node.RightHash).ConfigureAwait(false)) { neededHashes.AddLast(give.Node.RightHash); } } } var broadcastMessagesByNodeHash = nodesToImport.Where(n => n.Item2.TypeTag == MerkleNodeTypeTag.Data) .ToDictionary( n => n.Item1, n => broadcastMessageSerializer.Deserialize(n.Item2.Contents) ); Console.WriteLine($"Need to add {broadcastMessagesByNodeHash.Count} hashes that we don't have"); var neededSourceIdHashes = broadcastMessagesByNodeHash.Select(kvp => kvp.Value.SourceIdHash) .GroupBy(sourceIdHash => sourceIdHash.ToHexString()) .Select(g => new { Bytes = g.First(), Hex = g.Key }) .Where(pair => !IdentityManager.IsKnownIdentity(pair.Bytes)) .ToList(); foreach (var neededSourceId in neededSourceIdHashes) { var whois = new WhoisPacket { IdHash = neededSourceId.Bytes }; DebugPrint("SEND WHOIS {0}", neededSourceId.Hex); neighbor.SendAsync(serializer.ToByteArray(whois)).Forget(); } foreach (var i in Enumerable.Range(0, neededSourceIdHashes.Count)) { var ident = await ChannelsExtensions.ReadAsync(identChannel).ConfigureAwait(false); Identity.ValidateAndAdd(ident.TrustChain); } foreach (var neededSourceId in neededSourceIdHashes) { if (!IdentityManager.IsKnownIdentity(neededSourceId.Bytes)) { throw new InvalidStateException(); } } foreach (var tuple in nodesToImport) { var node = tuple.Item2; if (node.Descendents == 0 && await localMerkleTree.GetNodeAsync(tuple.Item1).ConfigureAwait(false) == null) { var isDataNode = node.TypeTag == MerkleNodeTypeTag.Data; BroadcastMessageDto message = isDataNode ? broadcastMessageSerializer.Deserialize(node.Contents) : null; var sender = IdentityManager.LookupIdentity(message.SourceIdHash); if (message.DestinationIdHash.All(val => val == 0)) { if ((sender.HeldPermissions & Permission.Broadcast) == 0) { Console.WriteLine("Sender does not have broadcast permissions. Malicious peer!"); throw new InvalidStateException(); } } else { if ((sender.HeldPermissions & Permission.Unicast) == 0) { Console.WriteLine("Sender does not have unicast permissions. Malicious peer!"); throw new InvalidStateException(); } } } } await remoteMerkleTree.ImportAsync(have.MerkleRootHash, nodesToImport).ConfigureAwait(false); Console.WriteLine($"Currently have {nodesToImport.Count} nodes to import still"); foreach (var tuple in nodesToImport) { var node = tuple.Item2; if (node.Descendents == 0 && await localMerkleTree.GetNodeAsync(tuple.Item1).ConfigureAwait(false) == null) { var isDataNode = node.TypeTag == MerkleNodeTypeTag.Data; BroadcastMessageDto message = isDataNode ? broadcastMessageSerializer.Deserialize(node.Contents) : null; Console.WriteLine("Got data node"); var insertionResult = await localMerkleTree.TryInsertAsync(tuple.Item2).ConfigureAwait(false); if (insertionResult.Item1 && isDataNode) { byte[] decryptedPayload; Console.WriteLine("Got a message"); if (identity.TryDecodePayload(message, out decryptedPayload)) { BroadcastReceived?.Invoke(new MessageReceivedEventArgs(neighbor, new BroadcastMessage { SourceId = IdentityHash.GetFlyweight(message.SourceIdHash), DestinationId = IdentityHash.GetFlyweight(message.DestinationIdHash), DecryptedPayload = decryptedPayload, Dto = message })); } } } } } DebugPrint("SEND DONE"); await neighbor.SendAsync(serializer.ToByteArray(new DonePacket())).ConfigureAwait(false); }