motion-master-client 0.0.423 → 0.0.424

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3365,21 +3365,27 @@ class MotionMasterReqResClient {
3365
3365
  * attempt will fail unless the user logs out beforehand.
3366
3366
  *
3367
3367
  * @param deviceRef - The reference to the device to which the login command will be sent.
3368
- * @param username - The optional username used for logging in to the SMM. If not provided, it will be treated as an empty string.
3369
- * @param password - The password used for logging in to the SMM.
3368
+ * @param username - The name of the user who logs in, 4 to 24 printable ASCII characters. It tells who configured
3369
+ * the SMM, so pass the real user's name.
3370
+ * @param password - The password used for logging in to the SMM, 1 to 24 printable ASCII characters.
3370
3371
  * @param commandTimeout - The timeout in milliseconds for the command to complete.
3371
3372
  * @param responsePollingInterval - The interval in milliseconds between polling for the response.
3372
3373
  *
3373
- * @throws {Error} If the login attempt fails.
3374
+ * @throws {Error} If the username or the password is not valid, in which case nothing is sent, or if the login
3375
+ * attempt fails.
3374
3376
  *
3375
3377
  * @remarks
3376
3378
  * If the device is already logged in, the next login attempt will fail unless the user logs out first.
3377
3379
  */
3378
3380
  loginToSmmForParameterDownload(deviceRef, username, password, commandTimeout = 5000, responsePollingInterval = 500) {
3379
- const command = (0, os_command_1.createSmmAcyclicHandlerOsCommand)(os_command_1.SmmAcyclicHandlerSubcommandId.PARAMETER_DOWNLOAD_LOGIN);
3380
- const content = (0, smm_1.packSmmCredentials)(username, password);
3381
- // @ts-ignore
3382
- return this.runOsCommandAndWriteFsBuffer(deviceRef, command, content, commandTimeout, responsePollingInterval).pipe((0, operators_1.last)(), (0, operators_1.map)((response) => {
3381
+ return (0, rxjs_1.defer)(() => {
3382
+ (0, smm_1.assertValidSmmCredential)(username, 'Username', smm_1.SMM_USERNAME_MIN_LENGTH);
3383
+ (0, smm_1.assertValidSmmCredential)(password, 'Password');
3384
+ const command = (0, os_command_1.createSmmAcyclicHandlerOsCommand)(os_command_1.SmmAcyclicHandlerSubcommandId.PARAMETER_DOWNLOAD_LOGIN);
3385
+ const content = (0, smm_1.packSmmCredentials)(username, password);
3386
+ // @ts-ignore
3387
+ return this.runOsCommandAndWriteFsBuffer(deviceRef, command, content, commandTimeout, responsePollingInterval);
3388
+ }).pipe((0, operators_1.last)(), (0, operators_1.map)((response) => {
3383
3389
  if (response.request !== 'succeeded') {
3384
3390
  throw new Error(`Login to SMM for parameter download failed: ${(0, os_command_1.describeOsCommandFailure)(response)}.`);
3385
3391
  }
@@ -3393,21 +3399,27 @@ class MotionMasterReqResClient {
3393
3399
  * attempt will fail unless the user logs out beforehand.
3394
3400
  *
3395
3401
  * @param deviceRef - The reference to the device to which the login command will be sent.
3396
- * @param username - The optional username used for logging in to the SMM. If not provided, it will be treated as an empty string.
3397
- * @param password - The password used for logging in to the SMM.
3402
+ * @param username - The name of the user who logs in, 4 to 24 printable ASCII characters. It tells who configured
3403
+ * the SMM, so pass the real user's name.
3404
+ * @param password - The password used for logging in to the SMM, 1 to 24 printable ASCII characters.
3398
3405
  * @param commandTimeout - The timeout in milliseconds for the command to complete.
3399
3406
  * @param responsePollingInterval - The interval in milliseconds between polling for the response.
3400
3407
  *
3401
- * @throws {Error} If the login attempt fails.
3408
+ * @throws {Error} If the username or the password is not valid, in which case nothing is sent, or if the login
3409
+ * attempt fails.
3402
3410
  *
3403
3411
  * @remarks
3404
3412
  * If the device is already logged in, the next login attempt will fail unless the user logs out first.
3405
3413
  */
3406
3414
  loginToSmmForSoftwareUpdate(deviceRef, username, password, commandTimeout = 10000, responsePollingInterval = 500) {
3407
- const command = (0, os_command_1.createSmmAcyclicHandlerOsCommand)(os_command_1.SmmAcyclicHandlerSubcommandId.SOFTWARE_UPDATE_LOGIN);
3408
- const content = (0, smm_1.packSmmCredentials)(username, password);
3409
- // @ts-ignore
3410
- return this.runOsCommandAndWriteFsBuffer(deviceRef, command, content, commandTimeout, responsePollingInterval).pipe((0, operators_1.last)(), (0, operators_1.map)((response) => {
3415
+ return (0, rxjs_1.defer)(() => {
3416
+ (0, smm_1.assertValidSmmCredential)(username, 'Username', smm_1.SMM_USERNAME_MIN_LENGTH);
3417
+ (0, smm_1.assertValidSmmCredential)(password, 'Password');
3418
+ const command = (0, os_command_1.createSmmAcyclicHandlerOsCommand)(os_command_1.SmmAcyclicHandlerSubcommandId.SOFTWARE_UPDATE_LOGIN);
3419
+ const content = (0, smm_1.packSmmCredentials)(username, password);
3420
+ // @ts-ignore
3421
+ return this.runOsCommandAndWriteFsBuffer(deviceRef, command, content, commandTimeout, responsePollingInterval);
3422
+ }).pipe((0, operators_1.last)(), (0, operators_1.map)((response) => {
3411
3423
  if (response.request !== 'succeeded') {
3412
3424
  throw new Error(`Login to SMM for software update failed: ${(0, os_command_1.describeOsCommandFailure)(response)}.`);
3413
3425
  }
@@ -3455,38 +3467,46 @@ class MotionMasterReqResClient {
3455
3467
  * Changes the SMM password for the specified device.
3456
3468
  *
3457
3469
  * The sequence is: write `<newPassword><oldPassword>` to the fs-buffer and run CHANGE_PASSWORD. If, and only if, the
3458
- * SMM accepts the change, log out from the SMM, trigger an SMM restart (unless `triggerRestart` is false) and then
3459
- * wait `rebootDelay` milliseconds before completing, so the next SMM command a caller issues does not land in the
3460
- * reboot.
3470
+ * SMM accepts the change, log in for parameter download with the new password until the SMM accepts the login. The
3471
+ * SMM is not restarted, because it does not need a restart to use a new password.
3461
3472
  *
3462
- * The logout has to come before the restart. When the SMM is restarted while the session is still open, it stores
3463
- * neither the new nor the old password, although it accepted the change, and only the master password gets in again.
3464
- * After an accepted change the session is therefore closed; log in again with the new password to continue.
3473
+ * The SMM acknowledges CHANGE_PASSWORD before it stores the new password. It writes the password to its EEPROM in the
3474
+ * background, refuses every login while the write runs, and closes the session itself when the write is done. A
3475
+ * restart during the write leaves a stored password that the SMM discards at boot, so neither the new nor the old
3476
+ * password logs in and only the master password gets in again. A logout does not wait for the write either. The
3477
+ * first login that the SMM accepts with the new password is therefore the proof that the write is done and that the
3478
+ * SMM stored the intended password.
3479
+ *
3480
+ * After the call, a session for parameter download is open, logged in with the new password, so a caller can go on
3481
+ * with SMM commands without a new login. Log out with {@link logoutFromSmm} when done.
3465
3482
  *
3466
3483
  * @param deviceRef - A reference to the target device.
3484
+ * @param username - The name of the logged-in user, 4 to 24 printable ASCII characters, for the login with the new
3485
+ * password. Pass the same name the user logged in with: it tells who configured the SMM.
3467
3486
  * @param oldPassword - The current SMM password.
3468
3487
  * @param newPassword - The new password to set for the SMM, 4 to 24 printable ASCII characters.
3469
3488
  * @param commandTimeout - The timeout in milliseconds for the CHANGE_PASSWORD command. On firmware below 5.2.0 it also
3470
- * covers the FoE write of the fs-buffer, because the buffer is written before the command is issued. If it runs out
3471
- * while the SMM is still storing the password, the client gives up, the SMM is not restarted, and the result of the
3472
- * change is unknown. Defaults to 12000: the drive gives up on the SMM after 10 s, so do not set it lower, and do not
3473
- * retry after a timeout, the SMM may still be running the change.
3489
+ * covers the FoE write of the fs-buffer, because the buffer is written before the command is issued. Defaults to
3490
+ * 12000: the drive gives up on the SMM after 10 s, so do not set it lower. If it runs out, the result of the change
3491
+ * is unknown. Do not retry after a timeout, because the SMM may still be running the change.
3474
3492
  * @param responsePollingInterval - The interval in milliseconds between polling for the response.
3475
- * @param triggerRestart - Whether to restart the SMM after an accepted change and the logout. Defaults to true. The
3476
- * firmware requires a restart after a password change, so pass false only if you restart the SMM yourself (with
3477
- * {@link triggerSmmRestart}) before issuing any other SMM command. The logout happens either way, so your restart
3478
- * comes after it.
3479
- * @param rebootDelay - How long to wait after the restart command completes, in milliseconds, before the observable
3480
- * completes. Defaults to 3000, the `SMM_REBOOT_DELAY` the firmware test reference uses. Ignored when
3481
- * `triggerRestart` is false.
3482
- *
3483
- * @throws {Error} If a password is not 1 (old) or 4 (new) to 24 printable ASCII characters, if the SMM rejects the
3484
- * change (the SMM is then not restarted and the session stays open), if the logout after an accepted change fails
3485
- * (the SMM is then not restarted), or if the restart fails.
3493
+ * @param verifyTimeout - How long to keep trying the login with the new password, in milliseconds, counted from the
3494
+ * accepted change. Defaults to 10000.
3495
+ * @param verifyInterval - The pause in milliseconds between two login attempts with the new password. Defaults to
3496
+ * 500.
3497
+ *
3498
+ * @throws {Error} If the username is not 4, or a password not 1 (old) or 4 (new), to 24 printable ASCII characters
3499
+ * (nothing is sent then), if the SMM rejects the change (the session then stays open), or if the SMM does not
3500
+ * accept a login with the new password within `verifyTimeout`.
3486
3501
  *
3487
3502
  * @remarks
3488
- * Completion means the SMM accepted the change. It does not prove that the SMM stored the intended password; only a
3489
- * login with the new password does.
3503
+ * Completion means the SMM accepted a login with the new password, so the new password is stored.
3504
+ *
3505
+ * When the SMM does not accept the new password within `verifyTimeout`, the stored password is unknown. Do not run
3506
+ * the change again. Try to log in with the new password, then with the old one.
3507
+ *
3508
+ * Do not restart the SMM, and do not power the device off, until the call completes. Either one during the write
3509
+ * leaves a stored password that the SMM discards.
3490
3510
  *
3491
3511
  * Rules a caller has to follow, because the SMM and the drive do not enforce them for you:
3492
3512
  *
@@ -3498,28 +3518,32 @@ class MotionMasterReqResClient {
3498
3518
  * - When the SMM rejects the change, the response does not say why: a wrong old password, a missing or expired
3499
3519
  * session and an SMM that is still booting all produce the same "the SMM rejected the request (status 2)".
3500
3520
  */
3501
- changeSmmPassword(deviceRef, oldPassword, newPassword, commandTimeout = 12000, responsePollingInterval = 500, triggerRestart = true, rebootDelay = 3000) {
3521
+ changeSmmPassword(deviceRef, username, oldPassword, newPassword, commandTimeout = 12000, responsePollingInterval = 500, verifyTimeout = 10000, verifyInterval = 500) {
3502
3522
  return (0, rxjs_1.defer)(() => {
3503
- (0, smm_1.assertValidSmmPassword)(oldPassword, 'Old password');
3504
- (0, smm_1.assertValidSmmPassword)(newPassword, 'New password', smm_1.SMM_PASSWORD_MIN_LENGTH);
3523
+ (0, smm_1.assertValidSmmCredential)(username, 'Username', smm_1.SMM_USERNAME_MIN_LENGTH);
3524
+ (0, smm_1.assertValidSmmCredential)(oldPassword, 'Old password');
3525
+ (0, smm_1.assertValidSmmCredential)(newPassword, 'New password', smm_1.SMM_PASSWORD_MIN_LENGTH);
3505
3526
  const command = (0, os_command_1.createSmmAcyclicHandlerOsCommand)(os_command_1.SmmAcyclicHandlerSubcommandId.CHANGE_PASSWORD);
3506
3527
  const content = (0, smm_1.packSmmChangePassword)(newPassword, oldPassword);
3507
3528
  // @ts-ignore
3508
3529
  return this.runOsCommandAndWriteFsBuffer(deviceRef, command, content, commandTimeout, responsePollingInterval);
3509
3530
  }).pipe((0, operators_1.last)(), (0, operators_1.concatMap)((response) => {
3510
3531
  if (response.request !== 'succeeded') {
3511
- throw new Error(`Changing SMM password failed: ${(0, os_command_1.describeOsCommandFailure)(response)}. The password was not changed and the SMM was not restarted.`);
3512
- }
3513
- // Log out before the restart. A restart while the session is still open makes the SMM store neither the new
3514
- // nor the old password, although it accepted the change (reproduced on firmware v5.6.6, issue #185).
3515
- const logout$ = this.logoutFromSmm(deviceRef).pipe((0, operators_1.catchError)((err) => (0, rxjs_1.throwError)(() => {
3516
- var _a;
3517
- return new Error(`The SMM accepted the password change, but the logout failed, so the SMM was not restarted. Log out and restart the SMM before using the new password. ${(_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err}`);
3518
- })), (0, operators_1.last)(null, undefined));
3519
- if (!triggerRestart) {
3520
- return logout$;
3532
+ throw new Error(`Changing SMM password failed: ${(0, os_command_1.describeOsCommandFailure)(response)}. The password was not changed.`);
3521
3533
  }
3522
- return logout$.pipe((0, operators_1.concatMap)(() => this.triggerSmmRestart(deviceRef).pipe((0, operators_1.catchError)((err) => (0, rxjs_1.throwError)(() => { var _a; return new Error(`The SMM accepted the password change, but the restart failed. ${(_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err}`); })), (0, operators_1.last)(null, undefined))), (0, operators_1.concatMap)(() => (0, rxjs_1.timer)(rebootDelay)));
3534
+ // The SMM acknowledges the change before it writes the password to its EEPROM, and refuses logins until the
3535
+ // write is done. A restart during the write makes the SMM discard the stored password (issue #185), so the
3536
+ // first accepted login with the new password is what ends the write, not a logout or a delay. That login's
3537
+ // session stays open for the caller.
3538
+ const deadline = Date.now() + verifyTimeout;
3539
+ return (0, rxjs_1.defer)(() => this.loginToSmmForParameterDownload(deviceRef, username, newPassword, undefined, responsePollingInterval)).pipe((0, operators_1.retry)({
3540
+ delay: (err) => Date.now() + verifyInterval < deadline
3541
+ ? (0, rxjs_1.timer)(verifyInterval)
3542
+ : (0, rxjs_1.throwError)(() => {
3543
+ var _a;
3544
+ return new Error(`The SMM accepted the password change, but did not accept a login with the new password within ${verifyTimeout} ms, so the stored password is unknown. Do not change the password again; try to log in with the new password, then with the old one. ${(_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err}`);
3545
+ }),
3546
+ }), (0, operators_1.last)(null, undefined));
3523
3547
  }), (0, operators_1.last)(null, undefined), (0, operators_1.map)(() => undefined));
3524
3548
  }
3525
3549
  /**