This commit is contained in:
Evert Prants 2025-03-08 10:04:52 +02:00
parent 82fe88189d
commit 15e02f978c
Signed by: evert
GPG Key ID: 0960A17F9F40237D
8 changed files with 68 additions and 10 deletions

View File

@ -73,3 +73,8 @@ a[target='_blank']::after {
position: absolute; position: absolute;
} }
} }
ul {
padding-left: 1.45rem;
margin: 0;
}

View File

@ -37,7 +37,6 @@
height: 120px; height: 120px;
width: 120px; width: 120px;
flex: 0 0 120px; flex: 0 0 120px;
background-color: var(--in-normalized-background);
&.small { &.small {
height: 60px; height: 60px;

View File

@ -0,0 +1,26 @@
<script lang="ts">
interface Props {
children?: import('svelte').Snippet;
padded?: boolean;
}
let { children, padded }: Props = $props();
</script>
<div class="form-actions{padded ? ' padded' : ''}">
{@render children?.()}
</div>
<style>
.form-actions {
display: flex;
gap: 16px;
width: 100%;
align-items: center;
justify-content: flex-end;
&.padded {
padding-right: 24px;
}
}
</style>

View File

@ -20,6 +20,7 @@ import { UserTokens, Users } from '$lib/server/users';
import type { OAuth2ClientInfo, PaginationMeta } from '$lib/types'; import type { OAuth2ClientInfo, PaginationMeta } from '$lib/types';
import { and, count, eq, like, or, sql } from 'drizzle-orm'; import { and, count, eq, like, or, sql } from 'drizzle-orm';
import { createLocalJWKSet, exportJWK, importJWK, jwtVerify, type JWK } from 'jose'; import { createLocalJWKSet, exportJWK, importJWK, jwtVerify, type JWK } from 'jose';
import { ensureArray } from '$lib/utils';
export enum OAuth2ClientURLType { export enum OAuth2ClientURLType {
REDIRECT_URI = 'redirect_uri', REDIRECT_URI = 'redirect_uri',
@ -203,7 +204,15 @@ export class OAuth2Clients {
return scope; return scope;
} }
return scope.includes(',') ? scope.split(',').map((item) => item.trim()) : scope.split(' '); const delimeterSplit = scope.includes(',') ? scope.split(',') : scope.split(' ');
return delimeterSplit.reduce<string[]>((list, scope) => {
const trimmed = scope.trim();
if (!!trimmed) {
list.push(trimmed);
}
return list;
}, []);
} }
static joinScope(scope: string[]): string { static joinScope(scope: string[]): string {
@ -549,7 +558,7 @@ export class OAuth2Clients {
}); });
// Check audience, token must be intended for our service // Check audience, token must be intended for our service
const checkAudience = Array.isArray(payload.aud) ? payload.aud : [payload.aud]; const checkAudience = ensureArray(payload.aud);
if ( if (
!checkAudience.some( !checkAudience.some(
(entry) => entry?.startsWith(env.PUBLIC_URL) || entry?.startsWith(privateEnv.JWT_ISSUER) (entry) => entry?.startsWith(env.PUBLIC_URL) || entry?.startsWith(privateEnv.JWT_ISSUER)

View File

@ -168,7 +168,7 @@ export class OAuth2Codes {
const user = await Users.getById(userId); const user = await Users.getById(userId);
const accessToken = CryptoUtils.generateString(64); const accessToken = CryptoUtils.generateString(64);
const scopes = (!Array.isArray(scope) ? OAuth2Clients.splitScope(scope) : scope).join(' '); const scopes = OAuth2Clients.joinScope(OAuth2Clients.splitScope(scope));
const expiresAt = new Date(Date.now() + ttl * 1000); const expiresAt = new Date(Date.now() + ttl * 1000);
const pcke = const pcke =
@ -238,7 +238,7 @@ export class OAuth2AccessTokens {
const user = userId != null ? await Users.getById(userId) : undefined; const user = userId != null ? await Users.getById(userId) : undefined;
const accessToken = CryptoUtils.generateString(128); const accessToken = CryptoUtils.generateString(128);
const scopes = (!Array.isArray(scope) ? OAuth2Clients.splitScope(scope) : scope).join(' '); const scopes = OAuth2Clients.joinScope(OAuth2Clients.splitScope(scope));
const expiresAt = new Date(Date.now() + ttl * 1000); const expiresAt = new Date(Date.now() + ttl * 1000);
@ -298,7 +298,7 @@ export class OAuth2RefreshTokens {
const user = await Users.getById(userId); const user = await Users.getById(userId);
const accessToken = CryptoUtils.generateString(64); const accessToken = CryptoUtils.generateString(64);
const scopes = (!Array.isArray(scope) ? OAuth2Clients.splitScope(scope) : scope).join(' '); const scopes = OAuth2Clients.joinScope(OAuth2Clients.splitScope(scope));
const expiresAt = new Date(Date.now() + OAuth2Tokens.refreshTtl * 1000); const expiresAt = new Date(Date.now() + OAuth2Tokens.refreshTtl * 1000);
@ -350,7 +350,7 @@ export class OAuth2DeviceCodes {
const userCode = const userCode =
`${CryptoUtils.generateString(3)}-${CryptoUtils.generateString(3)}`.toUpperCase(); `${CryptoUtils.generateString(3)}-${CryptoUtils.generateString(3)}`.toUpperCase();
const scopes = (!Array.isArray(scope) ? OAuth2Clients.splitScope(scope) : scope).join(' '); const scopes = OAuth2Clients.joinScope(OAuth2Clients.splitScope(scope));
const expiresAt = new Date(Date.now() + OAuth2Tokens.deviceTtl * 1000); const expiresAt = new Date(Date.now() + OAuth2Tokens.deviceTtl * 1000);
await OAuth2Tokens.insert( await OAuth2Tokens.insert(
@ -442,7 +442,7 @@ export class OAuth2ParCodes {
const client = await OAuth2Clients.fetchById(clientId); const client = await OAuth2Clients.fetchById(clientId);
const parCode = CryptoUtils.generateString(32); const parCode = CryptoUtils.generateString(32);
const scopes = (!Array.isArray(scope) ? OAuth2Clients.splitScope(scope) : scope).join(' '); const scopes = OAuth2Clients.joinScope(OAuth2Clients.splitScope(scope));
const expiresAt = new Date(Date.now() + OAuth2Tokens.parTtl * 1000); const expiresAt = new Date(Date.now() + OAuth2Tokens.parTtl * 1000);
const pcke = const pcke =

View File

@ -14,6 +14,12 @@ export const hasPrivileges = (list: string[], privileges: RequiredPrivileges) =>
return list.includes(item); return list.includes(item);
}); });
/**
* Wait until the `check` function returns a truthy value.
* @param check Condition to run
* @param checkInterval Interval to run condition (ms)
* @param checkTimeout Timeout of the check (ms)
*/
export const waitIsTruthy = (check: () => boolean, checkInterval = 500, checkTimeout = 5000) => { export const waitIsTruthy = (check: () => boolean, checkInterval = 500, checkTimeout = 5000) => {
let time = 0; let time = 0;
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
@ -46,3 +52,10 @@ export function self<TFn extends (event: Event, ...args: Array<unknown>) => void
} }
}; };
} }
/**
* Ensures that the given input is an array.
* @param input Array or single value
* @returns Array
*/
export const ensureArray = <T>(input: T | T[]): T[] => (Array.isArray(input) ? input : [input]);

View File

@ -9,6 +9,7 @@
import SplitView from '$lib/components/container/SplitView.svelte'; import SplitView from '$lib/components/container/SplitView.svelte';
import Button from '$lib/components/Button.svelte'; import Button from '$lib/components/Button.svelte';
import AdminAuditCard from '$lib/components/admin/AdminAuditCard.svelte'; import AdminAuditCard from '$lib/components/admin/AdminAuditCard.svelte';
import FormActions from '$lib/components/form/FormActions.svelte';
interface Props { interface Props {
data: PageData; data: PageData;
@ -70,9 +71,10 @@
/> />
</FormControl> </FormControl>
<div> <FormActions padded>
<a href="/ssoadmin/audit">{$t('common.clear')}</a>
<Button type="submit">{$t('common.filter')}</Button> <Button type="submit">{$t('common.filter')}</Button>
</div> </FormActions>
</ColumnView> </ColumnView>
</form> </form>

View File

@ -16,6 +16,10 @@ const config = {
// This is reimplemented in hooks.server.ts to allow certain endpoints // This is reimplemented in hooks.server.ts to allow certain endpoints
csrf: { csrf: {
checkOrigin: false checkOrigin: false
},
router: {
resolution: 'server'
} }
} }
}; };