Handle invalidated application keys after auth failures
This commit is contained in:
@@ -67,6 +67,7 @@ export async function logout(store) {
|
||||
application: TRYTON_APPLICATION,
|
||||
},
|
||||
includeKitchen: false,
|
||||
skipAuthFailureHandler: true,
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
|
||||
@@ -183,6 +183,32 @@ function logApiFailure(message, context) {
|
||||
console.error(message, context);
|
||||
}
|
||||
|
||||
function isAuthErrorStatus(status) {
|
||||
return status === 401 || status === 403;
|
||||
}
|
||||
|
||||
function isKitchensPath(path) {
|
||||
return String(path || '').replace(/^\/+/, '').replace(/\/+$/, '') === API_PATHS.kitchens;
|
||||
}
|
||||
|
||||
function shouldInvalidateValidatedSession(store, path, options = {}) {
|
||||
if (options.skipAuthFailureHandler) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!store.session?.applicationKey || !store.session?.hasValidated) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
isKitchensPath(path) ||
|
||||
options.includeKitchen !== false ||
|
||||
path === API_PATHS.items ||
|
||||
path === API_PATHS.locations ||
|
||||
String(path || '').startsWith(`${API_PATHS.items}/`)
|
||||
);
|
||||
}
|
||||
|
||||
export async function apiRequest(store, path, options = {}) {
|
||||
const { config, session, activeKitchen } = store;
|
||||
|
||||
@@ -240,6 +266,9 @@ export async function apiRequest(store, path, options = {}) {
|
||||
method,
|
||||
error,
|
||||
});
|
||||
if (shouldInvalidateValidatedSession(store, path, options)) {
|
||||
window.__loncApp?.handleAuthFailure?.(networkError);
|
||||
}
|
||||
throw networkError;
|
||||
}
|
||||
|
||||
@@ -252,6 +281,15 @@ export async function apiRequest(store, path, options = {}) {
|
||||
status: response.status,
|
||||
payload,
|
||||
});
|
||||
if (
|
||||
isAuthErrorStatus(response.status) &&
|
||||
(
|
||||
shouldInvalidateValidatedSession(store, path, options) ||
|
||||
(store.session?.state === 'connected' && response.status === 403 && isKitchensPath(path))
|
||||
)
|
||||
) {
|
||||
window.__loncApp?.handleAuthFailure?.(apiError);
|
||||
}
|
||||
throw apiError;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+29
@@ -44,6 +44,7 @@ export function bootstrapApp() {
|
||||
store,
|
||||
outlet: document.querySelector('#route-view'),
|
||||
});
|
||||
let authFailureHandled = false;
|
||||
|
||||
function applyKitchens(kitchens) {
|
||||
store.setKitchens(kitchens);
|
||||
@@ -67,6 +68,9 @@ export function bootstrapApp() {
|
||||
} else if (store.isConnected) {
|
||||
await window.__loncApp.refreshKitchens();
|
||||
}
|
||||
if (store.isConnected) {
|
||||
authFailureHandled = false;
|
||||
}
|
||||
renderNav();
|
||||
} catch (error) {
|
||||
renderNav();
|
||||
@@ -82,11 +86,36 @@ export function bootstrapApp() {
|
||||
} else if (store.isConnected) {
|
||||
await window.__loncApp.refreshKitchens();
|
||||
}
|
||||
if (store.isConnected) {
|
||||
authFailureHandled = false;
|
||||
}
|
||||
renderNav();
|
||||
return result;
|
||||
},
|
||||
handleAuthFailure(error) {
|
||||
if (!store.session?.applicationKey || !store.session?.hasValidated || authFailureHandled) {
|
||||
return;
|
||||
}
|
||||
|
||||
authFailureHandled = true;
|
||||
store.markSessionInvalid();
|
||||
renderNav();
|
||||
const status = error?.status || error?.cause?.status;
|
||||
const message =
|
||||
status === 401 || status === 403
|
||||
? 'This application key is no longer accepted by Tryton. Please verify it again or disconnect and create a new key.'
|
||||
: 'Authenticated requests are no longer succeeding. The application key may have been cancelled, or access is being denied by the server. Please reconnect or create a new key.';
|
||||
store.addAlert({
|
||||
type: 'warning',
|
||||
timeout: 0,
|
||||
message,
|
||||
});
|
||||
navigate('/login');
|
||||
window.setTimeout(() => router.render(), 0);
|
||||
},
|
||||
async logout() {
|
||||
await logout(store);
|
||||
authFailureHandled = false;
|
||||
renderNav();
|
||||
navigate('/login');
|
||||
},
|
||||
|
||||
@@ -108,5 +108,18 @@ export function createAppStore() {
|
||||
this.setKitchens([]);
|
||||
this.setActiveKitchen(null);
|
||||
},
|
||||
markSessionInvalid() {
|
||||
if (!this.session) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setSession({
|
||||
...this.session,
|
||||
state: CONNECTION_STATES.invalidKey,
|
||||
hasValidated: true,
|
||||
});
|
||||
this.setKitchens([]);
|
||||
this.setActiveKitchen(null);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -515,6 +515,9 @@ export function labelCreatePageData(store) {
|
||||
...loadLabelDraft(),
|
||||
},
|
||||
async init() {
|
||||
if (!store.isConnected) {
|
||||
return;
|
||||
}
|
||||
await this.loadLocations();
|
||||
this.$watch('form', () => this.persistDraft(), { deep: true });
|
||||
this.$watch('form.stockType', (value) => {
|
||||
@@ -536,6 +539,10 @@ export function labelCreatePageData(store) {
|
||||
}, 250);
|
||||
},
|
||||
async loadLocations() {
|
||||
if (!store.isConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const { flat } = await fetchLocations(store);
|
||||
this.locations = flat;
|
||||
|
||||
@@ -152,6 +152,10 @@ export function stockDetailPageData(store) {
|
||||
level: 'plenty',
|
||||
},
|
||||
async init() {
|
||||
if (!store.isConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { params } = getRouteContext();
|
||||
await runAsyncState(this.state, async () => {
|
||||
this.entry = await getStockEntry(store, params.id);
|
||||
|
||||
@@ -442,9 +442,16 @@ export function stockListPageData(store) {
|
||||
location: '',
|
||||
},
|
||||
async init() {
|
||||
if (!store.isConnected) {
|
||||
return;
|
||||
}
|
||||
await Promise.all([this.loadLocations(), this.loadEntries()]);
|
||||
},
|
||||
async loadEntries() {
|
||||
if (!store.isConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
await runAsyncState(this.state, async () => {
|
||||
const loadedEntries = await listStockEntries(store);
|
||||
this.entries = sortEntries(loadedEntries);
|
||||
@@ -461,6 +468,10 @@ export function stockListPageData(store) {
|
||||
}).catch(() => {});
|
||||
},
|
||||
async loadLocations() {
|
||||
if (!store.isConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const { flat } = await fetchLocations(store);
|
||||
this.locations = flat;
|
||||
|
||||
Reference in New Issue
Block a user