NFC
This commit is contained in:
parent
c991fe7b6d
commit
e6b5fed399
8 changed files with 6647 additions and 6623 deletions
|
|
@ -13,7 +13,8 @@ export async function POST(req: NextRequest) {
|
|||
});
|
||||
|
||||
if (!res.ok) {
|
||||
return NextResponse.json({ error: "Invalid credentials" }, { status: 401 });
|
||||
const text = await res.text();
|
||||
return NextResponse.json({ error: text }, { status: 401 });
|
||||
}
|
||||
|
||||
// Returns { session_id, challenge } — browser completes the WebAuthn step
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
const ENROLLMENT_OPEN = process.env.ENROLLMENT_OPEN === "true";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
if (!ENROLLMENT_OPEN) {
|
||||
return new NextResponse(null, { status: 404 });
|
||||
}
|
||||
const body = await req.json();
|
||||
|
||||
const res = await fetch("http://localhost:3001/auth/register/finish", {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
const ENROLLMENT_OPEN = process.env.ENROLLMENT_OPEN === "true";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
if (!ENROLLMENT_OPEN) {
|
||||
return new NextResponse(null, { status: 404 });
|
||||
}
|
||||
const { username, password } = await req.json();
|
||||
|
||||
const res = await fetch("http://localhost:3001/auth/register/start", {
|
||||
|
|
|
|||
|
|
@ -69,11 +69,13 @@ export default function AuthPage() {
|
|||
setStatus("waiting_yubikey");
|
||||
const opts = challenge.publicKey;
|
||||
opts.challenge = b64uToBuf(opts.challenge);
|
||||
opts.userVerification = "discouraged";
|
||||
if (opts.allowCredentials) {
|
||||
opts.allowCredentials = opts.allowCredentials.map(
|
||||
(c: { id: string; type: string; transports?: string[] }) => ({
|
||||
...c,
|
||||
type: c.type,
|
||||
id: b64uToBuf(c.id),
|
||||
transports: ["usb", "nfc", "ble", "hybrid"],
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,14 @@ export default function EnrollPage() {
|
|||
const opts = challenge.publicKey;
|
||||
opts.challenge = b64uToBuf(opts.challenge);
|
||||
opts.user.id = b64uToBuf(opts.user.id);
|
||||
// Force security key UI — residentKey/UV discouraged so Android
|
||||
// Chrome doesn't suppress the NFC option in favour of biometrics
|
||||
opts.authenticatorSelection = {
|
||||
authenticatorAttachment: "cross-platform",
|
||||
residentKey: "discouraged",
|
||||
requireResidentKey: false,
|
||||
userVerification: "discouraged",
|
||||
};
|
||||
if (opts.excludeCredentials) {
|
||||
opts.excludeCredentials = opts.excludeCredentials.map(
|
||||
(c: { id: string; type: string; transports?: string[] }) => ({
|
||||
|
|
@ -89,9 +97,7 @@ export default function EnrollPage() {
|
|||
response: {
|
||||
attestationObject: bufToB64u(attestation.attestationObject),
|
||||
clientDataJSON: bufToB64u(attestation.clientDataJSON),
|
||||
transports: attestation.getTransports
|
||||
? attestation.getTransports()
|
||||
: [],
|
||||
transports: ["usb", "nfc", "ble", "hybrid"],
|
||||
},
|
||||
extensions: {},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -29,7 +29,12 @@ export default function RootLayout({
|
|||
lang="en"
|
||||
className={`${dmSans.variable} ${playfair.variable} h-full antialiased`}
|
||||
>
|
||||
<body className="min-h-full h-full flex flex-col">{children}</body>
|
||||
<body className="min-h-full h-full flex flex-col">
|
||||
{children}
|
||||
<span className="fixed bottom-3 right-4 text-[10px] text-gray-300 select-none pointer-events-none">
|
||||
v0.1.0
|
||||
</span>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,28 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import type { NextRequest } from "next/server";
|
||||
|
||||
export function proxy(req: NextRequest) {
|
||||
const token = req.cookies.get("token")?.value;
|
||||
const ENROLLMENT_OPEN = process.env.ENROLLMENT_OPEN === "true";
|
||||
|
||||
export function middleware(req: NextRequest) {
|
||||
const { pathname } = req.nextUrl;
|
||||
|
||||
// always allow login page and auth api routes
|
||||
// Enrollment routes — only accessible when enrollment is open
|
||||
if (
|
||||
pathname.startsWith("/enroll") ||
|
||||
pathname.startsWith("/api/auth/register")
|
||||
) {
|
||||
return ENROLLMENT_OPEN
|
||||
? NextResponse.next()
|
||||
: new NextResponse(null, { status: 404 });
|
||||
}
|
||||
|
||||
// Always allow login page and auth api routes
|
||||
if (pathname.startsWith("/auth") || pathname.startsWith("/api/auth")) {
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
// no token — redirect to login
|
||||
// No token — redirect to login
|
||||
const token = req.cookies.get("token")?.value;
|
||||
if (!token) {
|
||||
const loginUrl = new URL("/auth", req.url);
|
||||
loginUrl.searchParams.set("callbackUrl", pathname);
|
||||
13214
package-lock.json
generated
13214
package-lock.json
generated
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue