Skip to content

Commit

Permalink
Test handleWebFinger()
Browse files Browse the repository at this point in the history
  • Loading branch information
dahlia committed Mar 5, 2024
1 parent 61af958 commit a0ec9bf
Show file tree
Hide file tree
Showing 2 changed files with 202 additions and 1 deletion.
176 changes: 176 additions & 0 deletions webfinger/handler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import { assertEquals } from "jsr:@std/assert@^0.218.2";
import { ActorDispatcher } from "../federation/callback.ts";
import { RequestContext } from "../federation/context.ts";
import { Router, RouterError } from "../federation/router.ts";
import { mockDocumentLoader } from "../testing/docloader.ts";
import { CryptographicKey, Link, Person } from "../vocab/vocab.ts";
import { handleWebFinger } from "./handler.ts";

Deno.test("handleWebFinger()", async () => {
const url = new URL("https://example.com/.well-known/webfinger");
let request = new Request(url);
const context: RequestContext<void> = {
url,
request,
data: undefined,
documentLoader: mockDocumentLoader,
getActorUri(handle) {
return new URL(`https://example.com/users/${handle}`);
},
getOutboxUri(_handle) {
throw new RouterError("Not implemented");
},
getInboxUri(_handle?) {
throw new RouterError("Not implemented");
},
getFollowingUri(_handle) {
throw new RouterError("Not implemented");
},
getFollowersUri(_handle) {
throw new RouterError("Not implemented");
},
getActorKey(_handle) {
return Promise.resolve(
new CryptographicKey({
id: new URL("https://example.com/keys/someone"),
}),
);
},
sendActivity(_params) {
throw new Error("Not implemented");
},
};
const router = new Router();
router.add("/users/{handle}", "actor");
const actorDispatcher: ActorDispatcher<void> = (ctx, handle, _key) => {
if (handle !== "someone") return null;
return new Person({
id: ctx.getActorUri(handle),
name: "Someone",
urls: [
new URL("https://example.com/@someone"),
new Link({
href: new URL("https://example.org/@someone"),
rel: "alternate",
mediaType: "text/html",
}),
],
});
};
let onNotFoundCalled: Request | null = null;
const onNotFound = (request: Request) => {
onNotFoundCalled = request;
return new Response("Not found", { status: 404 });
};

let response = await handleWebFinger(request, {
context,
router,
onNotFound,
});
assertEquals(response.status, 404);
assertEquals(onNotFoundCalled, request);

onNotFoundCalled = null;
response = await handleWebFinger(request, {
context,
router,
actorDispatcher,
onNotFound,
});
assertEquals(response.status, 400);
assertEquals(await response.text(), "Missing resource parameter.");
assertEquals(onNotFoundCalled, null);

url.searchParams.set("resource", " invalid ");
request = new Request(url);
response = await handleWebFinger(request, {
context,
router,
actorDispatcher,
onNotFound,
});
assertEquals(response.status, 400);
assertEquals(await response.text(), "Invalid resource URL.");
assertEquals(onNotFoundCalled, null);

url.searchParams.set("resource", "acct:[email protected]");
request = new Request(url);
response = await handleWebFinger(request, {
context,
router,
actorDispatcher,
onNotFound,
});
assertEquals(response.status, 200);
const expected = {
subject: "acct:[email protected]",
aliases: [
"https://example.com/users/someone",
],
links: [
{
href: "https://example.com/users/someone",
rel: "self",
type: "application/activity+json",
},
{
href: "https://example.com/@someone",
rel: "http://webfinger.net/rel/profile-page",
type: "application/activity+json",
},
{
href: "https://example.org/@someone",
rel: "alternate",
type: "text/html",
},
],
};
assertEquals(await response.json(), expected);

url.searchParams.set("resource", "https://example.com/users/someone");
request = new Request(url);
response = await handleWebFinger(request, {
context,
router,
actorDispatcher,
onNotFound,
});
assertEquals(response.status, 200);
assertEquals(await response.json(), expected);

url.searchParams.set("resource", "acct:[email protected]");
request = new Request(url);
response = await handleWebFinger(request, {
context,
router,
actorDispatcher,
onNotFound,
});
assertEquals(response.status, 404);
assertEquals(onNotFoundCalled, request);

onNotFoundCalled = null;
url.searchParams.set("resource", "https://example.com/users/no-one");
request = new Request(url);
response = await handleWebFinger(request, {
context,
router,
actorDispatcher,
onNotFound,
});
assertEquals(response.status, 404);
assertEquals(onNotFoundCalled, request);

onNotFoundCalled = null;
url.searchParams.set("resource", "https://google.com/");
request = new Request(url);
response = await handleWebFinger(request, {
context,
router,
actorDispatcher,
onNotFound,
});
assertEquals(response.status, 404);
assertEquals(onNotFoundCalled, request);
});
27 changes: 26 additions & 1 deletion webfinger/handler.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,41 @@
import { RequestContext } from "../federation/context.ts";
import { ActorDispatcher } from "../federation/callback.ts";
import { RequestContext } from "../federation/context.ts";
import { Router } from "../federation/router.ts";
import { Link as LinkObject } from "../vocab/mod.ts";
import { Link, ResourceDescriptor } from "./jrd.ts";

/**
* Parameters for {@link handleWebFinger}.
*/
export interface WebFingerHandlerParameters<TContextData> {
/**
* The request context.
*/
context: RequestContext<TContextData>;

/**
* The router to use for routing the actor's URL.
*/
router: Router;

/**
* The actor dispatcher to use for dispatching the actor.
*/
actorDispatcher?: ActorDispatcher<TContextData>;

/**
* The function to call when the actor is not found.
*/
onNotFound(request: Request): Response | Promise<Response>;
}

/**
* Handles a WebFinger request. You would not typically call this function
* directly, but instead use {@link Federation.handle} method.
* @param request The WebFinger request to handle.
* @param parameters The parameters for handling the request.
* @returns The response to the request.
*/
export async function handleWebFinger<TContextData>(
request: Request,
{
Expand Down

0 comments on commit a0ec9bf

Please sign in to comment.