public void DeleteAllEstablishedTrust(IUserOrGroup userOrGroup) { this.persistedUserManagerData.Read(userManagerData => { var user = userManagerData.GetUser(userOrGroup.Id); user.receiveNotificationEndpointsBySenderToken.Clear(); user.receiveNotificationSenderTokensByEndpoint.Clear(); }); }
/// <summary> /// Establishes trust as part of GetRecipientInfos when trust isn't established /// </summary> /// <param name="sender"></param> /// <param name="receiveNotificationEndpoint"></param> /// <param name="recipients"></param> /// <param name="callback"></param> private void GetRecipientInfos( IUserOrGroup sender, string receiveNotificationEndpoint, string establishTrustEndpoint, List<string> recipients, string requestedEndpoint, Action<EndpointInfo> callback, Action<IEnumerable<string>> errorCallback) { this.BeginEstablishTrust(sender, receiveNotificationEndpoint, establishTrustEndpoint, delegate(string senderToken) { var recipientInfo = new EndpointInfo() { RecipientIdentities = recipients, Endpoint = requestedEndpoint, SenderToken = senderToken }; callback(recipientInfo); }, delegate(Exception e) { log.Error( string.Format("Could not establish trust between {0} and {1}", sender.Name, StringGenerator.GenerateCommaSeperatedList(recipients)), e); errorCallback(recipients); }); }
/// <summary> /// Establishes trust between a user and another server /// </summary> /// <param name="sender"></param> /// <param name="receiveNotificationEndpoint"></param> /// <param name="callback"></param> private void BeginEstablishTrust( IUserOrGroup sender, string receiveNotificationEndpoint, string establishTrustEndpoint, Action<string> callback, Action<Exception> errorCallback) { // Make sure the timer is created if (null == EstablishTrustDataTimer) { Timer timer = new Timer(EstablishTrustDataCleanup, null, 600000, 600000); if (null != Interlocked.CompareExchange<Timer>(ref EstablishTrustDataTimer, timer, null)) timer.Dispose(); } // Get the avatar byte[] avatar; ISession session = FileHandlerFactoryLocator.SessionManagerHandler.CreateSession(); try { IWebConnection webConnection = new BlockingShellWebConnection( FileHandlerFactoryLocator.WebServer, session, "/Users/" + sender.Name + ".user?Method=GetAvatar", null, null, null, CallingFrom.Web, WebMethod.GET); IWebResults webResults = webConnection.ShellTo("/Users/" + sender.Name + ".user?Method=GetAvatar"); using (Stream stream = webResults.ResultsAsStream) { avatar = new byte[stream.Length]; stream.Read(avatar, 0, avatar.Length); } } finally { FileHandlerFactoryLocator.SessionManagerHandler.EndSession(session.SessionId); } // Hold on to callback information for use after trust is established string token; using (TimedLock.Lock(EstablishTrustDatasByToken)) { do token = Convert.ToBase64String(SRandom.NextBytes(100)); while (EstablishTrustDatasByToken.ContainsKey(token)); EstablishTrustDatasByToken[token] = new EstablishTrustData(); } HttpWebClient httpWebClient = new HttpWebClient(); httpWebClient.BeginPost( establishTrustEndpoint, delegate(HttpResponseHandler httpResponseHandler) { if (httpResponseHandler.StatusCode == System.Net.HttpStatusCode.Created) { string senderToken; using (TimedLock.Lock(EstablishTrustDatasByToken)) { senderToken = EstablishTrustDatasByToken[token].SenderToken; EstablishTrustDatasByToken.Remove(token); } this.persistedUserManagerData.Write(userManagerData => { var user = userManagerData.GetUser(sender.Id); string oldSenderToken; if (user.receiveNotificationSenderTokensByEndpoint.TryGetValue(receiveNotificationEndpoint, out oldSenderToken)) user.receiveNotificationEndpointsBySenderToken.Remove(oldSenderToken); user.receiveNotificationEndpointsBySenderToken[senderToken] = receiveNotificationEndpoint; user.receiveNotificationSenderTokensByEndpoint[receiveNotificationEndpoint] = senderToken; }); callback(senderToken); } else errorCallback(new ParticleException.CouldNotEstablishTrust("Couldn't establish trust: " + httpResponseHandler.AsString())); }, errorCallback, new KeyValuePair<string, string>("senderIdentity", sender.Identity), new KeyValuePair<string, string>("token", token), new KeyValuePair<string, string>("avatar", Convert.ToBase64String(avatar)), new KeyValuePair<string, string>("loginURL", string.Format("http://{0}/Users/UserDB?Method=OpenIDLogin", FileHandlerFactoryLocator.HostnameAndPort)), new KeyValuePair<string, string>("loginURLOpenID", "openid_url"), new KeyValuePair<string, string>("loginURLWebFinger", "openid_url"), new KeyValuePair<string, string>("loginURLRedirect", "redirect"), GenerateSecurityTimestamp()); }
/// <summary> /// Continues to get more information about recipients after all information about endpoints is loaded /// </summary> /// <param name="sender"></param> /// <param name="recipientIdentities"></param> /// <param name="loadedEndpoints"></param> /// <param name="callback"></param> private void GetRecipientInfos( IUserOrGroup sender, bool forceRefresh, HashSet<string> recipientIdentities, LockFreeQueue<Endpoints> loadedEndpoints, ParticleEndpoint particleEndpoint, Action<EndpointInfo> callback, Action<IEnumerable<string>> errorCallback, Action<Exception> exceptionCallback) { try { // All of the unique particle endpoints, with the recipients at each Dictionary<string, List<string>> recipientsAtEndpoints = new Dictionary<string, List<string>>(); Dictionary<string, string> establishTrustEndpoints = new Dictionary<string, string>(); Dictionary<string, string> requestedEndpoints = new Dictionary<string, string>(); Endpoints particleEndpoints; while (loadedEndpoints.Dequeue(out particleEndpoints)) { string endpoint; if (particleEndpoints.TryGetEndpoint(particleEndpoint, out endpoint)) { List<string> users; if (recipientsAtEndpoints.TryGetValue(particleEndpoints[ParticleEndpoint.ReceiveNotification], out users)) users.Add(particleEndpoints.OpenIdOrWebFinger); else { users = new List<string>(); users.Add(particleEndpoints.OpenIdOrWebFinger); recipientsAtEndpoints[particleEndpoints[ParticleEndpoint.ReceiveNotification]] = users; establishTrustEndpoints[particleEndpoints[ParticleEndpoint.ReceiveNotification]] = particleEndpoints[ParticleEndpoint.EstablishTrust]; requestedEndpoints[particleEndpoints[ParticleEndpoint.ReceiveNotification]] = particleEndpoints[particleEndpoint]; } } } if (!forceRefresh) { // Load for situations where trust is already established // copy is to avoid locked the database this.persistedUserManagerData.Read(userManagerData => { var recipientUser = userManagerData.GetUser(sender.Id); foreach (var recipientAndToken in recipientUser.receiveNotificationEndpointsBySenderToken.Where( r => recipientsAtEndpoints.ContainsKey(r.Value))) { var receiveNotificationEndpoint = recipientAndToken.Value; var senderToken = recipientAndToken.Key; string endpoint; if (requestedEndpoints.TryGetValue(receiveNotificationEndpoint, out endpoint)) { var recipientInfo = new EndpointInfo() { RecipientIdentities = recipientsAtEndpoints[receiveNotificationEndpoint], Endpoint = endpoint, SenderToken = senderToken }; recipientsAtEndpoints.Remove(receiveNotificationEndpoint); callback(recipientInfo); } } }); } // For situations where trust isn't established, establish trust and then use the callback foreach (KeyValuePair<string, List<string>> endpointAndRecipients in recipientsAtEndpoints) GetRecipientInfos( sender, endpointAndRecipients.Key, establishTrustEndpoints[endpointAndRecipients.Key], endpointAndRecipients.Value, requestedEndpoints[endpointAndRecipients.Key], callback, errorCallback); } catch (Exception e) { exceptionCallback(e); } }
// TODO // A lot of the logic in this file that's not tied to the DB should move someplace else so that independent implementations can use it /// <summary> /// Gets information about recipients for sending a notification /// </summary> /// <param name="openIdOrWebFinger"></param> /// <param name="forceRefresh"></param> /// <returns></returns> public void GetEndpointInfos( IUserOrGroup sender, bool forceRefresh, IEnumerable<string> recipientIdentitiesArg, ParticleEndpoint particleEndpoint, Action<EndpointInfo> callback, Action<IEnumerable<string>> errorCallback, Action<Exception> exceptionCallback) { HashSet<string> recipientIdentities = new HashSet<string>(recipientIdentitiesArg); long outstandingRequests = recipientIdentities.Count; LockFreeQueue<Endpoints> loadedEndpoints = new LockFreeQueue<Endpoints>(); Action<Endpoints> endpointLoaded = delegate(Endpoints endpoints) { loadedEndpoints.Enqueue(endpoints); if (0 == Interlocked.Decrement(ref outstandingRequests)) GetRecipientInfos(sender, forceRefresh, recipientIdentities, loadedEndpoints, particleEndpoint, callback, errorCallback, exceptionCallback); }; Action<Exception> endpointException = delegate(Exception e) { if (0 == Interlocked.Decrement(ref outstandingRequests)) GetRecipientInfos(sender, forceRefresh, recipientIdentities, loadedEndpoints, particleEndpoint, callback, errorCallback, exceptionCallback); }; foreach (string openIdOrWebFinger in recipientIdentities) Endpoints.GetEndpoints(openIdOrWebFinger, forceRefresh, endpointLoaded, endpointException); }