Пример #1
0
        public override async Task <bool> Handle()
        {
            if (MainObject.Type != "https://www.w3.org/ns/activitystreams#Delete")
            {
                return(true);
            }

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

            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);
            await EntityStore.StoreEntity(newObject);

            return(true);
        }
Пример #2
0
        public override async Task <bool> Handle()
        {
            if (_entityData.IsActivity(MainObject.Data))
            {
                return(true);
            }
            var data = MainObject.Data;

            var createActivity = new ASObject();

            createActivity.Type.Add("https://www.w3.org/ns/activitystreams#Create");
            createActivity["to"].AddRange(data["to"]);
            createActivity["bto"].AddRange(data["bto"]);
            createActivity["cc"].AddRange(data["cc"]);
            createActivity["bcc"].AddRange(data["bcc"]);
            createActivity["audience"].AddRange(data["audience"]);
            createActivity["actor"].Add(ASTerm.MakeId(Actor.Id));
            createActivity["object"].Add(ASTerm.MakeId(MainObject.Id));
            createActivity.Id = await _entityData.FindUnusedID(EntityStore, createActivity);

            var activityEntity = await EntityStore.StoreEntity(APEntity.From(createActivity, true));

            MainObject = activityEntity;

            return(true);
        }
Пример #3
0
        private void _merge(List <ASTerm> to, List <ASTerm> from)
        {
            var str = new HashSet <string>(to.Select(a => a.Id).Concat(from.Select(a => a.Id)));

            to.Clear();
            to.AddRange(str.Select(a => ASTerm.MakeId(a)));
        }
Пример #4
0
        private async Task <ASObject> _buildPage(APEntity entity, int from_id, int to_id)
        {
            var collection = entity.Data;
            var maxitem    = (await _collectionTools.GetItems(entity.Id, count: 1)).FirstOrDefault()?.CollectionItemId;
            var items      = await _collectionTools.GetItems(entity.Id, from_id, to_id, 11);

            var hasItems = items.Any();
            var page     = new ASObject();

            page.Type.Add("https://www.w3.org/ns/activitystreams#OrderedCollectionPage");
            page["summary"].Add(ASTerm.MakePrimitive("A collection"));
            page.Id = entity.Id + "?from_id=" + (hasItems ? from_id : 0);
            page["partOf"].Add(ASTerm.MakeId(entity.Id));
            if (collection["attributedTo"].Any())
            {
                page["attributedTo"].Add(collection["attributedTo"].First());
            }
            if (items.Count > 0 && items[0].CollectionItemId != maxitem)
            {
                page["prev"].Add(ASTerm.MakeId(entity.Id + "?to_id=" + items[0].CollectionItemId.ToString()));
            }
            if (items.Count > 10)
            {
                page["next"].Add(ASTerm.MakeId(entity.Id + "?from_id=" + (items[9].CollectionItemId - 1).ToString()));
            }
            page["orderedItems"].AddRange(items.Take(10).Select(a => ASTerm.MakeId(a.Entity.Id)));
            return(page);
        }
Пример #5
0
        public async Task <APEntity> ClientToServer(APEntity outbox, ASObject activity)
        {
            var stagingStore = new StagingEntityStore(_mainStore);
            var userId       = outbox.Data["attributedTo"].Single().Id;
            var user         = await _mainStore.GetEntity(userId, false);

            if (!EntityData.IsActivity(activity))
            {
#pragma warning disable CS0618 // Type or member is obsolete
                if (EntityData.IsActivity(activity.Type.FirstOrDefault()))
#pragma warning restore CS0618 // Type or member is obsolete
                {
                    throw new UnauthorizedAccessException("Sending an Activity without an actor isn't allowed. Are you sure you wanted to do that?");
                }

                var createActivity = new ASObject();
                createActivity.Type.Add("https://www.w3.org/ns/activitystreams#Create");
                createActivity["to"].AddRange(activity["to"]);
                createActivity["bto"].AddRange(activity["bto"]);
                createActivity["cc"].AddRange(activity["cc"]);
                createActivity["bcc"].AddRange(activity["bcc"]);
                createActivity["audience"].AddRange(activity["audience"]);
                createActivity["actor"].Add(ASTerm.MakeId(userId));
                createActivity["object"].Add(ASTerm.MakeSubObject(activity));
                activity = createActivity;
            }

            if (activity.Type.Contains("https://www.w3.org/ns/activitystreams#Create"))
            {
                activity.Id = null;
                if (activity["object"].SingleOrDefault()?.SubObject != null)
                {
                    activity["object"].Single().SubObject.Id = null;
                }
            }

            var flattened = await _flattener.FlattenAndStore(stagingStore, activity);

            IEntityStore store = stagingStore;

            foreach (var type in ServerConfig.ClientToServerHandlers)
            {
                var handler = (BaseHandler)ActivatorUtilities.CreateInstance(_serviceProvider, type,
                                                                             store, flattened, user, outbox, _user);
                var handled = await handler.Handle();

                flattened = handler.MainObject;
                if (!handled)
                {
                    break;
                }
                if (type == typeof(CommitChangesHandler))
                {
                    store = _mainStore;
                }
            }

            return(flattened);
        }
Пример #6
0
        public override async Task <bool> Handle()
        {
            if (MainObject.Type != "https://www.w3.org/ns/activitystreams#Create")
            {
                return(true);
            }

            var activityData = MainObject.Data;
            var objectEntity = await EntityStore.GetEntity(activityData["object"].First().Id, false);

            if (!_entityData.IsActor(objectEntity.Data))
            {
                return(true);
            }
            var objectData = objectEntity.Data;
            var id         = objectEntity.Id;

            await AddCollection(objectData, "inbox", id);
            await AddCollection(objectData, "outbox", id);
            await AddCollection(objectData, "following", id);
            await AddCollection(objectData, "followers", id);
            await AddCollection(objectData, "liked", id);

            var blocks = await AddCollection(objectData, "blocks", id);

            var blocked = await _collection.NewCollection(EntityStore, null, "blocked", blocks.Id);

            var blocksData = blocks.Data;

            blocksData["blocked"].Add(ASTerm.MakeId(blocked.Id));
            blocks.Data = blocksData;

            if (!objectData["manuallyApprovesFollowers"].Any())
            {
                objectData.Replace("manuallyApprovesFollowers", ASTerm.MakePrimitive(false));
            }

            objectEntity.Data = objectData;

            await EntityStore.StoreEntity(blocked);

            await EntityStore.StoreEntity(blocks);

            await EntityStore.StoreEntity(objectEntity);

            var userId = UserOverride ?? User.FindFirst(ClaimTypes.NameIdentifier).Value;

            if (!activityData["actor"].Any())
            {
                activityData["actor"].Add(ASTerm.MakeId(objectEntity.Id));
            }

            MainObject.Data = activityData;
            await EntityStore.StoreEntity(MainObject);

            await _connection.ExecuteAsync("insert into \"UserActorPermissions\" (\"UserId\", \"ActorId\", \"IsAdmin\") values (@UserId, @ActorId, TRUE)", new { UserId = userId, ActorId = objectEntity.DbId });

            return(true);
        }
Пример #7
0
 private string _getId(ASTerm term)
 {
     if (term.Primitive != null)
     {
         return((string)term.Primitive);
     }
     return(term.SubObject.Id);
 }
Пример #8
0
        private ASObject _getEndpoints(APEntity entity)
        {
            var data = entity.Data;

            data.Replace("endpoints", ASTerm.MakeId(entity.Id + "#endpoints"));
            data.Replace("publicKey", ASTerm.MakeId(entity.Id + "#key"));
            return(data);
        }
Пример #9
0
 private string _getId(ASTerm term)
 {
     if (term.Primitive != null)
     {
         return((string)term.Primitive);
     }
     return((string)term.SubObject["id"].Single().Primitive);
 }
Пример #10
0
        private async Task AddCollection(ASObject entity, string obj, string type, string parent)
        {
            var collection = await _collection.NewCollection(EntityStore, null, type, parent);

            await EntityStore.StoreEntity(collection);

            entity.Replace(obj, ASTerm.MakeId(collection.Id));
        }
Пример #11
0
 private async Task <ASObject> _get(ASTerm id)
 {
     if (id.Primitive != null)
     {
         return((await _entityStore.GetEntity((string)id.Primitive, false)).Data);
     }
     return(id.SubObject);
 }
Пример #12
0
        public async Task <IActionResult> UploadMedia()
        {
            var @object = Request.Form["object"];
            var file    = Request.Form.Files["file"];

            var handler = ActivatorUtilities.CreateInstance <GetEntityMiddleware.GetEntityHandler>(_provider, User);
            var obj     = ASObject.Parse(@object);
            var mainObj = obj;

            if (obj["object"].Any())
            {
                mainObj = obj["object"].Single().SubObject;
            }

            var uploadPath = _configuration.GetSection("Kroeg")["FileUploadPath"];
            var uploadUri  = _configuration.GetSection("Kroeg")["FileUploadUrl"];

            var extension = file.FileName.Split('.').Last().Replace('/', '_');

            var fileName = Guid.NewGuid().ToString() + "." + extension;

            var str = System.IO.File.OpenWrite(uploadPath + fileName);
            await file.CopyToAsync(str);

            str.Dispose();

            mainObj.Replace("url", ASTerm.MakePrimitive(uploadUri + fileName));

            var entity = await _entityStore.GetEntity((string)HttpContext.Items["fullPath"], false);

            try
            {
                using (var transaction = _connection.BeginTransaction())
                {
                    var entOut = await handler.Post(HttpContext, (string)HttpContext.Items["fullPath"], entity, obj);

                    if (entOut == null)
                    {
                        return(NotFound());
                    }
                    obj = await _flattener.Unflatten(_entityStore, entOut);

                    transaction.Commit();
                    return(Content(obj.Serialize().ToString(), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""));
                }
            }
            catch (UnauthorizedAccessException e)
            {
                Console.WriteLine(e);
                return(StatusCode(403, e));
            }
            catch (InvalidOperationException e)
            {
                Console.WriteLine(e);
                return(StatusCode(401, e));
            }
        }
Пример #13
0
        private async Task <ASObject> _object()
        {
            var user     = (await _entityStore.GetEntity(Data.SourceUserId, false)).Data;
            var outboxId = user["outbox"].First().Id;

            var page = new ASObject();

            page.Type.Add("https://www.w3.org/ns/activitystreams#OrderedCollectionPage");
            page.Id = outboxId + "?from_id=" + (Data.CollectionItem + 1);
            page["attributedTo"].Add(ASTerm.MakeId(Data.SourceUserId));
            page["orderedItems"].Add(ASTerm.MakeId(Data.ObjectId));
            return(page);
        }
Пример #14
0
        private async Task <ASObject> _getCollection(APEntity entity, IQueryCollection arguments)
        {
            var  from_id    = arguments["from_id"].FirstOrDefault();
            var  to_id      = arguments["to_id"].FirstOrDefault();
            var  collection = entity.Data;
            bool seePrivate = collection["attributedTo"].Any() && _user.FindFirstValue("actor") == collection["attributedTo"].First().Id;

            if (from_id != null || to_id != null)
            {
                var fromId = from_id != null?int.Parse(from_id) : int.MaxValue;

                var toId = to_id != null?int.Parse(to_id) : int.MinValue;

                var maxitem = (await _collectionTools.GetItems(entity.Id, count: 1)).FirstOrDefault()?.CollectionItemId;
                var items   = await _collectionTools.GetItems(entity.Id, fromId, toId, count : 11);

                var hasItems = items.Any();
                var page     = new ASObject();
                page.Type.Add("https://www.w3.org/ns/activitystreams#OrderedCollectionPage");
                page["summary"].Add(ASTerm.MakePrimitive("A collection"));
                page.Id = entity.Id + "?from_id=" + (hasItems ? fromId : 0);
                page["partOf"].Add(ASTerm.MakeId(entity.Id));
                if (collection["attributedTo"].Any())
                {
                    page["attributedTo"].Add(collection["attributedTo"].First());
                }
                if (items.Count > 0 && items[0].CollectionItemId != maxitem)
                {
                    page["prev"].Add(ASTerm.MakeId(entity.Id + "?to_id=" + items[0].CollectionItemId.ToString()));
                }
                if (items.Count > 10)
                {
                    page["next"].Add(ASTerm.MakeId(entity.Id + "?from_id=" + (items[9].CollectionItemId - 1).ToString()));
                }
                page["orderedItems"].AddRange(items.Take(10).Select(a => ASTerm.MakeId(a.Entity.Id)));

                return(page);
            }
            else
            {
                var items = await _collectionTools.GetItems(entity.Id, count : 1);

                var hasItems = items.Any();
                var page     = entity.Id + "?from_id=" + (hasItems ? items.First().CollectionItemId + 1 : 0);
                collection["current"].Add(ASTerm.MakeId(entity.Id));
                collection["totalItems"].Add(ASTerm.MakePrimitive(await _collectionTools.Count(entity.Id), ASTerm.NON_NEGATIVE_INTEGER));
                collection["first"].Add(ASTerm.MakeId(page));
                return(collection);
            }
        }
Пример #15
0
        private async Task <APEntity> AddCollection(ASObject entity, string obj, string parent, string store = null)
        {
            var collection = await _collection.NewCollection(EntityStore, null, "_" + obj, parent);

            var data = collection.Data;

            data.Replace("attributedTo", ASTerm.MakeId(parent));
            collection.Data = data;

            await EntityStore.StoreEntity(collection);

            entity.Replace(store ?? obj, ASTerm.MakeId(collection.Id));
            return(collection);
        }
Пример #16
0
        private XElement _buildMention(ASTerm term)
        {
            var objectType = "Person";
            var s          = (string)term.Primitive;

            if (s == "https://www.w3.org/ns/activitystreams#Public")
            {
                s          = "http://activityschema.org/collection/public";
                objectType = "Collection";
            }

            return(new XElement(Atom + "link",
                                new XAttribute(NoNamespace + "rel", "mentioned"),
                                new XAttribute(OStatus + "object-type", _typeToObjectType(objectType)),
                                new XAttribute(NoNamespace + "href", s)));
        }
Пример #17
0
        private async Task <ASObject> _buildCollection(APEntity entity)
        {
            var collection = entity.Data;

            collection["current"].Add(ASTerm.MakeId(entity.Id));
            collection["totalItems"].Add(ASTerm.MakePrimitive(await _collectionTools.Count(entity.Id), ASTerm.NON_NEGATIVE_INTEGER));
            var item = await _collectionTools.GetItems(entity.Id, count : 1);

            if (item.Any())
            {
                collection["first"].Add(ASTerm.MakeId(entity.Id + $"?from_id={item.First().CollectionItemId + 1}"));
            }
            else
            {
                collection["first"].Add(ASTerm.MakeId(entity.Id + $"?from_id=0"));
            }
            return(collection);
        }
Пример #18
0
        private async Task <APEntity> _fixupPointing(ASTerm term)
        {
            var id     = (string)term.Primitive;
            var entity = await _entityStore.GetEntity(id, false);

            if (entity == null)
            {
                return(null);
            }

            if (_entityConfiguration.IsActivity(entity.Data))
            {
                return(entity);
            }

            var target = await _activityService.DetermineOriginatingCreate(id);

            return(target);
        }
Пример #19
0
        public async Task <ASObject> BuildFakeObject(APEntity entity, string fragment)
        {
            if (!EntityData.IsActor(entity.Data))
            {
                return(null);
            }

            if (fragment == "key")
            {
                var key = await _keyService.GetKey(entity.Id);

                var salm    = new MagicKey(key.PrivateKey);
                var pemData = salm.AsPEM;

                var keyObj = new ASObject();
                keyObj.Replace("owner", ASTerm.MakeId(entity.Id));
                keyObj.Replace("publicKeyPem", ASTerm.MakePrimitive(pemData));
                keyObj.Id = $"{entity.Id}#key";
                return(keyObj);
            }
            else if (fragment == "endpoints")
            {
                var data = entity.Data;
                var idu  = new Uri(entity.Id);

                var basePath = $"{idu.Scheme}://{idu.Host}{(idu.IsDefaultPort?"":$":{idu.Port}")}{_configuration.BasePath}";

                var endpoints = new ASObject();
                endpoints.Replace("oauthAuthorizationEndpoint", ASTerm.MakeId(basePath + "oauth/authorize?id=" + Uri.EscapeDataString(entity.Id)));
                endpoints.Replace("oauthTokenEndpoint", ASTerm.MakeId(basePath + "oauth/token?"));
                endpoints.Replace("settingsEndpoint", ASTerm.MakeId(basePath + "settings/auth"));
                endpoints.Replace("uploadMedia", data["outbox"].Single());
                endpoints.Replace("relevantObjects", ASTerm.MakeId(basePath + "settings/relevant"));
                endpoints.Replace("proxyUrl", ASTerm.MakeId(basePath + "auth/proxy"));
                endpoints.Replace("jwks", ASTerm.MakeId(basePath + "auth/jwks?id=" + Uri.EscapeDataString(entity.Id)));
                endpoints.Replace("sharedInbox", ASTerm.MakeId(basePath + "auth/sharedInbox"));
                endpoints.Replace("search", ASTerm.MakeId(basePath + "auth/search"));
                endpoints.Id = entity.Id + "#endpoints";
                return(endpoints);
            }

            return(null);
        }
Пример #20
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();

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

            return(Content((await _flattener.Unflatten(_entityStore, APEntity.From(relevantObject), 5)).Serialize().ToString(), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""));
        }
Пример #21
0
        public async Task <IActionResult> MakeNewActor(NewActorModel model)
        {
            var data = await _getUserInfo();

            if (string.IsNullOrWhiteSpace(model.Username))
            {
                return(View("NewActor", model));
            }
            var user = model.Username;

            var obj = new ASObject();

            obj.Type.Add("https://www.w3.org/ns/activitystreams#Person");
            obj["preferredUsername"].Add(ASTerm.MakePrimitive(user));
            obj["name"].Add(ASTerm.MakePrimitive(string.IsNullOrWhiteSpace(model.Name) ? "Unnamed" : model.Name));
            if (!string.IsNullOrWhiteSpace(model.Summary))
            {
                obj["summary"].Add(ASTerm.MakePrimitive(model.Summary));
            }

            var create = new ASObject();

            create.Type.Add("https://www.w3.org/ns/activitystreams#Create");
            create["object"].Add(ASTerm.MakeSubObject(obj));
            create["to"].Add(ASTerm.MakeId("https://www.w3.org/ns/activitystreams#Public"));

            var stagingStore = new StagingEntityStore(_entityStore);
            var apo          = await _flattener.FlattenAndStore(stagingStore, create);

            var handler = new CreateActorHandler(stagingStore, apo, null, null, User, _collectionTools, _entityData, _connection);
            await handler.Handle();

            var resultUser = await _entityStore.GetEntity(handler.MainObject.Data["object"].First().Id, false);

            var outbox = await _entityStore.GetEntity(resultUser.Data["outbox"].First().Id, false);

            var delivery = new DeliveryHandler(stagingStore, handler.MainObject, resultUser, outbox, User, _collectionTools, _provider.GetRequiredService <DeliveryService>());
            await delivery.Handle();

            return(RedirectToAction("Edit", new { id = resultUser.Id }));
        }
        public override async Task <bool> Handle()
        {
            await Task.Yield();

            var data = MainObject.Data;

            if (data["actor"].Count != 1)
            {
                throw new InvalidOperationException("Cannot create an activity with no or more than one actor!");
            }
            if (data["actor"].First().Id != User.FindFirstValue("actor"))
            {
                throw new InvalidOperationException("Cannot create an activity with an actor that isn't the one you log in to");
            }

            // add published and updated.
            data.Replace("published", ASTerm.MakeDateTime(DateTime.Now));

            MainObject.Data = data;

            return(true);
        }
Пример #23
0
        public override async Task <bool> Handle()
        {
            if (MainObject.Type != "https://www.w3.org/ns/activitystreams#Create")
            {
                return(true);
            }

            var activityData = MainObject.Data;
            var objectEntity = await EntityStore.GetEntity(activityData["object"].First().Id, false);

            var objectData = objectEntity.Data;

            if (_entityData.IsActivity(objectData))
            {
                throw new InvalidOperationException("Cannot Create another activity!");
            }

            objectData["attributedTo"].AddRange(activityData["actor"]);

            await AddCollection(objectData, "likes", "_likes", objectEntity.Id);
            await AddCollection(objectData, "shares", "_shares", objectEntity.Id);
            await AddCollection(objectData, "replies", "_replies", objectEntity.Id);

            _merge(activityData["to"], objectData["to"]);
            _merge(activityData["bto"], objectData["bto"]);
            _merge(activityData["cc"], objectData["cc"]);
            _merge(activityData["bcc"], objectData["bcc"]);
            _merge(activityData["audience"], objectData["audience"]);

            objectData.Replace("published", ASTerm.MakeDateTime(DateTime.Now));

            objectEntity.Data = objectData;
            MainObject.Data   = activityData;

            return(true);
        }
Пример #24
0
        public async Task FindTransparentPredicates(Dictionary <string, APEntity> objects, string actor)
        {
            var allObjectIds  = _entityStore.FindAttributes(objects.Values.Select(a => a.Id).ToList()).Values.ToList();
            var actorId       = (await _entityStore.ReverseAttribute(actor, true)).Value;
            var objectAttr    = (await _entityStore.ReverseAttribute("https://www.w3.org/ns/activitystreams#object", true)).Value;
            var inReplyToAttr = (await _entityStore.ReverseAttribute("https://www.w3.org/ns/activitystreams#inReplyTo", true)).Value;
            var actorAttr     = (await _entityStore.ReverseAttribute("https://www.w3.org/ns/activitystreams#actor", true)).Value;
            var typeAttr      = (await _entityStore.ReverseAttribute("rdf:type", true)).Value;
            var undoAttr      = (await _entityStore.ReverseAttribute("https://www.w3.org/ns/activitystreams#Undo", true)).Value;

            var query = "select a.* from \"TripleEntities\" a where a.\"IsOwner\" = TRUE" +
                        $" and exists(select 1 from \"Triples\" where \"PredicateId\" = @ActorAttr and \"AttributeId\" = @ActorId and \"SubjectId\" = a.\"IdId\" and \"SubjectEntityId\" = a.\"EntityId\")" +
                        $" and exists(select 1 from \"Triples\" where \"PredicateId\" = @ObjectAttr and \"AttributeId\" = any(@Ids) and \"SubjectId\" = a.\"IdId\" and \"SubjectEntityId\" = a.\"EntityId\")";

            var replyQuery = "select a.* from \"TripleEntities\" a where" +
                             $" exists(select 1 from \"Triples\" where \"PredicateId\" = @ObjectAttr and \"AttributeId\" = any(@Ids) and \"SubjectId\" = a.\"IdId\" and \"SubjectEntityId\" = a.\"EntityId\")";

            var entityShapes = await _connection.QueryAsync <APTripleEntity>(query,
                                                                             new {
                ActorAttr  = actorAttr,
                ActorId    = actorId,
                ObjectAttr = objectAttr,
                Ids        = allObjectIds
            });

            var undoneShapes = await _connection.QueryAsync <APTripleEntity>(query,
                                                                             new {
                ActorAttr  = typeAttr,
                ActorId    = undoAttr,
                ObjectAttr = objectAttr,
                Ids        = entityShapes.Select(a => a.IdId).ToList()
            });

            var replyShapes = await _connection.QueryAsync <APTripleEntity>(replyQuery,
                                                                            new {
                ObjectAttr = inReplyToAttr,
                Ids        = allObjectIds
            });

            Console.WriteLine(string.Join(", ", replyShapes.Select(a => a.EntityId.ToString())));

            var properEntities = await _entityStore.GetEntities(entityShapes.Concat(undoneShapes).Concat(replyShapes).Select(a => a.EntityId).ToList());

            var undoneObjects = properEntities.Where(a => a.Data.Type.Contains("https://www.w3.org/ns/activitystreams#Undo")).Select(a => a.Data["object"].First().Id).ToList();

            var intactObjects = properEntities.Where(a => !undoneObjects.Contains(a.Id)).ToList();

            foreach (var obj in intactObjects)
            {
                var idToUse = obj.Data["actor"].Any() ? obj.Data["object"].First().Id : obj.Data["inReplyTo"].First().Id;
                if (!objects.ContainsKey(idToUse))
                {
                    continue;
                }

                var target = objects[idToUse];
                if (obj.Data.Type.Contains("https://www.w3.org/ns/activitystreams#Like"))
                {
                    target.Data["c2s:likes"].Add(ASTerm.MakeSubObject(obj.Data));
                }
                if (obj.Data.Type.Contains("https://www.w3.org/ns/activitystreams#Follow"))
                {
                    target.Data["c2s:follows"].Add(ASTerm.MakeSubObject(obj.Data));
                }
                if (obj.Data.Type.Contains("https://www.w3.org/ns/activitystreams#Announce"))
                {
                    target.Data["c2s:announces"].Add(ASTerm.MakeSubObject(obj.Data));
                }
                if (obj.Data.Type.Contains("https://www.w3.org/ns/activitystreams#Accept"))
                {
                    target.Data["c2s:accepts"].Add(ASTerm.MakeSubObject(obj.Data));
                }
                if (obj.Data.Type.Contains("https://www.w3.org/ns/activitystreams#Reject"))
                {
                    target.Data["c2s:rejects"].Add(ASTerm.MakeSubObject(obj.Data));
                }
                if (obj.Data["inReplyTo"].Any())
                {
                    target.Data["c2s:replies"].Add(ASTerm.MakeSubObject(obj.Data));
                }
            }
        }
Пример #25
0
        private ASObject _parseAuthor(XElement element)
        {
            var ao = new ASObject();

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

            // set preferredUsername and name
            {
                var atomName              = element.Element(Atom + "name")?.Value;
                var pocoDisplayName       = element.Element(PortableContacts + "displayName")?.Value;
                var pocoPreferredUsername = element.Element(PortableContacts + "preferredUsername")?.Value;

                ao.Replace("preferredUsername", ASTerm.MakePrimitive(pocoPreferredUsername ?? atomName));
                ao.Replace("name", ASTerm.MakePrimitive(pocoDisplayName ?? pocoPreferredUsername ?? atomName));
            }

            // set summary
            {
                var atomSummary = element.Element(Atom + "summary")?.Value;
                var pocoNote    = element.Element(PortableContacts + "note")?.Value;

                ao.Replace("summary", ASTerm.MakePrimitive(pocoNote ?? atomSummary));
            }

            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;

                    switch (rel)
                    {
                    case "avatar":
                        var avatarObject = new ASObject();
                        avatarObject.Type.Add("https://www.w3.org/ns/activitystreams#Image");
                        avatarObject.Replace("mediaType", ASTerm.MakePrimitive(type));
                        var width  = link.Attribute(AtomMedia + "width")?.Value;
                        var height = link.Attribute(AtomMedia + "height")?.Value;

                        if (width != null && height != null)
                        {
                            avatarObject.Replace("width", ASTerm.MakePrimitive(int.Parse(width)));
                            avatarObject.Replace("height", ASTerm.MakePrimitive(int.Parse(height)));
                        }

                        avatarObject.Replace("url", ASTerm.MakePrimitive(href));

                        ao["icon"].Add(ASTerm.MakeSubObject(avatarObject));
                        break;

                    case "alternate":
                        if (type == "text/html")
                        {
                            if (retrievalUrl == null)
                            {
                                retrievalUrl = href;
                            }

                            ao["atomUri"].Add(ASTerm.MakePrimitive(href));
                        }
                        break;

                    case "self":
                        if (type == "application/atom+xml")
                        {
                            retrievalUrl = href;
                        }
                        break;
                    }
                }
            }

            // should be Mastodon *and* GNU social compatible: Mastodon uses uri as id

            if (element.Element(Atom + "id") != null)
            {
                ao.Id = element.Element(Atom + "id")?.Value;
            }
            else
            {
                ao.Id = element.Element(Atom + "uri")?.Value;
            }

            if (element.Element(Atom + "uri") != null)
            {
                ao["url"].Add(ASTerm.MakePrimitive(element.Element(Atom + "uri")?.Value));
            }

            if (element.Element(Atom + "email") != null)
            {
                ao["email"].Add(ASTerm.MakePrimitive(element.Element(Atom + "email")?.Value));
            }

            foreach (var url in element.Elements(PortableContacts + "urls"))
            {
                ao["url"].Add(ASTerm.MakePrimitive(url.Element(PortableContacts + "value")?.Value));
            }

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

            return(ao);
        }
Пример #26
0
        public override async Task <bool> Handle()
        {
            if (MainObject.Type == "https://www.w3.org/ns/activitystreams#Follow")
            {
                if (Actor.Data["manuallyApprovesFollowers"].Any(a => !(bool)a.Primitive))
                {
                    var accept = new ASObject();
                    accept.Type.Add("https://www.w3.org/ns/activitystreams#Accept");
                    accept.Replace("actor", ASTerm.MakeId(Actor.Id));
                    accept.Replace("object", ASTerm.MakeId(MainObject.Id));
                    accept["to"].AddRange(MainObject.Data["actor"]);

                    var claims = new ClaimsPrincipal();
                    var id     = new ClaimsIdentity();
                    id.AddClaim(new Claim("actor", Actor.Id));
                    claims.AddIdentity(id);

                    var handler = ActivatorUtilities.CreateInstance <GetEntityHandler>(_serviceProvider, claims, EntityStore);
                    var outbox  = await EntityStore.GetEntity(Actor.Data["outbox"].First().Id, false);

                    await handler.ClientToServer(outbox, accept);
                }

                return(true);
            }

            if (MainObject.Type != "https://www.w3.org/ns/activitystreams#Like" && MainObject.Type != "https://www.w3.org/ns/activitystreams#Announce")
            {
                return(true);
            }

            var toFollowOrLike = await EntityStore.GetEntity(MainObject.Data["object"].Single().Id, false);

            if (toFollowOrLike == null)
            {
                await GetEntityTask.Make(MainObject.Data["object"].Single().Id, _connection);

                return(true);
            }

            // sent to not the owner, so not updating!
            if (toFollowOrLike.Data["attributedTo"].Single().Id != Actor.Id)
            {
                return(true);
            }

            string collectionId = null, objectToAdd = null;

            switch (MainObject.Type)
            {
            case "https://www.w3.org/ns/activitystreams#Like":
                collectionId = toFollowOrLike.Data["likes"].SingleOrDefault()?.Id;
                objectToAdd  = MainObject.Id;
                break;

            case "https://www.w3.org/ns/activitystreams#Announce":
                collectionId = toFollowOrLike.Data["shares"].SingleOrDefault()?.Id;
                objectToAdd  = MainObject.Id;
                break;
            }

            if (collectionId == null)
            {
                return(true);                      // no way to store followers/likse
            }
            var collection = await EntityStore.GetEntity(collectionId, false);

            var entityToAdd = await EntityStore.GetEntity(objectToAdd, true);

            if (entityToAdd == null)
            {
                throw new InvalidOperationException("Can't like or announce a non-existant object!");
            }

            await _collection.AddToCollection(collection, entityToAdd);

            return(true);
        }
Пример #27
0
 private static bool _isEqual(ASTerm a, ASTerm b)
 {
     return((a.Id == b.Id) || (a.Primitive.GetType() == b.Primitive.GetType() && (a.Primitive is string
                                                                                  ?(string)a.Primitive == (string)b.Primitive
                                                                                  : a.Primitive == b.Primitive)));
 }
Пример #28
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);
        }
Пример #29
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);
        }
Пример #30
0
        private APEntity _buildRaw(APTripleEntity mold, IEnumerable <Triple> triples, int rdfType, int rdfEnd)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            var subjects = triples.GroupBy(a => a.SubjectId).ToDictionary(a => a.Key, a => a);
            Dictionary <int, ASObject> objects = subjects.ToDictionary(a => a.Key, a => new ASObject {
                Id = _attributeMapping[a.Key]
            });
            var listEnds   = new HashSet <int>();
            var blankNodes = new Dictionary <int, Tuple <ASObject, string> >();
            var listParts  = triples.Where(a => a.PredicateId == rdfEnd).ToDictionary(a => a.AttributeId.Value, a => a.SubjectId);

            foreach (var obj in objects)
            {
                var result = obj.Value;

                if (result.Id.StartsWith("_:"))
                {
                    result.Id = null;
                }

                result.Type.AddRange(subjects[obj.Key].Where(a => a.PredicateId == rdfType).Select(a => _attributeMapping[a.AttributeId.Value]));

                foreach (var triple in subjects[obj.Key])
                {
                    if (triple.PredicateId == rdfType)
                    {
                        continue;
                    }

                    var term         = new ASTerm();
                    var predicateUrl = _attributeMapping[triple.PredicateId];

                    if (triple.AttributeId.HasValue && !listParts.ContainsValue(triple.AttributeId.Value) && objects.ContainsKey(triple.AttributeId.Value) && _attributeMapping[triple.AttributeId.Value].StartsWith("_:"))
                    {
                        term.SubObject = objects[triple.AttributeId.Value];
                    }
                    else
                    {
                        if (triple.TypeId.HasValue)
                        {
                            term.Type = _attributeMapping[triple.TypeId.Value];
                        }

                        if (triple.AttributeId.HasValue)
                        {
                            term.Id = _attributeMapping[triple.AttributeId.Value];
                        }

                        term.Primitive = _tripleToJson(triple.Object, term.Type);
                        if (_defaultTypes.Contains(term.Type))
                        {
                            term.Type = null;
                        }

                        if (predicateUrl == "rdf:rest")
                        {
                            if (term.Id == "rdf:nil")
                            {
                                listEnds.Add(triple.SubjectId);
                            }
                            listParts[triple.AttributeId.Value] = triple.SubjectId;
                        }

                        if (term.Id?.StartsWith("_:") == true)
                        {
                            blankNodes[triple.AttributeId.Value] = new Tuple <ASObject, string>(result, predicateUrl);
                        }
                    }


                    result[predicateUrl].Add(term);
                }
            }

            foreach (var listEnd in listEnds)
            {
                var listId = listEnd;
                var list   = new List <ASTerm>();
                list.Add(objects[listId]["rdf:first"].First());
                while (listParts.ContainsKey(listId))
                {
                    listId = listParts[listId];
                    list.Add(objects[listId]["rdf:first"].First());
                }

                if (blankNodes.ContainsKey(listId))
                {
                    blankNodes[listId].Deconstruct(out var obj, out var name);

                    list.Reverse();

                    obj[name].Clear();
                    obj[name].AddRange(list);
                }
            }

            var mainObj = objects[mold.IdId];

            stopwatch.Stop();
            _logger.LogWarning("Molding {id} from cache took {time}", mainObj.Id, stopwatch.Elapsed);
            return(new APEntity {
                Data = mainObj, Id = mainObj.Id, Updated = mold.Updated, IsOwner = mold.IsOwner, Type = mold.Type, DbId = mold.EntityId
            });
        }