refactor(host): single-source ChannelPolicy, space-signed file grants, whole-file registration
- all authorization rules (owner/creator, per-channel read/write grants, who may remove whom, delete rules, structure management) live in ChannelPolicy; a test fails if they are reimplemented elsewhere - ChannelInfo carries what the caller may do (can_*), member and invitation lists say who can be removed; clients display it and never derive it - the host no longer stores or calls the file service: it only signs short-lived tickets from space permissions (create/put/get/delete/domain), and keeps an opaque fileDomain reference on the channel - a whole file is registered in one request (last frame header + per-frame length and digest) instead of one request per 1 MiB frame; the signed manifest still has to match every digest - drop file quota/threshold, receipts, reconcile and delete-queue code from the host - contract generator emits constants for enums, error codes, token roles, permissions and share states
This commit is contained in:
1 parent
ccb2c074d6
commit
17638b6e20
36 files changed
+926
-589
No files matched your search
@@ -4,6 +4,13 @@ namespace WebDrop.Core.Tests;
|
||||
|
||||
public sealed class ChannelCryptoTests
|
||||
{
|
||||
/// <summary>文件域的对象主后端只登记头部和摘要,字节不在这里:一个单帧文件</summary>
|
||||
private static Task Register(ChannelService svc, Id16 id, Credentials creds, byte[] frame)
|
||||
{
|
||||
svc.RegisterFileItem(id, creds, frame.AsMemory(0, Envelope.HeaderSize), [new ChannelService.FrameEntry(frame.Length - Envelope.HeaderSize, System.Security.Cryptography.SHA256.HashData(frame))], null);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ClientMayBootstrapButCannotChooseAChannelEpochOrGrantAccess()
|
||||
{
|
||||
@@ -81,7 +88,7 @@ public sealed class ChannelCryptoTests
|
||||
var channelId = env.Service.GetWorkspace(space.Id, owner).Channels.Single().Id;
|
||||
var oldFile = TestEnv.NewId();
|
||||
env.Service.DeclareObject(space.Id, owner, new ObjectEnvelope { ItemId = oldFile.ToBase64Url(), ChannelId = channelId, Domain = CryptoDomain.Files, Epoch = 0, KeyEnvelope = "" });
|
||||
await env.Service.AppendFrameAsync(space.Id, owner, TestEnv.Frame(oldFile, 0, FrameFlags.Final, 16), null);
|
||||
await Register(env.Service, space.Id, owner, TestEnv.Frame(oldFile, 0, FrameFlags.Final, 16));
|
||||
env.Service.MoveWorkspaceItems(space.Id, owner, [oldFile.ToBase64Url()], channelId, null);
|
||||
env.Service.SetChannelHistory(space.Id, owner, channelId, chat: false, files: false);
|
||||
|
||||
@@ -98,22 +105,6 @@ public sealed class ChannelCryptoTests
|
||||
Assert.Single((await env.Service.ReadLogAsync(space.Id, member, 0, 100)).Records);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AnUnfinishedUploadCanBeDeletedWithoutASignedEvent()
|
||||
{
|
||||
using var env = new TestEnv(); var ownerEndpoint = TestEnv.Endpoint(); var memberEndpoint = TestEnv.Endpoint();
|
||||
var space = env.Create(ownerEndpoint, ChannelMode.Raw); var owner = space.Owner(ownerEndpoint) with { RequireSignedContent = true };
|
||||
var channelId = env.Service.GetWorkspace(space.Id, owner).Channels.Single().Id;
|
||||
var member = space.Member(memberEndpoint) with { AccountName = "member", RequireSignedContent = true }; env.Service.Join(space.Id, member);
|
||||
var file = TestEnv.NewId();
|
||||
env.Service.DeclareObject(space.Id, member, new ObjectEnvelope { ItemId = file.ToBase64Url(), ChannelId = channelId, Domain = CryptoDomain.Files, Epoch = 0, KeyEnvelope = "" });
|
||||
// 只传了第 0 帧,没有末帧:上传被打断
|
||||
await env.Service.AppendFrameAsync(space.Id, member, TestEnv.Frame(file, 0, FrameFlags.Gated, 16), null);
|
||||
Assert.Throws<WebDropException>(() => env.Service.DeleteItem(space.Id, space.Member(TestEnv.Endpoint()) with { AccountName = "stranger", RequireSignedContent = true }, file));
|
||||
env.Service.DeleteItem(space.Id, owner, file);
|
||||
Assert.Null(env.Service.ReadCrypto(space.Id, owner).Objects.Find(o => o.ItemId == file.ToBase64Url())?.Event);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MemberOnlySeesChannelsItWasGrantedAndNeverTheirKeysObjectsOrWrites()
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user