Skip to content

Commit e62704c

Browse files
committed
Implement the websocket interfaces, fix identity handling
1 parent 9bd3db4 commit e62704c

File tree

7 files changed

+140
-12
lines changed

7 files changed

+140
-12
lines changed

Signal-Windows.Lib/Signal-Windows.Lib.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@
113113
<Compile Include="Migrations\SignalDB\20180521001340_m6.designer.cs">
114114
<DependentUpon>20180521001340_m6.cs</DependentUpon>
115115
</Compile>
116+
<Compile Include="SignalWebSocket.cs" />
116117
<Compile Include="Util\LibUtils.cs" />
117118
<Compile Include="Migrations\LibsignalDB\20170806145530_ls1.cs" />
118119
<Compile Include="Migrations\LibsignalDB\20170806145530_ls1.Designer.cs">
@@ -166,7 +167,7 @@
166167
</ItemGroup>
167168
<ItemGroup>
168169
<PackageReference Include="libsignal-service-dotnet">
169-
<Version>2.7.5.11</Version>
170+
<Version>2.7.5.12</Version>
170171
</PackageReference>
171172
<PackageReference Include="Microsoft.EntityFrameworkCore">
172173
<Version>1.1.4</Version>

Signal-Windows.Lib/SignalLibHandle.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -864,8 +864,8 @@ private async Task InitNetwork()
864864
{
865865
try
866866
{
867-
MessageReceiver = new SignalServiceMessageReceiver(LibUtils.ServiceConfiguration, new StaticCredentialsProvider(Store.Username, Store.Password, Store.SignalingKey, (int)Store.DeviceId), LibUtils.USER_AGENT, null);
868-
Pipe = await MessageReceiver.CreateMessagePipe(CancelSource.Token);
867+
MessageReceiver = new SignalServiceMessageReceiver(LibUtils.ServiceConfiguration, new StaticCredentialsProvider(Store.Username, Store.Password, Store.SignalingKey, (int)Store.DeviceId), LibUtils.USER_AGENT);
868+
Pipe = await MessageReceiver.CreateMessagePipe(CancelSource.Token, new SignalWebSocketFactory());
869869
MessageSender = new SignalServiceMessageSender(CancelSource.Token, LibUtils.ServiceConfiguration, Store.Username, Store.Password, (int)Store.DeviceId, new Store(), Pipe, null, LibUtils.USER_AGENT);
870870
IncomingMessagesTask = Task.Factory.StartNew(async () => await new IncomingMessages(CancelSource.Token, Pipe, MessageReceiver).HandleIncomingMessages(), TaskCreationOptions.LongRunning);
871871
OutgoingMessages = new OutgoingMessages(CancelSource.Token, MessageSender, this);

Signal-Windows.Lib/SignalWebSocket.cs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
using libsignalservice;
2+
using libsignalservice.push.exceptions;
3+
using libsignalservice.websocket;
4+
using Microsoft.Extensions.Logging;
5+
using System;
6+
using System.IO;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
using Windows.Networking.Sockets;
10+
using Windows.Storage.Streams;
11+
12+
namespace Signal_Windows.Lib
13+
{
14+
public class SignalWebSocketFactory : ISignalWebSocketFactory
15+
{
16+
public ISignalWebSocket CreateSignalWebSocket(CancellationToken token, Uri uri)
17+
{
18+
return new SignalWebSocket(token, uri);
19+
}
20+
}
21+
22+
class SignalWebSocket : ISignalWebSocket
23+
{
24+
private readonly ILogger Logger = LibsignalLogging.CreateLogger<SignalWebSocket>();
25+
private readonly MessageWebSocket WebSocket;
26+
private readonly SemaphoreSlim SemaphoreSlim = new SemaphoreSlim(1, 1);
27+
private readonly Uri SignalWSUri;
28+
private readonly CancellationToken Token;
29+
public event EventHandler<SignalWebSocketClosedEventArgs> Closed;
30+
public event EventHandler<SignalWebSocketMessageReceivedEventArgs> MessageReceived;
31+
32+
public SignalWebSocket(CancellationToken token, Uri uri)
33+
{
34+
WebSocket = new MessageWebSocket();
35+
WebSocket.MessageReceived += WebSocket_MessageReceived;
36+
WebSocket.Closed += WebSocket_Closed;
37+
Token = token;
38+
SignalWSUri = uri;
39+
}
40+
41+
private void WebSocket_Closed(IWebSocket sender, WebSocketClosedEventArgs args)
42+
{
43+
Closed?.Invoke(sender, new SignalWebSocketClosedEventArgs() { Code = args.Code, Reason = args.Reason });
44+
Logger.LogWarning("WebSocket_Closed() {0} ({1})", args.Code, args.Reason);
45+
}
46+
47+
private async void WebSocket_MessageReceived(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args)
48+
{
49+
try
50+
{
51+
using (var data = args.GetDataStream())
52+
{
53+
MessageReceived.Invoke(sender, new SignalWebSocketMessageReceivedEventArgs() { Message = data.AsStreamForRead() });
54+
}
55+
}
56+
catch(Exception e)
57+
{
58+
Logger.LogError("WebSocket_MessageReceived failed: {0}\n{1}", e.Message, e.StackTrace);
59+
try
60+
{
61+
await ConnectAsync();
62+
}
63+
catch (TaskCanceledException) { }
64+
}
65+
}
66+
67+
public void Close(ushort code, string reason)
68+
{
69+
Logger.LogTrace("Closing SignalWebSocket connection");
70+
WebSocket.Close(code, reason);
71+
}
72+
73+
public async Task ConnectAsync()
74+
{
75+
var locked = await SemaphoreSlim.WaitAsync(0, Token); // ensure no threads are reconnecting at the same time
76+
if (locked)
77+
{
78+
while (!Token.IsCancellationRequested)
79+
{
80+
try
81+
{
82+
await WebSocket.ConnectAsync(SignalWSUri).AsTask(Token);
83+
SemaphoreSlim.Release();
84+
break;
85+
}
86+
catch (OperationCanceledException) { }
87+
catch (Exception e)
88+
{
89+
if (e.Message.Contains("(403)"))
90+
{
91+
SemaphoreSlim.Release();
92+
throw new AuthorizationFailedException("OWS server rejected authorization.");
93+
}
94+
Logger.LogError("ConnectAsync() failed: {0}\n{1}", e.Message, e.StackTrace); //System.Runtime.InteropServices.COMException (0x80072EE7)
95+
await Task.Delay(10 * 1000);
96+
}
97+
}
98+
}
99+
}
100+
101+
public void Dispose()
102+
{
103+
WebSocket.Dispose();
104+
}
105+
106+
public async Task SendMessage(byte[] data)
107+
{
108+
using (var dataWriter = new DataWriter(WebSocket.OutputStream))
109+
{
110+
dataWriter.WriteBytes(data);
111+
await dataWriter.StoreAsync();
112+
dataWriter.DetachStream();
113+
}
114+
}
115+
}
116+
}

Signal-Windows.Lib/Storage/DB.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,16 @@ public static async Task SaveIdentityLocked(SignalProtocolAddress address, strin
188188
old.VerifiedStatus = VerifiedStatus.Unverified;
189189
}
190190
old.IdentityKey = identity;
191-
var childSessions = ctx.Sessions
192-
.Where(s => s.Username == address.Name && s.DeviceId != address.DeviceId);
193-
ctx.Sessions.RemoveRange(childSessions);
191+
var oldSession = ctx.Sessions
192+
.Where(s => s.Username == address.Name && s.DeviceId == 1)
193+
.SingleOrDefault();
194+
if (oldSession != null)
195+
{
196+
SessionRecord sessionRecord = new SessionRecord(Base64.Decode(oldSession.Session));
197+
sessionRecord.archiveCurrentState();
198+
oldSession.Session = Base64.EncodeBytes(sessionRecord.serialize());
199+
SessionsCache[address.Name] = sessionRecord;
200+
}
194201
messages = InsertIdentityChangedMessages(address.Name);
195202
}
196203
ctx.SaveChanges();
@@ -317,7 +324,7 @@ private static string GetSessionCacheIndex(string username, uint deviceid)
317324

318325
private static Dictionary<string, SessionRecord> SessionsCache = new Dictionary<string, SessionRecord>();
319326

320-
public static SessionRecord LoadSession(SignalProtocolAddress address)
327+
public static SessionRecord LoadSessionLocked(SignalProtocolAddress address)
321328
{
322329
lock (DBLock)
323330
{
@@ -407,7 +414,12 @@ public static bool ContainsSession(SignalProtocolAddress address)
407414
var session = ctx.Sessions
408415
.Where(s => s.Username == address.Name && s.DeviceId == address.DeviceId)
409416
.SingleOrDefault();
410-
return session != null;
417+
if (session == null)
418+
return false;
419+
420+
SessionRecord sessionRecord = new SessionRecord(Base64.Decode(session.Session));
421+
return sessionRecord.getSessionState().hasSenderChain() &&
422+
sessionRecord.getSessionState().getSessionVersion() == libsignal.protocol.CiphertextMessage.CURRENT_VERSION;
411423
}
412424
}
413425
}

Signal-Windows.Lib/Storage/Store.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public void RemovePreKey(uint preKeyId)
6464

6565
public SessionRecord LoadSession(SignalProtocolAddress address)
6666
{
67-
return LibsignalDBContext.LoadSession(address);
67+
return LibsignalDBContext.LoadSessionLocked(address);
6868
}
6969

7070
public List<uint> GetSubDeviceSessions(string name)

Signal-Windows/ViewModels/LinkPageViewModel.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ await Task.Run(() =>
8282
});
8383

8484
// fetch new device uuid
85-
SignalServiceAccountManager accountManager = new SignalServiceAccountManager(App.ServiceConfiguration, "Signal-Windows");
86-
string uuid = await accountManager.GetNewDeviceUuid(CancelSource.Token);
85+
SignalServiceAccountManager accountManager = new SignalServiceAccountManager(App.ServiceConfiguration, "Signal-Windows", new SignalWebSocketFactory());
86+
string uuid = await accountManager.GetNewDeviceUuid(CancelSource.Token, new SignalWebSocketFactory());
8787
string tsdevice = "tsdevice:/?uuid=" + Uri.EscapeDataString(uuid) + "&pub_key=" + Uri.EscapeDataString(Base64.EncodeBytesWithoutPadding(tmpIdentity.getPublicKey().serialize()));
8888

8989
View.SetQR(tsdevice); //TODO generate qrcode in worker task

Signal-Windows/ViewModels/MainPageViewModel.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ public bool ThreadListAlignRight
9090

9191
private async Task<bool> SendMessage(string messageText)
9292
{
93-
Debug.WriteLine("starting sendmessage");
9493
try
9594
{
9695
if (!string.IsNullOrEmpty(messageText))

0 commit comments

Comments
 (0)