Multi-backup enhances data security by allowing users to utilize multiple backup methods, ensuring greater resilience and recovery options. In previous versions, recovery attempts could fail if they didn't match the latest backup method used. With multi-backup, users can recover data using any of the methods they've backed up with, such as GDRIVE, ICLOUD,PASSWORD, or PASSKEY.
Key Changes in the Migration
Webhook Adjustments:
POST /backup: Now includes a "backupMethod" key.
POST /backup/fetch: Replaces "backupShare" with "backupShares".
API Endpoint Modifications: The POST /stored-client-backup-share endpoint now requires "backupMethod".
Database Schema Alterations: To support multi-backup, you may need to modify your database schema.
Applicable SDK Version Upgrades
This guide is applicable for the following SDK upgrades:
React Native:^2.0.0 -> ^3.0.0
Swift:^2.0.0 -> ^3.0.0
Kotlin:^2.0.0 -> ^3.0.0
Web:^0.0.0 -> ^1.0.0
Database Changes
Multi-backup requires storing both custodian and user backup shares by their respective backup method. We recommend the following database model structure:
// Encrypted backup share received from portal.backup().modelUserBackupShare { backupMethod String @default("UNKNOWN") // (String) The method used for the backup. Defaults to "UNKNOWN" if not specified.
createdAt DateTime @default(now()) // (DateTime) The timestamp when the backup share was created.
id String@id@default(cuid()) // (String) A unique identifier for each backup share cipherText String// (String) The encrypted backup share data. userId String // (Int) The identifier of the user to whom the backup share belongs.
user User @relation(fields: [userId], references: [id]) // (User) A relation field that links to the corresponding user in the User model.
@@unique([userId, backupMethod]) // A unique constraint ensuring that each user has only one backup share per method.
}// Raw backup share received from the POST /backup webhook.modelCustodianBackupShare { backupMethod String @default("UNKNOWN") // (String) The method used for the backup. Defaults to "UNKNOWN" if not specified.
createdAt DateTime @default(now()) // (DateTime) The timestamp when the backup share was created.
id String@id@default(cuid()) // (String) A unique identifier for each backup share share String// (String) The raw backup share data. userId String // (String) The identifier of the user to whom the backup share belongs.
user User @relation(fields: [userId], references: [id]) // (User) A relation field that links to the corresponding user in the User model.
@@unique([userId, backupMethod]) // A unique constraint ensuring that each user has only one backup share per method.
}// User model, often referred to as "Client" in documentation.modelUser { clientApiKey String@unique// (String) The unique Client API Key assigned to the user. clientId String@unique// (String) The unique identifier for the client that Portal uses. id String@id@default(cuid()) // (String) The primary key for the user userBackupShares UserBackupShare[]// (UserBackupShare[]) A list of the user backup shares related to the user. custodianBackupShares CustodianBackupShare[] // (CustodianBackupShare[]) A list of the custodian backup shares related to the user.
}
For assistance or more details on structuring your database for this migration, please reach out to our team, we are here to help! 😊
Webhook Changes
Before upgrading to multi-backup, update your webhook implementations. These new implementations are backwards compatible. Here's what you need to account for:
POST /backup: This request now includes a backupMethod key. Store the custodian backup share accordingly.
Example body:
{"clientId":"some-client-id","share":"stringified-share",// New key-value pair 👇 "backupMethod": "PASSWORD-SECP256K1" // One of: "GDRIVE-SECP256K1", "ICLOUD-SECP256K1", "PASSWORD-SECP256K1", "PASSKEY-SECP256K1", "GDRIVE-ED25519", "ICLOUD-ED25519", "PASSWORD-ED25519", "PASSKEY-ED25519" (@WARNING: we may add others or modify them in the future)
}
Be sure to store the share for the user by backupMethod.
Store the share for the user by backupMethod.Since a user can now have a backup share per backup method. If a share already exists for that user with the same backupMethod, delete the old share and keep the new one.
POST /backup/fetch: Expect an array of backup shares in the response, reflecting the user's multiple backup methods.
Storing the Encrypted User Backup Share: After portal.backup(), store the returned cipherText by the backup method that was used in your database.
Upgrading the API Endpoint to v2: Use PUT https://api.portalhq.io/api/v2/clients/me/wallet/stored-client-backup-share, providing the backupMethod in the request body. You can provide it in the request body like this:
{"success":true,// New key-value pair 👇 "backupMethod": "PASSWORD-SECP256K1" // One of: "GDRIVE-SECP256K1", "ICLOUD-SECP256K1", "PASSWORD-SECP256K1", "PASSKEY-SECP256K1", "GDRIVE-ED25519", "ICLOUD-ED25519", "PASSWORD-ED25519", "PASSKEY-ED25519" (@WARNING: we may add others or modify them in the future)
}
Retrieving the User Backup Share: Update your retrieval process to match the backup method used in portal.recover().
Update isMultiBackupEnabled feature flag: Update the feature flag isMultiBackupEnabled to true when instantiating Portal.
You did it! 🙌 You've successfully navigated the intricacies of enabling multiple backups for your users. Please reach out if you have any questions or if we can assist in any way.