Exemple #1
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));
        }
Exemple #2
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);
        }
Exemple #3
0
        public async Task <IActionResult> GetKey(string id)
        {
            var user = await _entityStore.GetEntity(id, false);

            if (user == null || !user.IsOwner)
            {
                return(NotFound());
            }

            var key = await _context.GetKey(user.Id);

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

            var keyObj = new ASObject();

            keyObj.Replace("owner", new ASTerm(user.Id));
            keyObj.Replace("publicKeyPem", new ASTerm(data));
            keyObj.Replace("id", new ASTerm($"{Request.Scheme}://{Request.Host}{Request.Path}{Request.QueryString}"));
            return(Content(keyObj.Serialize().ToString(), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""));
        }
Exemple #4
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);
        }
Exemple #5
0
        private async Task <APEntity> _newCollection(string type, string attributedTo)
        {
            var obj = new ASObject();

            obj["type"].Add(new ASTerm("OrderedCollection"));
            obj["attributedTo"].Add(new ASTerm(attributedTo));
            obj.Replace("id", new ASTerm(await _entityData.FindUnusedID(_entityStore, obj, type, attributedTo)));
            var entity = APEntity.From(obj, true);

            entity.Type = "_" + type;
            entity      = await _entityStore.StoreEntity(entity);

            await _entityStore.CommitChanges();

            return(entity);
        }
Exemple #6
0
        public static APEntity From(string id, ASObject @object)
        {
            var type = (string)@object["type"].FirstOrDefault()?.Primitive;

            if (type?.StartsWith("_") != false)
            {
                type = "Unknown";
            }

            @object.Replace("id", new ASTerm(id));

            return(new APEntity
            {
                Id = id,
                Data = @object,
                Type = type
            });
        }
Exemple #7
0
        private ASObject _getEndpoints(APEntity entity)
        {
            var data = entity.Data;
            var idu  = new Uri(entity.Id);

            var basePath = $"{idu.Scheme}://{idu.Host}{_configuration.BasePath}";

            var endpoints = new ASObject();

            endpoints.Replace("oauthAuthorizationEndpoint", new ASTerm(basePath + "auth/oauth?id=" + Uri.EscapeDataString(entity.Id)));
            endpoints.Replace("oauthTokenEndpoint", new ASTerm(basePath + "auth/token?"));
            endpoints.Replace("settingsEndpoint", new ASTerm(basePath + "settings/auth"));
            endpoints.Replace("uploadMedia", new ASTerm((string)data["outbox"].Single().Primitive));
            endpoints.Replace("relevantObjects", new ASTerm(basePath + "settings/relevant"));
            endpoints.Replace("proxyUrl", new ASTerm(basePath + "auth/proxy"));
            endpoints.Replace("jwks", new ASTerm(basePath + "auth/jwks?id=" + Uri.EscapeDataString(entity.Id)));
            endpoints.Replace("id", new ASTerm((string)null));

            data.Replace("endpoints", new ASTerm(endpoints));
            data.Replace("publicKey", new ASTerm(basePath + "auth/key?id=" + Uri.EscapeDataString(entity.Id)));
            return(data);
        }
Exemple #8
0
        public override async Task <bool> Handle()
        {
            if (MainObject.Type == "Follow")
            {
                if (Actor.Data["_:locked"].Any(a => !(bool)a.Primitive) || Actor.Data["locked"].Any(a => !(bool)a.Primitive))
                {
                    var accept = new ASObject();
                    accept.Replace("type", new ASTerm("Accept"));
                    accept.Replace("actor", new ASTerm(Actor.Id));
                    accept.Replace("object", new ASTerm(MainObject.Id));

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

                    await handler.ClientToServer(outbox, accept);
                }

                return(true);
            }

            if (MainObject.Type != "Like" && MainObject.Type != "Announce")
            {
                return(true);
            }

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

            if (toFollowOrLike == null || !toFollowOrLike.IsOwner)
            {
                return(true);                                                   // not going to update side effects now.
            }
            // sent to not the owner, so not updating!
            if ((string)toFollowOrLike.Data["attributedTo"].Single().Primitive != Actor.Id)
            {
                return(true);
            }

            string collectionId = null, objectToAdd = null;

            switch (MainObject.Type)
            {
            case "Like":
                collectionId = (string)toFollowOrLike.Data["likes"].SingleOrDefault()?.Primitive;
                objectToAdd  = MainObject.Id;
                break;

            case "Announce":
                collectionId = (string)toFollowOrLike.Data["shares"].SingleOrDefault()?.Primitive;
                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);
        }
Exemple #9
0
        public async Task <APEntity> GetEntity(string id, bool doRemote)
        {
            if (id == "https://www.w3.org/ns/activitystreams#Public")
            {
                var aso = new ASObject();
                aso.Replace("type", new ASTerm("Collection"));
                aso.Replace("id", new ASTerm("https://www.w3.org/ns/activitystreams#Public"));

                var ent = APEntity.From(aso);
                return(ent);
            }

            APEntity entity = null;

            if (Next != null)
            {
                entity = await Next.GetEntity(id, doRemote);
            }

            if (entity?.Type == "_:LazyLoad" && !doRemote)
            {
                return(null);
            }
            if ((entity != null && entity.Type != "_:LazyLoad") || !doRemote)
            {
                return(entity);
            }

            var loadUrl = id;

            if (entity?.Type == "_:LazyLoad")
            {
                loadUrl = (string)entity.Data["href"].First().Primitive;
            }

            if (loadUrl.StartsWith("tag:"))
            {
                return(null);
            }

            var htc = new HttpClient();

            htc.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\", application/activity+json, application/json, application/atom+xml, text/html");

            if (_context != null)
            {
                var deliveryService = _serviceProvider.GetRequiredService <DeliveryService>();
                var user            = await Next.GetEntity(_context.User.FindFirstValue(JwtTokenSettings.ActorClaim), false);

                if (user != null)
                {
                    var jwt = await deliveryService.BuildFederatedJWS(user, id);

                    htc.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", jwt);
                }
            }

            var response = await htc.GetAsync(loadUrl);

            if (!response.IsSuccessStatusCode)
            {
                response = await htc.GetAsync(loadUrl + ".atom"); // hack!

                if (!response.IsSuccessStatusCode)
                {
                    return(null);
                }
            }
            var converters = new List <IConverterFactory> {
                new AS2ConverterFactory(), new AtomConverterFactory(false)
            };

tryAgain:
            ASObject data = null;

            foreach (var converter in converters)
            {
                if (converter.CanParse && ConverterHelpers.GetBestMatch(converter.MimeTypes, response.Content.Headers.ContentType.ToString()) != null)
                {
                    data = await converter.Build(_serviceProvider, null).Parse(await response.Content.ReadAsStreamAsync());

                    break;
                }
            }

            if (data == null)
            {
                if (response.Headers.Contains("Link"))
                {
                    var split = string.Join(", ", response.Headers.GetValues("Link")).Split(new[] { ", " }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (var spl in split)
                    {
                        var args = spl.Split(';').Select(a => a.Trim()).ToArray();
                        if (args.Contains("rel=\"alternate\"") && args.Contains("type=\"application/atom+xml\""))
                        {
                            response = await htc.GetAsync(args[0].Substring(1, args[0].Length - 2));

                            goto tryAgain;
                        }
                    }
                }

                try
                {
                    var links = (await response.Content.ReadAsStringAsync()).Split('\n');
                    var alt   = links.FirstOrDefault(a => a.Contains("application/atom+xml") && a.Contains("alternate"));
                    if (alt == null)
                    {
                        return(null);
                    }
                    var l = XDocument.Parse(alt + "</link>").Root;
                    if (l.Attribute(XNamespace.None + "type")?.Value == "application/atom+xml")
                    {
                        response = await htc.GetAsync(l.Attribute(XNamespace.None + "href")?.Value);

                        goto tryAgain;
                    }
                }
                catch (Exception) { }

                return(null);
            }

            // forces out the old lazy load, if used
            await _entityFlattener.FlattenAndStore(Next, data, false);

            await Next.CommitChanges();

            return(await Next.GetEntity(id, true));
        }
        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);
        }
Exemple #11
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);
        }
Exemple #12
0
        private async Task <ASObject> _parseFeed(XElement element, string targetUser)
        {
            var ao = new ASObject();

            ao.Type.Add("https://www.w3.org/ns/activitystreams#OrderedCollectionPage");
            ao.Replace("_:origin", ASTerm.MakePrimitive("atom"));
            ao.Id = element.Element(Atom + "id").Value;

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

            var author = _parseAuthor(element.Element(Atom + "author"));

            ao.Replace("attributedTo", ASTerm.MakeSubObject(author));

            var authorId = author.Id;

            foreach (var entry in element.Elements(Atom + "entry"))
            {
                ao["orderedItems"].Add(await _parseActivity(entry, authorId, targetUser));
            }


            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 == "alternate" && type == "text/html")
                {
                    ao["url"].Add(ASTerm.MakePrimitive(href));
                }
                else if (rel == "self" && type == "application/atom+xml")
                {
                    author.Replace("atomUri", ASTerm.MakePrimitive(href));
                }
                else
                {
                    switch (rel)
                    {
                    case "salmon":
                        ao["_:salmonUrl"].Add(ASTerm.MakePrimitive(href));
                        break;

                    case "hub":
                        ao["_:hubUrl"].Add(ASTerm.MakePrimitive(href));
                        break;

                    case "prev":
                        ao["prev"].Add(ASTerm.MakeId(href));
                        break;

                    case "next":
                        ao["next"].Add(ASTerm.MakeId(href));
                        break;
                    }
                }
            }

            author["_:salmonUrl"].AddRange(ao["_:salmonUrl"]);
            author["_:hubUrl"].AddRange(ao["_:hubUrl"]);

            return(ao);
        }
Exemple #13
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));
        }
Exemple #14
0
        private async Task <ASTerm> _parseActivityObject(XElement element, string authorId, string targetUser, bool isActivity = false)
        {
            if (!isActivity && element.Element(ActivityStreams + "verb") != null)
            {
                return(await _parseActivity(element, authorId, targetUser));
            }
            var entity = await _entityStore.GetEntity(element.Element(Atom + "id")?.Value, true);

            if (entity != null)
            {
                if (entity.Type.Contains("https://www.w3.org/ns/activitystreams#Create"))
                {
                    return(ASTerm.MakeId(entity.Data["object"].First().Id));
                }

                return(ASTerm.MakeId(element.Element(Atom + "id")?.Value));
            }

            var ao = new ASObject();

            ao.Id = element.Element(Atom + "id")?.Value + (isActivity ? "#object" : "");
            ao.Replace("kroeg:origin", ASTerm.MakePrimitive("atom"));

            var objectType = _objectTypeToType(element.Element(ActivityStreams + "object-type")?.Value);

            if (objectType == "https://www.w3.org/ns/activitystreams#Person")
            {
                return(ASTerm.MakeSubObject(_parseAuthor(element)));
            }

            ao.Type.Add(objectType);
            ao.Replace("attributedTo", ASTerm.MakeId(authorId));


            if (element.Element(Atom + "summary") != null)
            {
                ao.Replace("summary", ASTerm.MakePrimitive(element.Element(Atom + "summary")?.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));
            }

            ao.Replace("content", ASTerm.MakePrimitive(element.Element(Atom + "content")?.Value));
            var mediaType = element.Element(Atom + "content")?.Attribute(NoNamespace + "type")?.Value;

            if (mediaType != null)
            {
                if (mediaType == "text")
                {
                    mediaType = "text/plain";
                }
                if (mediaType.Contains("/"))
                {
                    ao.Replace("mediaType", ASTerm.MakePrimitive(mediaType));
                }
            }

            if (element.Element(OStatus + "conversation") != null)
            {
                ao.Replace("conversation", ASTerm.MakePrimitive(element.Element(OStatus + "conversation").Attribute(NoNamespace + "ref")?.Value ?? element.Element(OStatus + "conversation").Value));
            }

            if (element.Element(AtomThreading + "in-reply-to") != null)
            {
                var elm  = element.Element(AtomThreading + "in-reply-to");
                var @ref = await _findInReplyTo(elm.Attribute(NoNamespace + "ref").Value);

                var hrel = elm.Attribute(NoNamespace + "href")?.Value;

                if (hrel == null)
                {
                    ao.Replace("inReplyTo", ASTerm.MakeId(@ref));
                }
                else if (await _entityStore.GetEntity(@ref, false) != null)
                {
                    ao.Replace("inReplyTo", ASTerm.MakeId(@ref));
                }
                else
                {
                    var lazyLoad = new ASObject();
                    lazyLoad.Id = @ref;
                    lazyLoad.Type.Add("_:LazyLoad");
                    lazyLoad.Replace("href", ASTerm.MakePrimitive(hrel));
                    ao.Replace("inReplyTo", ASTerm.MakeSubObject(lazyLoad));
                }
            }

            foreach (var tag in element.Elements(Atom + "category"))
            {
                var val = tag.Attribute(NoNamespace + "term").Value;

                var tagao = new ASObject();
                tagao.Id = $"{_entityConfiguration.BaseUri}/tag/{val}";
                tagao["name"].Add(ASTerm.MakePrimitive("#" + val));
                tagao.Type.Add("Hashtag");

                ao["tag"].Add(ASTerm.MakeSubObject(tagao));
            }

            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));
                }
                else if (rel == "enclosure")
                {
                    // image
                    var subAo = new ASObject();
                    subAo["url"].Add(ASTerm.MakePrimitive(href));
                    subAo["mediaType"].Add(ASTerm.MakePrimitive(type));

                    switch (type.Split('/')[0])
                    {
                    case "image":
                        subAo.Type.Add("https://www.w3.org/ns/activitystreams#Image");
                        break;

                    case "video":
                        subAo.Type.Add("https://www.w3.org/ns/activitystreams#Video");
                        break;

                    default:
                        continue;
                    }

                    if (link.Attribute(NoNamespace + "length") != null)
                    {
                        subAo["fileSize"].Add(ASTerm.MakePrimitive(int.Parse(link.Attribute(NoNamespace + "length").Value)));
                    }

                    ao["attachment"].Add(ASTerm.MakeSubObject(subAo));
                }
            }

            return(ASTerm.MakeSubObject(ao));
        }