forked from baron/baron-sso
chore(devfront): fix biome formatting and lints
This commit is contained in:
@@ -73,7 +73,10 @@ const HEADLESS_LOGIN_ALLOWED_ALGORITHM_SET = new Set<string>(
|
||||
HEADLESS_LOGIN_ALLOWED_ALGORITHMS,
|
||||
);
|
||||
|
||||
function formatHeadlessParsedKeyLabel(kid: string | undefined, index: number): string {
|
||||
function formatHeadlessParsedKeyLabel(
|
||||
kid: string | undefined,
|
||||
index: number,
|
||||
): string {
|
||||
const trimmedKid = kid?.trim();
|
||||
if (trimmedKid) {
|
||||
return trimmedKid;
|
||||
@@ -302,7 +305,7 @@ function ClientGeneralPage() {
|
||||
headlessLoginEnabled &&
|
||||
trimmedJwksUri !== "" &&
|
||||
currentHeadlessJwksCache?.jwksUri === trimmedJwksUri
|
||||
? currentHeadlessJwksCache.parsedKeys ?? []
|
||||
? (currentHeadlessJwksCache.parsedKeys ?? [])
|
||||
: [];
|
||||
const unsupportedParsedAlgorithms = parsedKeysForCurrentJwksUri
|
||||
.map((key, index) => ({
|
||||
@@ -463,8 +466,7 @@ function ClientGeneralPage() {
|
||||
? tokenEndpointAuthMethod
|
||||
: undefined,
|
||||
headless_jwks_uri:
|
||||
clientType === "pkce" &&
|
||||
headlessLoginEnabled
|
||||
clientType === "pkce" && headlessLoginEnabled
|
||||
? trimmedJwksUri
|
||||
: undefined,
|
||||
},
|
||||
@@ -1148,9 +1150,7 @@ function ClientGeneralPage() {
|
||||
type="button"
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() =>
|
||||
refreshHeadlessJwksCacheMutation.mutate()
|
||||
}
|
||||
onClick={() => refreshHeadlessJwksCacheMutation.mutate()}
|
||||
disabled={refreshHeadlessJwksCacheMutation.isPending}
|
||||
>
|
||||
{refreshHeadlessJwksCacheMutation.isPending
|
||||
@@ -1202,10 +1202,7 @@ function ClientGeneralPage() {
|
||||
"Status",
|
||||
)}
|
||||
</p>
|
||||
<Badge
|
||||
variant="info"
|
||||
className="w-fit capitalize"
|
||||
>
|
||||
<Badge variant="info" className="w-fit capitalize">
|
||||
{currentHeadlessJwksCache.lastRefreshStatus ||
|
||||
t("ui.common.unknown", "Unknown")}
|
||||
</Badge>
|
||||
@@ -1237,7 +1234,9 @@ function ClientGeneralPage() {
|
||||
"Expires At",
|
||||
)}
|
||||
</p>
|
||||
<p>{formatDateTime(currentHeadlessJwksCache.expiresAt)}</p>
|
||||
<p>
|
||||
{formatDateTime(currentHeadlessJwksCache.expiresAt)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<p className="text-xs font-semibold uppercase text-muted-foreground">
|
||||
@@ -1247,9 +1246,7 @@ function ClientGeneralPage() {
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
{formatDateTime(
|
||||
currentHeadlessJwksCache.lastCheckedAt,
|
||||
)}
|
||||
{formatDateTime(currentHeadlessJwksCache.lastCheckedAt)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
@@ -1272,9 +1269,7 @@ function ClientGeneralPage() {
|
||||
"Consecutive Failures",
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
{currentHeadlessJwksCache.consecutiveFailures ?? 0}
|
||||
</p>
|
||||
<p>{currentHeadlessJwksCache.consecutiveFailures ?? 0}</p>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<p className="text-xs font-semibold uppercase text-muted-foreground">
|
||||
@@ -1346,101 +1341,104 @@ function ClientGeneralPage() {
|
||||
</div>
|
||||
{currentHeadlessJwksCache.parsedKeys?.length ? (
|
||||
<div className="space-y-3">
|
||||
{currentHeadlessJwksCache.parsedKeys.map((key, index) => {
|
||||
const normalizedAlgorithm = key.alg?.trim() ?? "";
|
||||
const isMissingAlgorithm =
|
||||
normalizedAlgorithm === "";
|
||||
const isUnsupportedAlgorithm =
|
||||
!isMissingAlgorithm &&
|
||||
!HEADLESS_LOGIN_ALLOWED_ALGORITHM_SET.has(
|
||||
normalizedAlgorithm,
|
||||
);
|
||||
{currentHeadlessJwksCache.parsedKeys.map(
|
||||
(key, index) => {
|
||||
const normalizedAlgorithm = key.alg?.trim() ?? "";
|
||||
const isMissingAlgorithm =
|
||||
normalizedAlgorithm === "";
|
||||
const isUnsupportedAlgorithm =
|
||||
!isMissingAlgorithm &&
|
||||
!HEADLESS_LOGIN_ALLOWED_ALGORITHM_SET.has(
|
||||
normalizedAlgorithm,
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={`${key.kid || "key"}-${index}`}
|
||||
className={cn(
|
||||
"rounded-xl border bg-muted/30 p-3",
|
||||
isUnsupportedAlgorithm || isMissingAlgorithm
|
||||
? "border-destructive/50 bg-destructive/5"
|
||||
: "border-border",
|
||||
)}
|
||||
>
|
||||
<div className="grid gap-3 md:grid-cols-2 xl:grid-cols-4">
|
||||
<div className="space-y-1">
|
||||
<p className="text-[11px] font-semibold uppercase text-muted-foreground">
|
||||
KID
|
||||
</p>
|
||||
<p className="break-all rounded-lg border border-border bg-background px-3 py-2 font-mono text-[11px]">
|
||||
{key.kid || "-"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<p className="text-[11px] font-semibold uppercase text-muted-foreground">
|
||||
KTY
|
||||
</p>
|
||||
<p className="break-all rounded-lg border border-border bg-background px-3 py-2 font-mono text-[11px]">
|
||||
{key.kty || "-"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<p className="text-[11px] font-semibold uppercase text-muted-foreground">
|
||||
USE
|
||||
</p>
|
||||
<p className="break-all rounded-lg border border-border bg-background px-3 py-2 font-mono text-[11px]">
|
||||
{key.use || "-"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<p className="text-[11px] font-semibold uppercase text-muted-foreground">
|
||||
ALG
|
||||
</p>
|
||||
<p
|
||||
className={cn(
|
||||
"break-all rounded-lg border bg-background px-3 py-2 font-mono text-[11px]",
|
||||
isUnsupportedAlgorithm || isMissingAlgorithm
|
||||
? "border-destructive/50 text-destructive"
|
||||
: "border-border",
|
||||
return (
|
||||
<div
|
||||
key={`${key.kid || "key"}-${index}`}
|
||||
className={cn(
|
||||
"rounded-xl border bg-muted/30 p-3",
|
||||
isUnsupportedAlgorithm || isMissingAlgorithm
|
||||
? "border-destructive/50 bg-destructive/5"
|
||||
: "border-border",
|
||||
)}
|
||||
>
|
||||
<div className="grid gap-3 md:grid-cols-2 xl:grid-cols-4">
|
||||
<div className="space-y-1">
|
||||
<p className="text-[11px] font-semibold uppercase text-muted-foreground">
|
||||
KID
|
||||
</p>
|
||||
<p className="break-all rounded-lg border border-border bg-background px-3 py-2 font-mono text-[11px]">
|
||||
{key.kid || "-"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<p className="text-[11px] font-semibold uppercase text-muted-foreground">
|
||||
KTY
|
||||
</p>
|
||||
<p className="break-all rounded-lg border border-border bg-background px-3 py-2 font-mono text-[11px]">
|
||||
{key.kty || "-"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<p className="text-[11px] font-semibold uppercase text-muted-foreground">
|
||||
USE
|
||||
</p>
|
||||
<p className="break-all rounded-lg border border-border bg-background px-3 py-2 font-mono text-[11px]">
|
||||
{key.use || "-"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<p className="text-[11px] font-semibold uppercase text-muted-foreground">
|
||||
ALG
|
||||
</p>
|
||||
<p
|
||||
className={cn(
|
||||
"break-all rounded-lg border bg-background px-3 py-2 font-mono text-[11px]",
|
||||
isUnsupportedAlgorithm ||
|
||||
isMissingAlgorithm
|
||||
? "border-destructive/50 text-destructive"
|
||||
: "border-border",
|
||||
)}
|
||||
>
|
||||
{key.alg ||
|
||||
t(
|
||||
"msg.dev.clients.general.public_key.cache.missing_algorithm_badge",
|
||||
"알고리즘 미선언",
|
||||
)}
|
||||
</p>
|
||||
{isMissingAlgorithm && (
|
||||
<p className="text-[11px] text-destructive">
|
||||
{t(
|
||||
"msg.dev.clients.general.public_key.cache.missing_algorithm_reason",
|
||||
"이 키는 `alg`가 비어 있어서 저장할 수 없습니다.",
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
{isUnsupportedAlgorithm && (
|
||||
<p className="text-[11px] text-destructive">
|
||||
{t(
|
||||
"msg.dev.clients.general.public_key.cache.unsupported_algorithm_reason",
|
||||
"이 알고리즘은 Headless Login에서 지원되지 않습니다.",
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-3 space-y-1">
|
||||
<p className="text-[11px] font-semibold uppercase text-muted-foreground">
|
||||
{t(
|
||||
"ui.dev.clients.general.public_key.cache.parsed_key_n",
|
||||
"N",
|
||||
)}
|
||||
>
|
||||
{key.alg ||
|
||||
t(
|
||||
"msg.dev.clients.general.public_key.cache.missing_algorithm_badge",
|
||||
"알고리즘 미선언",
|
||||
)}
|
||||
</p>
|
||||
{isMissingAlgorithm && (
|
||||
<p className="text-[11px] text-destructive">
|
||||
{t(
|
||||
"msg.dev.clients.general.public_key.cache.missing_algorithm_reason",
|
||||
"이 키는 `alg`가 비어 있어서 저장할 수 없습니다.",
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
{isUnsupportedAlgorithm && (
|
||||
<p className="text-[11px] text-destructive">
|
||||
{t(
|
||||
"msg.dev.clients.general.public_key.cache.unsupported_algorithm_reason",
|
||||
"이 알고리즘은 Headless Login에서 지원되지 않습니다.",
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
<p className="min-h-16 break-all rounded-lg border border-border bg-background px-3 py-2 font-mono text-[11px] leading-5">
|
||||
{key.n || "-"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-3 space-y-1">
|
||||
<p className="text-[11px] font-semibold uppercase text-muted-foreground">
|
||||
{t(
|
||||
"ui.dev.clients.general.public_key.cache.parsed_key_n",
|
||||
"N",
|
||||
)}
|
||||
</p>
|
||||
<p className="min-h-16 break-all rounded-lg border border-border bg-background px-3 py-2 font-mono text-[11px] leading-5">
|
||||
{key.n || "-"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
);
|
||||
},
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="rounded-lg border border-dashed border-border px-4 py-5 text-sm text-muted-foreground">
|
||||
|
||||
@@ -152,8 +152,7 @@ test.describe("DevFront clients lifecycle", () => {
|
||||
kty: "RSA",
|
||||
use: "sig",
|
||||
alg: "RS256",
|
||||
n:
|
||||
"voVbHlo_UHkjtT7Q_8owyjZ2omE8n8mbGlpraZziStHPfe08q_RGiEXO6Pyiz42NVi-Yo0c7qiaqRwB4h9s5phpT2wwcUxnkrQeRhe7BpigInZPzpwq1hsaB2zyhE7zTRCC3hinGtFdVpNzTVKYKGPbXfeEXaRL3P838vi-_iB4IN3WQk_pAakUQvajL2H-vcWSMSNslMGPDZxobqE9MHSWocNXemrcmtCeE7ruUND0qHZOb8k-hHUBqsNoJ63WKdapzGYF6e2qgDRveYrjgOCBigZPi8npN0xStQ0YcrH_RxeTogsdRZ8SuXmLqavryVDnrT8czPkkJ-EHb8PiTCQ",
|
||||
n: "voVbHlo_UHkjtT7Q_8owyjZ2omE8n8mbGlpraZziStHPfe08q_RGiEXO6Pyiz42NVi-Yo0c7qiaqRwB4h9s5phpT2wwcUxnkrQeRhe7BpigInZPzpwq1hsaB2zyhE7zTRCC3hinGtFdVpNzTVKYKGPbXfeEXaRL3P838vi-_iB4IN3WQk_pAakUQvajL2H-vcWSMSNslMGPDZxobqE9MHSWocNXemrcmtCeE7ruUND0qHZOb8k-hHUBqsNoJ63WKdapzGYF6e2qgDRveYrjgOCBigZPi8npN0xStQ0YcrH_RxeTogsdRZ8SuXmLqavryVDnrT8czPkkJ-EHb8PiTCQ",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -162,11 +161,13 @@ test.describe("DevFront clients lifecycle", () => {
|
||||
consents: [] as Consent[],
|
||||
auditLogsByCursor: undefined,
|
||||
onRefreshHeadlessJwks(clientId: string) {
|
||||
this.clients[0].headlessJwksCache = {
|
||||
...this.clients[0].headlessJwksCache!,
|
||||
lastRefreshStatus: "success",
|
||||
lastCheckedAt: "2026-04-01T00:00:00.000Z",
|
||||
};
|
||||
if (this.clients[0].headlessJwksCache) {
|
||||
this.clients[0].headlessJwksCache = {
|
||||
...this.clients[0].headlessJwksCache,
|
||||
lastRefreshStatus: "success",
|
||||
lastCheckedAt: "2026-04-01T00:00:00.000Z",
|
||||
};
|
||||
}
|
||||
expect(clientId).toBe("client-headless-login");
|
||||
},
|
||||
onRevokeHeadlessJwksCache(clientId: string) {
|
||||
@@ -184,13 +185,17 @@ test.describe("DevFront clients lifecycle", () => {
|
||||
.click();
|
||||
|
||||
await expect(
|
||||
page.getByRole("heading", { name: /공개키 등록|Public Key Registration/i }),
|
||||
page.getByRole("heading", {
|
||||
name: /공개키 등록|Public Key Registration/i,
|
||||
}),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
page.getByText(/Request Object Signing Algorithm/i),
|
||||
).toHaveCount(0);
|
||||
await expect(page.getByText(/Allowed algorithms|허용 알고리즘/i)).toHaveCount(0);
|
||||
await expect(
|
||||
page.getByText(/Allowed algorithms|허용 알고리즘/i),
|
||||
).toHaveCount(0);
|
||||
await page
|
||||
.getByPlaceholder(/https:\/\/rp\.example\.com\/\.well-known\/jwks\.json/i)
|
||||
.fill(jwksUri);
|
||||
@@ -256,7 +261,9 @@ test.describe("DevFront clients lifecycle", () => {
|
||||
name: /공개키 등록|Public Key Registration/i,
|
||||
}),
|
||||
).toBeVisible();
|
||||
await expect(page.getByRole("textbox", { name: /JWKS URI|JWKS URI/i })).toHaveValue(jwksUri);
|
||||
await expect(
|
||||
page.getByRole("textbox", { name: /JWKS URI|JWKS URI/i }),
|
||||
).toHaveValue(jwksUri);
|
||||
});
|
||||
|
||||
test("pkce headless login blocks save when parsed jwks algorithm is unsupported", async ({
|
||||
@@ -306,9 +313,13 @@ test.describe("DevFront clients lifecycle", () => {
|
||||
.fill(jwksUri);
|
||||
|
||||
await expect(
|
||||
page.getByText("지원하지 않는 알고리즘이 감지되었습니다.", { exact: true }),
|
||||
page.getByText("지원하지 않는 알고리즘이 감지되었습니다.", {
|
||||
exact: true,
|
||||
}),
|
||||
).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: /^저장$|^Save$/i })).toBeDisabled();
|
||||
await expect(
|
||||
page.getByRole("button", { name: /^저장$|^Save$/i }),
|
||||
).toBeDisabled();
|
||||
});
|
||||
|
||||
test("pkce headless login blocks save when parsed jwks algorithm is missing", async ({
|
||||
@@ -356,6 +367,8 @@ test.describe("DevFront clients lifecycle", () => {
|
||||
await expect(
|
||||
page.getByText(/알고리즘이 선언되지 않았습니다|algorithm is missing/i),
|
||||
).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: /^저장$|^Save$/i })).toBeDisabled();
|
||||
await expect(
|
||||
page.getByRole("button", { name: /^저장$|^Save$/i }),
|
||||
).toBeDisabled();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user