diff --git a/packages/api/src/controllers/auth.js b/packages/api/src/controllers/auth.js index 1d890b88f..7978a7c00 100644 --- a/packages/api/src/controllers/auth.js +++ b/packages/api/src/controllers/auth.js @@ -36,8 +36,9 @@ function authMiddleware(req, res, next) { '/auth/login', '/auth/redirect', '/stream', - 'storage/get-connections-for-login-page', - 'auth/get-providers', + '/storage/get-connections-for-login-page', + '/storage/set-admin-password', + '/auth/get-providers', '/connections/dblogin-web', '/connections/dblogin-app', '/connections/dblogin-auth', @@ -69,6 +70,7 @@ function authMiddleware(req, res, next) { return next(); } catch (err) { if (skipAuth) { + req.isInvalidToken = true; return next(); } diff --git a/packages/api/src/controllers/config.js b/packages/api/src/controllers/config.js index 25b253bc4..ac0f4fb7b 100644 --- a/packages/api/src/controllers/config.js +++ b/packages/api/src/controllers/config.js @@ -60,6 +60,14 @@ module.exports = { const checkedLicense = storageConnectionError ? null : await checkLicense(); const isLicenseValid = checkedLicense?.status == 'ok'; const logoutUrl = storageConnectionError ? null : await authProvider.getLogoutUrl(); + const adminConfig = storageConnectionError ? null : await storage.readConfig({ group: 'admin' }); + + const isAdminPasswordMissing = !!( + process.env.STORAGE_DATABASE && + !process.env.ADMIN_PASSWORD && + !process.env.BASIC_AUTH && + !adminConfig?.adminPasswordState + ); return { runAsPortal: !!connections.portalConnections, @@ -87,6 +95,9 @@ module.exports = { !process.env.BASIC_AUTH && checkedLicense?.type == 'premium' ), + isAdminPasswordMissing, + isInvalidToken: req.isInvalidToken, + adminPasswordState: adminConfig?.adminPasswordState, storageDatabase: process.env.STORAGE_DATABASE, logsFilePath: getLogsFilePath(), connectionsFilePath: path.join(datadir(), 'connections.jsonl'), diff --git a/packages/api/src/controllers/storage.js b/packages/api/src/controllers/storage.js index 3f9dd9dc4..58e21dc8d 100644 --- a/packages/api/src/controllers/storage.js +++ b/packages/api/src/controllers/storage.js @@ -20,5 +20,10 @@ module.exports = { getStorageConnectionError() { return null; - } + }, + + readConfig_meta: true, + async readConfig({ group }) { + return {}; + }, }; diff --git a/packages/web/build-index.js b/packages/web/build-index.js index 91650e4c2..67fe0d5b5 100644 --- a/packages/web/build-index.js +++ b/packages/web/build-index.js @@ -2,7 +2,17 @@ const fs = require('fs'); const template = fs.readFileSync('./index.html.tpl', 'utf-8'); -for (const page of ['', 'not-logged', 'error', 'admin-login', 'login', 'admin', 'license']) { +for (const page of [ + '', + 'not-logged', + 'error', + 'admin-login', + 'login', + 'admin', + 'license', + 'set-admin-password', + 'redirect', +]) { const text = template.replace(/{{page}}/g, page); fs.writeFileSync(`public/${page || 'index'}.html`, text); } diff --git a/packages/web/src/App.svelte b/packages/web/src/App.svelte index 4669f628a..66d95e176 100644 --- a/packages/web/src/App.svelte +++ b/packages/web/src/App.svelte @@ -38,7 +38,7 @@ // console.log('************** LOADING API'); const config = await getConfig(); - await handleAuthOnStartup(config, isAdminPage); + await handleAuthOnStartup(config); const connections = await apiCall('connections/list'); const settings = await getSettings(); diff --git a/packages/web/src/EnterLicensePage.svelte b/packages/web/src/EnterLicensePage.svelte index a20ae7b19..1424e6fe7 100644 --- a/packages/web/src/EnterLicensePage.svelte +++ b/packages/web/src/EnterLicensePage.svelte @@ -11,6 +11,8 @@ import getElectron from './utility/getElectron'; import { openWebLink } from './utility/exportFileTools'; import SpecialPageLayout from './widgets/SpecialPageLayout.svelte'; + import hasPermission from './utility/hasPermission'; + import ErrorInfo from './elements/ErrorInfo.svelte'; const config = useConfig(); const values = writable({ amoid: null, databaseServer: null }); @@ -25,89 +27,95 @@ errorMessage = 'Your license is expired'; expiredMessageSet = true; } + + // $: console.log('CONFIG', $config); -
License
- + {#if getElectron() || ($config?.storageDatabase && hasPermission('admin/license'))} +
License
+ -
- { - sessionStorage.setItem('continueTrialConfirmed', '1'); - const { licenseKey } = e.detail; - const resp = await apiCall('config/save-license-key', { licenseKey }); - if (resp?.status == 'ok') { - internalRedirectTo('/index.html'); - } else { - errorMessage = resp?.errorMessage || 'Error saving license key'; - } - }} - /> -
- - {#if !isExpired && trialDaysLeft == null}
- { - errorMessage = ''; - const license = await apiCall('config/start-trial'); - if (license?.status == 'ok') { - sessionStorage.setItem('continueTrialConfirmed', '1'); + sessionStorage.setItem('continueTrialConfirmed', '1'); + const { licenseKey } = e.detail; + const resp = await apiCall('config/save-license-key', { licenseKey }); + if (resp?.status == 'ok') { internalRedirectTo('/index.html'); } else { - errorMessage = license?.errorMessage || 'Error starting trial'; + errorMessage = resp?.errorMessage || 'Error saving license key'; } }} />
- {/if} - {#if trialDaysLeft > 0} + {#if !isExpired && trialDaysLeft == null} +
+ { + errorMessage = ''; + const license = await apiCall('config/start-trial'); + if (license?.status == 'ok') { + sessionStorage.setItem('continueTrialConfirmed', '1'); + internalRedirectTo('/index.html'); + } else { + errorMessage = license?.errorMessage || 'Error starting trial'; + } + }} + /> +
+ {/if} + + {#if trialDaysLeft > 0} +
+ { + sessionStorage.setItem('continueTrialConfirmed', '1'); + internalRedirectTo('/index.html'); + }} + /> +
+ {/if} +
{ - sessionStorage.setItem('continueTrialConfirmed', '1'); - internalRedirectTo('/index.html'); + openWebLink( + `https://auth.dbgate.eu/create-checkout-session-simple?source=trial-${isExpired ? 'expired' : (trialDaysLeft ?? 'no')}` + ); }} />
- {/if} -
- { - openWebLink( - `https://auth.dbgate.eu/create-checkout-session-simple?source=trial-${isExpired ? 'expired' : (trialDaysLeft ?? 'no')}` - ); - }} - /> -
+ {#if getElectron()} +
+ { + getElectron().send('quit-app'); + }} + /> +
+ {/if} - {#if getElectron()} -
- { - getElectron().send('quit-app'); - }} - /> + {#if errorMessage} +
{errorMessage}
+ {/if} + +
+ For more info about DbGate licensing, you could visit dbgate.eu web or contact + us at sales@dbgate.eu
+ {:else} + {/if} - - {#if errorMessage} -
{errorMessage}
- {/if} - -
- For more info about DbGate licensing, you could visit dbgate.eu web or contact - us at sales@dbgate.eu -
diff --git a/packages/web/src/RedirectPage.svelte b/packages/web/src/RedirectPage.svelte new file mode 100644 index 000000000..e08fae7ad --- /dev/null +++ b/packages/web/src/RedirectPage.svelte @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/web/src/SetAdminPasswordPage.svelte b/packages/web/src/SetAdminPasswordPage.svelte new file mode 100644 index 000000000..7b337b957 --- /dev/null +++ b/packages/web/src/SetAdminPasswordPage.svelte @@ -0,0 +1,79 @@ + + + + +
Set admin password
+ +
+ Please set password for DbGate administrator account. If you lose this paassword, you can change it later in + DbGate internal database, in table config. +
+ + + + {#if $values?.denyUseAdminPassword} +
+ You have selected to not use admin password. You can change this setting later in DbGate internal database, in + table config. Please assign to some regular user admin role, to be able to perform admin tasks. +
+ {:else} + {#if $config?.adminPasswordState == 'set'} + + {/if} + + + {/if} + + {#if error} + + {/if} + +
+ { + const resp = await apiCall('storage/set-admin-password', e.detail); + if (resp?.status == 'error') { + error = resp?.errorMessage; + return; + } + internalRedirectTo('/admin.html'); + }} + /> +
+
+
+ + diff --git a/packages/web/src/clientAuth.ts b/packages/web/src/clientAuth.ts index 91f3135ff..695733e86 100644 --- a/packages/web/src/clientAuth.ts +++ b/packages/web/src/clientAuth.ts @@ -116,48 +116,120 @@ export function handleOauthCallback() { return false; } -export async function handleAuthOnStartup(config, isAdminPage = false) { - if (config.configurationError) { - internalRedirectTo(`/error.html`); - return; - } +export async function handleAuthOnStartup(config) { + const page = window['dbgate_page']; - if (!config.isLicenseValid) { - if (config.storageDatabase || getElectron()) { - internalRedirectTo(`/license.html`); - } else { + function checkConfigError() { + if (config.configurationError) { internalRedirectTo(`/error.html`); + return true; } } - if ( - config.trialDaysLeft != null && - config.trialDaysLeft <= 14 && - !sessionStorage.getItem('continueTrialConfirmed') && - getElectron() - ) { - internalRedirectTo(`/license.html`); + function checkInvalidLicense() { + if (!config.isLicenseValid) { + if (config.storageDatabase || getElectron()) { + internalRedirectTo(`/license.html`); + } else { + internalRedirectTo(`/error.html`); + } + return true; + } } - if (getAuthCategory(config) == 'admin') { - if (localStorage.getItem('adminAccessToken')) { - return; + function checkTrialDaysLeft() { + if ( + config.trialDaysLeft != null && + config.trialDaysLeft <= 14 && + !sessionStorage.getItem('continueTrialConfirmed') && + getElectron() + ) { + internalRedirectTo(`/license.html`); + return true; + } + } + + function checkLoggedUser() { + if (getAuthCategory(config) == 'admin') { + if (!config.isInvalidToken && localStorage.getItem('adminAccessToken')) { + return false; + } + + redirectToAdminLogin(); + return true; } - redirectToAdminLogin(); - return; + if (getAuthCategory(config) == 'token') { + if (!config.isInvalidToken && localStorage.getItem('accessToken')) { + return false; + } + + redirectToLogin(config); + return true; + } } - // if (config.oauth) { - // console.log('OAUTH callback URL:', location.origin + location.pathname); + function checkAdminPasswordSet() { + if (config.isAdminPasswordMissing) { + internalRedirectTo(`/set-admin-password.html`); + return true; + } + } + + if (page == 'error') return; + if (checkConfigError()) return; + + if (page == 'set-admin-password') return; + if (checkAdminPasswordSet()) return; + + if (page == 'login' || page == 'admin-login' || page == 'not-logged') return; + if (checkLoggedUser()) return; + + if (page == 'license') return; + if (checkTrialDaysLeft()) return; + if (checkInvalidLicense()) return; + + // if (config.configurationError) { + // internalRedirectTo(`/error.html`); + // return; // } - if (getAuthCategory(config) == 'token') { - if (localStorage.getItem('accessToken')) { - return; - } - redirectToLogin(config); - } + // if (!config.isLicenseValid) { + // if (config.storageDatabase || getElectron()) { + // internalRedirectTo(`/license.html`); + // } else { + // internalRedirectTo(`/error.html`); + // } + // } + + // if ( + // config.trialDaysLeft != null && + // config.trialDaysLeft <= 14 && + // !sessionStorage.getItem('continueTrialConfirmed') && + // getElectron() + // ) { + // internalRedirectTo(`/license.html`); + // } + + // if (getAuthCategory(config) == 'admin') { + // if (localStorage.getItem('adminAccessToken')) { + // return; + // } + + // redirectToAdminLogin(); + // return; + // } + + // // if (config.oauth) { + // // console.log('OAUTH callback URL:', location.origin + location.pathname); + // // } + // if (getAuthCategory(config) == 'token') { + // if (localStorage.getItem('accessToken')) { + // return; + // } + + // redirectToLogin(config); + // } } export async function redirectToAdminLogin() { diff --git a/packages/web/src/commands/stdCommands.ts b/packages/web/src/commands/stdCommands.ts index 78423b620..7163b9e72 100644 --- a/packages/web/src/commands/stdCommands.ts +++ b/packages/web/src/commands/stdCommands.ts @@ -36,7 +36,7 @@ import runCommand from './runCommand'; import { openWebLink } from '../utility/exportFileTools'; import { getSettings } from '../utility/metadataLoaders'; import { isMac, switchCurrentDatabase } from '../utility/common'; -import { doLogout, internalRedirectTo } from '../clientAuth'; +import { doLogout } from '../clientAuth'; import { disconnectServerConnection } from '../appobj/ConnectionAppObject.svelte'; import UploadErrorModal from '../modals/UploadErrorModal.svelte'; import ErrorMessageModal from '../modals/ErrorMessageModal.svelte'; diff --git a/packages/web/src/main.ts b/packages/web/src/main.ts index 5348c585b..9e16797b8 100644 --- a/packages/web/src/main.ts +++ b/packages/web/src/main.ts @@ -8,6 +8,8 @@ import LoginPage from './LoginPage.svelte'; import NotLoggedPage from './NotLoggedPage.svelte'; import ErrorPage from './ErrorPage.svelte'; import EnterLicensePage from './EnterLicensePage.svelte'; +import SetAdminPasswordPage from './SetAdminPasswordPage.svelte'; +import RedirectPage from './RedirectPage.svelte'; const isOauthCallback = handleOauthCallback(); @@ -43,11 +45,20 @@ function createApp() { isAdminPage: true, }, }); + case 'redirect': + return new RedirectPage({ + target: document.body, + }); case 'not-logged': return new NotLoggedPage({ target: document.body, props: {}, }); + case 'set-admin-password': + return new SetAdminPasswordPage({ + target: document.body, + props: {}, + }); case 'admin': return new App({ target: document.body, diff --git a/packages/web/src/utility/api.ts b/packages/web/src/utility/api.ts index b39ee3a2b..f98b6c30b 100644 --- a/packages/web/src/utility/api.ts +++ b/packages/web/src/utility/api.ts @@ -4,7 +4,7 @@ import { writable } from 'svelte/store'; import getElectron from './getElectron'; // import socket from './socket'; import { showSnackbarError } from '../utility/snackbar'; -import { isOauthCallback, redirectToAdminLogin, redirectToLogin } from '../clientAuth'; +import { handleAuthOnStartup, isOauthCallback, redirectToAdminLogin, redirectToLogin } from '../clientAuth'; import { showModal } from '../modals/modalTools'; import DatabaseLoginModal, { isDatabaseLoginVisible } from '../modals/DatabaseLoginModal.svelte'; import _ from 'lodash'; @@ -144,17 +144,23 @@ export function transformApiArgsInv(args) { }); } -export async function apiCall(route: string, args: {} = undefined) { +export async function apiCall( + route: string, + args: {} = undefined, + options: { skipDisableChecks: boolean } = undefined +) { if (apiLogging) { console.log('>>> API CALL', route, args); } - if (apiDisabled) { - console.log('API disabled!!', route); - return; - } - if (disabledOnOauth && route != 'auth/oauth-token') { - console.log('API disabled because oauth callback!!', route); - return; + if (!options?.skipDisableChecks) { + if (apiDisabled) { + console.log('API disabled!!', route); + return; + } + if (disabledOnOauth && route != 'auth/oauth-token') { + console.log('API disabled because oauth callback!!', route); + return; + } } args = transformApiArgs(args); @@ -180,12 +186,15 @@ export async function apiCall(route: string, args: {} = undefined) { disableApi(); console.log('Disabling API', route); if (page != 'login' && page != 'admin-login' && page != 'not-logged') { - // unauthorized - if (page == 'admin') { - redirectToAdminLogin(); - } else { - redirectToLogin(); - } + const config = await apiCall('config/get', {}, { skipDisableChecks: true }); + await handleAuthOnStartup(config); + + // // unauthorized + // if (page == 'admin') { + // redirectToAdminLogin(); + // } else { + // redirectToLogin(); + // } } return; } diff --git a/packages/web/src/utility/hasPermission.ts b/packages/web/src/utility/hasPermission.ts index 64f162671..5db1258a8 100644 --- a/packages/web/src/utility/hasPermission.ts +++ b/packages/web/src/utility/hasPermission.ts @@ -18,3 +18,7 @@ export function subscribePermissionCompiler() { // console.log('COMPILED PERMS', compiled); }); } + +export function setConfigForPermissions(config) { + compiled = compilePermissions(config?.permissions || {}); +} diff --git a/packages/web/src/widgets/SpecialPageLayout.svelte b/packages/web/src/widgets/SpecialPageLayout.svelte index 3da0701ca..b0174eb5b 100644 --- a/packages/web/src/widgets/SpecialPageLayout.svelte +++ b/packages/web/src/widgets/SpecialPageLayout.svelte @@ -1,9 +1,25 @@