Fix precommit isssues
This commit is contained in:
parent
df38d8f48b
commit
d54e1d0879
@ -456,41 +456,42 @@ or per service widget (`services.yaml`) with:
|
|||||||
|
|
||||||
If either value is set to true, the error message will be hidden.
|
If either value is set to true, the error message will be hidden.
|
||||||
|
|
||||||
## Authentication
|
## Authentication
|
||||||
|
|
||||||
Basic auth integration is implemeted via an `auth` section. An auth provider can be configured using the `provider` section with the given type. Currently the only provider supported is `proxy`, where the users identification and group membership are passed via HTTP Request headers (in plaintext). The expectation is that the application will be accessed only via an authenticating proxy (i.e treafik ).
|
Basic auth integration is implemeted via an `auth` section. An auth provider can be configured using the `provider` section with the given type. Currently the only provider supported is `proxy`, where the users identification and group membership are passed via HTTP Request headers (in plaintext). The expectation is that the application will be accessed only via an authenticating proxy (i.e treafik ).
|
||||||
|
|
||||||
The group and user headers are both configurable like so:
|
The group and user headers are both configurable like so:
|
||||||
```yaml
|
|
||||||
auth:
|
|
||||||
provider:
|
|
||||||
type: proxy
|
|
||||||
groupHeader: "X-group-header"
|
|
||||||
userHeader: "X-user-header"
|
|
||||||
```
|
|
||||||
|
|
||||||
Auth can be configured on the service, bookmark, and widget level using the `allowUsers` and `allowGroups` list.
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- Example Servie:
|
auth:
|
||||||
allowGroups:
|
provider:
|
||||||
|
type: proxy
|
||||||
|
groupHeader: "X-group-header"
|
||||||
|
userHeader: "X-user-header"
|
||||||
|
```
|
||||||
|
|
||||||
|
Auth can be configured on the service, bookmark, and widget level using the `allowUsers` and `allowGroups` list.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- Example Servie:
|
||||||
|
allowGroups:
|
||||||
- Group1
|
- Group1
|
||||||
- Group2
|
- Group2
|
||||||
- Group3
|
- Group3
|
||||||
allowUsers:
|
allowUsers:
|
||||||
- User1
|
- User1
|
||||||
- User2
|
- User2
|
||||||
- User3
|
- User3
|
||||||
```
|
```
|
||||||
|
|
||||||
Auth for groups can be set in the `groups` under `auth`. In general the `groups` tag follows the format of the `layout`
|
Auth for groups can be set in the `groups` under `auth`. In general the `groups` tag follows the format of the `layout`
|
||||||
section. For example:
|
section. For example:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
auth:
|
auth:
|
||||||
groups:
|
groups:
|
||||||
My Service Group:
|
My Service Group:
|
||||||
allowGroups: ['Group1', 'Group2']
|
allowGroups: ["Group1", "Group2"]
|
||||||
My Other Group:
|
My Other Group:
|
||||||
allowGroups: ['Group1']
|
allowGroups: ["Group1"]
|
||||||
```
|
```
|
||||||
|
|||||||
@ -2,16 +2,16 @@ import { checkAllowedGroup, readAuthSettings } from "utils/auth/auth-helpers";
|
|||||||
import { getSettings } from "utils/config/config";
|
import { getSettings } from "utils/config/config";
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
export default async function handler(req, res) {
|
||||||
const { group } = req.query;
|
const { group } = req.query;
|
||||||
const { provider, groups } = readAuthSettings(getSettings().auth)
|
const { provider, groups } = readAuthSettings(getSettings().auth);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (checkAllowedGroup(provider.permissions(req), groups, group)) {
|
if (checkAllowedGroup(provider.permissions(req), groups, group)) {
|
||||||
res.json({group})
|
res.json({ group });
|
||||||
} else {
|
} else {
|
||||||
res.status(401).json({message:"Group unathorized"})
|
res.status(401).json({ message: "Group unathorized" });
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).send("Error authenticating");
|
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
res.status(500).send("Error authenticating");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,6 @@ import { bookmarksResponse } from "utils/config/api-response";
|
|||||||
import { getSettings } from "utils/config/config";
|
import { getSettings } from "utils/config/config";
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
export default async function handler(req, res) {
|
||||||
const { provider, groups } = readAuthSettings(getSettings().auth)
|
const { provider, groups } = readAuthSettings(getSettings().auth);
|
||||||
res.send(await bookmarksResponse(provider.permissions(req), groups));
|
res.send(await bookmarksResponse(provider.permissions(req), groups));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,6 @@ import { servicesResponse } from "utils/config/api-response";
|
|||||||
import { getSettings } from "utils/config/config";
|
import { getSettings } from "utils/config/config";
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
export default async function handler(req, res) {
|
||||||
const { provider, groups } = readAuthSettings(getSettings().auth)
|
const { provider, groups } = readAuthSettings(getSettings().auth);
|
||||||
res.send(await servicesResponse(provider.permissions(req), groups));
|
res.send(await servicesResponse(provider.permissions(req), groups));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,6 @@ import { widgetsResponse } from "utils/config/api-response";
|
|||||||
import { getSettings } from "utils/config/config";
|
import { getSettings } from "utils/config/config";
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
export default async function handler(req, res) {
|
||||||
const { provider } = readAuthSettings(getSettings().auth)
|
const { provider } = readAuthSettings(getSettings().auth);
|
||||||
res.send(await widgetsResponse(provider.permissions(req)));
|
res.send(await widgetsResponse(provider.permissions(req)));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,17 +44,17 @@ const Version = dynamic(() => import("components/version"), {
|
|||||||
|
|
||||||
const rightAlignedWidgets = ["weatherapi", "openweathermap", "weather", "openmeteo", "search", "datetime"];
|
const rightAlignedWidgets = ["weatherapi", "openweathermap", "weather", "openmeteo", "search", "datetime"];
|
||||||
|
|
||||||
export async function getServerSideProps({req}) {
|
export async function getServerSideProps({ req }) {
|
||||||
let logger;
|
let logger;
|
||||||
try {
|
try {
|
||||||
logger = createLogger("index");
|
logger = createLogger("index");
|
||||||
const { providers, auth, ...settings } = getSettings();
|
const { providers, auth, ...settings } = getSettings();
|
||||||
const { provider, groups } = readAuthSettings(auth);
|
const { provider, groups } = readAuthSettings(auth);
|
||||||
|
|
||||||
const services = await servicesResponse(provider.authorize(req), groups);
|
const services = await servicesResponse(provider.authorize(req), groups);
|
||||||
const bookmarks = await bookmarksResponse(provider.authorize(req), groups);
|
const bookmarks = await bookmarksResponse(provider.authorize(req), groups);
|
||||||
const widgets = await widgetsResponse(provider.authorize(req));
|
const widgets = await widgetsResponse(provider.authorize(req));
|
||||||
const authContext = provider.getContext(req);
|
const authContext = provider.getContext(req);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
@ -160,7 +160,7 @@ function Index({ initialSettings, fallback, authContext }) {
|
|||||||
return (
|
return (
|
||||||
<SWRConfig value={{ fallback, fetcher: (resource, init) => fetch(resource, init).then((res) => res.json()) }}>
|
<SWRConfig value={{ fallback, fetcher: (resource, init) => fetch(resource, init).then((res) => res.json()) }}>
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<Home initialSettings={initialSettings} authContext={authContext}/>
|
<Home initialSettings={initialSettings} authContext={authContext} />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
</SWRConfig>
|
</SWRConfig>
|
||||||
);
|
);
|
||||||
@ -187,7 +187,7 @@ function Home({ initialSettings, authContext }) {
|
|||||||
}, [initialSettings, setSettings]);
|
}, [initialSettings, setSettings]);
|
||||||
|
|
||||||
const { data: services } = useSWR(["/api/services", authContext], fetchWithAuth);
|
const { data: services } = useSWR(["/api/services", authContext], fetchWithAuth);
|
||||||
const { data: bookmarks } = useSWR(["/api/bookmarks", authContext], fetchWithAuth);
|
const { data: bookmarks } = useSWR(["/api/bookmarks", authContext], fetchWithAuth);
|
||||||
const { data: widgets } = useSWR(["/api/widgets", authContext], fetchWithAuth);
|
const { data: widgets } = useSWR(["/api/widgets", authContext], fetchWithAuth);
|
||||||
|
|
||||||
const servicesAndBookmarks = [
|
const servicesAndBookmarks = [
|
||||||
@ -530,7 +530,7 @@ export default function Wrapper({ initialSettings, fallback, authContext }) {
|
|||||||
backgroundBrightness && `backdrop-brightness-${initialSettings.background.brightness}`,
|
backgroundBrightness && `backdrop-brightness-${initialSettings.background.brightness}`,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Index initialSettings={initialSettings} fallback={fallback} authContext={authContext}/>
|
<Index initialSettings={initialSettings} fallback={fallback} authContext={authContext} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,53 +1,57 @@
|
|||||||
import ProxyAuthProvider from "./proxy";
|
import ProxyAuthProvider from "./proxy";
|
||||||
import NullAuthProvider from "./null";
|
import NullAuthProvider from "./null";
|
||||||
|
|
||||||
const AuthProviders = {
|
const AuthProviders = {
|
||||||
NullAuthProvider,
|
NullAuthProvider,
|
||||||
ProxyAuthProvider
|
ProxyAuthProvider,
|
||||||
};
|
};
|
||||||
|
|
||||||
function getProviderByKey(key) {
|
function getProviderByKey(key) {
|
||||||
return AuthProviders.find((provider) => provider.key === key) ?? NullAuthProvider;
|
return AuthProviders.find((provider) => provider.key === key) ?? NullAuthProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
function authAllow({user, groups}, item) {
|
function authAllow({ user, groups }, item) {
|
||||||
const groupAllow = (('allowGroups' in item)) && groups.some(group => item.allowGroups.includes(group));
|
const groupAllow = "allowGroups" in item && groups.some((group) => item.allowGroups.includes(group));
|
||||||
const userAllow = (('allowUsers' in item)) && item.allowUsers.includes(user);
|
const userAllow = "allowUsers" in item && item.allowUsers.includes(user);
|
||||||
const allowAll = (!('allowGroups' in item)) && (!('allowUsers' in item));
|
const allowAll = !("allowGroups" in item) && !("allowUsers" in item);
|
||||||
|
|
||||||
return userAllow || groupAllow || allowAll;
|
return userAllow || groupAllow || allowAll;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkAllowedGroup(perms, authGroups, groupName) {
|
export function checkAllowedGroup(perms, authGroups, groupName) {
|
||||||
const testGroup = authGroups.find((group) => group.name === groupName )
|
const testGroup = authGroups.find((group) => group.name === groupName);
|
||||||
return testGroup ? authAllow(perms, testGroup) : true
|
return testGroup ? authAllow(perms, testGroup) : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function filterAllowedItems(perms, authGroups, groups, groupKey) {
|
function filterAllowedItems(perms, authGroups, groups, groupKey) {
|
||||||
return groups.filter((group) => checkAllowedGroup(perms, authGroups, group.name))
|
return groups
|
||||||
|
.filter((group) => checkAllowedGroup(perms, authGroups, group.name))
|
||||||
.map((group) => ({
|
.map((group) => ({
|
||||||
name: group.name,
|
name: group.name,
|
||||||
[groupKey]: group[groupKey].filter((item) => authAllow(perms, item))
|
[groupKey]: group[groupKey].filter((item) => authAllow(perms, item)),
|
||||||
}))
|
}))
|
||||||
.filter((group) => group[groupKey].length);
|
.filter((group) => group[groupKey].length);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function readAuthSettings({provider, groups} = {}) {
|
export function readAuthSettings({ provider, groups } = {}) {
|
||||||
return {
|
return {
|
||||||
provider: provider ? getProviderByKey(provider.type).create(provider) : NullAuthProvider.create(),
|
provider: provider ? getProviderByKey(provider.type).create(provider) : NullAuthProvider.create(),
|
||||||
groups: groups ? groups.map((group) => ({
|
groups: groups
|
||||||
name: Object.keys(group)[0],
|
? groups.map((group) => ({
|
||||||
allowUsers: group[Object.keys(group)[0]].allowUsers,
|
name: Object.keys(group)[0],
|
||||||
allowGroups: group[Object.keys(group)[0]].allowGroups
|
allowUsers: group[Object.keys(group)[0]].allowUsers,
|
||||||
})) : []
|
allowGroups: group[Object.keys(group)[0]].allowGroups,
|
||||||
}
|
}))
|
||||||
|
: [],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchWithAuth(key, context) {
|
export async function fetchWithAuth(key, context) {
|
||||||
return getProviderByKey(context.provider).fetch([key, context]);
|
return getProviderByKey(context.provider).fetch([key, context]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const filterAllowedServices = (perms, authGroups, services) => filterAllowedItems(perms, authGroups, services, 'services');
|
export const filterAllowedServices = (perms, authGroups, services) =>
|
||||||
export const filterAllowedBookmarks = (perms, authGroups, bookmarks) => filterAllowedItems(perms, authGroups, bookmarks, 'bookmarks');
|
filterAllowedItems(perms, authGroups, services, "services");
|
||||||
export const filterAllowedWidgets = (perms, widgets) => widgets.filter((widget) => authAllow(perms, widget.options))
|
export const filterAllowedBookmarks = (perms, authGroups, bookmarks) =>
|
||||||
|
filterAllowedItems(perms, authGroups, bookmarks, "bookmarks");
|
||||||
|
export const filterAllowedWidgets = (perms, widgets) => widgets.filter((widget) => authAllow(perms, widget.options));
|
||||||
|
|||||||
@ -1,23 +1,23 @@
|
|||||||
const NullPermissions = { user: null, groups:[]}
|
const NullPermissions = { user: null, groups: [] };
|
||||||
const NullAuthKey = "none"
|
const NullAuthKey = "none";
|
||||||
|
|
||||||
function createNullAuth() {
|
function createNullAuth() {
|
||||||
return {
|
return {
|
||||||
authorize: () => NullPermissions,
|
authorize: () => NullPermissions,
|
||||||
getContext: () => ({
|
getContext: () => ({
|
||||||
provider: NullAuthKey
|
provider: NullAuthKey,
|
||||||
}),
|
}),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchNullAuth([key]) {
|
async function fetchNullAuth([key]) {
|
||||||
return fetch(key).then((res) => res.json())
|
return fetch(key).then((res) => res.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
const NullAuthProvider = {
|
const NullAuthProvider = {
|
||||||
key: NullAuthKey,
|
key: NullAuthKey,
|
||||||
create: createNullAuth,
|
create: createNullAuth,
|
||||||
fetch: fetchNullAuth
|
fetch: fetchNullAuth,
|
||||||
}
|
};
|
||||||
|
|
||||||
export default NullAuthProvider;
|
export default NullAuthProvider;
|
||||||
|
|||||||
@ -1,33 +1,33 @@
|
|||||||
// 'proxy' auth provider is meant to be used by a reverse proxy that injects permission headers into the origin
|
// 'proxy' auth provider 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.
|
// request. In this case we are relying on our proxy to authenitcate our users and validate.
|
||||||
const ProxyAuthKey="proxy"
|
const ProxyAuthKey = "proxy";
|
||||||
|
|
||||||
function getProxyPermissions(userHeader, groupHeader, request) {
|
function getProxyPermissions(userHeader, groupHeader, request) {
|
||||||
const user = (userHeader)?request.headers.get(userHeader):null;
|
const user = userHeader ? request.headers.get(userHeader) : null;
|
||||||
const groupsString = (groupHeader)?request.headers.get(groupHeader):"";
|
const groupsString = groupHeader ? request.headers.get(groupHeader) : "";
|
||||||
|
|
||||||
return {user, groups: (groupsString)?groupsString.split(",").map((v) => v.trimStart()):[]}
|
return { user, groups: groupsString ? groupsString.split(",").map((v) => v.trimStart()) : [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
function createProxyAuth({groupHeader, userHeader}) {
|
function createProxyAuth({ groupHeader, userHeader }) {
|
||||||
return {
|
return {
|
||||||
getContext : (request) => ({
|
getContext: (request) => ({
|
||||||
type: ProxyAuthKey,
|
type: ProxyAuthKey,
|
||||||
...userHeader && {[userHeader]: request.headers.get(userHeader) },
|
...(userHeader && { [userHeader]: request.headers.get(userHeader) }),
|
||||||
...groupHeader && {[groupHeader]: request.headers.get(groupHeader)}
|
...(groupHeader && { [groupHeader]: request.headers.get(groupHeader) }),
|
||||||
}),
|
}),
|
||||||
authorize : (request) => getProxyPermissions(userHeader, groupHeader, request)
|
authorize: (request) => getProxyPermissions(userHeader, groupHeader, request),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchProxyAuth([key, context]) {
|
async function fetchProxyAuth([key, context]) {
|
||||||
return fetch(key, {headers: context.headers}).then((res) => res.json())
|
return fetch(key, { headers: context.headers }).then((res) => res.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProxyAuthProvider = {
|
const ProxyAuthProvider = {
|
||||||
key: ProxyAuthKey,
|
key: ProxyAuthKey,
|
||||||
create: createProxyAuth,
|
create: createProxyAuth,
|
||||||
fetch: fetchProxyAuth
|
fetch: fetchProxyAuth,
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ProxyAuthProvider;
|
export default ProxyAuthProvider;
|
||||||
|
|||||||
@ -12,11 +12,7 @@ import {
|
|||||||
servicesFromKubernetes,
|
servicesFromKubernetes,
|
||||||
} from "utils/config/service-helpers";
|
} from "utils/config/service-helpers";
|
||||||
import { cleanWidgetGroups, widgetsFromConfig } from "utils/config/widget-helpers";
|
import { cleanWidgetGroups, widgetsFromConfig } from "utils/config/widget-helpers";
|
||||||
import {
|
import { filterAllowedBookmarks, filterAllowedServices, filterAllowedWidgets } from "utils/auth/auth-helpers";
|
||||||
filterAllowedBookmarks,
|
|
||||||
filterAllowedServices,
|
|
||||||
filterAllowedWidgets
|
|
||||||
} from "utils/auth/auth-helpers";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares services by weight then by name.
|
* Compares services by weight then by name.
|
||||||
@ -35,7 +31,7 @@ export async function bookmarksResponse(perms, authGroups) {
|
|||||||
const bookmarksYaml = path.join(CONF_DIR, "bookmarks.yaml");
|
const bookmarksYaml = path.join(CONF_DIR, "bookmarks.yaml");
|
||||||
const rawFileContents = await fs.readFile(bookmarksYaml, "utf8");
|
const rawFileContents = await fs.readFile(bookmarksYaml, "utf8");
|
||||||
const fileContents = substituteEnvironmentVars(rawFileContents);
|
const fileContents = substituteEnvironmentVars(rawFileContents);
|
||||||
const bookmarks = yaml.load(fileContents);
|
const bookmarks = yaml.load(fileContents);
|
||||||
|
|
||||||
if (!bookmarks) return [];
|
if (!bookmarks) return [];
|
||||||
|
|
||||||
@ -50,14 +46,16 @@ export async function bookmarksResponse(perms, authGroups) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// map easy to write YAML objects into easy to consume JS arrays
|
// map easy to write YAML objects into easy to consume JS arrays
|
||||||
const bookmarksArray = filterAllowedBookmarks(perms, authGroups,
|
const bookmarksArray = filterAllowedBookmarks(
|
||||||
|
perms,
|
||||||
|
authGroups,
|
||||||
bookmarks.map((group) => ({
|
bookmarks.map((group) => ({
|
||||||
name: Object.keys(group)[0],
|
name: Object.keys(group)[0],
|
||||||
bookmarks: group[Object.keys(group)[0]].map((entries) => ({
|
bookmarks: group[Object.keys(group)[0]].map((entries) => ({
|
||||||
name: Object.keys(entries)[0],
|
name: Object.keys(entries)[0],
|
||||||
...entries[Object.keys(entries)[0]][0],
|
...entries[Object.keys(entries)[0]][0],
|
||||||
})),
|
})),
|
||||||
}))
|
})),
|
||||||
);
|
);
|
||||||
|
|
||||||
const sortedGroups = [];
|
const sortedGroups = [];
|
||||||
@ -109,7 +107,11 @@ export async function servicesResponse(perms, authGroups) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
discoveredKubernetesServices = filterAllowedServices(perms, authGroups, cleanServiceGroups(await servicesFromKubernetes()));
|
discoveredKubernetesServices = filterAllowedServices(
|
||||||
|
perms,
|
||||||
|
authGroups,
|
||||||
|
cleanServiceGroups(await servicesFromKubernetes()),
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to discover services, please check kubernetes.yaml for errors or remove example entries.");
|
console.error("Failed to discover services, please check kubernetes.yaml for errors or remove example entries.");
|
||||||
if (e) console.error(e.toString());
|
if (e) console.error(e.toString());
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user