Fix incorrect reporting of decryption errors

This commit is contained in:
drive
2026-05-13 13:52:27 +02:00
parent ba7263e21f
commit 41102bf140
3 changed files with 67 additions and 31 deletions
@@ -265,30 +265,36 @@ internal static class NodeCrypto
return new ProtonDriveError("Cannot get node key", error); return new ProtonDriveError("Cannot get node key", error);
} }
ArraySegment<byte> serializedExtendedAttributes;
AuthorshipVerificationFailure? authorshipVerificationFailure;
try try
{ {
var serializedExtendedAttributes = DecryptMessage( serializedExtendedAttributes = DecryptMessage(
encryptedExtendedAttributes.Value, encryptedExtendedAttributes.Value,
detachedSignature: null, detachedSignature: null,
nodeKey, nodeKey,
authorshipClaim.GetKeyRing(nodeKey), authorshipClaim.GetKeyRing(nodeKey),
out _, out _,
out var author); out authorshipVerificationFailure);
try
{
var extendedAttributes = JsonSerializer.Deserialize(serializedExtendedAttributes, DriveApiSerializerContext.Default.ExtendedAttributes);
return new DecryptionOutput<ExtendedAttributes?>(extendedAttributes, author);
}
catch (Exception e)
{
return new ProtonDriveError("Failed to deserialize extended attributes", e.ToProtonDriveError());
}
} }
catch (Exception e) catch (Exception e)
{ {
return new ProtonDriveError("Failed to decrypt extended attributes", e.ToProtonDriveError()); return new DecryptionError("Failed to decrypt extended attributes", e.ToProtonDriveError());
}
try
{
var extendedAttributes = JsonSerializer.Deserialize(serializedExtendedAttributes, DriveApiSerializerContext.Default.ExtendedAttributes);
return new DecryptionOutput<ExtendedAttributes?>(extendedAttributes, authorshipVerificationFailure);
}
catch (JsonException e)
{
return new ExtendedAttributesDeserializationError(e.ToProtonDriveError());
}
catch (Exception e)
{
return new ProtonDriveError("Unknown error while deserializing extended attributes", e.ToProtonDriveError());
} }
} }
@@ -299,17 +299,25 @@ internal static class DtoToMetadataConverter
ShareMembershipSummaryDto? membershipDto) ShareMembershipSummaryDto? membershipDto)
{ {
Dictionary<EncryptedField, ProtonDriveError> failedDecryptionFields = []; Dictionary<EncryptedField, ProtonDriveError> failedDecryptionFields = [];
List<ProtonDriveError> errors = []; List<ProtonDriveError> nodeKeyErrors = [];
if (decryptionResult.Link.Passphrase.TryGetError(out var passphraseError)) if (decryptionResult.Link.Passphrase.TryGetError(out var passphraseError))
{ {
errors.Add(new DecryptionError("Passphrase decryption failed", passphraseError)); nodeKeyErrors.Add(passphraseError);
failedDecryptionFields.Add(EncryptedField.NodeKey, passphraseError);
if (passphraseError is DecryptionError)
{
failedDecryptionFields.Add(EncryptedField.NodeKey, passphraseError);
}
} }
else if (decryptionResult.Link.NodeKey.TryGetError(out var nodeKeyError)) else if (decryptionResult.Link.NodeKey.TryGetError(out var nodeKeyError))
{ {
errors.Add(new DecryptionError("Node key decryption failed", nodeKeyError)); nodeKeyErrors.Add(nodeKeyError);
failedDecryptionFields.Add(EncryptedField.NodeKey, nodeKeyError);
if (passphraseError is DecryptionError)
{
failedDecryptionFields.Add(EncryptedField.NodeKey, nodeKeyError);
}
} }
else if (decryptionResult.ContentKey.TryGetError(out var contentKeyError)) else if (decryptionResult.ContentKey.TryGetError(out var contentKeyError))
{ {
@@ -324,8 +332,12 @@ internal static class DtoToMetadataConverter
var revisionErrors = new List<ProtonDriveError>(); var revisionErrors = new List<ProtonDriveError>();
if (decryptionResult.ExtendedAttributes.TryGetError(out var extendedAttributesError)) if (decryptionResult.ExtendedAttributes.TryGetError(out var extendedAttributesError))
{ {
revisionErrors.Add(new DecryptionError("Extended attributes decryption failed", extendedAttributesError)); revisionErrors.Add(extendedAttributesError);
failedDecryptionFields.Add(EncryptedField.NodeExtendedAttributes, extendedAttributesError);
if (extendedAttributesError is DecryptionError)
{
failedDecryptionFields.Add(EncryptedField.NodeExtendedAttributes, extendedAttributesError);
}
} }
var nodeAuthor = decryptionResult.Link.Passphrase.Merge( var nodeAuthor = decryptionResult.Link.Passphrase.Merge(
@@ -369,7 +381,7 @@ internal static class DtoToMetadataConverter
MediaType = fileDto.MediaType, MediaType = fileDto.MediaType,
ActiveRevision = degradedRevision, ActiveRevision = degradedRevision,
TotalStorageQuotaUsage = fileDto.TotalSizeOnStorage, TotalStorageQuotaUsage = fileDto.TotalSizeOnStorage,
Errors = errors, Errors = nodeKeyErrors,
CaptureTime = linkDetailsDto.Photo.CaptureTime, CaptureTime = linkDetailsDto.Photo.CaptureTime,
AlbumUids = linkDetailsDto.Photo.AlbumInclusions.Select(a => new NodeUid(uid.VolumeId, a.Id)).ToList(), AlbumUids = linkDetailsDto.Photo.AlbumInclusions.Select(a => new NodeUid(uid.VolumeId, a.Id)).ToList(),
OwnedBy = ownedBy, OwnedBy = ownedBy,
@@ -386,7 +398,7 @@ internal static class DtoToMetadataConverter
MediaType = fileDto.MediaType, MediaType = fileDto.MediaType,
ActiveRevision = degradedRevision, ActiveRevision = degradedRevision,
TotalStorageQuotaUsage = fileDto.TotalSizeOnStorage, TotalStorageQuotaUsage = fileDto.TotalSizeOnStorage,
Errors = errors, Errors = nodeKeyErrors,
OwnedBy = ownedBy, OwnedBy = ownedBy,
}; };
@@ -495,25 +507,34 @@ internal static class DtoToMetadataConverter
ShareMembershipSummaryDto? membershipDto) ShareMembershipSummaryDto? membershipDto)
{ {
Dictionary<EncryptedField, ProtonDriveError> failedDecryptionFields = []; Dictionary<EncryptedField, ProtonDriveError> failedDecryptionFields = [];
List<ProtonDriveError> errors = []; List<ProtonDriveError> nodeKeyAndHashKeyErrors = [];
if (decryptionResult.Link.Passphrase.TryGetError(out var passphraseError)) if (decryptionResult.Link.Passphrase.TryGetError(out var passphraseError))
{ {
errors.Add(new DecryptionError("Passphrase decryption failed", passphraseError)); nodeKeyAndHashKeyErrors.Add(passphraseError);
failedDecryptionFields.Add(EncryptedField.NodeKey, passphraseError);
if (passphraseError is DecryptionError)
{
failedDecryptionFields.Add(EncryptedField.NodeKey, passphraseError);
}
} }
else if (decryptionResult.Link.NodeKey.TryGetError(out var nodeKeyError)) else if (decryptionResult.Link.NodeKey.TryGetError(out var nodeKeyError))
{ {
errors.Add(new DecryptionError("Node key decryption failed", nodeKeyError)); nodeKeyAndHashKeyErrors.Add(nodeKeyError);
failedDecryptionFields.Add(EncryptedField.NodeKey, nodeKeyError);
if (nodeKeyError is DecryptionError)
{
failedDecryptionFields.Add(EncryptedField.NodeKey, nodeKeyError);
}
} }
else if (decryptionResult.HashKey.TryGetError(out var hashKeyError)) else if (decryptionResult.HashKey.TryGetError(out var hashKeyError))
{ {
errors.Add(new DecryptionError("Hash key decryption failed", hashKeyError)); nodeKeyAndHashKeyErrors.Add(hashKeyError);
failedDecryptionFields.Add(EncryptedField.NodeHashKey, hashKeyError); failedDecryptionFields.Add(EncryptedField.NodeHashKey, hashKeyError);
} }
if (nameResult.TryGetError(out var nameError)) if (nameResult.TryGetError(out var nameError) && nameError is DecryptionError)
{ {
failedDecryptionFields.Add(EncryptedField.NodeName, nameError); failedDecryptionFields.Add(EncryptedField.NodeName, nameError);
} }
@@ -541,7 +562,7 @@ internal static class DtoToMetadataConverter
CreationTime = linkDto.CreationTime, CreationTime = linkDto.CreationTime,
TrashTime = linkDto.TrashTime, TrashTime = linkDto.TrashTime,
Author = nodeAuthor, Author = nodeAuthor,
Errors = errors, Errors = nodeKeyAndHashKeyErrors,
OwnedBy = MapOwnedBy(linkDto.OwnedBy), OwnedBy = MapOwnedBy(linkDto.OwnedBy),
}; };
@@ -0,0 +1,9 @@
using System.Text.Json.Serialization;
namespace Proton.Drive.Sdk.Nodes;
[method: JsonConstructor]
public sealed class ExtendedAttributesDeserializationError(ProtonDriveError? innerError = null)
: ProtonDriveError("Failed to deserialize extended attributes", innerError)
{
}