fix(server): trim every workspace structure response to the caller's grants and restrict avatars to shared spaces
- structure mutations returned the full structure to any member who could call them (moving an item after sending a message exposed channels the member has no access to) - moving items now requires write access to the destination channel; new folders require an existing channel - account avatars are only readable by the owner or accounts sharing a space
This commit is contained in:
1 parent
d66c93fe98
commit
78b4e2aa63
3 files changed
+62
-7
No files matched your search
@@ -114,6 +114,33 @@ public sealed class ChannelCryptoTests
|
||||
Assert.Null(env.Service.ReadCrypto(space.Id, owner).Objects.Find(o => o.ItemId == file.ToBase64Url())?.Event);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MemberOnlySeesChannelsItWasGrantedAndNeverTheirKeysObjectsOrWrites()
|
||||
{
|
||||
using var env = new TestEnv(); var ep = TestEnv.Endpoint(); var memberEp = TestEnv.Endpoint(); var space = env.Create(ep); var owner = space.Owner(ep);
|
||||
var defaultId = env.Service.GetWorkspace(space.Id, owner).Channels.Single().Id;
|
||||
Bootstrap(env, space, owner, defaultId);
|
||||
var secret = env.Service.CreateWorkspaceChannelResult(space.Id, owner, "secret", null).Channel.Id;
|
||||
Bootstrap(env, space, owner, secret);
|
||||
var hidden = TestEnv.NewId().ToBase64Url();
|
||||
env.Service.DeclareObject(space.Id, owner, new ObjectEnvelope { ItemId = hidden, ChannelId = secret, Domain = CryptoDomain.Chat, Epoch = 1, KeyEnvelope = "k" });
|
||||
|
||||
var plan = env.Service.InvitationPlan(space.Id, owner, "member");
|
||||
var packages = plan.Batches.SelectMany(batch => batch.Recipients.Select(recipient => new DomainEnvelope
|
||||
{ ChannelId = plan.ChannelId, Domain = batch.Domain, Epoch = batch.Epoch, Username = recipient, Payload = $"wrapped-{batch.Domain}-{recipient}" })).ToList();
|
||||
env.Service.InviteUser(space.Id, owner, "member", "opaque-account-grant", packages);
|
||||
var member = space.Member(memberEp) with { AccountName = "member" }; env.Service.Join(space.Id, member);
|
||||
|
||||
// 结构里没有没授权的频道;密钥包、对象登记里也没有它的任何东西
|
||||
Assert.Equal(new[] { defaultId }, env.Service.GetWorkspace(space.Id, member).Channels.Select(c => c.Id));
|
||||
var crypto = env.Service.ReadCrypto(space.Id, member);
|
||||
Assert.DoesNotContain(crypto.Envelopes, e => e.ChannelId == secret);
|
||||
Assert.DoesNotContain(crypto.Objects, o => o.ChannelId == secret);
|
||||
Assert.DoesNotContain(crypto.Access, a => a.ChannelId == secret);
|
||||
// 也不能往没授权的频道登记对象
|
||||
Assert.Throws<WebDropException>(() => env.Service.DeclareObject(space.Id, member, new ObjectEnvelope { ItemId = TestEnv.NewId().ToBase64Url(), ChannelId = secret, Domain = CryptoDomain.Chat, Epoch = 1, KeyEnvelope = "x" }));
|
||||
}
|
||||
|
||||
private static void Bootstrap(TestEnv env, TestChannel space, Credentials owner, string channelId)
|
||||
{
|
||||
foreach (var domain in new[] { CryptoDomain.Chat, CryptoDomain.Files }) env.Service.PublishDomain(space.Id, owner, new DomainPublishRequest
|
||||
|
||||
Reference in new issue
Block a user