🔀 Merge pull request #171 from Lissy93/FEATURE/granular-access-165
[FEATURE] Granular User Access Fixes #165
This commit is contained in:
@@ -102,7 +102,7 @@ export default {
|
||||
methods: {
|
||||
shouldAllowWriteToDisk() {
|
||||
const { appConfig } = this.config;
|
||||
return appConfig.allowConfigEdit !== false && isUserAdmin(appConfig.auth);
|
||||
return appConfig.allowConfigEdit !== false && isUserAdmin();
|
||||
},
|
||||
save() {
|
||||
if (this.saveMode === 'local' || !this.allowWriteToDisk) {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
:rows="displayData.rows"
|
||||
:color="displayData.color"
|
||||
:customStyles="displayData.customStyles"
|
||||
v-if="isSectionVisibleToUser()"
|
||||
>
|
||||
<div v-if="!items || items.length < 1" class="no-items">
|
||||
No Items to Show Yet
|
||||
@@ -51,6 +52,7 @@
|
||||
import Item from '@/components/LinkItems/Item.vue';
|
||||
import Collapsable from '@/components/LinkItems/Collapsable.vue';
|
||||
import IframeModal from '@/components/LinkItems/IframeModal.vue';
|
||||
import { getCurrentUser, isLoggedInAsGuest } from '@/utils/Auth';
|
||||
|
||||
export default {
|
||||
name: 'ItemGroup',
|
||||
@@ -85,6 +87,9 @@ export default {
|
||||
? `grid-template-rows: repeat(${this.displayData.itemCountY}, 1fr);` : '';
|
||||
return styles;
|
||||
},
|
||||
currentUser() {
|
||||
return getCurrentUser();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
/* Returns a unique lowercase string, based on name, for section ID */
|
||||
@@ -95,9 +100,11 @@ export default {
|
||||
triggerModal(url) {
|
||||
this.$refs[`iframeModal-${this.groupId}`].show(url);
|
||||
},
|
||||
/* Emmit value upwards when iframe modal opened/ closed */
|
||||
modalChanged(changedTo) {
|
||||
this.$emit('change-modal-visibility', changedTo);
|
||||
},
|
||||
/* Determines if user has enabled online status checks */
|
||||
shouldEnableStatusCheck(itemPreference) {
|
||||
const globalPreference = this.config.appConfig.statusCheck || false;
|
||||
return itemPreference !== undefined ? itemPreference : globalPreference;
|
||||
@@ -109,6 +116,35 @@ export default {
|
||||
if (interval < 1) interval = 0;
|
||||
return interval;
|
||||
},
|
||||
/* Returns false if this section should not be rendered for the current user/ guest */
|
||||
isSectionVisibleToUser() {
|
||||
const determineVisibility = (visibilityList, currentUser) => {
|
||||
let isFound = false;
|
||||
visibilityList.forEach((userInList) => {
|
||||
if (userInList.toLowerCase() === currentUser) isFound = true;
|
||||
});
|
||||
return isFound;
|
||||
};
|
||||
const checkVisiblity = () => {
|
||||
if (!this.currentUser) return true;
|
||||
const hideFor = this.displayData.hideForUsers || [];
|
||||
const currentUser = this.currentUser.user.toLowerCase();
|
||||
return !determineVisibility(hideFor, currentUser);
|
||||
};
|
||||
const checkHiddenability = () => {
|
||||
if (!this.currentUser) return true;
|
||||
const currentUser = this.currentUser.user.toLowerCase();
|
||||
const showForUsers = this.displayData.showForUsers || [];
|
||||
if (showForUsers.length < 1) return true;
|
||||
return determineVisibility(showForUsers, currentUser);
|
||||
};
|
||||
const checkIfHideForGuest = () => {
|
||||
const hideForGuest = this.displayData.hideForGuests;
|
||||
const isGuest = isLoggedInAsGuest();
|
||||
return !(hideForGuest && isGuest);
|
||||
};
|
||||
return checkVisiblity() && checkHiddenability() && checkIfHideForGuest();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -114,7 +114,7 @@ export default {
|
||||
* then they will never be able to view the homepage, so no button needed
|
||||
*/
|
||||
userState() {
|
||||
return getUserState(this.appConfig || {});
|
||||
return getUserState();
|
||||
},
|
||||
},
|
||||
data() {
|
||||
|
||||
@@ -31,7 +31,7 @@ const isGuestEnabled = () => {
|
||||
/* Returns true if user is already authenticated, or if auth is not enabled */
|
||||
const isAuthenticated = () => {
|
||||
const users = config.appConfig.auth;
|
||||
return (!users || users.length === 0 || isLoggedIn(users) || isGuestEnabled());
|
||||
return (!users || users.length === 0 || isLoggedIn() || isGuestEnabled());
|
||||
};
|
||||
|
||||
/* Get the users chosen starting view from app config, or return default */
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
import sha256 from 'crypto-js/sha256';
|
||||
import { cookieKeys, localStorageKeys, userStateEnum } from './defaults';
|
||||
import ConfigAccumulator from '@/utils/ConfigAccumalator';
|
||||
import { cookieKeys, localStorageKeys, userStateEnum } from '@/utils/defaults';
|
||||
|
||||
/* Uses config accumulator to get and return app config */
|
||||
const getAppConfig = () => {
|
||||
const Accumulator = new ConfigAccumulator();
|
||||
const config = Accumulator.config();
|
||||
return config.appConfig || {};
|
||||
};
|
||||
|
||||
/* Returns the users array from appConfig, if available, else an empty array */
|
||||
const getUsers = () => {
|
||||
const appConfig = getAppConfig();
|
||||
return appConfig.auth || [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a 1-way hash, in order to be stored in local storage for authentication
|
||||
@@ -17,7 +31,8 @@ const generateUserToken = (user) => {
|
||||
* @param {Array[Object]} users An array of user objects pulled from the config
|
||||
* @returns {Boolean} Will return true if the user is logged in, else false
|
||||
*/
|
||||
export const isLoggedIn = (users) => {
|
||||
export const isLoggedIn = () => {
|
||||
const users = getUsers();
|
||||
const validTokens = users.map((user) => generateUserToken(user));
|
||||
let userAuthenticated = false;
|
||||
document.cookie.split(';').forEach((cookie) => {
|
||||
@@ -35,10 +50,16 @@ export const isLoggedIn = (users) => {
|
||||
};
|
||||
|
||||
/* Returns true if authentication is enabled */
|
||||
export const isAuthEnabled = (users) => (users && users.length > 0);
|
||||
export const isAuthEnabled = () => {
|
||||
const users = getUsers();
|
||||
return (users.length > 0);
|
||||
};
|
||||
|
||||
/* Returns true if guest access is enabled */
|
||||
export const isGuestAccessEnabled = (appConfig) => appConfig.enableGuestAccess || false;
|
||||
export const isGuestAccessEnabled = () => {
|
||||
const appConfig = getAppConfig();
|
||||
return appConfig.enableGuestAccess || false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks credentials entered by the user against those in the config
|
||||
@@ -92,6 +113,33 @@ export const logout = () => {
|
||||
localStorage.removeItem(localStorageKeys.USERNAME);
|
||||
};
|
||||
|
||||
/**
|
||||
* If correctly logged in as a valid, authenticated user,
|
||||
* then returns the user object for the current user
|
||||
* If not logged in, will return false
|
||||
* */
|
||||
export const getCurrentUser = () => {
|
||||
if (!isLoggedIn()) return false; // User not logged in
|
||||
const username = localStorage[localStorageKeys.USERNAME]; // Get username
|
||||
if (!username) return false; // No username
|
||||
let foundUserObject = false; // Value to return
|
||||
getUsers().forEach((user) => {
|
||||
// If current logged in user found, then return that user
|
||||
if (user.user === username) foundUserObject = user;
|
||||
});
|
||||
return foundUserObject;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the user is viewing the dashboard as a guest
|
||||
* Returns true if guest mode enabled, and user not logged in
|
||||
* */
|
||||
export const isLoggedInAsGuest = () => {
|
||||
const guestEnabled = isGuestAccessEnabled();
|
||||
const notLoggedIn = !isLoggedIn();
|
||||
return guestEnabled && notLoggedIn;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the current user has admin privileges.
|
||||
* If no users are setup, then function will always return true
|
||||
@@ -101,9 +149,10 @@ export const logout = () => {
|
||||
* @param {String[]} - Array of users
|
||||
* @returns {Boolean} - True if admin privileges
|
||||
*/
|
||||
export const isUserAdmin = (users) => {
|
||||
if (!users || users.length === 0) return true; // Authentication not setup
|
||||
if (!isLoggedIn(users)) return false; // Auth setup, but not signed in as a valid user
|
||||
export const isUserAdmin = () => {
|
||||
const users = getUsers();
|
||||
if (users.length === 0) return true; // Authentication not setup
|
||||
if (!isLoggedIn()) return false; // Auth setup, but not signed in as a valid user
|
||||
const currentUser = localStorage[localStorageKeys.USERNAME];
|
||||
let isAdmin = false;
|
||||
users.forEach((user) => {
|
||||
@@ -122,11 +171,10 @@ export const isUserAdmin = (users) => {
|
||||
* Note that if auth is enabled, but not guest access, and user not logged in,
|
||||
* then they will never be able to view the homepage, so no button needed
|
||||
*/
|
||||
export const getUserState = (appConfig) => {
|
||||
export const getUserState = () => {
|
||||
const { notConfigured, loggedIn, guestAccess } = userStateEnum; // Numeric enum options
|
||||
const users = appConfig.auth || []; // Get auth object
|
||||
if (!isAuthEnabled(users)) return notConfigured; // No auth enabled
|
||||
if (isLoggedIn(users)) return loggedIn; // User is logged in
|
||||
if (isGuestAccessEnabled(appConfig)) return guestAccess; // Guest is viewing
|
||||
if (!isAuthEnabled()) return notConfigured; // No auth enabled
|
||||
if (isLoggedIn()) return loggedIn; // User is logged in
|
||||
if (isGuestAccessEnabled()) return guestAccess; // Guest is viewing
|
||||
return notConfigured;
|
||||
};
|
||||
|
||||
@@ -24,21 +24,25 @@ export default class ConfigAccumulator {
|
||||
/* App Config */
|
||||
appConfig() {
|
||||
let appConfigFile = {};
|
||||
if (this.conf) {
|
||||
appConfigFile = this.conf.appConfig || {};
|
||||
}
|
||||
// Set app config from file
|
||||
if (this.conf) appConfigFile = this.conf.appConfig || {};
|
||||
// Fill in defaults if anything missing
|
||||
let usersAppConfig = defaultAppConfig;
|
||||
if (localStorage[localStorageKeys.APP_CONFIG]) {
|
||||
usersAppConfig = JSON.parse(localStorage[localStorageKeys.APP_CONFIG]);
|
||||
} else if (appConfigFile !== {}) {
|
||||
usersAppConfig = appConfigFile;
|
||||
}
|
||||
// Some settings have their own local storage keys, apply them here
|
||||
usersAppConfig.layout = localStorage[localStorageKeys.LAYOUT_ORIENTATION]
|
||||
|| appConfigFile.layout || defaultLayout;
|
||||
usersAppConfig.iconSize = localStorage[localStorageKeys.ICON_SIZE]
|
||||
|| appConfigFile.iconSize || defaultIconSize;
|
||||
usersAppConfig.language = localStorage[localStorageKeys.LANGUAGE]
|
||||
|| appConfigFile.language || defaultLanguage;
|
||||
// Don't let users modify users locally
|
||||
if (appConfigFile.auth) usersAppConfig.auth = appConfigFile.auth;
|
||||
// All done, return final appConfig object
|
||||
return usersAppConfig;
|
||||
}
|
||||
|
||||
|
||||
@@ -369,6 +369,27 @@
|
||||
"minimum": 1,
|
||||
"maximum": 12,
|
||||
"description": "Number of items per row"
|
||||
},
|
||||
"hideForUsers": {
|
||||
"type": "array",
|
||||
"description": "Section will be visible to all users, except for those specified in this list",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "Username for the user that will not be able to view this section"
|
||||
}
|
||||
},
|
||||
"showForUsers": {
|
||||
"type": "array",
|
||||
"description": "Section will be hidden from all users, except for those specified in this list",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "Username for the user that will have access to this section"
|
||||
}
|
||||
},
|
||||
"hideForGuests": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "If set to true, section will be visible for logged in users, but not for guests"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -126,7 +126,7 @@ export default {
|
||||
},
|
||||
isUserAlreadyLoggedIn() {
|
||||
const users = this.appConfig.auth;
|
||||
const loggedIn = (!users || users.length === 0 || isLoggedIn(users));
|
||||
const loggedIn = (!users || users.length === 0 || isLoggedIn());
|
||||
return (loggedIn && this.existingUsername);
|
||||
},
|
||||
isGuestAccessEnabled() {
|
||||
|
||||
Reference in New Issue
Block a user