Handle invalidated application keys after auth failures
This commit is contained in:
@@ -67,6 +67,7 @@ export async function logout(store) {
|
|||||||
application: TRYTON_APPLICATION,
|
application: TRYTON_APPLICATION,
|
||||||
},
|
},
|
||||||
includeKitchen: false,
|
includeKitchen: false,
|
||||||
|
skipAuthFailureHandler: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -183,6 +183,32 @@ function logApiFailure(message, context) {
|
|||||||
console.error(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 = {}) {
|
export async function apiRequest(store, path, options = {}) {
|
||||||
const { config, session, activeKitchen } = store;
|
const { config, session, activeKitchen } = store;
|
||||||
|
|
||||||
@@ -240,6 +266,9 @@ export async function apiRequest(store, path, options = {}) {
|
|||||||
method,
|
method,
|
||||||
error,
|
error,
|
||||||
});
|
});
|
||||||
|
if (shouldInvalidateValidatedSession(store, path, options)) {
|
||||||
|
window.__loncApp?.handleAuthFailure?.(networkError);
|
||||||
|
}
|
||||||
throw networkError;
|
throw networkError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,6 +281,15 @@ export async function apiRequest(store, path, options = {}) {
|
|||||||
status: response.status,
|
status: response.status,
|
||||||
payload,
|
payload,
|
||||||
});
|
});
|
||||||
|
if (
|
||||||
|
isAuthErrorStatus(response.status) &&
|
||||||
|
(
|
||||||
|
shouldInvalidateValidatedSession(store, path, options) ||
|
||||||
|
(store.session?.state === 'connected' && response.status === 403 && isKitchensPath(path))
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
window.__loncApp?.handleAuthFailure?.(apiError);
|
||||||
|
}
|
||||||
throw apiError;
|
throw apiError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+29
@@ -44,6 +44,7 @@ export function bootstrapApp() {
|
|||||||
store,
|
store,
|
||||||
outlet: document.querySelector('#route-view'),
|
outlet: document.querySelector('#route-view'),
|
||||||
});
|
});
|
||||||
|
let authFailureHandled = false;
|
||||||
|
|
||||||
function applyKitchens(kitchens) {
|
function applyKitchens(kitchens) {
|
||||||
store.setKitchens(kitchens);
|
store.setKitchens(kitchens);
|
||||||
@@ -67,6 +68,9 @@ export function bootstrapApp() {
|
|||||||
} else if (store.isConnected) {
|
} else if (store.isConnected) {
|
||||||
await window.__loncApp.refreshKitchens();
|
await window.__loncApp.refreshKitchens();
|
||||||
}
|
}
|
||||||
|
if (store.isConnected) {
|
||||||
|
authFailureHandled = false;
|
||||||
|
}
|
||||||
renderNav();
|
renderNav();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
renderNav();
|
renderNav();
|
||||||
@@ -82,11 +86,36 @@ export function bootstrapApp() {
|
|||||||
} else if (store.isConnected) {
|
} else if (store.isConnected) {
|
||||||
await window.__loncApp.refreshKitchens();
|
await window.__loncApp.refreshKitchens();
|
||||||
}
|
}
|
||||||
|
if (store.isConnected) {
|
||||||
|
authFailureHandled = false;
|
||||||
|
}
|
||||||
renderNav();
|
renderNav();
|
||||||
return result;
|
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() {
|
async logout() {
|
||||||
await logout(store);
|
await logout(store);
|
||||||
|
authFailureHandled = false;
|
||||||
renderNav();
|
renderNav();
|
||||||
navigate('/login');
|
navigate('/login');
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -108,5 +108,18 @@ export function createAppStore() {
|
|||||||
this.setKitchens([]);
|
this.setKitchens([]);
|
||||||
this.setActiveKitchen(null);
|
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(),
|
...loadLabelDraft(),
|
||||||
},
|
},
|
||||||
async init() {
|
async init() {
|
||||||
|
if (!store.isConnected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
await this.loadLocations();
|
await this.loadLocations();
|
||||||
this.$watch('form', () => this.persistDraft(), { deep: true });
|
this.$watch('form', () => this.persistDraft(), { deep: true });
|
||||||
this.$watch('form.stockType', (value) => {
|
this.$watch('form.stockType', (value) => {
|
||||||
@@ -536,6 +539,10 @@ export function labelCreatePageData(store) {
|
|||||||
}, 250);
|
}, 250);
|
||||||
},
|
},
|
||||||
async loadLocations() {
|
async loadLocations() {
|
||||||
|
if (!store.isConnected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { flat } = await fetchLocations(store);
|
const { flat } = await fetchLocations(store);
|
||||||
this.locations = flat;
|
this.locations = flat;
|
||||||
|
|||||||
@@ -152,6 +152,10 @@ export function stockDetailPageData(store) {
|
|||||||
level: 'plenty',
|
level: 'plenty',
|
||||||
},
|
},
|
||||||
async init() {
|
async init() {
|
||||||
|
if (!store.isConnected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const { params } = getRouteContext();
|
const { params } = getRouteContext();
|
||||||
await runAsyncState(this.state, async () => {
|
await runAsyncState(this.state, async () => {
|
||||||
this.entry = await getStockEntry(store, params.id);
|
this.entry = await getStockEntry(store, params.id);
|
||||||
|
|||||||
@@ -442,9 +442,16 @@ export function stockListPageData(store) {
|
|||||||
location: '',
|
location: '',
|
||||||
},
|
},
|
||||||
async init() {
|
async init() {
|
||||||
|
if (!store.isConnected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
await Promise.all([this.loadLocations(), this.loadEntries()]);
|
await Promise.all([this.loadLocations(), this.loadEntries()]);
|
||||||
},
|
},
|
||||||
async loadEntries() {
|
async loadEntries() {
|
||||||
|
if (!store.isConnected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await runAsyncState(this.state, async () => {
|
await runAsyncState(this.state, async () => {
|
||||||
const loadedEntries = await listStockEntries(store);
|
const loadedEntries = await listStockEntries(store);
|
||||||
this.entries = sortEntries(loadedEntries);
|
this.entries = sortEntries(loadedEntries);
|
||||||
@@ -461,6 +468,10 @@ export function stockListPageData(store) {
|
|||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
},
|
},
|
||||||
async loadLocations() {
|
async loadLocations() {
|
||||||
|
if (!store.isConnected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { flat } = await fetchLocations(store);
|
const { flat } = await fetchLocations(store);
|
||||||
this.locations = flat;
|
this.locations = flat;
|
||||||
|
|||||||
Reference in New Issue
Block a user