chore: fix build issues
This commit is contained in:
parent
6922548317
commit
843cfc4d4f
@ -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 {
|
||||||
|
|||||||
@ -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">
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user