Commit a47d29ea authored by ChanHaeng Lee's avatar ChanHaeng Lee
Browse files

Handle ActivityPub requests by `@fedify/next`

parent e7d0f76d
Loading
Loading
Loading
Loading
+24 −10
Original line number Diff line number Diff line
@@ -531,16 +531,30 @@ export default fedifyWith(federation)(
// More details: https://nextjs.org/docs/app/api-reference/file-conventions/middleware#config-object-optional
export const config = {
  runtime: "nodejs",
  matcher: [{
  matcher: [
    {
      source: "/:path*",
      has: [
        {
          type: "header",
          key: "Accept",
        value: ".*application\\\\/((jrd|activity|ld)\\\\+json|xrd\\\\+xml).*",
          value: ".*application\\/((jrd|activity|ld)\\+json|xrd\\+xml).*",
        },
      ],
    },
    {
      source: "/:path*",
      has: [
        {
          type: "header",
          key: "content-type",
          value: ".*application\\/((jrd|activity|ld)\\+json|xrd\\+xml).*",
        },
      ],
    },
    { source: "/.well-known/nodeinfo" },
    { source: "/.well-known/x-nodeinfo2" },
  ],
  }],
};
~~~~

+24 −10
Original line number Diff line number Diff line
@@ -486,16 +486,30 @@ export default fedifyWith(federation)(
// More details: https://nextjs.org/docs/app/api-reference/file-conventions/middleware#config-object-optional
export const config = {
  runtime: "nodejs",
  matcher: [{
  matcher: [
    {
      source: "/:path*",
      has: [
        {
          type: "header",
          key: "Accept",
        value: ".*application\\\\/((jrd|activity|ld)\\\\+json|xrd\\\\+xml).*",
          value: ".*application\\/((jrd|activity|ld)\\+json|xrd\\+xml).*",
        },
      ],
    },
    {
      source: "/:path*",
      has: [
        {
          type: "header",
          key: "content-type",
          value: ".*application\\/((jrd|activity|ld)\\+json|xrd\\+xml).*",
        },
      ],
    },
    { source: "/.well-known/nodeinfo" },
    { source: "/.well-known/x-nodeinfo2" },
  ],
  }],
};
`,
      },
+48 −20
Original line number Diff line number Diff line
@@ -37,7 +37,8 @@ export default fedifyWith(federation)();
// This config must be defined on `middleware.ts`.
export const config = {
  runtime: "nodejs",
  matcher: [{
  matcher: [
    {
      source: "/:path*",
      has: [
        {
@@ -46,7 +47,20 @@ export const config = {
          value: ".*application\\/((jrd|activity|ld)\\+json|xrd\\+xml).*",
        },
      ],
  }],
    },
    {
      source: "/:path*",
      has: [
        {
          type: "header",
          key: "content-type",
          value: ".*application\\/((jrd|activity|ld)\\+json|xrd\\+xml).*",
        },
      ],
    },
    { source: "/.well-known/nodeinfo" },
    { source: "/.well-known/x-nodeinfo2" },
  ],
};
~~~~

@@ -108,7 +122,8 @@ type ErrorHandlers = Omit<FederationFetchOptions<unknown>, "contextData">;
 * // More details: https://nextjs.org/docs/app/api-reference/file-conventions/middleware#config-object-optional.
 * export const config = {
 *   runtime: "nodejs",
 *   matcher: [{
 *   matcher: [
 *     {
 *       source: "/:path*",
 *       has: [
 *         {
@@ -117,7 +132,20 @@ type ErrorHandlers = Omit<FederationFetchOptions<unknown>, "contextData">;
 *           value: ".*application\\/((jrd|activity|ld)\\+json|xrd\\+xml).*",
 *         },
 *       ],
 *   }],
 *     },
 *     {
 *       source: "/:path*",
 *       has: [
 *         {
 *           type: "header",
 *           key: "content-type",
 *           value: ".*application\\/((jrd|activity|ld)\\+json|xrd\\+xml).*",
 *         },
 *       ],
 *     },
 *     { source: "/.well-known/nodeinfo" },
 *     { source: "/.well-known/x-nodeinfo2" },
 *   ],
 * };
 * ```
 */
+52 −23
Original line number Diff line number Diff line
@@ -51,7 +51,8 @@ type ErrorHandlers = Omit<FederationFetchOptions<unknown>, "contextData">;
 * // More details: https://nextjs.org/docs/app/api-reference/file-conventions/middleware#config-object-optional.
 * export const config = {
 *   runtime: "nodejs",
 *   matcher: [{
 *   matcher: [
 *     {
 *       source: "/:path*",
 *       has: [
 *         {
@@ -60,7 +61,20 @@ type ErrorHandlers = Omit<FederationFetchOptions<unknown>, "contextData">;
 *           value: ".*application\\/((jrd|activity|ld)\\+json|xrd\\+xml).*",
 *         },
 *       ],
 *   }],
 *     },
 *     {
 *       source: "/:path*",
 *       has: [
 *         {
 *           type: "header",
 *           key: "content-type",
 *           value: ".*application\\/((jrd|activity|ld)\\+json|xrd\\+xml).*",
 *         },
 *       ],
 *     },
 *     { source: "/.well-known/nodeinfo" },
 *     { source: "/.well-known/x-nodeinfo2" },
 *   ],
 * };
 * ```
 */
@@ -70,13 +84,11 @@ export const fedifyWith = <TContextData>(
  errorHandlers?: Partial<ErrorHandlers>,
) =>
(
  middleware: (request: Request) => unknown = ((_: Request) => {
    console.log(_);
    return NextResponse.next();
  }),
  middleware: (request: Request) => unknown =
    ((_: Request) => NextResponse.next()),
): (request: Request) => unknown =>
async (request: Request) => {
  if (hasFederationAcceptHeader(request)) {
  if (isFederationRequest(request)) {
    return await integrateFederation(
      federation,
      contextDataFactory,
@@ -86,20 +98,37 @@ async (request: Request) => {
  return await middleware(request);
};

export const isFederationRequest = (request: Request): boolean =>
  [
    hasFederationHeader("accept"),
    hasFederationHeader("content-type"),
    isNodeInfoRequest,
  ].some((f) => f(request));

/**
 * Check if the request has the "Accept" header matching the federation
 * Check if the request has the header matching the federation
 * accept regex.
 *
 * @param key The header key to check.
 * @param request The request to check.
 * @returns `true` if the request has the "Accept" header matching
 * @returns `true` if the request has the header matching
 *                    the federation accept regex, `false` otherwise.
 */
export const hasFederationAcceptHeader = (request: Request): boolean => {
  const acceptHeader = request.headers.get("Accept");
  // Check if the Accept header matches the federation accept regex.
  // If the header is not present, return false.
  return acceptHeader ? FEDERATION_ACCEPT_REGEX.test(acceptHeader) : false;
export const hasFederationHeader =
  (key: string) => (request: Request): boolean => {
    const value = request.headers.get(key);
    return value ? FEDERATION_ACCEPT_REGEX.test(value) : false;
  };

export const isNodeInfoRequest = (request: Request): boolean => {
  const url = new URL(request.url);
  return NODEINFO_PATHS.some((path) => url.pathname.startsWith(path));
};

const NODEINFO_PATHS = [
  "/.well-known/nodeinfo",
  "/.well-known/x-nodeinfo2",
];

const FEDERATION_ACCEPT_REGEX =
  /.*application\/((jrd|activity|ld)\+json|xrd\+xml).*/;