First somewhat working image
This commit is contained in:
parent
2fee5a8db7
commit
a8bedc24a4
@ -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)));
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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)));
|
||||
}
|
||||
|
||||
@ -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 (
|
||||
<SWRConfig value={{ fallback, fetcher: (resource, init) => fetch(resource, init).then((res) => res.json()) }}>
|
||||
<ErrorBoundary>
|
||||
<Home initialSettings={initialSettings} />
|
||||
<Home initialSettings={initialSettings} authContext={authContext}/>
|
||||
</ErrorBoundary>
|
||||
</SWRConfig>
|
||||
);
|
||||
@ -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}`,
|
||||
)}
|
||||
>
|
||||
<Index initialSettings={initialSettings} fallback={fallback} />
|
||||
<Index initialSettings={initialSettings} fallback={fallback} authContext={authContext}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
21
src/utils/auth/null.js
Normal file
21
src/utils/auth/null.js
Normal file
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user