Fix login issues

- Properly clear secure token
- Better error messages
This commit is contained in:
Oliver Walters
2026-07-06 22:55:46 +10:00
parent cb6b5a437d
commit 1b072174ff
3 changed files with 55 additions and 12 deletions
+2 -6
View File
@@ -471,11 +471,7 @@ class InvenTreeAPI {
if (!response.successful()) { if (!response.successful()) {
debug("Server returned invalid response: ${response.statusCode}"); debug("Server returned invalid response: ${response.statusCode}");
showStatusCodeError( showStatusCodeError(apiUrl, response.statusCode, details: response.data);
apiUrl,
response.statusCode,
details: response.data.toString(),
);
return false; return false;
} }
@@ -1535,7 +1531,7 @@ class InvenTreeAPI {
showStatusCodeError( showStatusCodeError(
url, url,
_response.statusCode, _response.statusCode,
details: response.data.toString(), details: response.data,
); );
} }
} }
+8 -3
View File
@@ -112,9 +112,11 @@ class UserProfileDBManager {
profile.token = secureToken; profile.token = secureToken;
} else if (profile.token.isNotEmpty) { } else if (profile.token.isNotEmpty) {
// Legacy profile - migrate its plaintext token into secure storage, // Legacy profile - migrate its plaintext token into secure storage,
// and strip it from the Sembast record on next write // and strip it from the Sembast record now. Must use put() (full
// replace) rather than update() (merge), otherwise the stale legacy
// "token" field survives and gets re-migrated on every future read.
await _saveToken(key, profile.token); await _saveToken(key, profile.token);
await store.record(key).update(await _db, profile.toJson()); await store.record(key).put(await _db, profile.toJson());
} }
return profile; return profile;
@@ -185,7 +187,10 @@ class UserProfileDBManager {
return result; return result;
} }
await store.record(profile.key).update(await _db, profile.toJson()); // put() (full replace) rather than update() (merge) - a legacy record's
// stale "token" field must not survive a write, or it will be
// re-migrated into secure storage on the next read (see _loadToken)
await store.record(profile.key).put(await _db, profile.toJson());
await _saveToken(profile.key!, profile.token); await _saveToken(profile.key!, profile.token);
return true; return true;
+45 -3
View File
@@ -310,19 +310,61 @@ Future<void> showServerError(
Future<void> showStatusCodeError( Future<void> showStatusCodeError(
String url, String url,
int status, { int status, {
String details = "", dynamic details,
}) async { }) async {
String msg = statusCodeToString(status); String msg = statusCodeToString(status);
String extra = url + "\n" + "${L10().statusCode}: ${status}"; String extra = url + "\n" + "${L10().statusCode}: ${status}";
if (details.isNotEmpty) { String errorDetails = extractErrorDetails(details);
if (errorDetails.isNotEmpty) {
extra += "\n"; extra += "\n";
extra += details; extra += errorDetails;
} }
showServerError(url, msg, extra); showServerError(url, msg, extra);
} }
/*
* Attempt to extract a human-readable error message from API response data.
* The server commonly returns error information under a "detail", "error"
* or "errors" key - prefer displaying that over the raw JSON.
* Falls back to displaying the raw data as a list of key : value pairs.
*/
String extractErrorDetails(dynamic data) {
if (data is Map) {
for (final key in ["detail", "error", "errors"]) {
var value = data[key];
if (value == null) {
continue;
}
if (value is List) {
return value.map((e) => e.toString()).join("\n");
}
return value.toString();
}
if (data.isNotEmpty) {
return data.entries.map((e) => "${e.key}: ${e.value}").join("\n");
}
return "";
}
if (data is List && data.isNotEmpty) {
return data.map((e) => e.toString()).join("\n");
}
if (data is String) {
return data;
}
return "";
}
/* /*
* Provide a human-readable descriptor for a particular error code * Provide a human-readable descriptor for a particular error code
*/ */