From da98ea5cf27d0cb40db77a263b77b3fc2b3bf320 Mon Sep 17 00:00:00 2001 From: Leonardo Covarrubias Date: Sat, 1 Jan 2022 15:33:46 -0500 Subject: [PATCH 01/39] :sparkle: add keycloak group and role based visibility --- docs/configuring.md | 11 +++++ package.json | 2 +- src/main.js | 22 +++------- src/utils/Auth.js | 68 ++++++++++++++++++++++++++--- src/utils/CheckSectionVisibility.js | 48 ++++++++++++++++---- src/utils/ConfigSchema.json | 54 +++++++++++++++++++++++ src/utils/defaults.js | 1 + 7 files changed, 175 insertions(+), 31 deletions(-) diff --git a/docs/configuring.md b/docs/configuring.md index 23f8d186..71fb1ceb 100644 --- a/docs/configuring.md +++ b/docs/configuring.md @@ -215,6 +215,8 @@ For more info, see the **[Authentication Docs](/docs/authentication.md)** **`hideForUsers`** | `string[]` | _Optional_ | Current section will be visible to all users, except for those specified in this list **`showForUsers`** | `string[]` | _Optional_ | Current section will be hidden from all users, except for those specified in this list **`hideForGuests`** | `boolean` | _Optional_ | Current section will be visible for logged in users, but not for guests (see `appConfig.enableGuestAccess`). Defaults to `false` +**`hideForKeycloakUsers`** | `object` | _Optional_ | Current section will be visible to all keycloak users, except for those configured via these groups and roles. See `hideForKeycloakUsers` +**`showForKeycloakUsers`** | `object` | _Optional_ | Current section will be hidden from all keyclaok users, except for those configured via these groups and roles. See `showForKeycloakUsers` **[⬆️ Back to Top](#configuring)** @@ -226,6 +228,15 @@ For more info, see the **[Authentication Docs](/docs/authentication.md)** **[⬆️ Back to Top](#configuring)** +### `section.displayData.hideForKeycloakUsers` and `section.displayData.showForKeycloakUsers` + +**Field** | **Type** | **Required**| **Description** +--- |------------| --- | --- +**`groups`** | `string[]` | _Optional_ | Current Section will be hidden or shown based on the user having any of the groups in this list +**`roles`** | `string[]` | _Optional_ | Current Section will be hidden or shown based on the user having any of the roles in this list + +**[⬆️ Back to Top](#configuring)** + --- ## Notes diff --git a/package.json b/package.json index ca3a3a6b..0a26e47c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Dashy", - "version": "1.9.5", + "version": "1.9.6", "license": "MIT", "main": "server", "author": "Alicia Sykes (https://aliciasykes.com)", diff --git a/src/main.js b/src/main.js index 86fc9863..d71d46ee 100644 --- a/src/main.js +++ b/src/main.js @@ -2,7 +2,6 @@ // Import core framework and essential utils import Vue from 'vue'; import VueI18n from 'vue-i18n'; // i18n for localization -import Keycloak from 'keycloak-js'; // Import component Vue plugins, used throughout the app import VTooltip from 'v-tooltip'; // A Vue directive for Popper.js, tooltip component @@ -21,7 +20,7 @@ import clickOutside from '@/utils/ClickOutside'; // Directive for closing p import { messages } from '@/utils/languages'; // Language texts import ErrorReporting from '@/utils/ErrorReporting'; // Error reporting initializer (off) import { toastedOptions, tooltipOptions, language as defaultLanguage } from '@/utils/defaults'; -import { isKeycloakEnabled, getKeycloakConfig } from '@/utils/Auth'; // Keycloak auth config +import { isKeycloakEnabled, cleanupKeycloakInfo, initKeycloak } from '@/utils/Auth'; // Keycloak auth config // Initialize global Vue components Vue.use(VueI18n); @@ -59,22 +58,13 @@ const mount = () => new Vue({ store, router, render, i18n, }).$mount('#app'); +// every page reload removes keycloak user data +cleanupKeycloakInfo(); // If Keycloak not enabled, then proceed straight to the app if (!isKeycloakEnabled()) { mount(); } else { // Keycloak is enabled, redirect to KC login page - const { serverUrl, realm, clientId } = getKeycloakConfig(); - const initOptions = { - url: `${serverUrl}/auth`, realm, clientId, onLoad: 'login-required', - }; - const keycloak = Keycloak(initOptions); - keycloak.init({ onLoad: initOptions.onLoad }).then((auth) => { - if (!auth) { - // Not authenticated, reload to Keycloak login page - window.location.reload(); - } else { - // Yay - user successfully authenticated with Keycloak, render the app! - mount(); - } - }); + initKeycloak() + .then(() => mount()) + .catch(() => window.location.reload()); } diff --git a/src/utils/Auth.js b/src/utils/Auth.js index a1ac8c90..7e49f2b5 100644 --- a/src/utils/Auth.js +++ b/src/utils/Auth.js @@ -1,4 +1,5 @@ import sha256 from 'crypto-js/sha256'; +import Keycloak from 'keycloak-js'; import ConfigAccumulator from '@/utils/ConfigAccumalator'; import ErrorHandler from '@/utils/ErrorHandler'; import { cookieKeys, localStorageKeys, userStateEnum } from '@/utils/defaults'; @@ -39,6 +40,62 @@ export const getKeycloakConfig = () => { return keycloak; }; +/** + * helper that persists keycloak user data in browser local storage + * @param {Keycloak.KeycloakInstance} keycloak The username of user + */ +const storeKeycloakInfo = (keycloak) => { + if (keycloak.tokenParsed && typeof keycloak.tokenParsed === 'object') { + const { + groups, + realm_access: realmAccess, + resource_access: resourceAccess, + azp: clientId, + } = keycloak.tokenParsed; + + const realmRoles = realmAccess.roles || []; + + let clientRoles = []; + if (Object.hasOwn(resourceAccess, clientId)) { + clientRoles = resourceAccess[clientId].roles || []; + } + + const roles = [...realmRoles, ...clientRoles]; + + const info = { + groups, + roles, + }; + + localStorage.setItem(localStorageKeys.KEYCLOAK_INFO, JSON.stringify(info)); + } +}; + +/* remove keycloak local storage */ +export const cleanupKeycloakInfo = () => localStorage.removeItem(localStorageKeys.KEYCLOAK_INFO); + +/* starts the keycloak login process and gathers user data */ +export const initKeycloak = () => { + const { serverUrl, realm, clientId } = getKeycloakConfig(); + const initOptions = { + url: `${serverUrl}/auth`, realm, clientId, onLoad: 'login-required', + }; + const keycloak = Keycloak(initOptions); + + return new Promise((resolve, reject) => { + keycloak.init({ onLoad: initOptions.onLoad }) + .then((auth) => { + if (auth) { + storeKeycloakInfo(keycloak); + return resolve(); + } else { + return reject(new Error('Not authenticated')); + } + }) + .catch((reason) => reject(reason)); + }); +}; + /* Returns array of users from appConfig.auth, if available, else an empty array */ const getUsers = () => { const appConfig = getAppConfig(); @@ -65,7 +122,6 @@ const generateUserToken = (user) => { /** * Checks if the user is currently authenticated - * @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 = () => { @@ -95,7 +151,7 @@ export const isAuthEnabled = () => { /* Returns true if guest access is enabled */ export const isGuestAccessEnabled = () => { const appConfig = getAppConfig(); - if (appConfig.auth && typeof appConfig.auth === 'object') { + if (appConfig.auth && typeof appConfig.auth === 'object' && !isKeycloakEnabled()) { return appConfig.auth.enableGuestAccess || false; } return false; @@ -108,6 +164,7 @@ export const isGuestAccessEnabled = () => { * @param {String} username The username entered by the user * @param {String} pass The password entered by the user * @param {String[]} users An array of valid user objects + * @param {Object} messages A static message template object * @returns {Object} An object containing a boolean result and a message */ export const checkCredentials = (username, pass, users, messages) => { @@ -146,7 +203,7 @@ export const login = (username, pass, timeout) => { }; /** - * Removed the browsers cookie, causing user to be logged out + * Removed the browsers' cookie, causing user to be logged out */ export const logout = () => { document.cookie = 'authenticationToken=null'; @@ -164,7 +221,7 @@ export const getCurrentUser = () => { 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 current logged-in user found, then return that user if (user.user === username) foundUserObject = user; }); return foundUserObject; @@ -182,11 +239,10 @@ export const isLoggedInAsGuest = () => { /** * Checks if the current user has admin privileges. - * If no users are setup, then function will always return true + * If no users are set up, then function will always return true * But if auth is configured, then will verify user is correctly * logged in and then check weather they are of type admin, and * return false if any conditions fail - * @param {String[]} - Array of users * @returns {Boolean} - True if admin privileges */ export const isUserAdmin = () => { diff --git a/src/utils/CheckSectionVisibility.js b/src/utils/CheckSectionVisibility.js index b5b65f4e..555fadcd 100644 --- a/src/utils/CheckSectionVisibility.js +++ b/src/utils/CheckSectionVisibility.js @@ -6,24 +6,32 @@ // Import helper functions from auth, to get current user, and check if guest import { getCurrentUser, isLoggedInAsGuest } from '@/utils/Auth'; +import { localStorageKeys } from '@/utils/defaults'; -/* Helper function, checks if a given username appears in a user array */ -const determineVisibility = (visibilityList, cUsername) => { +/* Helper function, checks if a given testValue is found in the visibility list */ +const determineVisibility = (visibilityList, testValue) => { let isFound = false; - visibilityList.forEach((userInList) => { - if (userInList.toLowerCase() === cUsername) isFound = true; + visibilityList.forEach((visibilityItem) => { + if (visibilityItem.toLowerCase() === testValue.toLowerCase()) isFound = true; }); return isFound; }; +/* Helper function, determines if two arrays have any intersecting elements + (one or more items that are the same) */ +const determineIntersection = (source = [], target = []) => { + const intersections = source.filter(item => target.indexOf(item) !== -1); + return intersections.length > 0; +}; + /* Returns false if this section should not be rendered for the current user/ guest */ const isSectionVisibleToUser = (displayData, currentUser, isGuest) => { // Checks if user explicitly has access to a certain section - const checkVisiblity = () => { + const checkVisibility = () => { if (!currentUser) return true; - const hideFor = displayData.hideForUsers || []; + const hideForUsers = displayData.hideForUsers || []; const cUsername = currentUser.user.toLowerCase(); - return !determineVisibility(hideFor, cUsername); + return !determineVisibility(hideForUsers, cUsername); }; // Checks if user is explicitly prevented from viewing a certain section const checkHiddenability = () => { @@ -33,12 +41,36 @@ const isSectionVisibleToUser = (displayData, currentUser, isGuest) => { if (showForUsers.length < 1) return true; return determineVisibility(showForUsers, cUsername); }; + const checkKeycloakVisibility = () => { + if (!displayData.hideForKeycloakUsers) return true; + + const { groups, roles } = JSON.parse(localStorage.getItem(localStorageKeys.KEYCLOAK_INFO) || '{}'); + const hideForGroups = displayData.hideForKeycloakUsers.groups || []; + const hideForRoles = displayData.hideForKeycloakUsers.roles || []; + + return !(determineIntersection(hideForRoles, roles) + || determineIntersection(hideForGroups, groups)); + }; + const checkKeycloakHiddenability = () => { + if (!displayData.showForKeycloakUsers) return true; + + const { groups, roles } = JSON.parse(localStorage.getItem(localStorageKeys.KEYCLOAK_INFO) || '{}'); + const showForGroups = displayData.showForKeycloakUsers.groups || []; + const showForRoles = displayData.showForKeycloakUsers.roles || []; + + return determineIntersection(showForRoles, roles) + || determineIntersection(showForGroups, groups); + }; // Checks if the current user is a guest, and if section allows for guests const checkIfHideForGuest = () => { const hideForGuest = displayData.hideForGuests; return !(hideForGuest && isGuest); }; - return checkVisiblity() && checkHiddenability() && checkIfHideForGuest(); + return checkVisibility() + && checkHiddenability() + && checkIfHideForGuest() + && checkKeycloakVisibility() + && checkKeycloakHiddenability(); }; /* Putting it all together, the function to export */ diff --git a/src/utils/ConfigSchema.json b/src/utils/ConfigSchema.json index 908bed3d..90c6e49c 100644 --- a/src/utils/ConfigSchema.json +++ b/src/utils/ConfigSchema.json @@ -613,6 +613,60 @@ "type": "boolean", "default": false, "description": "If set to true, section will be visible for logged in users, but not for guests" + }, + "showForKeycloakUsers": { + "title": "Show for select Keycloak groups or roles", + "type": "object", + "description": "Configure the Keycloak groups or roles that will have access to this section", + "additionalProperties": false, + "properties": { + "groups": { + "title": "Show for Groups", + "type": "array", + "description": "Section will be hidden from all users except those with one or more of these groups", + + "items": { + "type": "string", + "description": "Name of the group that will be able to view this section" + } + }, + "roles": { + "title": "Show for Roles", + "type": "array", + "description": "Section will be hidden from all users except those with one or more of these roles", + "items": { + "type": "string", + "description": "Name of the role that will be able to view this section" + } + } + } + }, + "hideForKeycloakUsers": { + "title": "Hide for select Keycloak groups or roles", + "type": "object", + "description": "Configure the Keycloak groups or roles that will not have access to this section", + "additionalProperties": false, + "properties": { + "groups": { + "title": "Hide for Groups", + "type": "array", + "description": "Section will be hidden from users with any of these groups", + + "items": { + "type": "string", + "description": "name of the group that will not be able to view this section" + } + }, + "roles": { + "title": "Hide for Roles", + "type": "array", + "description": "Section will be hidden from users with any of roles", + "items": { + "type": "string", + "description": "name of the role that will not be able to view this section" + } + } + } } } }, diff --git a/src/utils/defaults.js b/src/utils/defaults.js index d952f23c..7a05d047 100644 --- a/src/utils/defaults.js +++ b/src/utils/defaults.js @@ -124,6 +124,7 @@ module.exports = { USERNAME: 'username', MOST_USED: 'mostUsed', LAST_USED: 'lastUsed', + KEYCLOAK_INFO: 'keycloakInfo', }, /* Key names for cookie identifiers */ cookieKeys: { From 158919d882a212569f843288b3b1358cac64a412 Mon Sep 17 00:00:00 2001 From: BOZG Date: Sat, 1 Jan 2022 21:53:31 +0100 Subject: [PATCH 02/39] Updated Swedish translation --- src/assets/locales/sv.json | 526 ++++++++++++++++++++----------------- 1 file changed, 281 insertions(+), 245 deletions(-) diff --git a/src/assets/locales/sv.json b/src/assets/locales/sv.json index 30b7b53c..32a782b3 100644 --- a/src/assets/locales/sv.json +++ b/src/assets/locales/sv.json @@ -1,248 +1,284 @@ { - "home": { - "no-results": "Inga sökresultat", - "no-data": "Ingen data konfigurerad" + "home":{ + "no-results":"Inga sökresultat", + "no-data":"Ingen data konfigurerad", + "no-items-section":"Inga objekt att visa än" + }, + "search":{ + "search-label":"Sök", + "search-placeholder":"Börja skriva för att filtrera", + "clear-search-tooltip":"Rensa sök", + "enter-to-search-web":"Tryck på Retur för att söka på webben" + }, + "login":{ + "title":"Dashy", + "username-label":"Användarnamn", + "password-label":"Lösenord", + "login-button":"Logga in", + "remember-me-label":"Kom ihåg mig", + "remember-me-never":"Aldrig", + "remember-me-hour":"4 Timmar", + "remember-me-day":"1 Dag", + "remember-me-week":"1 Vecka", + "remember-me-long-time":"Länge", + "error-missing-username":"Användarnamn saknas", + "error-missing-password":"Lösenord saknas", + "error-incorrect-username":"Användaren hittas inte", + "error-incorrect-password":"Fel lösenord", + "success-message":"Loggar in...", + "logout-message":"Utloggad", + "already-logged-in-title":"Redan inloggad", + "already-logged-in-text":"Du är inloggad som", + "proceed-to-dashboard":"Fortsätt till Dashboard", + "log-out-button":"Logga ut", + "proceed-guest-button":"Fortsätt som Gäst" + }, + "config":{ + "main-tab":"Huvudmeny", + "view-config-tab":"Visa konfiguration", + "edit-config-tab":"Redigera konfiguration", + "custom-css-tab":"Egna stilmallar", + "heading":"Konfigurationsalternativ", + "download-config-button":"Visa / Exportera konfiguration", + "edit-config-button":"Redigera konfiguration", + "edit-css-button":"Redigera Custom CSS", + "cloud-sync-button":"Aktivera molnsynk", + "edit-cloud-sync-button":"Redigera molnsynk", + "rebuild-app-button":"Återuppbygga appen", + "change-language-button":"Ändra appspråk", + "reset-settings-button":"Återställ lokala inställningar", + "app-info-button":"Appinfo", + "backup-note":"Det rekommenderas att du gör en säkerhetskopia av din konfiguration innan du gör ändringar.", + "reset-config-msg-l1":"Detta tar bort alla användarinställningar från lokal lagring, men påverkar inte din 'conf.yml'-fil", + "reset-config-msg-l2":"Du bör först göra en säkerhetskopia av alla ändringar du har gjort lokalt, om du vill använda dem i framtiden.", + "reset-config-msg-l3":"Är du säker på att du vill fortsätta?", + "data-cleared-msg":"Datarensning har lyckats", + "actions-label":"Åtgärder", + "copy-config-label":"Kopiera konfiguration", + "data-copied-msg":"Konfiguration har kopierats till urklipp", + "reset-config-label":"Återställ konfiguration", + "css-save-btn":"Spara ändringar", + "css-note-label":"Not", + "css-note-l1":"Du måste uppdatera sidan för att dina ändringar ska gälla.", + "css-note-l2":"Styles overrides lagras bara lokalt, så det rekommenderas att du gör en kopia av din CSS.", + "css-note-l3":"För att ta bort alla egna stilmallar, radera innehållet och tryck på Spara ändringar" + }, + "alternate-views":{ + "alternate-view-heading":"Ändra vy", + "default":"Standard", + "workspace":"Workspace", + "minimal":"Minimal" + }, + "settings":{ + "theme-label":"Tema", + "layout-label":"Layout", + "layout-auto":"Auto", + "layout-horizontal":"Vågrät", + "layout-vertical":"Lodrät", + "item-size-label":"Storlek", + "item-size-small":"Liten", + "item-size-medium":"Mellan", + "item-size-large":"Stor", + "config-launcher-label":"Konfig", + "config-launcher-tooltip":"Uppdatera konfiguration", + "sign-out-tooltip":"Logga ut", + "sign-in-tooltip":"Logga in", + "sign-in-welcome":"Hej {username}!" + }, + "updates":{ + "app-version-note":"Dashy-version", + "up-to-date":"Uppdaterat", + "out-of-date":"Uppdatering finns", + "unsupported-version-l1":"Du använder en icke-stödd version av Dashy", + "unsupported-version-l2":"För den bästa upplevelsen och de senaste säkerhetskorrigeringarna, uppdatera till" + }, + "language-switcher":{ + "title":"Ändra appspråk", + "dropdown-label":"Välj språk", + "save-button":"Spara", + "success-msg":"Språket har ändrats till" + }, + "theme-maker":{ + "title":"Temakonfigurator", + "export-button":"Exportera egendefinierade variabler", + "reset-button":"Återställ stilmallar för", + "show-all-button":"Vissa alla variabler", + "change-fonts-button":"Ändra typsnitt", + "save-button":"Spara", + "cancel-button":"Avbryt", + "saved-toast":"{theme} har uppdaterats", + "copied-toast":"Temadatan för {theme} har kopierats till urklipp", + "reset-toast":"Egna färger för {theme} har tagits bort" + }, + "config-editor":{ + "save-location-label":"Sparningsplats", + "location-local-label":"Tillämpa lokalt", + "location-disk-label":"Skriv ändringar till konfigurationsfil", + "save-button":"Spara ändringar", + "preview-button":"Förhandsgranska ändringar", + "valid-label":"Konfigurationen är giltig", + "status-success-msg":"Åtgärden slutförts", + "status-fail-msg":"Åtgärden misslyckats", + "success-msg-disk":"Konfigurationsfil har skrivits till disk utan problem", + "success-msg-local":"Lokala ändringar har sparats utan problem", + "success-note-l1":"Återskapa", + "success-note-l2":"Detta kan ta upp till en minut.", + "success-note-l3":"Du måste uppdatera sidan för att ändringar ska gälla", + "error-msg-save-mode":"Välj Lagringsläge: Lokalt eller Fil", + "error-msg-cannot-save":"Ett fel uppstod när konfigurationen skulle sparas", + "error-msg-bad-json":"Fel i JSON, möjligen felformaterat", + "warning-msg-validation":"Valideringsvarning", + "not-admin-note":"Du kan inte skriva ändringar till disk, eftersom du inte är inloggad som admin" + }, + "app-rebuild":{ + "title":"Återskapa appen", + "rebuild-note-l1":"Appen måste återskapas för att ändringar som skrivits till filen conf.yml ska gälla.", + "rebuild-note-l2":"Detta bör ske automatiskt, men om det inte har gjort det kan du aktivera det manuellt här.", + "rebuild-note-l3":"Detta krävs inte för ändringar som lagras lokalt.", + "rebuild-button":"Återskapa", + "rebuilding-status-1":"Återskapar...", + "rebuilding-status-2":"Detta kan ta några minuter", + "error-permission":"Du har inte behörighet att utföra denna åtgärd", + "success-msg":"Återskapning lyckats", + "fail-msg":"Återskapning misslyckats", + "reload-note":"En omladdning av sidan krävs nu för att ändringarna ska gälla", + "reload-button":"Ladda om sidan" + }, + "cloud-sync":{ + "title":"Molnsäkerhetskopiering och återställning", + "intro-l1":"Molnsäkerhetskopiering och återställning är en valfri funktion som gör att du kan ladda upp din konfiguration till internet och sedan återställa den på någon annan enhet eller instans av Dashy.", + "intro-l2":"All data är fullständigt end-to-end krypterad med AES, med ditt lösenord som nyckel.", + "intro-l3":"För mer information, vänligen se", + "backup-title-setup":"Gör en säkerhetskopia", + "backup-title-update":"Uppdatera säkerhetskopia", + "password-label-setup":"Välj lösenord", + "password-label-update":"Ange ditt lösenord", + "backup-button-setup":"Säkerhetskopiering", + "backup-button-update":"Uppdatera säkerhetskopia", + "backup-id-label":"Ditt säkerhetskopierings-ID", + "backup-id-note":"Detta används för att återställa från säkerhetskopior senare. Så förvara det tillsammans med ditt lösenord någonstans säkert.", + "restore-title":"Återställ en säkerhetskopia", + "restore-id-label":"Återställ ID", + "restore-password-label":"Lösenord", + "restore-button":"Återställ", + "backup-missing-password":"Lösenord saknas", + "backup-error-unknown":"Begäran kan inte behandlas", + "backup-error-password":"Fel lösenord. Vänligen ange ditt aktuella lösenord.", + "backup-success-msg":"Slutfört utan problem", + "restore-success-msg":"Konfigurationen har återställts utan problem" + }, + "menu":{ + "open-section-title":"Öppna i", + "sametab":"Denna flik", + "newtab":"Ny flik", + "modal":"Pop-Up Modal", + "workspace":"Workspace-vy", + "options-section-title":"Alternativ", + "edit-item":"Redigera", + "move-item":"Kopiera eller flytta", + "remove-item":"Ta bort" + }, + "context-menus":{ + "item":{ + "open-section-title":"Öppna i", + "sametab":"Denna flik", + "newtab":"Ny flik", + "modal":"Pop-Up Modal", + "workspace":"Workspace View", + "options-section-title":"Alternativ", + "edit-item":"Redigera", + "move-item":"Kopiera eller flytta", + "remove-item":"Ta bort" }, - "search": { - "search-label": "Sök", - "search-placeholder": "Börja skriva för att filtrera", - "clear-search-tooltip": "Rensa sök", - "enter-to-search-web": "Tryck på Retur för att söka på webben" - }, - "login": { - "title": "Dashy", - "username-label": "Användarnamn", - "password-label": "Lösenord", - "login-button": "Logga in", - "remember-me-label": "Kom ihåg mig", - "remember-me-never": "Aldrig", - "remember-me-hour": "4 Timmar", - "remember-me-day": "1 Dag", - "remember-me-week": "1 Vecka", - "remember-me-long-time": "Länge", - "error-missing-username": "Användarnamn saknas", - "error-missing-password": "Lösenord saknas", - "error-incorrect-username": "Användaren hittas inte", - "error-incorrect-password": "Fel lösenord", - "success-message": "Loggar in...", - "logout-message": "Utloggad", - "already-logged-in-title": "Redan inloggad", - "already-logged-in-text": "Du är inloggad som", - "proceed-to-dashboard": "Fortsätt till Dashboard", - "log-out-button": "Logga ut", - "proceed-guest-button": "Fortsätt som Gäst" - }, - "config": { - "main-tab": "Huvudmeny", - "view-config-tab": "Visa konfiguration", - "edit-config-tab": "Redigera konfiguration", - "custom-css-tab": "Egendefinierade stilmallar", - "heading": "Konfigurationsalternativ", - "download-config-button": "Visa / Exportera konfiguration", - "edit-config-button": "Redigera konfiguration", - "edit-css-button": "Redigera egendefinierad CSS", - "cloud-sync-button": "Aktivera molnsynkronisering", - "edit-cloud-sync-button": "Redigera molnsynkronisering", - "rebuild-app-button": "Återuppbygga appen", - "change-language-button": "Ändra appspråk", - "reset-settings-button": "Återställ lokala inställningar", - "app-info-button": "Appinfo", - "backup-note": "Det rekommenderas att du gör en säkerhetskopia av din konfiguration innan du gör ändringar.", - "reset-config-msg-l1": "Detta tar bort alla användarinställningar från lokal lagring, men påverkar inte din 'conf.yml'-fil", - "reset-config-msg-l2": "Du bör först göra en säkerhetskopia av alla ändringar du har gjort lokalt, om du vill använda dem i framtiden.", - "reset-config-msg-l3": "Är du säker på att du vill fortsätta?", - "data-cleared-msg": "Datarensning har lyckats", - "actions-label": "Åtgärder", - "copy-config-label": "Kopiera konfiguration", - "data-copied-msg": "Konfiguration har kopierats till urklipp", - "reset-config-label": "Återställ konfiguration", - "css-save-btn": "Spara ändringar", - "css-note-label": "Not", - "css-note-l1": "Du måste uppdatera sidan för att dina ändringar ska gälla.", - "css-note-l2": "Styles overrides lagras bara lokalt, så det rekommenderas att du gör en kopia av din CSS.", - "css-note-l3": "För att ta bort alla egendefinierade stilmallar, radera innehållet och tryck på Spara ändringar" - }, - "alternate-views": { - "alternate-view-heading": "Ändra vy", - "default": "Standard", - "workspace": "Workspace", - "minimal": "Minimal" - }, - "settings": { - "theme-label": "Tema", - "layout-label": "Layout", - "layout-auto": "Auto", - "layout-horizontal": "Vågrät", - "layout-vertical": "Lodrät", - "item-size-label": "Storlek", - "item-size-small": "Liten", - "item-size-medium": "Mellan", - "item-size-large": "Stor", - "config-launcher-label": "Konfig", - "config-launcher-tooltip": "Uppdatera konfiguration", - "sign-out-tooltip": "Logga ut", - "sign-in-tooltip": "Logga in", - "sign-in-welcome": "Hej {username}!" - }, - "updates": { - "app-version-note": "Dashy-version", - "up-to-date": "Uppdaterat", - "out-of-date": "Uppdatering finns", - "unsupported-version-l1": "Du använder en icke-stödd version av Dashy", - "unsupported-version-l2": "För den bästa upplevelsen och de senaste säkerhetskorrigeringarna, uppdatera till" - }, - "language-switcher": { - "title": "Ändra appspråk", - "dropdown-label": "Välj språk", - "save-button": "Spara", - "success-msg": "Språket har ändrats till" - }, - "theme-maker": { - "title": "Temakonfigurator", - "export-button": "Exportera egendefinierade variabler", - "reset-button": "Återställ stilmallar för", - "show-all-button": "Visa alla variabler", - "change-fonts-button": "Ändra typsnitt", - "save-button": "Spara", - "cancel-button": "Avbryt", - "saved-toast": "Uppdatering av {theme} har lyckats", - "copied-toast": "Temadatan för {theme} har kopierats till urklipp", - "reset-toast": "Egendefinierade färger för {theme} har tagits bort" - }, - "config-editor": { - "save-location-label": "Sparningsplats", - "location-local-label": "Tillämpa lokalt", - "location-disk-label": "Skriv ändringar till konfigurationsfil", - "save-button": "Spara ändringar", - "preview-button": "Förhandsgranska ändringar", - "valid-label": "Konfigurationen är giltig", - "status-success-msg": "Åtgärden slutförts", - "status-fail-msg": "Åtgärden misslyckats", - "success-msg-disk": "Konfigurationsfil har skrivits till disk utan problem", - "success-msg-local": "Lokala ändringar har sparats utan problem", - "success-note-l1": "Återskapa", - "success-note-l2": "Detta kan ta upp till en minut.", - "success-note-l3": "Du måste uppdatera sidan för att ändringar ska gälla", - "error-msg-save-mode": "Välj Lagringsläge: Lokalt eller Fil", - "error-msg-cannot-save": "Ett fel uppstod när konfigurationen skulle sparas", - "error-msg-bad-json": "Fel i JSON, möjligen felformaterat", - "warning-msg-validation": "Valideringsvarning", - "not-admin-note": "Du kan inte skriva ändringar till disk, eftersom du inte är inloggad som admin" - }, - "app-rebuild": { - "title": "Återskapa appen", - "rebuild-note-l1": "Appen måste återskapas för att ändringar som skrivits till filen conf.yml ska gälla.", - "rebuild-note-l2": "Detta bör ske automatiskt, men om det inte har gjort det kan du aktivera det manuellt här.", - "rebuild-note-l3": "Detta krävs inte för ändringar som lagras lokalt.", - "rebuild-button": "Återskapa", - "rebuilding-status-1": "Återskapar...", - "rebuilding-status-2": "Detta kan ta några minuter", - "error-permission": "Du har inte behörighet att utföra denna åtgärd", - "success-msg": "Återskapning lyckats", - "fail-msg": "Återskapning misslyckats", - "reload-note": "En omladdning av sidan krävs nu för att ändringarna ska gälla", - "reload-button": "Ladda om sidan" - }, - "cloud-sync": { - "title": "Molnsäkerhetskopiering och återställning", - "intro-l1": "Molnsäkerhetskopiering och återställning är en valfri funktion som gör att du kan ladda upp din konfiguration till internet och sedan återställa den på någon annan enhet eller instans av Dashy.", - "intro-l2": "All data är fullständigt end-to-end krypterad med AES, med ditt lösenord som nyckel.", - "intro-l3": "För mer information, vänligen se", - "backup-title-setup": "Gör en säkerhetskopia", - "backup-title-update": "Uppdatera säkerhetskopia", - "password-label-setup": "Välj lösenord", - "password-label-update": "Ange ditt lösenord", - "backup-button-setup": "Säkerhetskopiering", - "backup-button-update": "Uppdatera säkerhetskopia", - "backup-id-label": "Ditt säkerhetskopierings-ID", - "backup-id-note": "Detta används för att återställa från säkerhetskopior senare. Så förvara det tillsammans med ditt lösenord någonstans säkert.", - "restore-title": "Återställ en säkerhetskopia", - "restore-id-label": "Återställ ID", - "restore-password-label": "Lösenord", - "restore-button": "Återställ", - "backup-missing-password": "Lösenord saknas", - "backup-error-unknown": "Begäran kan inte behandlas", - "backup-error-password": "Fel lösenord. Vänligen ange ditt aktuella lösenord.", - "backup-success-msg": "Slutfört utan problem", - "restore-success-msg": "Konfigurationen har återställts utan problem" - }, - "menu": { - "open-section-title": "Öppna i", - "sametab": "Denna flik", - "newtab": "Ny flik", - "modal": "Pop-Up Modal", - "workspace": "Workspace-vy", - "options-section-title": "Alternativ", - "edit-item": "Redigera", - "move-item": "Kopiera eller flytta", - "remove-item": "Ta bort" - }, - "context-menus": { - "item": { - "open-section-title": "Öppna i", - "sametab": "Denna flik", - "newtab": "Ny flik", - "modal": "Pop-Up Modal", - "workspace": "Workspace View", - "options-section-title": "Alternativ", - "edit-item": "Redigera", - "move-item": "Kopiera eller flytta", - "remove-item": "Ta bort" - }, - "section": { - "open-section": "Öppna sektion", - "edit-section": "Redigera", - "move-section": "Flytta till", - "remove-section": "Ta bort" - } - }, - "interactive-editor": { - "menu": { - "start-editing-tooltip": "Öppna den interaktiva redigeraren", - "edit-site-data-subheading": "Redigera webbplatsinformation", - "edit-page-info-btn": "Redigera sidinformation", - "edit-page-info-tooltip": "Appnamn, beskrivning, navigeringslänkar, sidfotstext, etc", - "edit-app-config-btn": "Redigera appkonfiguration", - "edit-app-config-tooltip": "Övriga appkonfigurationsalternativ", - "config-save-methods-subheading": "Alternativ för konfigurationssparande", - "save-locally-btn": "Spara lokalt", - "save-locally-tooltip": "Spara konfigurationen lokalt, till webbläsarens lagring. Detta påverkar inte din konfigurationsfil, men ändringarna sparas bara på denna enhet", - "save-disk-btn": "Spara till disk", - "save-disk-tooltip": "Spara konfiguration to conf.yml-filen på disk. Detta kommer att säkerhetskopiera och sedan skriva över din befintliga konfiguration", - "export-config-btn": "Exportera konfiguration", - "export-config-tooltip": "Visa och exportera den nya konfigurationen, antingen till fil eller urklipp", - "cloud-backup-btn": "Säkerhetskopiera till molnet", - "cloud-backup-tooltip": "Spara krypterad säkerhetskopia av konfigurationen i molnet", - "edit-raw-config-btn": "Redigera raw-konfiguration", - "edit-raw-config-tooltip": "Visa och redigera raw-konfiguration via JSON-redigeraren", - "cancel-changes-btn": "Avbryt redigering", - "cancel-changes-tooltip": "Radera nuvarande ändringar och lämna Redigeringsläge. Detta kommer in påverka din sparade konfiguration.", - "edit-mode-name": "Redigeringsläge", - "edit-mode-subtitle": "Du är i Redigeringsläge", - "edit-mode-description": "Detta innebär att du kan göra ändringar i din konfiguration och förhandsgranska resultaten, men tills du sparar kommer inga av dina ändringar att bevaras.", - "save-stage-btn": "Spara", - "cancel-stage-btn": "Avbryt" - }, - "edit-section": { - "edit-section-title": "Redigera sektion", - "add-section-title": "Lägg till ny sektion", - "edit-tooltip": "Tryck för att redigera, eller högerklicka för fler alternativ", - "remove-confirm": "Är du säker på att du vill ta bort denna sektion? Denna åtgärd kan ångras senare." - }, - "edit-app-config": { - "warning-msg-title": "Fortsätt med försiktighet", - "warning-msg-l1": "Följande alternativ är för avancerade appkonfigurationer.", - "warning-msg-l2": "Om du är osäker på något av fälten, vänligen kolla", - "warning-msg-docs": "dokumentationen", - "warning-msg-l3": "för att undvika oavsiktliga konsekvenser." - }, - "export": { - "export-title": "Exportera konfiguration", - "copy-clipboard-btn": "Kopiera till urklipp", - "copy-clipboard-tooltip": "Kopiera alla appkonfigurationer till systemets urklipp i YAML-format", - "download-file-btn": "Ladda ned som fil", - "download-file-tooltip": "Ladda ner alla appkonfigurationer till din enhet som en YAML-fil", - "view-title": "Visa konfiguration" - } + "section":{ + "open-section":"Öppna sektion", + "edit-section":"Redigera", + "move-section":"Flytta till", + "remove-section":"Ta bort" } - } \ No newline at end of file + }, + "interactive-editor":{ + "menu":{ + "start-editing-tooltip":"Öppna den interaktiva redigeraren", + "edit-site-data-subheading":"Redigera webbplatsinformation", + "edit-page-info-btn":"Redigera sidinformation", + "edit-page-info-tooltip":"Appnamn, beskrivning, navigeringslänkar, sidfotstext, etc", + "edit-app-config-btn":"Redigera appkonfiguration", + "edit-app-config-tooltip":"Övriga appkonfigurationsalternativ", + "config-save-methods-subheading":"Alternativ för konfigurationssparande", + "save-locally-btn":"Spara lokalt", + "save-locally-tooltip":"Spara konfigurationen lokalt, till webbläsarens lagring. Detta påverkar inte din konfigurationsfil, men ändringarna sparas bara på denna enhet", + "save-disk-btn":"Spara till disk", + "save-disk-tooltip":"Spara konfiguration to conf.yml-filen på disk. Detta kommer att säkerhetskopiera och sedan skriva över din befintliga konfiguration", + "export-config-btn":"Exportera konfiguration", + "export-config-tooltip":"Visa och exportera den nya konfigurationen, antingen till fil eller urklipp", + "cloud-backup-btn":"Säkerhetskopiera till molnet", + "cloud-backup-tooltip":"Spara krypterad säkerhetskopia av konfigurationen i molnet", + "edit-raw-config-btn":"Redigera raw-konfiguration", + "edit-raw-config-tooltip":"Visa och redigera raw-konfiguration via JSON-redigeraren", + "cancel-changes-btn":"Avbryt redigering", + "cancel-changes-tooltip":"Radera nuvarande ändringar och lämna Redigeringsläge. Detta kommer in påverka din sparade konfiguration.", + "edit-mode-name":"Redigeringsläge", + "edit-mode-subtitle":"Du är i Redigeringsläge", + "edit-mode-description":"Detta innebär att du kan göra ändringar i din konfiguration och förhandsgranska resultaten, men tills du sparar kommer inga av dina ändringar att bevaras.", + "save-stage-btn":"Spara", + "cancel-stage-btn":"Avbryt" + }, + "edit-item":{ + "missing-title-err":"Objektet måste ha en titel" + }, + "edit-section":{ + "edit-section-title":"Redigera sektion", + "add-section-title":"Lägg till ny sektion", + "edit-tooltip":"Tryck för att redigera, eller högerklicka för fler alternativ", + "remove-confirm":"Är du säker på att du vill ta bort denna sektion? Denna åtgärd kan ångras senare." + }, + "edit-app-config":{ + "warning-msg-title":"Fortsätt med försiktighet", + "warning-msg-l1":"Följande alternativ är för avancerade appkonfigurationer.", + "warning-msg-l2":"Om du är osäker på något av fälten, vänligen kolla", + "warning-msg-docs":"dokumentationen", + "warning-msg-l3":"för att undvika oavsiktliga konsekvenser." + }, + "export":{ + "export-title":"Exportera konfiguration", + "copy-clipboard-btn":"Kopiera till urklipp", + "copy-clipboard-tooltip":"Kopiera alla appkonfigurationer till systemets urklipp i YAML-format", + "download-file-btn":"Ladda ned som fil", + "download-file-tooltip":"Ladda ner alla appkonfigurationer till din enhet som en YAML-fil", + "view-title":"Visa konfiguration" + } + }, + "widgets":{ + "general":{ + "loading":"Laddar...", + "show-more":"Visa mer info", + "show-less":"Visa mindre", + "open-link":"Läs mer" + }, + "pi-hole":{ + "status-heading":"Status" + }, + "stat-ping":{ + "up":"Online", + "down":"Offline" + }, + "net-data":{ + "cpu-chart-title":"CPU History", + "mem-chart-title":"Memory Usage", + "mem-breakdown-title":"Memory Breakdown", + "load-chart-title":"System Load" + }, + "system-info":{ + "uptime":"Uptime" + }, + "flight-data":{ + "arrivals":"Ankomster", + "departures":"Avgångar" + }, + "tfl-status":{ + "good-service-all":"Good Service på alla linjer", + "good-service-rest":"Good Service på alla övriga linjer" + } + } +} \ No newline at end of file From dd30099ad8d7956dc6a539844ff8a74864c69111 Mon Sep 17 00:00:00 2001 From: Leonardo Covarrubias Date: Sat, 1 Jan 2022 17:32:48 -0500 Subject: [PATCH 03/39] :sparkle: added keycloak logout button --- src/components/Settings/AuthButtons.vue | 23 ++++- src/components/Settings/SettingsContainer.vue | 4 +- src/main.js | 6 +- src/utils/Auth.js | 86 ++--------------- src/utils/KeycloakAuth.js | 92 +++++++++++++++++++ src/utils/defaults.js | 1 + 6 files changed, 124 insertions(+), 88 deletions(-) create mode 100644 src/utils/KeycloakAuth.js diff --git a/src/components/Settings/AuthButtons.vue b/src/components/Settings/AuthButtons.vue index ddacc2c1..ad355d6c 100644 --- a/src/components/Settings/AuthButtons.vue +++ b/src/components/Settings/AuthButtons.vue @@ -1,7 +1,7 @@ @@ -24,6 +31,7 @@