FEP-521a and FEP-8b32. Every persona has an Ed25519 key of its own (Avatar.SigningKey; migration 014 gives the earlier ones theirs), named in its actor's assertionMethod as a Multikey, the terms defined in the actor's own context. A persona's activity going to a relay carries an eddsa-jcs-2022 proof (JSON canonicalised by RFC 8785, Jcs), so what Activity-Relay forwards reaches Mastodon, which verifies it with its own code. Nothing else carries one: Mitra takes a proof over the HTTP signature and refuses one by a key it has not read, without reading the actor again. Received: an actor's own Multikeys are kept, and a forwarded activity whose proof one of them verifies is taken as it came instead of being read again from its origin. Discovery: WebFinger for the server's origin links its instance actor (FEP-d556), NodeInfo links it as the application actor (FEP-2677), and actors name RFC 9421 under implements (FEP-844e). Checked live: relay 16 (Activity-Relay's forward of alice's post reaches Mastodon), Mitra, GoToSocial and Mastodon unchanged (165 in all). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
170 lines
6.3 KiB
C#
170 lines
6.3 KiB
C#
using MongoDB.Entities;
|
|
|
|
using PrivaPub.Infrastructure.Ids;
|
|
|
|
namespace PrivaPub.Models.User
|
|
{
|
|
public class Avatar : Entity
|
|
{
|
|
public string Url { get; set; }//url
|
|
public string Name { get; set; }//name
|
|
public string UserName { get; set; }//preferredUsername
|
|
public string Biography { get; set; }//summary
|
|
|
|
public Dictionary<string, string> SharedPersonalContacts { get; set; } = new();
|
|
public string PrivateKey { get; set; }
|
|
public string PublicKey { get; set; }
|
|
public string SigningKey { get; set; }//the seed of its Ed25519 key (FEP-521a), which signs its activities' proofs (FEP-8b32)
|
|
public AvatarAccountState AccountState { get; set; } = AvatarAccountState.Normal;
|
|
public AvatarSettings Settings { get; set; } = new();
|
|
public Dictionary<string, string> Fields { get; set; } = new();
|
|
|
|
public string Domain { get; set; }
|
|
public string PersonalNote { get; set; }
|
|
public string ModerationNote { get; set; }
|
|
|
|
public string InboxURL { get; set; }
|
|
public string OutboxURL { get; set; }
|
|
public string MovedToURL { get; set; }
|
|
public string PictureURL { get; set; }//icon
|
|
public string ThumbnailURL { get; set; }//image
|
|
public AvatarType AvatarType { get; set; } = AvatarType.Person;
|
|
public AvatarServer AvatarServer { get; set; } = AvatarServer.PrivaPub;
|
|
|
|
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
|
public DateTime PublishedOn { get; set; } = PrivacyIds.PublishedDay(DateTime.UtcNow);//the actor's published: a few days before CreatedAt, so same-day personas differ
|
|
public DateTime? SilencedAt { get; set; }
|
|
public DateTime? SuspendedAt { get; set; }
|
|
public DateTime? BannedAt { get; set; }
|
|
public DateTime? DeletionAt { get; set; }
|
|
|
|
public override object GenerateNewID() => PrivacyIds.ForDay(PublishedOn);
|
|
}
|
|
|
|
public class ForeignAvatar : Entity
|
|
{
|
|
public string Url { get; set; }//url
|
|
public string Name { get; set; }//name
|
|
public string UserName { get; set; }//preferredUsername
|
|
public string Biography { get; set; }//summary
|
|
|
|
public Dictionary<string, string> SharedPersonalContacts { get; set; } = new();
|
|
public string PrivateKey { get; set; }
|
|
public string PublicKey { get; set; }
|
|
public AvatarAccountState AccountState { get; set; } = AvatarAccountState.Normal;
|
|
public AvatarSettings Settings { get; set; } = new();
|
|
public Dictionary<string, string> Fields { get; set; } = new();
|
|
|
|
public string Domain { get; set; }
|
|
public string PersonalNote { get; set; }
|
|
public string ModerationNote { get; set; }
|
|
public bool IsDiscoverable { get; set; } = true;
|
|
public bool IsIndexable { get; set; }
|
|
public bool IsLocked { get; set; }//manuallyApprovesFollowers
|
|
public bool IsMemorial { get; set; }
|
|
public List<PrivaPub.Models.Post.CustomEmoji> Emojis { get; set; } = new();
|
|
public string PictureDescription { get; set; }
|
|
public string HeaderDescription { get; set; }
|
|
public DateTime? Published { get; set; }//the actor's own published
|
|
public List<string> Features { get; set; }//protocol extensions its document uses, for statistics (ActorFeatures)
|
|
|
|
public string ActorURI { get; set; }//id
|
|
public string PublicKeyId { get; set; }
|
|
public string FollowersURL { get; set; }
|
|
public string FollowingURL { get; set; }
|
|
public string SharedInboxURL { get; set; }
|
|
public string InboxURL { get; set; }
|
|
public string OutboxURL { get; set; }
|
|
public string FeaturedURL { get; set; }//featured: the posts it pins
|
|
public List<AssertionKey> AssertionKeys { get; set; } = new();//its Ed25519 keys (FEP-521a), which prove what it sends (FEP-8b32)
|
|
public string WallURL { get; set; }//sm:wall (FEP-400e): where others write to it, Smithereen's walls
|
|
public string MovedToURL { get; set; }
|
|
public List<string> AlsoKnownAs { get; set; } = new();//alsoKnownAs: the accounts it says it also is
|
|
public string PictureURL { get; set; }//icon
|
|
public string ThumbnailURL { get; set; }//image
|
|
public AvatarType AvatarType { get; set; } = AvatarType.Person;
|
|
public AvatarServer AvatarServer { get; set; } = AvatarServer.Unknown;
|
|
|
|
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
|
public DateTime? SilencedAt { get; set; }
|
|
public DateTime? SuspendedAt { get; set; }
|
|
public DateTime? BannedAt { get; set; }
|
|
public DateTime? DeletionAt { get; set; }
|
|
public DateTime? ForgottenAt { get; set; }//its likes, votes, boosts and replies were taken out of our counts (GoneActors)
|
|
public int? FollowersCount { get; set; }//its own collections' totalItems, read at most daily (AccountCountsJob)
|
|
public int? FollowingCount { get; set; }
|
|
public int? StatusesCount { get; set; }
|
|
public DateTime? CountedAt { get; set; }
|
|
}
|
|
|
|
public class AvatarSettings
|
|
{
|
|
public string LanguageCode { get; set; } = "en-GB";
|
|
|
|
public bool IsDefault { get; set; } = true;
|
|
|
|
public short IconsThemeIndexColour { get; set; } = 25;
|
|
public short LightThemeIndexColour { get; set; } = 25;
|
|
public short DarkThemeIndexColour { get; set; } = 215;
|
|
public bool PreferSystemTheming { get; set; } = true;
|
|
public bool ThemeIsDarkMode { get; set; } = false;
|
|
public bool ThemeIsDarkGray { get; set; } = false;
|
|
public bool ThemeIsLightGray { get; set; } = true;
|
|
|
|
public bool IsLocked { get; set; }
|
|
public bool IsBot { get; set; }
|
|
public bool IsDiscoverable { get; set; } = true;
|
|
public bool IsIndexable { get; set; }
|
|
public bool HideCollections { get; set; } = true;
|
|
public string DefaultVisibility { get; set; } = "public";
|
|
public bool DefaultSensitive { get; set; }
|
|
public string DefaultLanguage { get; set; }
|
|
public string QuotePolicy { get; set; } = QuotePolicies.Public;//owner decision: anyone may quote a public post, automatically
|
|
}
|
|
|
|
public static class QuotePolicies
|
|
{
|
|
public const string Public = "public";
|
|
public const string Followers = "followers";
|
|
public const string Nobody = "nobody";
|
|
|
|
public static bool IsKnown(string value) => value is Public or Followers or Nobody;
|
|
}
|
|
|
|
public enum AvatarServer
|
|
{
|
|
Unknown,
|
|
Pleroma,
|
|
Mastodon,
|
|
Akkoma,
|
|
Misskey,
|
|
PrivaPub
|
|
}
|
|
|
|
public enum AvatarType
|
|
{
|
|
Application,
|
|
Group,
|
|
Organization,
|
|
Person,
|
|
Service
|
|
}
|
|
|
|
public enum AvatarAccountState
|
|
{
|
|
Normal,
|
|
Silenced,
|
|
Suspended,
|
|
Banned,
|
|
Deleted
|
|
}
|
|
|
|
public class AssertionKey
|
|
{
|
|
public string Id { get; set; }
|
|
public string PublicKey { get; set; }//the raw Ed25519 key, base64
|
|
}
|
|
}
|