@truenas/api-client 10.0.0 → 11.0.0

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.
package/README.md CHANGED
@@ -84,6 +84,22 @@ errors with an `AuthError` carrying an `AuthErrorCode`, plus the refusing
84
84
  `response` when middleware answered with one (`response.response_type` tells
85
85
  `EXPIRED`, `DENIED` and `REDIRECT` apart from `AUTH_ERR`).
86
86
 
87
+ A wrong one-time code errors from `loginWithOtp(code)`; it never emits
88
+ `OTP_REQUIRED`. Releases differ on whether the login survives a wrong code
89
+ (25.10 keeps it for up to three tries, 27 and later drop it), and the API
90
+ version does not tell them apart, so read `loginPending` off the error instead:
91
+
92
+ ```typescript
93
+ client.authenticator.loginWithOtp(code).subscribe({
94
+ next: () => { /* signed in */ },
95
+ error: (err: unknown) => {
96
+ if (!(err instanceof AuthError)) throw err;
97
+ if (err.loginPending) askForAnotherCode(); // OtpAuthFailed, login still open
98
+ else startOverWithPassword(); // OtpAuthFailed or OtpLoginNotPending
99
+ },
100
+ });
101
+ ```
102
+
87
103
  ## Calls
88
104
 
89
105
  ```typescript
@@ -2202,6 +2202,7 @@ var TrueNasAuthMechanism = /* @__PURE__ */ ((TrueNasAuthMechanism2) => {
2202
2202
  var AuthErrorCode = /* @__PURE__ */ ((AuthErrorCode2) => {
2203
2203
  AuthErrorCode2["PasswordAuthFailed"] = "PASSWORD_AUTH_FAILED";
2204
2204
  AuthErrorCode2["OtpAuthFailed"] = "OTP_AUTH_FAILED";
2205
+ AuthErrorCode2["OtpLoginNotPending"] = "OTP_LOGIN_NOT_PENDING";
2205
2206
  AuthErrorCode2["ApiKeyAuthFailed"] = "API_KEY_AUTH_FAILED";
2206
2207
  AuthErrorCode2["TokenAuthFailed"] = "TOKEN_AUTH_FAILED";
2207
2208
  AuthErrorCode2["LoginSuperseded"] = "LOGIN_SUPERSEDED";
@@ -2215,11 +2216,12 @@ var AuthError = class _AuthError extends Error {
2215
2216
  * `AUTH_ERR`; the code alone says only which mechanism failed. Absent when the login
2216
2217
  * never got an answer of that kind (an error frame, or a superseded login).
2217
2218
  */
2218
- constructor(code, message, response) {
2219
+ constructor(code, message, response, options = {}) {
2219
2220
  super(message);
2220
2221
  this.code = code;
2221
2222
  this.response = response;
2222
2223
  this.name = "AuthError";
2224
+ this.loginPending = options.loginPending ?? false;
2223
2225
  Object.setPrototypeOf(this, _AuthError.prototype);
2224
2226
  }
2225
2227
  };
@@ -2760,6 +2762,7 @@ var throwOnAuthenticationFailure = (code, message) => rxjs.switchMap((response)
2760
2762
  }
2761
2763
  return rxjs.of(response);
2762
2764
  });
2765
+ var isOtpLoginNotPending = (error) => error.data?.errname === "EINVAL" && typeof error.data.reason === "string" && error.data.reason.includes("OTP_TOKEN: no authentication in progress");
2763
2766
  var TrueNasAuthenticator = class _TrueNasAuthenticator {
2764
2767
  constructor(connection, version) {
2765
2768
  this.connection = connection;
@@ -2943,6 +2946,19 @@ var TrueNasAuthenticator = class _TrueNasAuthenticator {
2943
2946
  rxjs.take(1)
2944
2947
  );
2945
2948
  }
2949
+ /**
2950
+ * The second step of a two-factor login, after `loginWithUserPass` answered
2951
+ * `OTP_REQUIRED`.
2952
+ *
2953
+ * Emits the answer when the code is accepted (`SUCCESS`), or when middleware
2954
+ * refuses the account outright (`EXPIRED`, `DENIED`, `REDIRECT`); never
2955
+ * `OTP_REQUIRED`. A refused code errors with `AuthError`, the same way on
2956
+ * every release:
2957
+ *
2958
+ * - `OtpAuthFailed` with `loginPending: true`: ask for another code.
2959
+ * - `OtpAuthFailed` with `loginPending: false`: start over with the password.
2960
+ * - `OtpLoginNotPending`: no login was waiting for a code; start over.
2961
+ */
2946
2962
  loginWithOtp(code) {
2947
2963
  const { sentDuring, callerInitiated } = this.beginLogin();
2948
2964
  let answered = false;
@@ -2962,6 +2978,12 @@ var TrueNasAuthenticator = class _TrueNasAuthenticator {
2962
2978
  }),
2963
2979
  rxjs.map((msg) => {
2964
2980
  if (msg.error) {
2981
+ if (isOtpLoginNotPending(msg.error)) {
2982
+ throw new AuthError(
2983
+ "OTP_LOGIN_NOT_PENDING" /* OtpLoginNotPending */,
2984
+ "TrueNAS is no longer waiting for a one-time passcode for this login. Please sign in with your password again."
2985
+ );
2986
+ }
2965
2987
  const errorMessage = getApiErrorMessage(
2966
2988
  msg.error,
2967
2989
  "Authentication failed"
@@ -2970,6 +2992,23 @@ var TrueNasAuthenticator = class _TrueNasAuthenticator {
2970
2992
  }
2971
2993
  return msg.result;
2972
2994
  }),
2995
+ // A wrong code is answered differently by release, and the API version
2996
+ // does not say which: 25.10 answers `OTP_REQUIRED` and keeps the login
2997
+ // for another code, 27+ answers `AUTH_ERR` and drops it. Both are the
2998
+ // same failure to the caller, told apart only by `loginPending`, so no
2999
+ // caller has to read `OTP_REQUIRED` as "wrong code".
3000
+ rxjs.map((res) => {
3001
+ const loginPending = res?.response_type === "OTP_REQUIRED" /* OtpRequired */;
3002
+ if (loginPending || res?.response_type === "AUTH_ERR" /* AuthErr */) {
3003
+ throw new AuthError(
3004
+ "OTP_AUTH_FAILED" /* OtpAuthFailed */,
3005
+ loginPending ? "TrueNAS rejected the one-time passcode. Please verify it and try again." : "TrueNAS rejected the one-time passcode. Please sign in with your password again.",
3006
+ res,
3007
+ { loginPending }
3008
+ );
3009
+ }
3010
+ return res;
3011
+ }),
2973
3012
  rxjs.tap((res) => {
2974
3013
  if (res?.response_type === "SUCCESS" /* Success */) {
2975
3014
  this.assertNotSuperseded(sentDuring);
@@ -2977,10 +3016,6 @@ var TrueNasAuthenticator = class _TrueNasAuthenticator {
2977
3016
  this.authenticated$.next(true);
2978
3017
  }
2979
3018
  }),
2980
- throwOnAuthenticationFailure(
2981
- "OTP_AUTH_FAILED" /* OtpAuthFailed */,
2982
- "TrueNAS authentication failed. Please verify your one-time passcode and try again."
2983
- ),
2984
3019
  rxjs.finalize(() => {
2985
3020
  this.endLogin(sentDuring, callerInitiated, answered);
2986
3021
  }),
@@ -4844,5 +4879,5 @@ exports.v25_10_4_exports = v25_10_4_exports;
4844
4879
  exports.v25_10_5_exports = v25_10_5_exports;
4845
4880
  exports.v27_0_0_exports = v27_0_0_exports;
4846
4881
  exports.v28_0_0_exports = v28_0_0_exports;
4847
- //# sourceMappingURL=chunk-PWRUBUVD.cjs.map
4848
- //# sourceMappingURL=chunk-PWRUBUVD.cjs.map
4882
+ //# sourceMappingURL=chunk-MQAS7GKB.cjs.map
4883
+ //# sourceMappingURL=chunk-MQAS7GKB.cjs.map