Public Access
Merge branch 'claude/team-key-share-rotate-4b2619'
Two conflicts, and the second is worth recording. main's M4 bullet gained the Android signing decision while this branch rewrote the M5 line either side of it; both are kept. The other is an ADR number collision: two sessions each took 0010, one for vault key rotation and one for Android distribution, and both are now on main. ADR numbers are identifiers — "see ADR 0010" appears in code comments as well as in prose — so leaving two would make every such reference ambiguous. The rotation ADR landed first and is referenced from crypto.md, the gaps document, ADR 0009 and the sync code; the Android one is referenced from README and android-port.md. So the later and cheaper one moves: 0010-android-distribution.md is now ADR 0011, with its title and both references updated. Nothing about either decision changes.
This commit is contained in:
@@ -1086,7 +1086,7 @@ internal sealed partial class TeamsViewModel(
|
||||
|
||||
var reports = await open
|
||||
.RekeyTeamVaultsAsync(
|
||||
server.Grants, server.Directory, team.TeamId, remaining, cancellationToken)
|
||||
server.Grants, server.Directory, server.Sync, team.TeamId, remaining, cancellationToken)
|
||||
.ConfigureAwait(true);
|
||||
|
||||
if (reports.Count == 0)
|
||||
@@ -1102,29 +1102,7 @@ internal sealed partial class TeamsViewModel(
|
||||
|
||||
if (rotated.Count > 0)
|
||||
{
|
||||
// Says what a rotation is and is not worth, because the word promises more than it can
|
||||
// deliver: from here on they cannot read this vault, and what is already in it was sealed
|
||||
// under the key they used to hold.
|
||||
sentences.Add(
|
||||
$"Rotated {VaultCount(rotated.Count)} — {Join(rotated.Select(r => r.Name))} — so nothing "
|
||||
+ "written from now on is readable to them.");
|
||||
|
||||
// The members who did not get the new key. They are still in the team and can still write,
|
||||
// but until somebody wraps it to them they will find the vault stops updating.
|
||||
// Distinct by id rather than by name, because two accounts can share a display name and
|
||||
// collapsing them would tell somebody one person is owed a key when two are.
|
||||
var missed = rotated
|
||||
.SelectMany(report => report.NotShared.Select(entry => entry.UserId))
|
||||
.Distinct()
|
||||
.Select(Name)
|
||||
.ToList();
|
||||
|
||||
if (missed.Count > 0)
|
||||
{
|
||||
sentences.Add(
|
||||
$"The new key did not reach {Join(missed)} — press SHARE KEY for them, or they "
|
||||
+ "will stop seeing changes.");
|
||||
}
|
||||
sentences.AddRange(Describe(rotated));
|
||||
}
|
||||
|
||||
if (failed.Count > 0)
|
||||
@@ -1136,6 +1114,42 @@ internal sealed partial class TeamsViewModel(
|
||||
return string.Join(" ", sentences);
|
||||
}
|
||||
|
||||
/// <summary>What the vaults that did rotate are now worth, in the order somebody needs it.</summary>
|
||||
private IEnumerable<string> Describe(List<VaultRekeyReport> rotated)
|
||||
{
|
||||
yield return
|
||||
$"Rotated {VaultCount(rotated.Count)} — {Join(rotated.Select(r => r.Name))} — so nothing "
|
||||
+ "written from now on is readable to them.";
|
||||
|
||||
// Two different promises, so two different sentences. A vault whose items were all moved onto
|
||||
// the new key is closed to them completely; one where some were left is closed to what happens
|
||||
// next, and the difference is not the interface's to blur.
|
||||
var sealedUp = rotated.Count(report => report.Sealed);
|
||||
|
||||
yield return sealedUp == rotated.Count
|
||||
? "Everything already stored was re-sealed under the new key too, so their old key opens "
|
||||
+ "nothing."
|
||||
: $"{sealedUp} of {rotated.Count} had everything already stored re-sealed under the new "
|
||||
+ "key; the rest still hold items under the old one and will be picked up next time. "
|
||||
+ "Rotate the credentials that mattered either way.";
|
||||
|
||||
// The members who did not get the new key. They are still in the team and can still write, but
|
||||
// until somebody wraps it to them they will find the vault stops updating. Distinct by id
|
||||
// rather than by name, because two accounts can share a display name and collapsing them would
|
||||
// tell somebody one person is owed a key when two are.
|
||||
var missed = rotated
|
||||
.SelectMany(report => report.NotShared.Select(entry => entry.UserId))
|
||||
.Distinct()
|
||||
.Select(Name)
|
||||
.ToList();
|
||||
|
||||
if (missed.Count > 0)
|
||||
{
|
||||
yield return $"The new key did not reach {Join(missed)} — press SHARE KEY for them, or "
|
||||
+ "they will stop seeing changes.";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>What to call a member in a sentence, from the list this screen already has.</summary>
|
||||
private string Name(Guid userId) =>
|
||||
Members.FirstOrDefault(row => row.UserId == userId)?.Name ?? userId.ToString();
|
||||
|
||||
Reference in New Issue
Block a user