Skip to content

Commit ad9bbfc

Browse files
committed
api/bitbox02: allow backups using recovery words, skipping sdcard
This adds a parameter to the createBackup endpoint to choose the sdcard backup or the recovery words backup. This can be then used later to allow skipping the sdcard backup in favor of the recovery words backup in the BitBox02 setup wizard. Since this feature is only possible since firmware v9.13.0, one must first check if `versionInfo.canBackupWithRecoveryWords` is true before using the recovery words method.
1 parent eb4af2f commit ad9bbfc

File tree

4 files changed

+43
-11
lines changed

4 files changed

+43
-11
lines changed

backend/devices/bitbox02/handlers/handlers.go

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,21 @@ func (handlers *Handlers) postSetPassword(r *http.Request) (interface{}, error)
161161
}
162162

163163
func (handlers *Handlers) postCreateBackup(r *http.Request) (interface{}, error) {
164-
if err := handlers.device.CreateBackup(); err != nil {
165-
return maybeBB02Err(err, handlers.log), nil
164+
var backupMethod string
165+
if err := json.NewDecoder(r.Body).Decode(&backupMethod); err != nil {
166+
return nil, errp.WithStack(err)
167+
}
168+
switch backupMethod {
169+
case "sdcard":
170+
if err := handlers.device.CreateBackup(); err != nil {
171+
return maybeBB02Err(err, handlers.log), nil
172+
}
173+
case "recovery-words":
174+
if err := handlers.device.ShowMnemonic(); err != nil {
175+
return maybeBB02Err(err, handlers.log), nil
176+
}
177+
default:
178+
return map[string]interface{}{"success": false}, nil
166179
}
167180
return map[string]interface{}{"success": true}, nil
168181
}
@@ -284,11 +297,20 @@ func (handlers *Handlers) getVersionHandler(_ *http.Request) (interface{}, error
284297
NewVersion string `json:"newVersion"`
285298
CanUpgrade bool `json:"canUpgrade"`
286299
CanGotoStartupSettings bool `json:"canGotoStartupSettings"`
300+
// If true, creating a backup using the mnemonic recovery words instead of the microSD card
301+
// is supported in the initial setup.
302+
//
303+
// If false, the backup must be performed using the microSD card in the initial setup.
304+
//
305+
// This has no influence over whether one can display the recovery words after the initial
306+
// setup - that is always possible regardless of this value.
307+
CanBackupWithRecoveryWords bool `json:"canBackupWithRecoveryWords"`
287308
}{
288-
CurrentVersion: currentVersion.String(),
289-
NewVersion: newVersion.String(),
290-
CanUpgrade: newVersion.AtLeast(currentVersion) && currentVersion.String() != newVersion.String(),
291-
CanGotoStartupSettings: currentVersion.AtLeast(semver.NewSemVer(9, 6, 0)),
309+
CurrentVersion: currentVersion.String(),
310+
NewVersion: newVersion.String(),
311+
CanUpgrade: newVersion.AtLeast(currentVersion) && currentVersion.String() != newVersion.String(),
312+
CanGotoStartupSettings: currentVersion.AtLeast(semver.NewSemVer(9, 6, 0)),
313+
CanBackupWithRecoveryWords: currentVersion.AtLeast(semver.NewSemVer(9, 13, 0)),
292314
}, nil
293315
}
294316

frontends/web/src/api/bitbox02.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ export type VersionInfo = {
6868
currentVersion: string;
6969
canUpgrade: boolean;
7070
canGotoStartupSettings: boolean;
71+
// If true, creating a backup using the mnemonic recovery words instead of the microSD card
72+
// is supported in the initial setup.
73+
//
74+
// If false, the backup must be performed using the microSD card in the initial setup.
75+
//
76+
// This has no influence over whether one can display the recovery words after the initial
77+
// setup - that is always possible regardless of this value.
78+
canBackupWithRecoveryWords: boolean;
7179
}
7280

7381
export const getVersion = (
@@ -96,10 +104,13 @@ export const checkBackup = (
96104
return apiPost(`devices/bitbox02/${deviceID}/backups/check`, { silent });
97105
};
98106

107+
// The 'recovery-words' method is only allowed if `canBackupWithRecoveryWords` returned by
108+
// `getVersion()` is true.
99109
export const createBackup = (
100110
deviceID: string,
111+
method: 'sdcard' | 'recovery-words',
101112
): Promise<FailResponse | SuccessResponse> => {
102-
return apiPost(`devices/bitbox02/${deviceID}/backups/create`);
113+
return apiPost(`devices/bitbox02/${deviceID}/backups/create`, method);
103114
};
104115

105116
export const restoreBackup = (

frontends/web/src/routes/device/bitbox02/bitbox02.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,7 @@ class BitBox02 extends Component<Props, State> {
309309
title: this.props.t('bitbox02Interact.confirmDate'),
310310
text: this.props.t('bitbox02Interact.confirmDateText'),
311311
} });
312-
313-
createBackup(this.props.deviceID)
312+
createBackup(this.props.deviceID, 'sdcard')
314313
.then(() => this.setState({ creatingBackup: false, waitDialog: undefined }))
315314
.catch(() => {
316315
alertUser(this.props.t('bitbox02Wizard.createBackupFailed'), { asDialog: false });

frontends/web/src/routes/device/bitbox02/createbackup.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export const Create = ({ deviceID }: TProps) => {
3434

3535
const createBackup = () => {
3636
setCreatingBackup(true);
37-
createBackupAPI(deviceID)
37+
createBackupAPI(deviceID, 'sdcard')
3838
.then((result) => {
3939
setCreatingBackup(false);
4040
setDisabled(false);
@@ -80,4 +80,4 @@ export const Create = ({ deviceID }: TProps) => {
8080
)}
8181
</span>
8282
);
83-
};
83+
};

0 commit comments

Comments
 (0)