OpenIddict 7.7 (MongoDB stores, keys kept in Mongo so tokens survive
restarts) serves /oauth/authorize, /oauth/token, /oauth/revoke and the
discovery documents, including /.well-known/oauth-authorization-server:
- authorization code (PKCE optional) and client credentials, Mastodon's
scopes including the granular ones, non-expiring reference tokens,
`created_at` in the token response, and the urn:ietf:wg:oauth:2.0:oob
page that shows the code;
- /oauth/login signs the private login into a fifteen-minute cookie that
only /oauth sees (rate limited, antiforgery-protected); /oauth/authorize
then asks which persona the application acts as. The token's subject
is that persona's id and nothing else; no root id reaches a token, an
authorization or a log line;
- the token exchange refuses a persona whose login is banned or deleted,
and every API request checks the same.
/api/v1/apps registers applications dynamically, /api/v1/apps/
verify_credentials, /api/v1/instance (v1 and v2, "4.2.0 (compatible;
PrivaPub)") and verify_credentials answer in Mastodon's shapes: snake_case
with explicit nulls, Rails-style parameters from query, form or JSON,
{"error": ...} on failure, Link paging. CORS exposes Link.
/api goes to OpenIddict validation and everything else to the existing
JWT; the JWT failure handler no longer sends the exception and stack trace
to the client.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012CzABvBkbcFqoHdmi8b9WB
201 lines
6.0 KiB
C#
201 lines
6.0 KiB
C#
namespace PrivaPub.Api.Mastodon.Entities
|
|
{
|
|
public class Account
|
|
{
|
|
public string Id { get; set; }
|
|
public string Username { get; set; }
|
|
public string Acct { get; set; }
|
|
public string DisplayName { get; set; }
|
|
public bool Locked { get; set; }
|
|
public bool Bot { get; set; }
|
|
public bool? Discoverable { get; set; }
|
|
public bool Indexable { get; set; }
|
|
public bool Group { get; set; }
|
|
public string CreatedAt { get; set; }
|
|
public string Note { get; set; }
|
|
public string Url { get; set; }
|
|
public string Uri { get; set; }
|
|
public string Avatar { get; set; }
|
|
public string AvatarStatic { get; set; }
|
|
public string Header { get; set; }
|
|
public string HeaderStatic { get; set; }
|
|
public int FollowersCount { get; set; }
|
|
public int FollowingCount { get; set; }
|
|
public int StatusesCount { get; set; }
|
|
public string LastStatusAt { get; set; }
|
|
public bool? HideCollections { get; set; }
|
|
public bool Noindex { get; set; } = true;
|
|
public List<object> Emojis { get; set; } = new();
|
|
public List<object> Roles { get; set; } = new();
|
|
public List<Field> Fields { get; set; } = new();
|
|
public Source Source { get; set; }
|
|
}
|
|
|
|
public class Field
|
|
{
|
|
public string Name { get; set; }
|
|
public string Value { get; set; }
|
|
public string VerifiedAt { get; set; }
|
|
}
|
|
|
|
public class Source
|
|
{
|
|
public string Privacy { get; set; } = "public";
|
|
public bool Sensitive { get; set; }
|
|
public string Language { get; set; }
|
|
public string Note { get; set; } = string.Empty;
|
|
public List<Field> Fields { get; set; } = new();
|
|
public int FollowRequestsCount { get; set; }
|
|
public string AttributionDomains { get; set; }
|
|
}
|
|
|
|
public class Status
|
|
{
|
|
public string Id { get; set; }
|
|
public string Uri { get; set; }
|
|
public string Url { get; set; }
|
|
public Account Account { get; set; }
|
|
public string InReplyToId { get; set; }
|
|
public string InReplyToAccountId { get; set; }
|
|
public Status Reblog { get; set; }
|
|
public string Content { get; set; } = string.Empty;
|
|
public string CreatedAt { get; set; }
|
|
public string EditedAt { get; set; }
|
|
public List<object> Emojis { get; set; } = new();
|
|
public int RepliesCount { get; set; }
|
|
public int ReblogsCount { get; set; }
|
|
public int FavouritesCount { get; set; }
|
|
public bool Reblogged { get; set; }
|
|
public bool Favourited { get; set; }
|
|
public bool Muted { get; set; }
|
|
public bool Bookmarked { get; set; }
|
|
public bool Pinned { get; set; }
|
|
public bool Sensitive { get; set; }
|
|
public string SpoilerText { get; set; } = string.Empty;
|
|
public string Visibility { get; set; }
|
|
public List<MediaAttachment> MediaAttachments { get; set; } = new();
|
|
public List<StatusMention> Mentions { get; set; } = new();
|
|
public List<StatusTag> Tags { get; set; } = new();
|
|
public object Card { get; set; }
|
|
public object Poll { get; set; }
|
|
public Application Application { get; set; }
|
|
public string Language { get; set; }
|
|
public string Text { get; set; }
|
|
public List<object> Filtered { get; set; } = new();
|
|
}
|
|
|
|
public class MediaAttachment
|
|
{
|
|
public string Id { get; set; }
|
|
public string Type { get; set; }
|
|
public string Url { get; set; }
|
|
public string PreviewUrl { get; set; }
|
|
public string RemoteUrl { get; set; }
|
|
public object Meta { get; set; }
|
|
public string Description { get; set; }
|
|
public string Blurhash { get; set; }
|
|
}
|
|
|
|
public class StatusMention
|
|
{
|
|
public string Id { get; set; }
|
|
public string Username { get; set; }
|
|
public string Url { get; set; }
|
|
public string Acct { get; set; }
|
|
}
|
|
|
|
public class StatusTag
|
|
{
|
|
public string Name { get; set; }
|
|
public string Url { get; set; }
|
|
}
|
|
|
|
public class Application
|
|
{
|
|
public string Id { get; set; }
|
|
public string Name { get; set; }
|
|
public string Website { get; set; }
|
|
public List<string> Scopes { get; set; } = new();
|
|
public List<string> RedirectUris { get; set; } = new();
|
|
public string RedirectUri { get; set; }
|
|
public string ClientId { get; set; }
|
|
public string ClientSecret { get; set; }
|
|
public string VapidKey { get; set; } = string.Empty;
|
|
}
|
|
|
|
public class Relationship
|
|
{
|
|
public string Id { get; set; }
|
|
public bool Following { get; set; }
|
|
public bool ShowingReblogs { get; set; }
|
|
public bool Notifying { get; set; }
|
|
public List<string> Languages { get; set; }
|
|
public bool FollowedBy { get; set; }
|
|
public bool Blocking { get; set; }
|
|
public bool BlockedBy { get; set; }
|
|
public bool Muting { get; set; }
|
|
public bool MutingNotifications { get; set; }
|
|
public bool Requested { get; set; }
|
|
public bool RequestedBy { get; set; }
|
|
public bool DomainBlocking { get; set; }
|
|
public bool Endorsed { get; set; }
|
|
public string Note { get; set; } = string.Empty;
|
|
}
|
|
|
|
public class Notification
|
|
{
|
|
public string Id { get; set; }
|
|
public string Type { get; set; }
|
|
public string CreatedAt { get; set; }
|
|
public string GroupKey { get; set; }
|
|
public Account Account { get; set; }
|
|
public Status Status { get; set; }
|
|
}
|
|
|
|
public class Context
|
|
{
|
|
public List<Status> Ancestors { get; set; } = new();
|
|
public List<Status> Descendants { get; set; } = new();
|
|
}
|
|
|
|
public class StatusEdit
|
|
{
|
|
public string Content { get; set; }
|
|
public string SpoilerText { get; set; }
|
|
public bool Sensitive { get; set; }
|
|
public string CreatedAt { get; set; }
|
|
public Account Account { get; set; }
|
|
public List<MediaAttachment> MediaAttachments { get; set; } = new();
|
|
public List<object> Emojis { get; set; } = new();
|
|
}
|
|
|
|
public class StatusSource
|
|
{
|
|
public string Id { get; set; }
|
|
public string Text { get; set; }
|
|
public string SpoilerText { get; set; }
|
|
}
|
|
|
|
public class SearchResults
|
|
{
|
|
public List<Account> Accounts { get; set; } = new();
|
|
public List<Status> Statuses { get; set; } = new();
|
|
public List<object> Hashtags { get; set; } = new();
|
|
}
|
|
|
|
public class Conversation
|
|
{
|
|
public string Id { get; set; }
|
|
public bool Unread { get; set; }
|
|
public List<Account> Accounts { get; set; } = new();
|
|
public Status LastStatus { get; set; }
|
|
}
|
|
|
|
public class Marker
|
|
{
|
|
public string LastReadId { get; set; }
|
|
public int Version { get; set; }
|
|
public string UpdatedAt { get; set; }
|
|
}
|
|
}
|