diff --git a/src/pages/api/bookmarks.js b/src/pages/api/bookmarks.js
index ae50c279..a7b0ae17 100644
--- a/src/pages/api/bookmarks.js
+++ b/src/pages/api/bookmarks.js
@@ -1,7 +1,8 @@
-import { createAuthFromSettings } from "utils/auth/auth-helpers";
+import { createAuthProvider } from "utils/auth/auth-helpers";
import { bookmarksResponse } from "utils/config/api-response";
+import { getSettings } from "utils/config/config";
export default async function handler(req, res) {
- const auth = createAuthFromSettings()
+ const auth = createAuthProvider(getSettings())
res.send(await bookmarksResponse(auth.permissions(req)));
}
diff --git a/src/pages/api/services/index.js b/src/pages/api/services/index.js
index 3140d6eb..749ee420 100644
--- a/src/pages/api/services/index.js
+++ b/src/pages/api/services/index.js
@@ -1,8 +1,14 @@
-import { createAuthFromSettings } from "utils/auth/auth-helpers";
+import { createAuthProvider } from "utils/auth/auth-helpers";
import { servicesResponse } from "utils/config/api-response";
+import { getSettings } from "utils/config/config";
+import createLogger from "utils/logger";
+
+let logger = createLogger("services_index")
export default async function handler(req, res) {
- const auth = createAuthFromSettings()
-
- res.send(await servicesResponse(auth.permissions(req)));
+ logger.log("Call services");
+ const auth = createAuthProvider(getSettings)
+ const result = await servicesResponse(auth.permissions(req))
+ logger.log(result);
+ res.send(result);
}
diff --git a/src/pages/api/widgets/index.js b/src/pages/api/widgets/index.js
index eae40397..beb642f3 100644
--- a/src/pages/api/widgets/index.js
+++ b/src/pages/api/widgets/index.js
@@ -1,8 +1,9 @@
-import { createAuthFromSettings } from "utils/auth/auth-helpers";
+import { createAuthProvider } from "utils/auth/auth-helpers";
import { widgetsResponse } from "utils/config/api-response";
+import { getSettings } from "utils/config/config";
export default async function handler(req, res) {
- const auth = createAuthFromSettings();
+ const auth = createAuthProvider(getSettings());
res.send(await widgetsResponse(auth.permissions(req)));
}
diff --git a/src/pages/index.jsx b/src/pages/index.jsx
index 590d39bb..6701b3a8 100644
--- a/src/pages/index.jsx
+++ b/src/pages/index.jsx
@@ -1,7 +1,6 @@
/* eslint-disable react/no-array-index-key */
-import useSWR, { SWRConfig } from "swr";
+import useSWR, { unstable_serialize, SWRConfig } from "swr";
import Head from "next/head";
-import {headers} from "next/header";
import dynamic from "next/dynamic";
import classNames from "classnames";
import { useTranslation } from "next-i18next";
@@ -28,8 +27,8 @@ import ErrorBoundary from "components/errorboundry";
import themes from "utils/styles/themes";
import QuickLaunch from "components/quicklaunch";
import { getStoredProvider, searchProviders } from "components/widgets/search/search";
-import { NullPermissions, createAuthFromSettings } from "utils/auth/auth-helpers";
-
+import { createAuthorizer, fetchWithAuth } from "utils/auth/auth-helpers";
+import { NullAuthProvider } from "utils/auth/null";
const ThemeToggle = dynamic(() => import("components/toggles/theme"), {
ssr: false,
});
@@ -44,25 +43,28 @@ const Version = dynamic(() => import("components/version"), {
const rightAlignedWidgets = ["weatherapi", "openweathermap", "weather", "openmeteo", "search", "datetime"];
-export async function getStaticProps() {
+export async function getServerSideProps({req}) {
let logger;
try {
logger = createLogger("index");
const { providers, auth, ...settings } = getSettings();
+ const authProvider = createAuthorizer({auth: auth});
- const services = await servicesResponse(NullPermissions);
- const bookmarks = await bookmarksResponse(NullPermissions);
- const widgets = await widgetsResponse(NullPermissions);
+ const services = await servicesResponse(authProvider.authorize(req));
+ const bookmarks = await bookmarksResponse(authProvider.authorize(req));
+ const widgets = await widgetsResponse(authProvider.authorize(req));
+ const authContext = authProvider.getContext(req);
return {
props: {
initialSettings: settings,
fallback: {
- "/api/services": services,
- "/api/bookmarks": bookmarks,
- "/api/widgets": widgets,
+ [unstable_serialize(["/api/services", authContext])]: services,
+ [unstable_serialize(["/api/bookmarks", authContext])]: bookmarks,
+ [unstable_serialize(["/api/widgets", authContext])]: widgets,
"/api/hash": false,
},
+ authContext: authContext,
...(await serverSideTranslations(settings.language ?? "en")),
},
};
@@ -70,22 +72,24 @@ export async function getStaticProps() {
if (logger) {
logger.error(e);
}
+ const authContext = NullAuthProvider.create().getContext(req);
return {
props: {
initialSettings: {},
fallback: {
- "/api/services": [],
- "/api/bookmarks": [],
- "/api/widgets": [],
+ [unstable_serialize(["/api/services", authContext])]: [],
+ [unstable_serialize(["/api/bookmarks", authContext])]: [],
+ [unstable_serialize(["/api/widgets", authContext])]: [],
"/api/hash": false,
},
+ authContext: authContext,
...(await serverSideTranslations("en")),
},
};
}
}
-function Index({ initialSettings, fallback }) {
+function Index({ initialSettings, fallback, authContext }) {
const windowFocused = useWindowFocus();
const [stale, setStale] = useState(false);
const { data: errorsData } = useSWR("/api/validate");
@@ -155,7 +159,7 @@ function Index({ initialSettings, fallback }) {
return (
fetch(resource, init).then((res) => res.json()) }}>
-
+
);
@@ -169,7 +173,7 @@ const headerStyles = {
boxedWidgets: "m-6 mb-0 sm:m-9 sm:mb-0 sm:mt-1",
};
-function Home({ initialSettings }) {
+function Home({ initialSettings, authContext }) {
const { i18n } = useTranslation();
const { theme, setTheme } = useContext(ThemeContext);
const { color, setColor } = useContext(ColorContext);
@@ -181,11 +185,9 @@ function Home({ initialSettings }) {
setSettings(initialSettings);
}, [initialSettings, setSettings]);
- const auth = createAuthFromSettings();
-
- const { data: services } = useSWR(auth.cacheContext("/api/services"), auth.fetcher);
- const { data: bookmarks } = useSWR(auth.cacheContext("/api/bookmarks"), auth.fetcher);
- const { data: widgets } = useSWR(auth.cacheContext("/api/widgets"), auth.fetcher);
+ const { data: services } = useSWR(["/api/services", authContext], fetchWithAuth);
+ const { data: bookmarks } = useSWR(["/api/bookmarks", authContext], fetchWithAuth);
+ const { data: widgets } = useSWR(["/api/widgets", authContext], fetchWithAuth);
const servicesAndBookmarks = [
...services.map((sg) => sg.services).flat(),
@@ -470,7 +472,7 @@ function Home({ initialSettings }) {
);
}
-export default function Wrapper({ initialSettings, fallback }) {
+export default function Wrapper({ initialSettings, fallback, authContext }) {
const wrappedStyle = {};
let backgroundBlur = false;
let backgroundSaturate = false;
@@ -521,7 +523,7 @@ export default function Wrapper({ initialSettings, fallback }) {
backgroundBrightness && `backdrop-brightness-${initialSettings.background.brightness}`,
)}
>
-
+
diff --git a/src/utils/auth/auth-helpers.js b/src/utils/auth/auth-helpers.js
index bf3ae242..a6c2ccbb 100644
--- a/src/utils/auth/auth-helpers.js
+++ b/src/utils/auth/auth-helpers.js
@@ -1,41 +1,42 @@
-import { getSettings } from "utils/config/config";
-import { ProxyAuthKey, createProxyAuth } from "./proxy";
+import { ProxyAuthProvider} from "./proxy";
+import { NullAuthProvider} from "./null";
-export const NullPermissions = { user: null, groups:[]}
+const AuthProviders = {
+ NullAuthProvider,
+ ProxyAuthProvider
+};
-export const NullAuth = {
- permissions: (request) => NullPermissions,
- cacheContext: (key) => key,
- fetcher: (key) => fetch(key).then((res) => res.json())
+function getProviderByKey(key) {
+ return AuthProviders.find((provider) => provider.key == key) ?? NullAuthProvider;
}
-export function createAuthFromSettings() {
- const {auth} = getSettings();
+export function createAuthorizer({auth}) {
if (auth) {
- switch (Object.keys(auth)[0]) {
- case ProxyAuthKey:
- return createProxyAuth(auth[ProxyAuthKey]);
- default:
- return NullAuth;
- }
+ getProviderByKey(Object.keys(auth)[0]).create(auth[ProxyAuthKey]);
}
- return NullAuth
+ return NullAuthProvider.create();
+}
+
+export async function fetchWithAuth(key, context) {
+ return getProviderByKey(context.provider).fetch([key, context]);
}
export const filterAllowedServices = (perms, services) => filterAllowedItems(perms, services, 'services');
export const filterAllowedBookmarks = (perms, bookmarks) => filterAllowedItems(perms, bookmarks, 'bookmarks');
-export const filterAllowedWidgets = (perms, widgets) => filterAllowedItems(perms, widgets, 'widgets')
+export const filterAllowedWidgets = (perms, widgets) => {
+ return widgets.filter((widget) => authItemFilter(perms, widget.options) )
+}
function filterAllowedItems({user, groups}, itemGroups, groupKey) {
return itemGroups.map((group) => ({
name: group.name,
[groupKey]: group[groupKey].filter((item) => authItemFilter({user, groups}, item))
- })).filter((group) => !group[groupKey].length)
+ })).filter((group) => !group[groupKey].length);
}
function authItemFilter({user, groups}, item) {
- const groupAllow = (!(allowGroups in item)) || groups.some(group => item.allowGroups.includes(group));
- const userAllow = (!(allowUsers in item)) || item.allowUsers.includes(user);
+ const groupAllow = (!('allowGroups' in item)) || groups.some(group => item.allowGroups.includes(group));
+ const userAllow = (!('allowUsers' in item)) || item.allowUsers.includes(user);
return userAllow || groupAllow;
}
diff --git a/src/utils/auth/null.js b/src/utils/auth/null.js
new file mode 100644
index 00000000..f1656823
--- /dev/null
+++ b/src/utils/auth/null.js
@@ -0,0 +1,21 @@
+const NullPermissions = { user: null, groups:[]}
+const NullAuthKey = "none"
+
+function createNullAuth() {
+ return {
+ authorize: (request) => NullPermissions,
+ getContext: (request) => { return {
+ provider: NullAuthKey
+ } },
+ }
+}
+
+async function fetchNullAuth([key, context]) {
+ return fetch(key).then((res) => res.json())
+}
+
+export const NullAuthProvider = {
+ key: NullAuthKey,
+ create: createNullAuth,
+ fetch: fetchNullAuth
+}
diff --git a/src/utils/auth/proxy.js b/src/utils/auth/proxy.js
index 17c51328..7e824cb0 100644
--- a/src/utils/auth/proxy.js
+++ b/src/utils/auth/proxy.js
@@ -1,42 +1,35 @@
// Proxy auth is meant to be used by a reverse proxy that injects permission headers into the origin
// request. In this case we are relying on our proxy to authenitcate our users and validate.
-import {createLogger} from "utils/logger";
-import { headers } from 'next/headers';
-
-export const ProxyAuthKey="proxy_auth"
-
+const ProxyAuthKey="proxy_auth"
function getProxyPermissions(userHeader, groupHeader, request) {
- const logger = createLogger("proxyAuth")
const user = (userHeader)?request.headers.get(userHeader):None;
- if (!user) {
- logger.debug("unable to retreive user. User header doesn't exist or unspecified.")
- }
const groupsString = (groupHeader)?request.headers.get(groupHeader):"";
- if (!groupsString) {
- logger.debug("unable to retrieve groups. Groups header doesn't exist or unspecified")
- }
return {user: user, groups: (groupsString)?groupsString.split(",").map((v) => v.trimStart()):[]}
}
-export function createProxyAuth({groupHeader, userHeader}) {
- const logger = createLogger("proxyAuth")
-
- if (!userHeader) {
- logger.debug("'userHeader' value not specified");
- }
- if (!groupHeader) {
- logger.debug("'groupHeader' value not specified")
- }
+function createProxyAuth({groupHeader, userHeader}) {
return {
- permissions : (request) => getProxyPermissions(userHeader, groupHeader, request),
- cacheContext: (key) => [ key, {
- ...userHeader && {[userHeader]: headers.get(userHeader) },
- ...groupHeader && {[groupHeader]: headers.get(groupHeader)}
- }],
- fetcher: ([key, context]) => {
- fetch(key, {headers: context}).then((res) => res.json())
- }
+ getContext : (request) => {
+ return {
+ provider: ProxyAuthKey,
+ headers: {
+ ...userHeader && {[userHeader]: request.headers.get(userHeader) },
+ ...groupHeader && {[groupHeader]: request.headers.get(groupHeader)}
+ }
+ }
+ },
+ authorize : (request) => getProxyPermissions(userHeader, groupHeader, request)
}
+}
+
+async function fetchProxyAuth([key, context]) {
+ return fetch(key, {headers: context.headers}).then((res) => res.json())
+}
+
+export const ProxyAuthProvider = {
+ key: ProxyAuthKey,
+ create: createProxyAuth,
+ fetch: fetchProxyAuth
}
\ No newline at end of file
diff --git a/src/utils/config/api-response.js b/src/utils/config/api-response.js
index bd86670e..62937e8a 100644
--- a/src/utils/config/api-response.js
+++ b/src/utils/config/api-response.js
@@ -83,7 +83,7 @@ export async function widgetsResponse(perms) {
let configuredWidgets;
try {
- configuredWidgets = filterAllowedWidgets(perms, cleanWidgetGroups(await widgetsFromConfig()));
+ configuredWidgets = filterAllowedWidgets(perms, await cleanWidgetGroups(await widgetsFromConfig()));
} catch (e) {
console.error("Failed to load widgets, please check widgets.yaml for errors or remove example entries.");
if (e) console.error(e);