Exemplo n.º 1
0
        public override async Task <bool> Handle()
        {
            if (MainObject.Type != "Accept")
            {
                return(true);
            }
            var followObject = await EntityStore.GetEntity((string)MainObject.Data["object"].Single().Primitive, false);

            if (followObject.Type != "Follow")
            {
                return(true);
            }
            if ((string)followObject.Data["object"].First().Primitive != (string)MainObject.Data["actor"].First().Primitive)
            {
                throw new InvalidOperationException("I won't let you do that, Starfox!");
            }
            var followUser = (string)followObject.Data["object"].First().Primitive;

            if (Actor.Id != (string)followObject.Data["object"].First().Primitive)
            {
                return(true);                                                                   // doesn't involve us, so meh
            }
            if (!followObject.IsOwner)
            {
                throw new InvalidOperationException("Follow isn't made on this server?");
            }

            var relevant = await _relevantEntities.FindRelevantObject(followUser, "Reject", followObject.Id);

            if (relevant != null)
            {
                throw new InvalidOperationException("Follow has already been Rejected before!");
            }

            if (MainObject.Type == "Accept")
            {
                relevant = await _relevantEntities.FindRelevantObject(followUser, "Accept", followObject.Id);

                if (relevant != null)
                {
                    throw new InvalidOperationException("Follow has already been Accepted before!");
                }
            }

            var following = await EntityStore.GetEntity((string)Actor.Data["following"].Single().Primitive, false);

            var user = await EntityStore.GetEntity((string)MainObject.Data["actor"].Single().Primitive, true);

            if (MainObject.Type == "Accept" && !await _collection.Contains(following.Id, user.Id))
            {
                await _collection.AddToCollection(following, user);
            }
            else if (MainObject.Type == "Reject")
            {
                await _collection.RemoveFromCollection(following, user);
            }

            return(true);
        }
Exemplo n.º 2
0
        public async Task <IActionResult> RelevantEntities(RelevantObjectsModel model)
        {
            var user = User.FindFirstValue(JwtTokenSettings.ActorClaim);

            if (user == null)
            {
                return(Json(new List <ASObject>()));
            }

            var relevant = await _relevantEntities.FindRelevantObject(user, null, model.id);

            ASObject relevantObject = new ASObject();

            relevantObject["id"].Add(new ASTerm((string)null));

            foreach (var item in relevant)
            {
                relevantObject["relevant"].Add(new ASTerm(item.Data));
            }

            return(Content((await _flattener.Unflatten(_entityStore, APEntity.From(relevantObject), 5)).Serialize().ToString(), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""));
        }
Exemplo n.º 3
0
        public override async Task <bool> Handle()
        {
            if (MainObject.Type != "https://www.w3.org/ns/activitystreams#Accept")
            {
                return(true);
            }
            var followObject = await EntityStore.GetEntity(MainObject.Data["object"].Single().Id, false);

            if (followObject == null || !followObject.IsOwner)
            {
                followObject = (await _relevantEntities.FindRelevantObject(Actor.Id, "https://www.w3.org/ns/activitystreams#Follow", MainObject.Data["actor"].First().Id)).FirstOrDefault();
                if (followObject != null)
                {
                    MainObject.Data.Replace("object", ASTerm.MakeId(followObject.Id));
                    await EntityStore.StoreEntity(MainObject);
                }
            }

            if (followObject == null || followObject.Type != "https://www.w3.org/ns/activitystreams#Follow")
            {
                return(true);
            }

            if (followObject.Data["object"].First().Id != MainObject.Data["actor"].First().Id)
            {
                throw new InvalidOperationException("I won't let you do that, Starfox!");
            }
            var followUser = followObject.Data["object"].First().Id;

            if (Actor.Id != followObject.Data["actor"].First().Id)
            {
                return(true);                                                   // doesn't involve us, so meh
            }
            if (!followObject.IsOwner)
            {
                throw new InvalidOperationException("Follow isn't made on this server?");
            }

            var relevant = await _relevantEntities.FindRelevantObject(followUser, "Reject", followObject.Id);

            if (relevant.Count != 0)
            {
                throw new InvalidOperationException("Follow has already been Rejected before!");
            }

            if (MainObject.Type == "https://www.w3.org/ns/activitystreams#Accept")
            {
                relevant = await _relevantEntities.FindRelevantObject(followUser, "Accept", followObject.Id);

                if (relevant.Count > 0)
                {
                    throw new InvalidOperationException("Follow has already been Accepted before!");
                }
            }

            var following = await EntityStore.GetEntity(Actor.Data["following"].Single().Id, false);

            var user = await EntityStore.GetEntity(MainObject.Data["actor"].Single().Id, true);

            if (MainObject.Type == "https://www.w3.org/ns/activitystreams#Accept" && !await _collection.Contains(following, user.Id))
            {
                await _collection.AddToCollection(following, user);
            }
            else if (MainObject.Type == "https://www.w3.org/ns/activitystreams#Reject")
            {
                await _collection.RemoveFromCollection(following, user);
            }

            return(true);
        }
Exemplo n.º 4
0
        public override async Task <bool> Handle()
        {
            if (MainObject.Type != "https://www.w3.org/ns/activitystreams#Update" && MainObject.Type != "https://www.w3.org/ns/activitystreams#Delete")
            {
                return(true);
            }

            var activityData = MainObject.Data;

            var oldObject =
                await EntityStore.Bypass.GetEntity(activityData["object"].Single().Id, false);

            if (oldObject == null)
            {
                throw new InvalidOperationException("Cannot remove or update a non-existant object!");
            }

            if (!oldObject.IsOwner)
            {
                throw new InvalidOperationException("Cannot remove or update an object not on this server!");
            }

            var originatingCreate = (await _relevantEntities.FindRelevantObject("https://www.w3.org/ns/activitystreams#Create", oldObject.Id)).FirstOrDefault();

            if (originatingCreate.Data["actor"].Single().Id != Actor.Id)
            {
                throw new InvalidOperationException("Cannot remove or update objects that weren't made by you!");
            }

            if (MainObject.Type == "https://www.w3.org/ns/activitystreams#Update")
            {
                var newObject = await EntityStore.GetEntity(activityData["object"].Single().Id, false);

                if (newObject == oldObject)
                {
                    throw new InvalidOperationException("No new object passed!");
                }

                var data = oldObject.Data;
                foreach (var item in newObject.Data)
                {
                    // SequenceEqual ensures that clients doing full-object updates won't cause this exception on e.g. type, attributedTo, etc
                    if (UpdateBlacklist.Contains(item.Key) && (data[item.Key].Count != item.Value.Count || data[item.Key].Zip(item.Value, _isEqual).Any(a => !a)))
                    {
                        throw new InvalidOperationException($"Cannot update key {item.Key} as it's on the blacklist!");
                    }

                    data[item.Key].Clear();
                    data[item.Key].AddRange(item.Value);
                }

                data.Replace("updated", ASTerm.MakePrimitive(DateTime.Now.ToString("o")));

                newObject.Data = data;
                newObject.Type = oldObject.Type;
                await EntityStore.StoreEntity(newObject);
            }
            else
            {
                var newData = oldObject.Data;
                foreach (var kv in newData)
                {
                    if (!DeleteWhitelist.Contains(kv.Key))
                    {
                        kv.Value.Clear();
                    }
                }

                newData.Type.Clear();
                newData.Type.Add("https://www.w3.org/ns/activitystreams#Tombstone");
                newData.Replace("deleted", ASTerm.MakePrimitive(DateTime.Now.ToString("o")));

                var newObject = APEntity.From(newData, true);
                await EntityStore.StoreEntity(newObject);
            }

            return(true);
        }
Exemplo n.º 5
0
        private async Task <ASTerm> _parseActivity(XElement element, string authorId, string targetUser)
        {
            if (await _isSelf(element.Element(Atom + "id").Value))
            {
                return(ASTerm.MakeId(await _fixActivityToObjectId(element.Element(Atom + "id").Value)));
            }

            var ao = new ASObject();

            ao.Id = element.Element(Atom + "id").Value;
            ao.Replace("_:origin", ASTerm.MakePrimitive("atom"));

            var verb         = _objectTypeToType(element.Element(ActivityStreams + "verb")?.Value) ?? "Post";
            var originalVerb = verb;

            if (verb == "Unfollow" && (await _entityStore.GetEntity(element.Element(Atom + "id").Value, false))?.Type == "Follow") // egh egh egh, why, mastodon
            {
                ao.Id += "#unfollow";
            }

            if (verb == "Unfavorite")
            {
                verb = "Undo";
            }
            if (verb == "Unfollow")
            {
                verb = "Undo";
            }
            if (verb == "Request-friend")
            {
                return(null);
            }

            if (verb == "Post")
            {
                verb = "Create";
            }
            else if (verb == "Share")
            {
                verb = "Announce";
            }
            else if (verb == "Favorite")
            {
                verb = "Like";
            }


#pragma warning disable 618
            if (!_entityConfiguration.IsActivity(verb))
            {
                return(null);
            }
#pragma warning restore 618

            ao.Type.Add("https://www.w3.org/ns/activitystreams#" + verb);

            if (element.Element(Atom + "title") != null)
            {
                ao.Replace("summary", ASTerm.MakePrimitive(element.Element(Atom + "title").Value));
            }
            if (element.Element(Atom + "published") != null)
            {
                ao.Replace("published", ASTerm.MakePrimitive(element.Element(Atom + "published").Value));
            }
            if (element.Element(Atom + "updated") != null)
            {
                ao.Replace("updated", ASTerm.MakePrimitive(element.Element(Atom + "updated").Value));
            }

            if (element.Element(Atom + "author") != null)
            {
                var newAuthor = _parseAuthor(element.Element(Atom + "author"));
                authorId = newAuthor.Id;
            }

            if (authorId != null)
            {
                ao.Replace("actor", ASTerm.MakeId(authorId));
            }


            string retrievalUrl = null;

            foreach (var link in element.Elements(Atom + "link"))
            {
                var rel  = link.Attribute(NoNamespace + "rel").Value;
                var type = link.Attribute(NoNamespace + "type")?.Value;
                var href = link.Attribute(NoNamespace + "href").Value;

                if (rel == "self" && type == "application/atom+xml")
                {
                    retrievalUrl = href;
                }
                else if (rel == "alternate" && type == "text/html")
                {
                    ao["url"].Add(ASTerm.MakePrimitive(href));

                    if (retrievalUrl == null)
                    {
                        retrievalUrl = href;
                    }
                }
                else if (rel == "mentioned")
                {
                    if (href == "http://activityschema.org/collection/public")
                    {
                        href = "https://www.w3.org/ns/activitystreams#Public";
                    }

                    ao["to"].Add(ASTerm.MakeId(href));
                }
            }

            if (targetUser != null)
            {
                ao["cc"].Add(ASTerm.MakeId(targetUser));
            }

            if (retrievalUrl != null)
            {
                ao.Replace("atomUri", ASTerm.MakePrimitive(retrievalUrl));
            }

            if (element.Element(ActivityStreams + "object") != null)
            {
                var parsedActivityObject = await _parseActivityObject(element.Element(ActivityStreams + "object"), authorId, targetUser);

                if (verb == "Undo" && originalVerb == "Unfavorite")
                {
                    parsedActivityObject = ASTerm.MakeId((await _relevantEntities.FindRelevantObject(authorId, "https://www.w3.org/ns/activitystreams#Like", _getId(parsedActivityObject))).FirstOrDefault()?.Id);
                }
                else if (verb == "Undo" && originalVerb == "Unfollow")
                {
                    parsedActivityObject = ASTerm.MakeId((await _relevantEntities.FindRelevantObject(authorId, "https://www.w3.org/ns/activitystreams#Follow", _getId(parsedActivityObject))).FirstOrDefault()?.Id);
                }

                ao.Replace("object", parsedActivityObject);
            }
            else if (element.Element(ActivityStreams + "object-type") == null && originalVerb == "Unfollow")
            {
                // you thought Mastodon was bad?
                // GNU Social doesn't send an object in an unfollow.

                // .. what

                ao.Replace("object", ASTerm.MakeId((await _relevantEntities.FindRelevantObject(authorId, "https://www.w3.org/ns/activitystreams#Follow", targetUser)).FirstOrDefault()?.Id));
            }
            else
            {
                ao.Replace("object", await _parseActivityObject(element, authorId, targetUser, true));
            }

            return(ASTerm.MakeSubObject(ao));
        }