net10, the refactor finished, and federation that works
The tree had not compiled since its first commit: Group, DmGroup and
IGroupUsersService were referenced and never written, an IDE rename had
turned the user-settings DTO into the ViewAvatarServer enum, and the settings
were saved as an entity they no longer were.
Built now:
- Group (an ActivityPub Group actor with its own keys, members, invitation
code and optional password) and DmGroup (a conversation), with
/clientapi/group/{list,insert,update,join,leave,approve}.
- Posts and DMs: /clientapi/post/{list,insert,delete}, /clientapi/dm/{list,insert};
DM recipients are local usernames or user@host handles resolved by WebFinger.
- Invitation sign-up and login against the group's invitation code, checking
the password before any account is created.
- Federation: WebFinger, NodeInfo 2.0, actors at /peasants/{name} (Person,
Group, and an Application instance actor) with SPKI keys, draft-cavage
RSA-SHA256 HTTP signatures both ways, an inbox handling Follow (+Accept),
Undo, Create, Delete and Update, an outbox, notes at /posts/{id}, and a
persisted, retried, signed delivery queue. A post to a group is announced
by the group to its followers (FEP-1b12).
- The unused, broken typed ActivityPub models are replaced by a renderer;
NSign's HMAC setup, which could not federate, is gone.
Upgrade: net10.0, MongoDB.Entities 25.1 (instance DB API, Standard GUIDs),
Swashbuckle 10 / OpenApi 2, Serilog.AspNetCore 10, MailKit 4.18,
PasswordGenerator 3. The JWT keys are 64 bytes (IdentityModel 8 refuses
shorter for HS512). Production runs its own mongod on 127.0.0.1:27022, as
Sintopia's apps do, and deploys to privapub.thepra.dev from the build runner.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012CzABvBkbcFqoHdmi8b9WB
This commit is contained in:
1 parent
56c5396106
commit
075c22228a
78 files changed
+3419
-1091
No files matched your search
@@ -1,4 +1,4 @@
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.ResponseCompression;
|
||||
|
||||
using PrivaPub.ClientModels;
|
||||
@@ -8,13 +8,10 @@ using PrivaPub.Services;
|
||||
using PrivaPub.StaticServices;
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using NSign.Providers;
|
||||
using NSign;
|
||||
using NSign.Signatures;
|
||||
using NSign.Client;
|
||||
using System.Text;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Microsoft.OpenApi;
|
||||
using PrivaPub.Services.ClientToServer.Private;
|
||||
using PrivaPub.Services.ClientToServer.Public;
|
||||
using PrivaPub.Services.Federation;
|
||||
|
||||
namespace PrivaPub.Middleware
|
||||
{
|
||||
@@ -33,74 +30,19 @@ namespace PrivaPub.Middleware
|
||||
//.AddHostedService<GroupsCleanerWorker>()
|
||||
//.AddHostedService<PoliciesCleanerWorker>();
|
||||
}
|
||||
public static IServiceCollection PrivaPubHTTPSignature(this IServiceCollection service, IConfiguration configuration)
|
||||
public static IServiceCollection PrivaPubFederationConfiguration(this IServiceCollection service)
|
||||
{
|
||||
//HTTP CLIENT
|
||||
service.Configure<AddDigestOptions>(options => options.WithHash(AddDigestOptions.Hash.Sha256))
|
||||
.ConfigureMessageSigningOptions(options =>
|
||||
{
|
||||
options.SignatureName = "PrivaPub";
|
||||
options
|
||||
.WithMandatoryComponent(SignatureComponent.Path)
|
||||
.WithMandatoryComponent(SignatureComponent.RequestTarget)
|
||||
.SetParameters = signatureParams => signatureParams.WithKeyId("keyId");
|
||||
})
|
||||
.Services.Configure<SignatureVerificationOptions>(options =>
|
||||
{
|
||||
|
||||
})
|
||||
.AddHttpClient<ActivityPubClient>(nameof(ActivityPubClient))
|
||||
.ConfigureHttpClient(httpClient =>
|
||||
{
|
||||
httpClient.DefaultRequestHeaders.Accept.Add(new("application/ld+json"));
|
||||
})
|
||||
.AddDigestAndSigningHandlers()
|
||||
//.AddSignatureVerifiationHandler()
|
||||
.Services
|
||||
.AddSingleton<ISigner>(new HmacSha256SignatureProvider(Encoding.UTF8.GetBytes(configuration["AppConfiguration:Jwt:Key"])));
|
||||
|
||||
//MESSAGE RESPONSE
|
||||
|
||||
|
||||
return service;
|
||||
//.Configure<RequestSignatureVerificationOptions>(options =>
|
||||
//{
|
||||
// options.SignaturesToVerify.Add("sample");
|
||||
// options.RequiredSignatureComponents.Add(SignatureComponent.Path);
|
||||
// options.RequiredSignatureComponents.Add(SignatureComponent.Method);
|
||||
// options.RequiredSignatureComponents.Add(SignatureComponent.Digest);
|
||||
//})
|
||||
//.AddSignatureVerification(serviceProvider =>
|
||||
//{
|
||||
// var memoryCache = serviceProvider.GetRequiredService<IMemoryCache>();
|
||||
// //var httpContextAccessor = serviceProvider.GetRequiredService<IHttpContextAccessor>();
|
||||
|
||||
// //httpContextAccessor.HttpContext.Request.
|
||||
|
||||
// var cert = memoryCache.GetOrCreate("PrivaPub", (cacheEntry) => Extensions.Extensions.GetX509Certificate2("PrivaPubCert"));
|
||||
// return new RsaPkcs15Sha256SignatureProvider(cert, "anon");
|
||||
//})
|
||||
//.ConfigureMessageSigningOptions(options =>
|
||||
//{
|
||||
// options.WithMandatoryComponent(SignatureComponent.Path)
|
||||
// .WithMandatoryComponent(SignatureComponent.Method)
|
||||
// .WithMandatoryComponent(SignatureComponent.Digest)
|
||||
// .WithOptionalComponent(new HttpHeaderDictionaryStructuredComponent(NSign.Constants.Headers.Signature, "sample", bindRequest: true));
|
||||
// options.SignatureName = "resp";
|
||||
// options.SetParameters = (sigParams) =>
|
||||
// {
|
||||
// sigParams.WithCreatedNow();
|
||||
// };
|
||||
//})
|
||||
//.ValidateOnStart()
|
||||
//.Services
|
||||
//.AddHttpClient("ActivityPub", (serviceProvider, client) =>
|
||||
//{
|
||||
// client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("NSignSample", "0.1-beta"));
|
||||
//}).Services;
|
||||
//.AddSingleton<ISigner>(new RsaPssSha512SignatureProvider(
|
||||
// new X509Certificate2(@"path\to\certificate.pfx", "PasswordForPfx"),
|
||||
// "my-cert"));
|
||||
service.AddHttpClient(RemoteActorService.HttpClientName, client =>
|
||||
{
|
||||
client.Timeout = TimeSpan.FromSeconds(20);
|
||||
client.DefaultRequestHeaders.UserAgent.ParseAdd($"PrivaPub/{BuildInfo.Ref}");
|
||||
});
|
||||
return service
|
||||
.AddSingleton<ILocalActorService, LocalActorService>()
|
||||
.AddSingleton<IRemoteActorService, RemoteActorService>()
|
||||
.AddSingleton<IDeliveryService, DeliveryService>()
|
||||
.AddTransient<IInboxService, InboxService>()
|
||||
.AddHostedService<DeliveryWorker>();
|
||||
}
|
||||
public static IServiceCollection PrivaPubAuthServicesConfiguration(this IServiceCollection service, IConfiguration configuration)
|
||||
{
|
||||
@@ -149,6 +91,9 @@ namespace PrivaPub.Middleware
|
||||
.AddTransient<IDataService, DataService>()
|
||||
.AddTransient<IRootUsersService, RootUsersService>()
|
||||
.AddTransient<IPublicAvatarUsersService, PublicAvatarUsersService>()
|
||||
.AddTransient<IPrivateAvatarUsersService, PrivateAvatarUsersService>()
|
||||
.AddTransient<IGroupUsersService, GroupUsersService>()
|
||||
.AddTransient<IPostsService, PostsService>()
|
||||
.AddSingleton<AppConfigurationService>()
|
||||
.AddHttpContextAccessor()
|
||||
.AddMemoryCache()
|
||||
@@ -161,28 +106,18 @@ namespace PrivaPub.Middleware
|
||||
.AddEndpointsApiExplorer()
|
||||
.AddSwaggerGen(c =>
|
||||
{
|
||||
c.AddSecurityDefinition("Bearer", new()
|
||||
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||
{
|
||||
In = ParameterLocation.Header,
|
||||
Description = "Please enter a valid token",
|
||||
Name = "Authorization",
|
||||
Type = SecuritySchemeType.Http,
|
||||
BearerFormat = "JWT",
|
||||
Scheme = "Bearer"
|
||||
Scheme = "bearer"
|
||||
});
|
||||
c.AddSecurityRequirement(new()
|
||||
c.AddSecurityRequirement(document => new OpenApiSecurityRequirement
|
||||
{
|
||||
{
|
||||
new()
|
||||
{
|
||||
Reference = new()
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Bearer"
|
||||
}
|
||||
},
|
||||
new string[]{}
|
||||
}
|
||||
[new OpenApiSecuritySchemeReference("Bearer", document)] = []
|
||||
});
|
||||
})
|
||||
.AddControllers(options => { options.Filters.Add<OperationCancelledExceptionFilter>(); })
|
||||
|
||||
Reference in new issue
Block a user