Skip to content

Commit 445dd46

Browse files
committed
dispose all secondary windows, bring up startpage and forbid new secondary windows if OWS says no to our credentials
1 parent 669ad20 commit 445dd46

File tree

3 files changed

+236
-95
lines changed

3 files changed

+236
-95
lines changed

Signal-Windows.Lib/SignalLibHandle.cs

Lines changed: 178 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ public interface ISignalLibHandle
4343
List<SignalMessageContainer> GetMessages(SignalConversation thread, int startIndex, int count);
4444
void SaveAndDispatchSignalConversation(SignalConversation updatedConversation, SignalMessage updateMessage);
4545
void PurgeAccountData();
46-
Task Acquire(CoreDispatcher d, ISignalFrontend w);
46+
Task<bool> Acquire(CoreDispatcher d, ISignalFrontend w);
4747
Task Reacquire();
4848
void Release();
49-
void AddFrontend(CoreDispatcher d, ISignalFrontend w);
49+
bool AddFrontend(CoreDispatcher d, ISignalFrontend w);
5050
void RemoveFrontend(CoreDispatcher d);
5151

5252
// Background API
@@ -75,8 +75,11 @@ internal class SignalLibHandle : ISignalLibHandle
7575
public SemaphoreSlim SemaphoreSlim = new SemaphoreSlim(1, 1);
7676
private bool Headless;
7777
private bool Running = false;
78+
private bool LikelyHasValidStore = false;
7879
private CancellationTokenSource CancelSource = new CancellationTokenSource();
7980
private Dictionary<CoreDispatcher, ISignalFrontend> Frames = new Dictionary<CoreDispatcher, ISignalFrontend>();
81+
private CoreDispatcher MainWindowDispatcher;
82+
private ISignalFrontend MainWindow;
8083
private Task IncomingMessagesTask;
8184
private Task OutgoingMessagesTask;
8285
internal OutgoingMessages OutgoingMessages;
@@ -96,23 +99,31 @@ public SignalLibHandle(bool headless)
9699
Instance = this;
97100
}
98101

99-
public void AddFrontend(CoreDispatcher d, ISignalFrontend w)
102+
public bool AddFrontend(CoreDispatcher d, ISignalFrontend w)
100103
{
101104
Logger.LogTrace("AddFrontend() locking");
102105
SemaphoreSlim.Wait(CancelSource.Token);
103-
Logger.LogTrace("AddFrontend() locked");
104-
if (Running)
106+
try
105107
{
106-
Logger.LogInformation("Registering frontend of dispatcher {0}", w.GetHashCode());
107-
Frames.Add(d, w);
108-
w.ReplaceConversationList(GetConversations());
108+
Logger.LogTrace("AddFrontend() locked");
109+
if (Running && LikelyHasValidStore)
110+
{
111+
Logger.LogInformation("Registering frontend of dispatcher {0}", w.GetHashCode());
112+
Frames.Add(d, w);
113+
w.ReplaceConversationList(GetConversations());
114+
return true;
115+
}
116+
else
117+
{
118+
Logger.LogInformation("Ignoring AddFrontend call");
119+
return false;
120+
}
109121
}
110-
else
122+
finally
111123
{
112-
Logger.LogInformation("Ignoring AddFrontend call, release in progress");
124+
SemaphoreSlim.Release();
125+
Logger.LogTrace("AddFrontend() released");
113126
}
114-
SemaphoreSlim.Release();
115-
Logger.LogTrace("AddFrontend() released");
116127
}
117128

118129
public void RemoveFrontend(CoreDispatcher d)
@@ -136,44 +147,60 @@ public void PurgeAccountData()
136147
Logger.LogTrace("PurgeAccountData() released");
137148
}
138149

139-
public async Task Acquire(CoreDispatcher d, ISignalFrontend w) //TODO wrap trycatch dispatch auth failure
150+
public async Task<bool> Acquire(CoreDispatcher d, ISignalFrontend w) //TODO wrap trycatch dispatch auth failure
140151
{
141152
Logger.LogTrace("Acquire() locking");
142153
CancelSource = new CancellationTokenSource();
143154
SemaphoreSlim.Wait(CancelSource.Token);
144-
GlobalResetEvent = LibUtils.OpenResetEventSet();
145-
LibUtils.Lock();
146-
GlobalResetEvent.Reset();
147-
var getConversationsTask = Task.Run(() =>
148-
{
149-
return GetConversations(); // we want to display the conversations asap!
150-
});
151-
Logger.LogDebug("Acquire() locked (global and local)");
152-
Instance = this;
153-
Frames.Add(d, w);
154-
w.ReplaceConversationList(await getConversationsTask);
155-
var failTask = Task.Run(() =>
156-
{
157-
SignalDBContext.FailAllPendingMessages(); // TODO GetMessages needs to be protected by semaphoreslim as we fail defered
158-
});
159-
Store = await Task.Run(() =>
155+
try
160156
{
161-
return LibsignalDBContext.GetSignalStore();
162-
});
163-
if (Store == null)
157+
GlobalResetEvent = LibUtils.OpenResetEventSet();
158+
LibUtils.Lock();
159+
GlobalResetEvent.Reset();
160+
MainWindowDispatcher = d;
161+
MainWindow = w;
162+
Logger.LogDebug("Acquire() locked (global and local)");
163+
var getConversationsTask = Task.Run(() =>
164+
{
165+
return GetConversations(); // we want to display the conversations asap!
166+
});
167+
Instance = this;
168+
Frames.Add(d, w);
169+
w.ReplaceConversationList(await getConversationsTask);
170+
var failTask = Task.Run(() =>
171+
{
172+
SignalDBContext.FailAllPendingMessages(); // TODO GetMessages needs to be protected by semaphoreslim as we fail defered
173+
});
174+
Store = await Task.Run(() =>
175+
{
176+
return LibsignalDBContext.GetSignalStore();
177+
});
178+
if (Store == null)
179+
{
180+
return false;
181+
}
182+
else
183+
{
184+
LikelyHasValidStore = true;
185+
}
186+
var initNetwork = Task.Run(() =>
187+
{
188+
InitNetwork();
189+
});
190+
var recoverDownloadsTask = Task.Run(() =>
191+
{
192+
RecoverDownloads().Wait();
193+
});
194+
await failTask; // has to complete before messages are loaded
195+
await recoverDownloadsTask;
196+
Running = true;
197+
return true;
198+
}
199+
finally
164200
{
165201
SemaphoreSlim.Release();
166-
throw new Exception("Signal Store has not been setup yet.");
202+
Logger.LogTrace("Acquire() released");
167203
}
168-
await Task.Run(() =>
169-
{
170-
InitNetwork();
171-
RecoverDownloads().Wait();
172-
});
173-
await failTask; // has to complete before messages are loaded
174-
Running = true;
175-
Logger.LogTrace("Acquire() releasing");
176-
SemaphoreSlim.Release();
177204
}
178205

179206
public void BackgroundAcquire()
@@ -192,46 +219,65 @@ public async Task Reacquire()
192219
Logger.LogTrace("Reacquire() locking");
193220
CancelSource = new CancellationTokenSource();
194221
SemaphoreSlim.Wait(CancelSource.Token);
195-
GlobalResetEvent = LibUtils.OpenResetEventSet();
196-
LibUtils.Lock();
197-
GlobalResetEvent.Reset();
198-
LibsignalDBContext.ClearSessionCache();
199-
Instance = this;
200-
await Task.Run(() =>
222+
try
201223
{
202-
List<Task> tasks = new List<Task>();
203-
foreach (var f in Frames)
224+
GlobalResetEvent = LibUtils.OpenResetEventSet();
225+
LibUtils.Lock();
226+
GlobalResetEvent.Reset();
227+
LibsignalDBContext.ClearSessionCache();
228+
Instance = this;
229+
await Task.Run(() =>
204230
{
205-
var conversations = GetConversations();
206-
tasks.Add(f.Key.RunTaskAsync(() =>
231+
List<Task> tasks = new List<Task>();
232+
foreach (var f in Frames)
207233
{
208-
f.Value.ReplaceConversationList(conversations);
209-
}));
234+
var conversations = GetConversations();
235+
tasks.Add(f.Key.RunTaskAsync(() =>
236+
{
237+
f.Value.ReplaceConversationList(conversations);
238+
}));
239+
}
240+
Task.WaitAll(tasks.ToArray());
241+
RecoverDownloads().Wait();
242+
});
243+
if (LikelyHasValidStore)
244+
{
245+
var initNetworkTask = Task.Run(() =>
246+
{
247+
InitNetwork();
248+
});
210249
}
211-
Task.WaitAll(tasks.ToArray());
212-
InitNetwork();
213-
RecoverDownloads().Wait();
214-
});
215-
Running = true;
216-
Logger.LogTrace("Reacquire() releasing");
217-
SemaphoreSlim.Release();
250+
Running = true;
251+
}
252+
finally
253+
{
254+
SemaphoreSlim.Release();
255+
Logger.LogTrace("Reacquire() released");
256+
}
218257
}
219258

220259
public void Release()
221260
{
222261
//TODO invalidate view information
223262
Logger.LogTrace("Release() locking");
224-
SemaphoreSlim.Wait(CancelSource.Token);
225-
Running = false;
226-
CancelSource.Cancel();
227-
IncomingMessagesTask?.Wait();
228-
OutgoingMessagesTask?.Wait();
229-
Instance = null;
230-
Logger.LogTrace("Release() releasing global)");
231-
LibUtils.Unlock();
232-
Logger.LogTrace("Release() releasing local)");
233-
SemaphoreSlim.Release();
234-
Logger.LogTrace("Release() released");
263+
if (Running)
264+
{
265+
SemaphoreSlim.Wait(CancelSource.Token);
266+
Running = false;
267+
CancelSource.Cancel();
268+
IncomingMessagesTask?.Wait();
269+
OutgoingMessagesTask?.Wait();
270+
Instance = null;
271+
Logger.LogTrace("Release() releasing global)");
272+
LibUtils.Unlock();
273+
Logger.LogTrace("Release() releasing local)");
274+
SemaphoreSlim.Release();
275+
Logger.LogTrace("Release() released");
276+
}
277+
else
278+
{
279+
Logger.LogTrace("SignalLibHandle was already closed");
280+
}
235281
}
236282

237283
public void BackgroundRelease()
@@ -317,6 +363,26 @@ public void StartAttachmentDownload(SignalAttachment sa)
317363
#endregion
318364

319365
#region internal api
366+
internal void DispatchHandleAuthFailure()
367+
{
368+
List<Task> operations = new List<Task>();
369+
foreach (var dispatcher in Frames.Keys)
370+
{
371+
operations.Add(dispatcher.RunTaskAsync(() =>
372+
{
373+
try
374+
{
375+
Frames[dispatcher].HandleAuthFailure();
376+
}
377+
catch(Exception e)
378+
{
379+
Logger.LogError("DispatchHandleAuthFailure failed: {0}\n{1}", e.Message, e.StackTrace);
380+
}
381+
}));
382+
}
383+
Task.WaitAll(operations.ToArray());
384+
}
385+
320386
internal void SaveAndDispatchSignalMessage(SignalMessage message, SignalConversation conversation)
321387
{
322388
conversation.MessagesCount += 1;
@@ -464,14 +530,48 @@ private List<SignalConversation> GetConversations()
464530
return conversations;
465531
}
466532

533+
/// <summary>
534+
/// Initializes the websocket connection handling. Must not not be called on a UI thread. Must not be called on a task which holds the handle lock.
535+
/// </summary>
467536
private void InitNetwork()
468537
{
469-
MessageReceiver = new SignalServiceMessageReceiver(CancelSource.Token, LibUtils.ServiceUrls, new StaticCredentialsProvider(Store.Username, Store.Password, Store.SignalingKey, (int)Store.DeviceId), LibUtils.USER_AGENT);
470-
Pipe = MessageReceiver.createMessagePipe();
471-
MessageSender = new SignalServiceMessageSender(CancelSource.Token, LibUtils.ServiceUrls, Store.Username, Store.Password, (int)Store.DeviceId, new Store(), Pipe, null, LibUtils.USER_AGENT);
472-
IncomingMessagesTask = Task.Factory.StartNew(() => new IncomingMessages(CancelSource.Token, Pipe, this).HandleIncomingMessages(), TaskCreationOptions.LongRunning);
473-
OutgoingMessages = new OutgoingMessages(CancelSource.Token, MessageSender, this);
474-
OutgoingMessagesTask = Task.Factory.StartNew(() => OutgoingMessages.HandleOutgoingMessages(), TaskCreationOptions.LongRunning);
538+
try
539+
{
540+
MessageReceiver = new SignalServiceMessageReceiver(CancelSource.Token, LibUtils.ServiceUrls, new StaticCredentialsProvider(Store.Username, Store.Password, Store.SignalingKey, (int)Store.DeviceId), LibUtils.USER_AGENT);
541+
Pipe = MessageReceiver.createMessagePipe();
542+
MessageSender = new SignalServiceMessageSender(CancelSource.Token, LibUtils.ServiceUrls, Store.Username, Store.Password, (int)Store.DeviceId, new Store(), Pipe, null, LibUtils.USER_AGENT);
543+
IncomingMessagesTask = Task.Factory.StartNew(() => new IncomingMessages(CancelSource.Token, Pipe, this).HandleIncomingMessages(), TaskCreationOptions.LongRunning);
544+
OutgoingMessages = new OutgoingMessages(CancelSource.Token, MessageSender, this);
545+
OutgoingMessagesTask = Task.Factory.StartNew(() => OutgoingMessages.HandleOutgoingMessages(), TaskCreationOptions.LongRunning);
546+
}
547+
catch(Exception e)
548+
{
549+
Logger.LogError("InitNetwork failed: {0}\n{1}", e.Message, e.StackTrace);
550+
HandleAuthFailure();
551+
}
552+
}
553+
554+
/// <summary>
555+
/// Dispatches the auth failure to all frontends and resets the frontend dict. Must not be called on a UI thread. Must not be called on a task which holds the handle lock.
556+
/// </summary>
557+
private void HandleAuthFailure()
558+
{
559+
Logger.LogTrace("HandleAuthFailure() locking");
560+
SemaphoreSlim.Wait(CancelSource.Token);
561+
try
562+
{
563+
LikelyHasValidStore = false;
564+
Running = false;
565+
CancelSource.Cancel();
566+
DispatchHandleAuthFailure();
567+
Frames.Clear();
568+
Frames.Add(MainWindowDispatcher, MainWindow);
569+
}
570+
finally
571+
{
572+
SemaphoreSlim.Release();
573+
Logger.LogTrace("HandleAuthFailure() released");
574+
}
475575
}
476576

477577
private void TryScheduleAttachmentDownload(SignalAttachment attachment)

0 commit comments

Comments
 (0)