chore: fix build issues

This commit is contained in:
Aarnav Tale 2025-01-28 16:18:51 -05:00
parent 6922548317
commit 843cfc4d4f
No known key found for this signature in database
5 changed files with 66 additions and 47 deletions

View File

@ -4,11 +4,11 @@ import { Link } from 'react-router';
import Chip from '~/components/Chip'; import Chip from '~/components/Chip';
import Menu from '~/components/Menu'; import Menu from '~/components/Menu';
import StatusCircle from '~/components/StatusCircle'; import StatusCircle from '~/components/StatusCircle';
import { toast } from '~/components/Toaster';
import type { HostInfo, Machine, Route, User } from '~/types'; import type { HostInfo, Machine, Route, User } from '~/types';
import { cn } from '~/utils/cn'; import { cn } from '~/utils/cn';
import * as hinfo from '~/utils/host-info'; import * as hinfo from '~/utils/host-info';
import toast from '~/utils/toast';
import MenuOptions from './menu'; import MenuOptions from './menu';
interface Props { interface Props {

View File

@ -183,14 +183,14 @@ export default function Page() {
<Select <Select
label="Filter by User" label="Filter by User"
placeholder="Select a user" placeholder="Select a user"
state={[user, setUser]} onSelectionChange={(value) => setUser(value?.toString() ?? '')}
> >
<Select.Item id="All">All</Select.Item> {[
{users.map((user) => ( <Select.Item key="All">All</Select.Item>,
<Select.Item key={user.id} id={user.name}> ...users.map((user) => (
{user.name} <Select.Item key={user.name}>{user.name}</Select.Item>
</Select.Item> )),
))} ]}
</Select> </Select>
</div> </div>
<div className="w-full"> <div className="w-full">

View File

@ -1,9 +1,9 @@
import { toast } from '~/components/Toaster';
import type { PreAuthKey } from '~/types'; import type { PreAuthKey } from '~/types';
import Attribute from '~/components/Attribute'; import Attribute from '~/components/Attribute';
import Button from '~/components/Button'; import Button from '~/components/Button';
import Code from '~/components/Code'; import Code from '~/components/Code';
import toast from '~/utils/toast';
import ExpireKey from '../dialogs/expire'; import ExpireKey from '../dialogs/expire';
interface Props { interface Props {

View File

@ -13,12 +13,8 @@ interface Props {
// TODO: Tags // TODO: Tags
export default function AddPreAuthKey(data: Props) { export default function AddPreAuthKey(data: Props) {
const fetcher = useFetcher();
const [user, setUser] = useState('');
const [reusable, setReusable] = useState(false); const [reusable, setReusable] = useState(false);
const [ephemeral, setEphemeral] = useState(false); const [ephemeral, setEphemeral] = useState(false);
const [aclTags, setAclTags] = useState([]);
const [expiry, setExpiry] = useState(90);
return ( return (
<Dialog> <Dialog>
@ -28,15 +24,13 @@ export default function AddPreAuthKey(data: Props) {
<Dialog.Text className="font-semibold">User</Dialog.Text> <Dialog.Text className="font-semibold">User</Dialog.Text>
<Dialog.Text className="text-sm">Attach this key to a user</Dialog.Text> <Dialog.Text className="text-sm">Attach this key to a user</Dialog.Text>
<Select <Select
isRequired
label="Owner" label="Owner"
name="user" name="user"
placeholder="Select a user" placeholder="Select a user"
state={[user, setUser]}
> >
{data.users.map((user) => ( {data.users.map((user) => (
<Select.Item key={user.id} id={user.name}> <Select.Item key={user.name}>{user.name}</Select.Item>
{user.name}
</Select.Item>
))} ))}
</Select> </Select>
<NumberInput <NumberInput

View File

@ -1,9 +1,6 @@
import { redirect } from 'react-router';
import * as client from 'openid-client'; import * as client from 'openid-client';
import log from '~/utils/log';
import type { HeadplaneContext } from './config/headplane';
import { z } from 'zod'; import { z } from 'zod';
import log from '~/utils/log';
const oidcConfigSchema = z.object({ const oidcConfigSchema = z.object({
issuer: z.string(), issuer: z.string(),
@ -49,14 +46,16 @@ export function getRedirectUri(req: Request) {
return url.href; return url.href;
} }
function clientAuthMethod(method: string): (secret: string) => client.ClientAuth { function clientAuthMethod(
method: string,
): (secret: string) => client.ClientAuth {
switch (method) { switch (method) {
case 'client_secret_post': case 'client_secret_post':
return client.ClientSecretPost return client.ClientSecretPost;
case 'client_secret_basic': case 'client_secret_basic':
return client.ClientSecretBasic return client.ClientSecretBasic;
case 'client_secret_jwt': case 'client_secret_jwt':
return client.ClientSecretJwt return client.ClientSecretJwt;
default: default:
throw new Error('Invalid client authentication method'); throw new Error('Invalid client authentication method');
} }
@ -67,12 +66,11 @@ export async function beginAuthFlow(oidc: OidcConfig, redirect_uri: string) {
new URL(oidc.issuer), new URL(oidc.issuer),
oidc.clientId, oidc.clientId,
oidc.clientSecret, oidc.clientSecret,
new clientAuthMethod(oidc.tokenEndpointAuthMethod)(oidc.clientSecret), clientAuthMethod(oidc.tokenEndpointAuthMethod)(oidc.clientSecret),
); );
let codeVerifier: string, codeChallenge: string; const codeVerifier = client.randomPKCECodeVerifier();
codeVerifier = client.randomPKCECodeVerifier(); const codeChallenge = await client.calculatePKCECodeChallenge(codeVerifier);
codeChallenge = await client.calculatePKCECodeChallenge(codeVerifier);
const params: Record<string, string> = { const params: Record<string, string> = {
redirect_uri, redirect_uri,
@ -81,7 +79,7 @@ export async function beginAuthFlow(oidc: OidcConfig, redirect_uri: string) {
code_challenge_method: 'S256', code_challenge_method: 'S256',
token_endpoint_auth_method: oidc.tokenEndpointAuthMethod, token_endpoint_auth_method: oidc.tokenEndpointAuthMethod,
state: client.randomState(), state: client.randomState(),
} };
// PKCE is backwards compatible with non-PKCE servers // PKCE is backwards compatible with non-PKCE servers
// so if we don't support it, just set our nonce // so if we don't support it, just set our nonce
@ -110,16 +108,22 @@ export async function finishAuthFlow(oidc: OidcConfig, options: FlowOptions) {
new URL(oidc.issuer), new URL(oidc.issuer),
oidc.clientId, oidc.clientId,
oidc.clientSecret, oidc.clientSecret,
new clientAuthMethod(oidc.tokenEndpointAuthMethod)(oidc.clientSecret), clientAuthMethod(oidc.tokenEndpointAuthMethod)(oidc.clientSecret),
); );
let subject: string, accessToken: string; let subject: string;
const tokens = await client.authorizationCodeGrant(config, new URL(options.redirect_uri), { let accessToken: string;
pkceCodeVerifier: options.codeVerifier,
expectedNonce: options.nonce, const tokens = await client.authorizationCodeGrant(
expectedState: options.state, config,
idTokenExpected: true new URL(options.redirect_uri),
}); {
pkceCodeVerifier: options.codeVerifier,
expectedNonce: options.nonce,
expectedState: options.state,
idTokenExpected: true,
},
);
const claims = tokens.claims(); const claims = tokens.claims();
if (!claims?.sub) { if (!claims?.sub) {
@ -136,8 +140,10 @@ export async function finishAuthFlow(oidc: OidcConfig, options: FlowOptions) {
subject: claims.sub, subject: claims.sub,
name: claims.name ? String(claims.name) : 'Anonymous', name: claims.name ? String(claims.name) : 'Anonymous',
email: claims.email ? String(claims.email) : undefined, email: claims.email ? String(claims.email) : undefined,
username: claims.preferred_username ? String(claims.preferred_username) : undefined, username: claims.preferred_username
} ? String(claims.preferred_username)
: undefined,
};
} }
export function formatError(error: unknown) { export function formatError(error: unknown) {
@ -188,7 +194,7 @@ export async function testOidc(oidc: OidcConfig) {
new URL(oidc.issuer), new URL(oidc.issuer),
oidc.clientId, oidc.clientId,
oidc.clientSecret, oidc.clientSecret,
new clientAuthMethod(oidc.tokenEndpointAuthMethod)(oidc.clientSecret), clientAuthMethod(oidc.tokenEndpointAuthMethod)(oidc.clientSecret),
); );
const meta = config.serverMetadata(); const meta = config.serverMetadata();
@ -199,14 +205,33 @@ export async function testOidc(oidc: OidcConfig) {
log.debug('OIDC', 'Authorization endpoint: %s', meta.authorization_endpoint); log.debug('OIDC', 'Authorization endpoint: %s', meta.authorization_endpoint);
log.debug('OIDC', 'Token endpoint: %s', meta.token_endpoint); log.debug('OIDC', 'Token endpoint: %s', meta.token_endpoint);
if (meta.response_types_supported.includes('code') === false) { if (meta.response_types_supported) {
log.error('OIDC', 'OIDC server does not support code flow'); if (meta.response_types_supported.includes('code') === false) {
return false; log.error('OIDC', 'OIDC server does not support code flow');
return false;
}
} else {
log.warn('OIDC', 'OIDC server does not advertise response_types_supported');
} }
if (meta.token_endpoint_auth_methods_supported.includes(oidc.tokenEndpointAuthMethod) === false) { if (meta.token_endpoint_auth_methods_supported) {
log.error('OIDC', 'OIDC server does not support %s', oidc.tokenEndpointAuthMethod); if (
return false; meta.token_endpoint_auth_methods_supported.includes(
oidc.tokenEndpointAuthMethod,
) === false
) {
log.error(
'OIDC',
'OIDC server does not support %s',
oidc.tokenEndpointAuthMethod,
);
return false;
}
} else {
log.warn(
'OIDC',
'OIDC server does not advertise token_endpoint_auth_methods_supported',
);
} }
log.debug('OIDC', 'OIDC configuration is valid'); log.debug('OIDC', 'OIDC configuration is valid');