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); }
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); }
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))); }
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); }
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); }
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); }
private string _getId(ASTerm term) { if (term.Primitive != null) { return((string)term.Primitive); } return(term.SubObject.Id); }
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); }
private string _getId(ASTerm term) { if (term.Primitive != null) { return((string)term.Primitive); } return((string)term.SubObject["id"].Single().Primitive); }
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)); }
private async Task <ASObject> _get(ASTerm id) { if (id.Primitive != null) { return((await _entityStore.GetEntity((string)id.Primitive, false)).Data); } return(id.SubObject); }
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)); } }
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); }
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); } }
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); }
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))); }
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); }
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); }
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); }
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\"")); }
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); }
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); }
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)); } } }
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); }
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); }
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))); }
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); }
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); }
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 }); }