private void GotSubscribed(object sender, IQ iq, object state) { if (iq.Type != IQType.result) { FireError(Op.SUBSCRIBE, "Subscription failed", iq); return; } PubSub ps = iq.Query as PubSub; if (ps == null) { FireError(Op.SUBSCRIBE, "Invalid protocol", iq); return; } PubSubSubscriptionType subType; PubSubSubscription sub = ps["subscription", URI.PUBSUB] as PubSubSubscription; if (sub != null) { subType = sub.Type; } else { XmlElement ent = ps["entity", URI.PUBSUB]; if (ent == null) { FireError(Op.SUBSCRIBE, "Invalid protocol", iq); return; } string s = ent.GetAttribute("subscription"); if (s == "") { subType = PubSubSubscriptionType.NONE_SPECIFIED; } else { subType = (PubSubSubscriptionType)Enum.Parse(typeof(PubSubSubscriptionType), s); } } switch (subType) { case PubSubSubscriptionType.NONE_SPECIFIED: case PubSubSubscriptionType.subscribed: break; case PubSubSubscriptionType.pending: FireError(Op.SUBSCRIBE, "Subscription pending authorization", iq); return; case PubSubSubscriptionType.unconfigured: FireError(Op.SUBSCRIBE, "Subscription configuration required. Not implemented yet.", iq); return; } this[Op.SUBSCRIBE] = STATE.Running; GetItemsIfPending(); }
protected override Yield FilterRecipients(DispatcherEvent ev, PubSubSubscription subscription, Result <DispatcherEvent> result) { var recipients2 = new List <DispatcherRecipient>(); uint? pageid = null; string wikiId = null; if (ev.HasDocument) { var changeDoc = ev.AsDocument(); pageid = changeDoc["pageid"].AsUInt; wikiId = changeDoc["@wikiid"].AsText; } var userIds = new Dictionary <int, DispatcherRecipient>(); foreach (var recipient in subscription.Recipients) { var authtoken = recipient.Doc["@authtoken"].AsText; if (string.IsNullOrEmpty(authtoken)) { // if the recipient has no authtoken, but has a userid, collect the Id so we can authorize it against the page int?userId = recipient.Doc["@userid"].AsInt; if (userId.HasValue) { userIds.Add(userId.Value, recipient); } } else if (authtoken == _authtoken) { // master authtoken means the recipient doesn't need page level authorization (such as lucene) recipients2.Add(recipient); } else if (!string.IsNullOrEmpty(wikiId)) { var key = authtoken + ":" + wikiId; if (!_validatedKeys.Contains(key)) { // no valid key found, need to check with API to validate XDoc settings = null; yield return(_deki.At("site", "settings") .With("apikey", _authtoken) .WithHeader("X-Deki-Site", "id=" + wikiId) .Get(new Result <DreamMessage>()) .Set(x => settings = x.IsSuccessful ? x.ToDocument() : null)); if (settings == null || !authtoken.EqualsInvariant(settings["security/api-key"].AsText)) { continue; } _validatedKeys.Add(key); } // instance authtoken means the recipient doesn't need page level authorization (such as lucene) recipients2.Add(recipient); } } if (userIds.Count > 0 && (ev.Channel.Segments.Length <= 2 || !ev.Channel.Segments[2].EqualsInvariantIgnoreCase("delete"))) { // check all userId's against the page to prune set to authorized users var users = new XDoc("users"); foreach (int userid in userIds.Keys) { users.Start("user").Attr("id", userid).End(); } if (pageid.HasValue) { Result <DreamMessage> userAuthResult; yield return(userAuthResult = _deki.At("pages", pageid.Value.ToString(), "allowed") .With("permissions", "read,subscribe") .With("filterdisabled", true) .WithHeader("X-Deki-Site", "id=" + wikiId) .PostAsync(users)); DreamMessage userAuth = userAuthResult.Value; if (userAuth.IsSuccessful) { int authorized = 0; foreach (XDoc userid in userAuth.ToDocument()["user/@id"]) { DispatcherRecipient recipient; if (!userIds.TryGetValue(userid.AsInt.GetValueOrDefault(), out recipient)) { continue; } authorized++; recipients2.Add(recipient); } if (authorized != userIds.Count) { _log.DebugFormat("requested auth on {0} users, received auth on {1} for page {2}", userIds.Count, authorized, pageid.Value); } } else { _log.WarnFormat("unable to retrieve user auth for page '{0}': {1}", pageid, userAuth.Status); } } } result.Return(recipients2.Count == 0 ? null : ev.WithRecipient(true, recipients2.ToArray())); yield break; }