dashboard/middleware/authenticated.js

167 lines
4.0 KiB
JavaScript

import { NORMAN } from '@/config/types';
import { findBy } from '@/utils/array';
import { SETUP } from '@/config/query-params';
import { get } from '@/utils/object';
import { ClusterNotFoundError } from '@/utils/error';
import { applyProducts } from '@/store/type-map';
import { NAME as EXPLORER } from '@/config/product/explorer';
let beforeEachSetup = false;
function setProduct(store, to) {
let product = to.params?.product;
if ( !product ) {
const match = to.name?.match(/^c-cluster-([^-]+)/);
if ( match ) {
product = match[1];
}
}
if ( !product ) {
product = EXPLORER;
}
store.commit('setProduct', product);
}
export default async function({
route, app, store, redirect, req, isDev
}) {
if ( route.path && typeof route.path === 'string') {
// Ignore webpack hot module reload requests
if ( route.path.startsWith('/__webpack_hmr/') ) {
return;
}
// Ignore the error page
if ( route.path.startsWith('/fail-whale') ) {
return;
}
}
// Initial ?setup=admin-password can technically be on any route
const initialPass = route.query[SETUP];
if ( initialPass ) {
const ok = await tryInitialSetup(store, initialPass, isDev);
if ( ok ) {
redirect(302, `/auth/setup?${ SETUP }=${ escape(initialPass) }`);
} else {
redirect(302, '/auth/login');
}
}
// Make sure you're actually logged in
if ( store.getters['auth/enabled'] !== false && !store.getters['auth/loggedIn'] ) {
try {
const principals = await store.dispatch('rancher/findAll', {
type: NORMAN.PRINCIPAL,
opt: { url: '/v3/principals' }
});
const me = findBy(principals, 'me', true);
store.commit('auth/hasAuth', true);
store.commit('auth/loggedInAs', me.id);
} catch (e) {
const status = e?._status;
if ( status === 404 ) {
store.commit('auth/hasAuth', false);
} else {
store.commit('auth/hasAuth', true);
if ( status === 401 ) {
if ( process.env.dev ) {
redirect(302, '/auth/login');
} else {
redirect(302, '/login');
}
} else {
store.commit('setError', e);
console.log(JSON.stringify(e)); // eslint-disable-line no-console
}
}
return;
}
}
// Load stuff
await applyProducts(store);
// Setup a beforeEach hook once to keep track of the current product
if ( !beforeEachSetup ) {
beforeEachSetup = true;
store.app.router.beforeEach((to, from, next) => {
setProduct(store, to);
next();
});
// Call it for the initial pageload
setProduct(store, route);
}
try {
let clusterId = get(route, 'params.cluster');
if ( clusterId ) {
// Run them in parallel
await Promise.all([
await store.dispatch('loadManagement'),
await store.dispatch('loadCluster', clusterId),
]);
} else {
await store.dispatch('loadManagement');
clusterId = store.getters['defaultClusterId']; // This needs the cluster list, so no parallel
if ( clusterId ) {
await store.dispatch('loadCluster', clusterId);
}
}
} catch (e) {
if ( e instanceof ClusterNotFoundError ) {
redirect(302, '/clusters');
} else {
store.commit('setError', e);
redirect(302, '/fail-whale');
}
}
}
async function tryInitialSetup(store, password, isDev) {
try {
const firstLogin = await store.dispatch('rancher/find', {
type: NORMAN.SETTING,
id: 'first-login',
opt: { url: '/v3/settings/first-login' }
});
if ( isDev ) {
// Ignore first-login for dev
} else if ( !firstLogin || firstLogin.value !== 'true' ) {
// Require first-login to be set for prod
return false;
}
const res = await store.dispatch('auth/login', {
provider: 'local',
body: {
username: 'admin',
password
},
});
return res === true;
} catch (e) {
console.error('Error trying initial setup', e); // eslint-disable-line no-console
return false;
}
}