Compare commits
2 Commits
34b8221376
...
6159ec00e0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6159ec00e0 | ||
|
|
3611add21a |
@@ -14,6 +14,8 @@ jobs:
|
|||||||
- uses: denoland/setup-deno@v2
|
- uses: denoland/setup-deno@v2
|
||||||
with:
|
with:
|
||||||
deno-version: v2.x
|
deno-version: v2.x
|
||||||
|
cache: true
|
||||||
|
cache-hash: ${{ hashFiles('deno.lock') }}
|
||||||
|
|
||||||
- name: Format check
|
- name: Format check
|
||||||
run: deno fmt --check
|
run: deno fmt --check
|
||||||
|
|||||||
118
tests/auth_verify_test.ts
Normal file
118
tests/auth_verify_test.ts
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
import { assertEquals, assertRejects, assertThrows } from "@std/assert";
|
||||||
|
import { authenticateRequest, decodeJwtPayload } from "../src/auth/verify.ts";
|
||||||
|
import { installFetchStub, jsonResponse } from "./_helpers/fetch_stub.ts";
|
||||||
|
|
||||||
|
const makeJwt = (payload: Record<string, unknown>): string => {
|
||||||
|
const header = btoa(JSON.stringify({ alg: "HS256", typ: "JWT" }));
|
||||||
|
const body = btoa(JSON.stringify(payload));
|
||||||
|
return `${header}.${body}.sig`;
|
||||||
|
};
|
||||||
|
|
||||||
|
Deno.test("decodeJwtPayload parses sub from a 3-segment JWT", () => {
|
||||||
|
const token = makeJwt({ sub: "did:plc:abc", iat: 1 });
|
||||||
|
const payload = decodeJwtPayload(token);
|
||||||
|
assertEquals(payload.sub, "did:plc:abc");
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test("decodeJwtPayload throws on malformed token", () => {
|
||||||
|
assertThrows(() => decodeJwtPayload("not.a.valid.jwt"));
|
||||||
|
assertThrows(() => decodeJwtPayload("onlytwo.parts"));
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test("authenticateRequest rejects missing or non-Bearer Authorization", async () => {
|
||||||
|
await assertRejects(() => authenticateRequest(null));
|
||||||
|
await assertRejects(() => authenticateRequest(""));
|
||||||
|
await assertRejects(() => authenticateRequest("Basic abc"));
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test(
|
||||||
|
"authenticateRequest resolves PDS then verifies session and returns did",
|
||||||
|
async () => {
|
||||||
|
const did = "did:plc:user";
|
||||||
|
const stub = installFetchStub((req) => {
|
||||||
|
if (req.url === `https://plc.directory/${did}`) {
|
||||||
|
return jsonResponse({
|
||||||
|
service: [{
|
||||||
|
id: "#atproto_pds",
|
||||||
|
serviceEndpoint: "https://pds.example.com",
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
req.url ===
|
||||||
|
"https://pds.example.com/xrpc/com.atproto.server.getSession"
|
||||||
|
) {
|
||||||
|
return jsonResponse({ did });
|
||||||
|
}
|
||||||
|
return jsonResponse({ error: "unexpected" }, { status: 500 });
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await authenticateRequest(
|
||||||
|
`Bearer ${makeJwt({ sub: did })}`,
|
||||||
|
);
|
||||||
|
assertEquals(result, did);
|
||||||
|
const sessionCall = stub.calls.find((c) => c.url.includes("/getSession"));
|
||||||
|
assertEquals(
|
||||||
|
sessionCall?.headers.get("Authorization")?.startsWith("Bearer "),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
stub.restore();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
Deno.test(
|
||||||
|
"authenticateRequest throws when plc.directory or getSession is non-2xx",
|
||||||
|
async () => {
|
||||||
|
const did = "did:plc:user";
|
||||||
|
|
||||||
|
const plcFailStub = installFetchStub(() =>
|
||||||
|
new Response("not found", { status: 404 })
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
await assertRejects(() =>
|
||||||
|
authenticateRequest(`Bearer ${makeJwt({ sub: did })}`)
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
plcFailStub.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
const sessionFailStub = installFetchStub((req) => {
|
||||||
|
if (req.url.startsWith("https://plc.directory/")) {
|
||||||
|
return jsonResponse({
|
||||||
|
service: [{
|
||||||
|
id: "#atproto_pds",
|
||||||
|
serviceEndpoint: "https://pds.example.com",
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return new Response("nope", { status: 401 });
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await assertRejects(() =>
|
||||||
|
authenticateRequest(`Bearer ${makeJwt({ sub: did })}`)
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
sessionFailStub.restore();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
Deno.test(
|
||||||
|
"authenticateRequest throws when DID document has no atproto_pds service",
|
||||||
|
async () => {
|
||||||
|
const did = "did:plc:user";
|
||||||
|
const stub = installFetchStub(() =>
|
||||||
|
jsonResponse({ service: [{ id: "#other", serviceEndpoint: "x" }] })
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
await assertRejects(() =>
|
||||||
|
authenticateRequest(`Bearer ${makeJwt({ sub: did })}`)
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
stub.restore();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user