Update behavior during import for missing oneof fields
This commit is contained in:
parent
22d30ec4eb
commit
d30ad37262
3 changed files with 99 additions and 54 deletions
|
@ -31,6 +31,7 @@ message BackupInfo {
|
|||
// For example, Chats may all be together at the beginning,
|
||||
// or may each immediately precede its first ChatItem.
|
||||
message Frame {
|
||||
// If unset, importers should skip this frame without throwing an error.
|
||||
oneof item {
|
||||
AccountData account = 1;
|
||||
Recipient recipient = 2;
|
||||
|
@ -45,13 +46,13 @@ message Frame {
|
|||
|
||||
message AccountData {
|
||||
enum PhoneNumberSharingMode {
|
||||
UNKNOWN = 0;
|
||||
UNKNOWN = 0; // Interpret as "Nobody"
|
||||
EVERYBODY = 1;
|
||||
NOBODY = 2;
|
||||
}
|
||||
message UsernameLink {
|
||||
enum Color {
|
||||
UNKNOWN = 0;
|
||||
UNKNOWN = 0; // Interpret as "Blue"
|
||||
BLUE = 1;
|
||||
WHITE = 2;
|
||||
GREY = 3;
|
||||
|
@ -98,6 +99,7 @@ message AccountData {
|
|||
message IAPSubscriberData {
|
||||
bytes subscriberId = 1;
|
||||
|
||||
// If unset, importers should ignore the subscriber data without throwing an error.
|
||||
oneof iapSubscriptionId {
|
||||
// Identifies an Android Play Store IAP subscription.
|
||||
string purchaseToken = 2;
|
||||
|
@ -120,6 +122,7 @@ message AccountData {
|
|||
|
||||
message Recipient {
|
||||
uint64 id = 1; // generated id for reference only within this file
|
||||
// If unset, importers should skip this frame without throwing an error.
|
||||
oneof destination {
|
||||
Contact contact = 2;
|
||||
Group group = 3;
|
||||
|
@ -132,9 +135,9 @@ message Recipient {
|
|||
|
||||
message Contact {
|
||||
enum IdentityState {
|
||||
DEFAULT = 0;
|
||||
DEFAULT = 0; // A valid value -- indicates unset by the user
|
||||
VERIFIED = 1;
|
||||
UNVERIFIED = 2;
|
||||
UNVERIFIED = 2; // Was once verified and is now unverified
|
||||
}
|
||||
|
||||
message Registered {}
|
||||
|
@ -143,7 +146,7 @@ message Contact {
|
|||
}
|
||||
|
||||
enum Visibility {
|
||||
VISIBLE = 0;
|
||||
VISIBLE = 0; // A valid value -- the contact is not hidden
|
||||
HIDDEN = 1;
|
||||
HIDDEN_MESSAGE_REQUEST = 2;
|
||||
}
|
||||
|
@ -160,6 +163,7 @@ message Contact {
|
|||
bool blocked = 5;
|
||||
Visibility visibility = 6;
|
||||
|
||||
// If unset, consider the user to be registered
|
||||
oneof registration {
|
||||
Registered registered = 7;
|
||||
NotRegistered notRegistered = 8;
|
||||
|
@ -178,7 +182,7 @@ message Contact {
|
|||
|
||||
message Group {
|
||||
enum StorySendMode {
|
||||
DEFAULT = 0;
|
||||
DEFAULT = 0; // A valid value -- indicates unset by the user
|
||||
DISABLED = 1;
|
||||
ENABLED = 2;
|
||||
}
|
||||
|
@ -212,6 +216,7 @@ message Group {
|
|||
}
|
||||
|
||||
message GroupAttributeBlob {
|
||||
// If unset, consider the field it represents to not be present
|
||||
oneof content {
|
||||
string title = 1;
|
||||
bytes avatar = 2;
|
||||
|
@ -222,7 +227,7 @@ message Group {
|
|||
|
||||
message Member {
|
||||
enum Role {
|
||||
UNKNOWN = 0;
|
||||
UNKNOWN = 0; // Intepret as "Default"
|
||||
DEFAULT = 1;
|
||||
ADMINISTRATOR = 2;
|
||||
}
|
||||
|
@ -254,7 +259,7 @@ message Group {
|
|||
|
||||
message AccessControl {
|
||||
enum AccessRequired {
|
||||
UNKNOWN = 0;
|
||||
UNKNOWN = 0; // Intepret as "Unsatisfiable"
|
||||
ANY = 1;
|
||||
MEMBER = 2;
|
||||
ADMINISTRATOR = 3;
|
||||
|
@ -294,7 +299,7 @@ message Chat {
|
|||
*/
|
||||
message CallLink {
|
||||
enum Restrictions {
|
||||
UNKNOWN = 0;
|
||||
UNKNOWN = 0; // Interpret as "Admin Approval"
|
||||
NONE = 1;
|
||||
ADMIN_APPROVAL = 2;
|
||||
}
|
||||
|
@ -308,7 +313,7 @@ message CallLink {
|
|||
|
||||
message AdHocCall {
|
||||
enum State {
|
||||
UNKNOWN_STATE = 0;
|
||||
UNKNOWN_STATE = 0; // Interpret as "Generic"
|
||||
GENERIC = 1;
|
||||
}
|
||||
|
||||
|
@ -324,6 +329,7 @@ message DistributionListItem {
|
|||
// by an all-0 UUID (00000000-0000-0000-0000-000000000000).
|
||||
bytes distributionId = 1; // distribution list ids are uuids
|
||||
|
||||
// If unset, importers should skip the item entirely without showing an error.
|
||||
oneof item {
|
||||
uint64 deletionTimestamp = 2;
|
||||
DistributionList distributionList = 3;
|
||||
|
@ -332,7 +338,7 @@ message DistributionListItem {
|
|||
|
||||
message DistributionList {
|
||||
enum PrivacyMode {
|
||||
UNKNOWN = 0;
|
||||
UNKNOWN = 0; // Interpret as "Only with"
|
||||
ONLY_WITH = 1;
|
||||
ALL_EXCEPT = 2;
|
||||
ALL = 3;
|
||||
|
@ -367,12 +373,14 @@ message ChatItem {
|
|||
repeated ChatItem revisions = 6; // ordered from oldest to newest
|
||||
bool sms = 7;
|
||||
|
||||
// If unset, importers should skip this item without throwing an error.
|
||||
oneof directionalDetails {
|
||||
IncomingMessageDetails incoming = 8;
|
||||
OutgoingMessageDetails outgoing = 9;
|
||||
DirectionlessMessageDetails directionless = 10;
|
||||
}
|
||||
|
||||
// If unset, importers should skip this item without throwing an error.
|
||||
oneof item {
|
||||
StandardMessage standardMessage = 11;
|
||||
ContactMessage contactMessage = 12;
|
||||
|
@ -421,6 +429,7 @@ message SendStatus {
|
|||
uint64 recipientId = 1;
|
||||
uint64 timestamp = 2; // the time the status was last updated -- if from a receipt, it should be the sentTime of the receipt
|
||||
|
||||
// If unset, importers should consider the status to be "pending"
|
||||
oneof deliveryStatus {
|
||||
Pending pending = 3;
|
||||
Sent sent = 4;
|
||||
|
@ -457,6 +466,7 @@ message DirectStoryReplyMessage {
|
|||
FilePointer longText = 2;
|
||||
}
|
||||
|
||||
// If unset, importers should ignore the message without throwing an error.
|
||||
oneof reply {
|
||||
TextReply textReply = 1;
|
||||
string emoji = 2;
|
||||
|
@ -475,7 +485,7 @@ message PaymentNotification {
|
|||
|
||||
message FailedTransaction { // Failed payments can't be synced from the ledger
|
||||
enum FailureReason {
|
||||
GENERIC = 0;
|
||||
GENERIC = 0; // A valid value -- reason unknown
|
||||
NETWORK = 1;
|
||||
INSUFFICIENT_FUNDS = 2;
|
||||
}
|
||||
|
@ -484,7 +494,7 @@ message PaymentNotification {
|
|||
|
||||
message Transaction {
|
||||
enum Status {
|
||||
INITIAL = 0;
|
||||
INITIAL = 0; // A valid value -- state unconfirmed
|
||||
SUBMITTED = 1;
|
||||
SUCCESSFUL = 2;
|
||||
}
|
||||
|
@ -501,6 +511,7 @@ message PaymentNotification {
|
|||
optional bytes receipt = 7; // mobile coin blobs
|
||||
}
|
||||
|
||||
// If unset, importers should treat the transaction as successful with no metadata.
|
||||
oneof payment {
|
||||
Transaction transaction = 1;
|
||||
FailedTransaction failedTransaction = 2;
|
||||
|
@ -515,7 +526,7 @@ message PaymentNotification {
|
|||
|
||||
message GiftBadge {
|
||||
enum State {
|
||||
UNOPENED = 0;
|
||||
UNOPENED = 0; // A valid state
|
||||
OPENED = 1;
|
||||
REDEEMED = 2;
|
||||
FAILED = 3;
|
||||
|
@ -543,7 +554,7 @@ message ContactAttachment {
|
|||
|
||||
message Phone {
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
UNKNOWN = 0; // Interpret as "Home"
|
||||
HOME = 1;
|
||||
MOBILE = 2;
|
||||
WORK = 3;
|
||||
|
@ -557,7 +568,7 @@ message ContactAttachment {
|
|||
|
||||
message Email {
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
UNKNOWN = 0; // Intepret as "Home"
|
||||
HOME = 1;
|
||||
MOBILE = 2;
|
||||
WORK = 3;
|
||||
|
@ -571,7 +582,7 @@ message ContactAttachment {
|
|||
|
||||
message PostalAddress {
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
UNKNOWN = 0; // Interpret as "Home"
|
||||
HOME = 1;
|
||||
WORK = 2;
|
||||
CUSTOM = 3;
|
||||
|
@ -631,7 +642,7 @@ message MessageAttachment {
|
|||
// but explicitly mutually exclusive. Note the different raw values
|
||||
// (non-zero starting values are not supported in proto3.)
|
||||
enum Flag {
|
||||
NONE = 0;
|
||||
NONE = 0; // A valid value -- no flag applied
|
||||
VOICE_MESSAGE = 1;
|
||||
BORDERLESS = 2;
|
||||
GIF = 3;
|
||||
|
@ -682,6 +693,7 @@ message FilePointer {
|
|||
message InvalidAttachmentLocator {
|
||||
}
|
||||
|
||||
// If unset, importers should consider it to be an InvalidAttachmentLocator without throwing an error.
|
||||
oneof locator {
|
||||
BackupLocator backupLocator = 1;
|
||||
AttachmentLocator attachmentLocator = 2;
|
||||
|
@ -700,7 +712,7 @@ message FilePointer {
|
|||
|
||||
message Quote {
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
UNKNOWN = 0; // Interpret as "Normal"
|
||||
NORMAL = 1;
|
||||
GIFT_BADGE = 2;
|
||||
VIEW_ONCE = 3;
|
||||
|
@ -721,7 +733,7 @@ message Quote {
|
|||
|
||||
message BodyRange {
|
||||
enum Style {
|
||||
NONE = 0;
|
||||
NONE = 0; // Importers should ignore the body range without throwing an error.
|
||||
BOLD = 1;
|
||||
ITALIC = 2;
|
||||
SPOILER = 3;
|
||||
|
@ -734,6 +746,7 @@ message BodyRange {
|
|||
uint32 start = 1;
|
||||
uint32 length = 2;
|
||||
|
||||
// If unset, importers should ignore the body range without throwing an error.
|
||||
oneof associatedValue {
|
||||
bytes mentionAci = 3;
|
||||
Style style = 4;
|
||||
|
@ -750,6 +763,7 @@ message Reaction {
|
|||
}
|
||||
|
||||
message ChatUpdateMessage {
|
||||
// If unset, importers should ignore the update message without throwing an error.
|
||||
oneof update {
|
||||
SimpleChatUpdate simpleUpdate = 1;
|
||||
GroupChangeChatUpdate groupChange = 2;
|
||||
|
@ -765,19 +779,19 @@ message ChatUpdateMessage {
|
|||
|
||||
message IndividualCall {
|
||||
enum Type {
|
||||
UNKNOWN_TYPE = 0;
|
||||
UNKNOWN_TYPE = 0; // Interpret as "Audio call"
|
||||
AUDIO_CALL = 1;
|
||||
VIDEO_CALL = 2;
|
||||
}
|
||||
|
||||
enum Direction {
|
||||
UNKNOWN_DIRECTION = 0;
|
||||
UNKNOWN_DIRECTION = 0; // Interpret as "Incoming"
|
||||
INCOMING = 1;
|
||||
OUTGOING = 2;
|
||||
}
|
||||
|
||||
enum State {
|
||||
UNKNOWN_STATE = 0;
|
||||
UNKNOWN_STATE = 0; // Interpret as "Accepted"
|
||||
ACCEPTED = 1;
|
||||
NOT_ACCEPTED = 2;
|
||||
// An incoming call that is no longer ongoing, which we neither accepted
|
||||
|
@ -798,7 +812,7 @@ message IndividualCall {
|
|||
|
||||
message GroupCall {
|
||||
enum State {
|
||||
UNKNOWN_STATE = 0;
|
||||
UNKNOWN_STATE = 0; // Interpret as "Generic"
|
||||
// A group call was started without ringing.
|
||||
GENERIC = 1;
|
||||
// We joined a group call that was started without ringing.
|
||||
|
@ -829,7 +843,7 @@ message GroupCall {
|
|||
|
||||
message SimpleChatUpdate {
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
UNKNOWN = 0; // Importers should skip the update without throwing an error.
|
||||
JOINED_SIGNAL = 1;
|
||||
IDENTITY_UPDATE = 2;
|
||||
IDENTITY_VERIFIED = 3;
|
||||
|
@ -863,6 +877,7 @@ message ProfileChangeChatUpdate {
|
|||
}
|
||||
|
||||
message LearnedProfileChatUpdate {
|
||||
// If unset, importers should consider the previous name to be an empty string.
|
||||
oneof previousName {
|
||||
uint64 e164 = 1;
|
||||
string username = 2;
|
||||
|
@ -879,6 +894,7 @@ message SessionSwitchoverChatUpdate {
|
|||
|
||||
message GroupChangeChatUpdate {
|
||||
message Update {
|
||||
// If unset, importers should consider it to be a GenericGroupUpdate with unset updaterAci
|
||||
oneof update {
|
||||
GenericGroupUpdate genericGroupUpdate = 1;
|
||||
GroupCreationUpdate groupCreationUpdate = 2;
|
||||
|
@ -948,7 +964,7 @@ message GroupDescriptionUpdate {
|
|||
}
|
||||
|
||||
enum GroupV2AccessLevel {
|
||||
UNKNOWN = 0;
|
||||
UNKNOWN = 0; // Interpret as "Unsatisfiable"
|
||||
ANY = 1;
|
||||
MEMBER = 2;
|
||||
ADMINISTRATOR = 3;
|
||||
|
@ -1138,6 +1154,7 @@ message ChatStyle {
|
|||
message CustomChatColor {
|
||||
uint64 id = 1;
|
||||
|
||||
// If unset, use the default chat color
|
||||
oneof color {
|
||||
fixed32 solid = 2; // 0xAARRGGBB
|
||||
Gradient gradient = 3;
|
||||
|
@ -1148,7 +1165,7 @@ message ChatStyle {
|
|||
}
|
||||
|
||||
enum WallpaperPreset {
|
||||
UNKNOWN_WALLPAPER_PRESET = 0;
|
||||
UNKNOWN_WALLPAPER_PRESET = 0; // Interpret as the wallpaper being unset
|
||||
SOLID_BLUSH = 1;
|
||||
SOLID_COPPER = 2;
|
||||
SOLID_DUST = 3;
|
||||
|
@ -1173,7 +1190,7 @@ message ChatStyle {
|
|||
}
|
||||
|
||||
enum BubbleColorPreset {
|
||||
UNKNOWN_BUBBLE_COLOR_PRESET = 0;
|
||||
UNKNOWN_BUBBLE_COLOR_PRESET = 0; // Interpret as the user's default chat bubble color
|
||||
SOLID_ULTRAMARINE = 1;
|
||||
SOLID_CRIMSON = 2;
|
||||
SOLID_VERMILION = 3;
|
||||
|
@ -1198,6 +1215,7 @@ message ChatStyle {
|
|||
GRADIENT_TANGERINE = 22;
|
||||
}
|
||||
|
||||
// If unset, importers should consider there to be no wallpaper.
|
||||
oneof wallpaper {
|
||||
WallpaperPreset wallpaperPreset = 1;
|
||||
// This `FilePointer` is expected not to contain a `fileName`, `width`,
|
||||
|
@ -1205,6 +1223,7 @@ message ChatStyle {
|
|||
FilePointer wallpaperPhoto = 2;
|
||||
}
|
||||
|
||||
// If unset, importers should consider it to be AutomaticBubbleColor
|
||||
oneof bubbleColor {
|
||||
// Bubble setting is automatically determined based on the wallpaper setting,
|
||||
// or `SOLID_ULTRAMARINE` for `noWallpaper`
|
||||
|
@ -1220,7 +1239,7 @@ message ChatStyle {
|
|||
|
||||
message NotificationProfile {
|
||||
enum DayOfWeek {
|
||||
UNKNOWN = 0;
|
||||
UNKNOWN = 0; // Interpret as "Monday"
|
||||
MONDAY = 1;
|
||||
TUESDAY = 2;
|
||||
WEDNESDAY = 3;
|
||||
|
@ -1246,7 +1265,7 @@ message NotificationProfile {
|
|||
message ChatFolder {
|
||||
// Represents the default "All chats" folder record vs all other custom folders
|
||||
enum FolderType {
|
||||
UNKNOWN = 0;
|
||||
UNKNOWN = 0; // Interpret as "Custom"
|
||||
ALL = 1;
|
||||
CUSTOM = 2;
|
||||
}
|
||||
|
|
|
@ -480,8 +480,8 @@ export class BackupImportStream extends Writable {
|
|||
// Not a conversation
|
||||
return;
|
||||
} else {
|
||||
log.warn(`${this.#logId}: unsupported recipient item`);
|
||||
return;
|
||||
log.warn(`${this.#logId}: unsupported recipient destination`);
|
||||
throw new Error('Unsupported recipient destination');
|
||||
}
|
||||
|
||||
if (convo !== this.#ourConversation) {
|
||||
|
@ -505,6 +505,7 @@ export class BackupImportStream extends Writable {
|
|||
await this.#fromAdHocCall(frame.adHocCall);
|
||||
} else {
|
||||
log.warn(`${this.#logId}: unsupported frame item ${frame.item}`);
|
||||
throw new Error('Unsupported frame type');
|
||||
}
|
||||
} catch (error) {
|
||||
this.#frameErrorCount += 1;
|
||||
|
@ -940,11 +941,12 @@ export class BackupImportStream extends Writable {
|
|||
);
|
||||
attrs.discoveredUnregisteredAt = timestamp || this.#now;
|
||||
attrs.firstUnregisteredAt = timestamp || undefined;
|
||||
} else {
|
||||
strictAssert(
|
||||
} else if (!contact.registered) {
|
||||
log.error(
|
||||
contact.registered,
|
||||
'contact is either registered or unregistered'
|
||||
'contact is neither registered nor unregistered; treating as registered'
|
||||
);
|
||||
this.#frameErrorCount += 1;
|
||||
}
|
||||
|
||||
if (contact.blocked) {
|
||||
|
@ -1649,7 +1651,12 @@ export class BackupImportStream extends Writable {
|
|||
} else if (status.skipped) {
|
||||
sendStatus = SendStatus.Skipped;
|
||||
} else {
|
||||
throw new Error(`Unknown sendStatus received: ${status}`);
|
||||
log.error(
|
||||
`${timestamp}: Unknown sendStatus received: ${status}, falling back to Pending`
|
||||
);
|
||||
// We fallback to pending for unknown send statuses
|
||||
sendStatus = SendStatus.Pending;
|
||||
this.#frameErrorCount += 1;
|
||||
}
|
||||
|
||||
sendStateByConversationId[target.id] = {
|
||||
|
@ -1896,6 +1903,10 @@ export class BackupImportStream extends Writable {
|
|||
targetAuthorAci: storyAuthorAci,
|
||||
targetTimestamp: 0, // stories are never imported
|
||||
};
|
||||
} else {
|
||||
throw new Error(
|
||||
'Direct story reply message missing both textReply and emoji'
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -2413,10 +2424,12 @@ export class BackupImportStream extends Writable {
|
|||
|
||||
if (updateMessage.learnedProfileChange) {
|
||||
const { e164, username } = updateMessage.learnedProfileChange;
|
||||
strictAssert(
|
||||
e164 != null || username != null,
|
||||
'learnedProfileChange must have an old name'
|
||||
if (e164 == null && username == null) {
|
||||
log.error(
|
||||
`${options.timestamp}: learnedProfileChange had no previous e164 or username`
|
||||
);
|
||||
this.#frameErrorCount += 1;
|
||||
}
|
||||
return {
|
||||
message: {
|
||||
type: 'title-transition-notification',
|
||||
|
@ -3392,7 +3405,7 @@ export class BackupImportStream extends Writable {
|
|||
value = {
|
||||
start: rgbIntToDesktopHSL(color.solid),
|
||||
};
|
||||
} else {
|
||||
} else if (color.gradient) {
|
||||
strictAssert(color.gradient != null, 'Either solid or gradient');
|
||||
strictAssert(color.gradient.colors != null, 'Missing gradient colors');
|
||||
|
||||
|
@ -3409,6 +3422,12 @@ export class BackupImportStream extends Writable {
|
|||
end: rgbIntToDesktopHSL(end),
|
||||
deg,
|
||||
};
|
||||
} else {
|
||||
log.error(
|
||||
'CustomChatColor missing both solid and gradient fields, dropping'
|
||||
);
|
||||
this.#frameErrorCount += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
customColors.colors[uuid] = value;
|
||||
|
@ -3532,16 +3551,23 @@ export class BackupImportStream extends Writable {
|
|||
color = 'ultramarine';
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
strictAssert(chatStyle.customColorId != null, 'Missing custom color id');
|
||||
|
||||
} else if (chatStyle.customColorId != null) {
|
||||
const entry = this.#customColorById.get(
|
||||
chatStyle.customColorId.toNumber()
|
||||
);
|
||||
strictAssert(entry != null, 'Missing custom color');
|
||||
|
||||
if (entry) {
|
||||
color = 'custom';
|
||||
customColorData = entry;
|
||||
} else {
|
||||
log.error('Chat style referenced missing custom color');
|
||||
this.#frameErrorCount += 1;
|
||||
autoBubbleColor = true;
|
||||
}
|
||||
} else {
|
||||
log.error('ChatStyle has no recognized field');
|
||||
this.#frameErrorCount += 1;
|
||||
autoBubbleColor = true;
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -120,15 +120,15 @@ export function convertFilePointerToAttachment(
|
|||
};
|
||||
}
|
||||
|
||||
if (invalidAttachmentLocator) {
|
||||
if (!invalidAttachmentLocator) {
|
||||
log.error('convertFilePointerToAttachment: filePointer had no locator');
|
||||
}
|
||||
|
||||
return {
|
||||
...omit(commonProps, 'downloadPath'),
|
||||
error: true,
|
||||
size: 0,
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error('convertFilePointerToAttachment: mising locator');
|
||||
}
|
||||
|
||||
export function convertBackupMessageAttachmentToAttachment(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue