From ddf7e074815ac1a06a4ed49511d6065189fdfe7d Mon Sep 17 00:00:00 2001 From: Natty Date: Sat, 22 Apr 2023 12:47:12 +0200 Subject: [PATCH] Removed NodeInfo and WebFinger endpoints --- .editorconfig | 9 +- calckey.nginx.conf | 72 -------- cliff.toml | 103 ----------- packages/backend/src/server/index.ts | 198 ++++++++++---------- packages/backend/src/server/nodeinfo.ts | 119 ------------ packages/backend/src/server/well-known.ts | 213 +++++++--------------- 6 files changed, 163 insertions(+), 551 deletions(-) delete mode 100644 calckey.nginx.conf delete mode 100644 cliff.toml delete mode 100644 packages/backend/src/server/nodeinfo.ts diff --git a/.editorconfig b/.editorconfig index edccf3a9d5..4c6a901bc9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,10 +1,7 @@ root = true [*] -indent_style = tab -indent_size = 2 -charset = utf-8 -insert_final_newline = true - -[*.yml] indent_style = space +indent_size = 4 +charset = utf-8 +insert_final_newline = true \ No newline at end of file diff --git a/calckey.nginx.conf b/calckey.nginx.conf deleted file mode 100644 index def7fe3a5a..0000000000 --- a/calckey.nginx.conf +++ /dev/null @@ -1,72 +0,0 @@ -# Replace example.tld with your domain - -# For WebSocket -map $http_upgrade $connection_upgrade { - default upgrade; - '' close; -} - -proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=cache1:16m max_size=1g inactive=720m use_temp_path=off; - -server { - listen 80; - listen [::]:80; - server_name example.tld; - - # For SSL domain validation - root /var/www/html; - location /.well-known/acme-challenge/ { allow all; } - location /.well-known/pki-validation/ { allow all; } - location / { return 301 https://$server_name$request_uri; } -} - -server { - listen 443 ssl http2; - listen [::]:443 ssl http2; - server_name example.tld; - - ssl_session_timeout 1d; - ssl_session_cache shared:ssl_session_cache:10m; - ssl_session_tickets off; - - # To use Let's Encrypt certificate - ssl_certificate /etc/letsencrypt/live/example.tld/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/example.tld/privkey.pem; - - # To use Debian/Ubuntu's self-signed certificate (For testing or before issuing a certificate) - #ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem; - #ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key; - - # SSL protocol settings - ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; - ssl_prefer_server_ciphers off; - ssl_stapling on; - ssl_stapling_verify on; - - # Change to your upload limit - client_max_body_size 80m; - - # Proxy to Node - location / { - proxy_pass http://127.0.0.1:3000; - proxy_set_header Host $host; - proxy_http_version 1.1; - proxy_redirect off; - - # If it's behind another reverse proxy or CDN, remove the following. - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto https; - - # For WebSocket - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $connection_upgrade; - - # Cache settings - proxy_cache cache1; - proxy_cache_lock on; - proxy_cache_use_stale updating; - add_header X-Cache $upstream_cache_status; - } -} diff --git a/cliff.toml b/cliff.toml deleted file mode 100644 index 394b845774..0000000000 --- a/cliff.toml +++ /dev/null @@ -1,103 +0,0 @@ -# configuration file for git-cliff (0.1.0) - -[changelog] -# changelog header -header = """ -# Changelog\n -All changes from v13.0.0 onwards, for a full list of differences read CALCKEY.md\n -""" -# template for the changelog body -# https://tera.netlify.app/docs/#introduction -body = """ -{% if version %}\ - ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} -{% else %}\ - ## [unreleased] -{% endif %}\ -{% for group, commits in commits | group_by(attribute="group") %} - ### {{ group | upper_first }} - {% for commit in commits %} - - {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }}\ - {% endfor %} -{% endfor %}\n -""" -# remove the leading and trailing whitespace from the template -trim = true -# changelog footer -footer = """ - -""" - -[git] -# parse the commits based on https://www.conventionalcommits.org -conventional_commits = false -# filter out the commits that are not conventional -filter_unconventional = true -# process each line of a commit as an individual commit -split_commits = false -# regex for preprocessing the commit messages -commit_preprocessors = [ - { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](https://github.com/orhun/git-cliff/issues/${2}))"}, -] -# regex for parsing and grouping commits -commit_parsers = [ - { message = "^feat", group = "Features"}, - { message = "^add", group = "Features"}, - { message = "^fix", group = "Bug Fixes"}, - { message = "^prevent", group = "Bug Fixes"}, - { message = "^doc", group = "Documentation"}, - { message = "^perf", group = "Performance"}, - { message = "^🎨", group = "Refactor"}, - { message = "^enhance", group = "Refactor"}, - { message = "^⚡️", group = "Refactor"}, - { message = "^🔥", group = "Features"}, - { message = "^🐛", group = "Bug Fixes"}, - { message = "^🚑️", group = "Bug Fixes"}, - { message = "^block", group = "Bug Fixes"}, - { message = "^✨", group = "Features"}, - { message = "^📝", group = "Documentation"}, - { message = "^🚀", group = "Features"}, - { message = "^💄", group = "Styling"}, - { message = "^✅", group = "Testing"}, - { message = "^🔒️", group = "Security"}, - { message = "^🚨", group = "Testing"}, - { message = "^💚", group = "CI"}, - { message = "^👷", group = "CI"}, - { message = "^⬇️", group = "Miscellaneous Tasks"}, - { message = "^⬆️", group = "Miscellaneous Tasks"}, - { message = "^📌", group = "Miscellaneous Tasks"}, - { message = "^➕", group = "Miscellaneous Tasks"}, - { message = "^➖", group = "Miscellaneous Tasks"}, - { message = "^♻️", group = "Refactor"}, - { message = "^🔧", group = "CI"}, - { message = "^🔨", group = "CI"}, - { message = "^🌐", group = "Localization"}, - { message = "^✏️", group = "Localization"}, - { message = "^👽️", group = "Bug Fixes"}, - { message = "^🍱", group = "Styling"}, - { message = "^♿️", group = "Styling"}, - { message = "^🩹", group = "Bug Fixes"}, - { message = "^refactor", group = "Refactor"}, - { message = "^style", group = "Styling"}, - { message = "^test", group = "Testing"}, - { message = "^chore\\(release\\): prepare for", skip = true}, - { message = "^chore", group = "Miscellaneous Tasks"}, - { message = "^update", group = "Miscellaneous Tasks"}, - { body = ".*security", group = "Security"}, -] -# protect breaking changes from being skipped due to matching a skipping commit_parser -protect_breaking_commits = false -# filter out the commits that are not matched by commit parsers -filter_commits = false -# glob pattern for matching git tags -tag_pattern = "v[0-9]*" -# regex for skipping tags -skip_tags = "v0.1.0-beta.1" -# regex for ignoring tags -ignore_tags = "" -# sort the tags chronologically -date_order = false -# sort the commits inside sections by oldest/newest order -sort_commits = "oldest" -# limit the number of commits included in the changelog. -# limit_commits = 42 diff --git a/packages/backend/src/server/index.ts b/packages/backend/src/server/index.ts index 4d4b81d7aa..86923b2ba9 100644 --- a/packages/backend/src/server/index.ts +++ b/packages/backend/src/server/index.ts @@ -21,7 +21,6 @@ import { publishMainStream } from "@/services/stream.js"; import * as Acct from "@/misc/acct.js"; import { envOption } from "@/env.js"; import activityPub from "./activitypub.js"; -import nodeinfo from "./nodeinfo.js"; import wellKnown from "./well-known.js"; import apiServer from "./api/index.js"; import fileServer from "./file/index.js"; @@ -36,30 +35,30 @@ const app = new Koa(); app.proxy = true; if (!["production", "test"].includes(process.env.NODE_ENV || "")) { - // Logger - app.use( - koaLogger((str) => { - serverLogger.info(str); - }), - ); + // Logger + app.use( + koaLogger((str) => { + serverLogger.info(str); + }) + ); - // Delay - if (envOption.slow) { - app.use( - slow({ - delay: 3000, - }), - ); - } + // Delay + if (envOption.slow) { + app.use( + slow({ + delay: 3000, + }) + ); + } } // HSTS // 6months (15552000sec) if (config.url.startsWith("https") && !config.disableHsts) { - app.use(async (ctx, next) => { - ctx.set("strict-transport-security", "max-age=15552000; preload"); - await next(); - }); + app.use(async (ctx, next) => { + ctx.set("strict-transport-security", "max-age=15552000; preload"); + await next(); + }); } app.use(mount("/api", apiServer)); @@ -71,66 +70,65 @@ const router = new Router(); // Routing router.use(activityPub.routes()); -router.use(nodeinfo.routes()); router.use(wellKnown.routes()); router.get("/avatar/@:acct", async (ctx) => { - const { username, host } = Acct.parse(ctx.params.acct); - const user = await Users.findOne({ - where: { - usernameLower: username.toLowerCase(), - host: host == null || host === config.host ? IsNull() : host, - isSuspended: false, - }, - relations: ["avatar"], - }); + const { username, host } = Acct.parse(ctx.params.acct); + const user = await Users.findOne({ + where: { + usernameLower: username.toLowerCase(), + host: host == null || host === config.host ? IsNull() : host, + isSuspended: false, + }, + relations: ["avatar"], + }); - if (user) { - ctx.redirect(Users.getAvatarUrlSync(user)); - } else { - ctx.redirect("/static-assets/user-unknown.png"); - } + if (user) { + ctx.redirect(Users.getAvatarUrlSync(user)); + } else { + ctx.redirect("/static-assets/user-unknown.png"); + } }); router.get("/identicon/:x", async (ctx) => { - const [temp, cleanup] = await createTemp(); - await genIdenticon(ctx.params.x, fs.createWriteStream(temp)); - ctx.set("Content-Type", "image/png"); - ctx.body = fs.createReadStream(temp).on("close", () => cleanup()); + const [temp, cleanup] = await createTemp(); + await genIdenticon(ctx.params.x, fs.createWriteStream(temp)); + ctx.set("Content-Type", "image/png"); + ctx.body = fs.createReadStream(temp).on("close", () => cleanup()); }); router.get("/verify-email/:code", async (ctx) => { - const profile = await UserProfiles.findOneBy({ - emailVerifyCode: ctx.params.code, - }); + const profile = await UserProfiles.findOneBy({ + emailVerifyCode: ctx.params.code, + }); - if (profile != null) { - ctx.body = "Verify succeeded!"; - ctx.status = 200; + if (profile != null) { + ctx.body = "Verify succeeded!"; + ctx.status = 200; - await UserProfiles.update( - { userId: profile.userId }, - { - emailVerified: true, - emailVerifyCode: null, - }, - ); + await UserProfiles.update( + { userId: profile.userId }, + { + emailVerified: true, + emailVerifyCode: null, + } + ); - publishMainStream( - profile.userId, - "meUpdated", - await Users.pack( - profile.userId, - { id: profile.userId }, - { - detail: true, - includeSecrets: true, - }, - ), - ); - } else { - ctx.status = 404; - } + publishMainStream( + profile.userId, + "meUpdated", + await Users.pack( + profile.userId, + { id: profile.userId }, + { + detail: true, + includeSecrets: true, + } + ) + ); + } else { + ctx.status = 404; + } }); // Register router @@ -139,51 +137,51 @@ app.use(router.routes()); app.use(mount(webServer)); function createServer() { - return http.createServer(app.callback()); + return http.createServer(app.callback()); } // For testing export const startServer = () => { - const server = createServer(); + const server = createServer(); - initializeStreamingServer(server); + initializeStreamingServer(server); - server.listen(config.port); + server.listen(config.port); - return server; + return server; }; export default () => - new Promise((resolve) => { - const server = createServer(); + new Promise((resolve) => { + const server = createServer(); - initializeStreamingServer(server); + initializeStreamingServer(server); - server.on("error", (e) => { - switch ((e as any).code) { - case "EACCES": - serverLogger.error( - `You do not have permission to listen on port ${config.port}.`, - ); - break; - case "EADDRINUSE": - serverLogger.error( - `Port ${config.port} is already in use by another process.`, - ); - break; - default: - serverLogger.error(e); - break; - } + server.on("error", (e) => { + switch ((e as any).code) { + case "EACCES": + serverLogger.error( + `You do not have permission to listen on port ${config.port}.` + ); + break; + case "EADDRINUSE": + serverLogger.error( + `Port ${config.port} is already in use by another process.` + ); + break; + default: + serverLogger.error(e); + break; + } - if (cluster.isWorker) { - process.send!("listenFailed"); - } else { - // disableClustering - process.exit(1); - } - }); + if (cluster.isWorker) { + process.send!("listenFailed"); + } else { + // disableClustering + process.exit(1); + } + }); - // @ts-ignore - server.listen(config.port, resolve); - }); + // @ts-ignore + server.listen(config.port, resolve); + }); diff --git a/packages/backend/src/server/nodeinfo.ts b/packages/backend/src/server/nodeinfo.ts deleted file mode 100644 index 8563573d47..0000000000 --- a/packages/backend/src/server/nodeinfo.ts +++ /dev/null @@ -1,119 +0,0 @@ -import Router from "@koa/router"; -import config from "@/config/index.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; -import { Users, Notes } from "@/models/index.js"; -import { IsNull, MoreThan } from "typeorm"; -import { MAX_NOTE_TEXT_LENGTH, MAX_CAPTION_TEXT_LENGTH } from "@/const.js"; -import { Cache } from "@/misc/cache.js"; - -const router = new Router(); - -const nodeinfo2_1path = "/nodeinfo/2.1"; -const nodeinfo2_0path = "/nodeinfo/2.0"; - -// to cleo: leave this http or bonks -export const links = [ - { - rel: "http://nodeinfo.diaspora.software/ns/schema/2.1", - href: config.url + nodeinfo2_1path, - }, - { - rel: "http://nodeinfo.diaspora.software/ns/schema/2.0", - href: config.url + nodeinfo2_0path, - }, -]; - -const nodeinfo2 = async () => { - const now = Date.now(); - const [meta, total, activeHalfyear, activeMonth, localPosts] = - await Promise.all([ - fetchMeta(true), - Users.count({ where: { host: IsNull() } }), - Users.count({ - where: { - host: IsNull(), - lastActiveDate: MoreThan(new Date(now - 15552000000)), - }, - }), - Users.count({ - where: { - host: IsNull(), - lastActiveDate: MoreThan(new Date(now - 2592000000)), - }, - }), - Notes.count({ where: { userHost: IsNull() } }), - ]); - - const proxyAccount = meta.proxyAccountId - ? await Users.pack(meta.proxyAccountId).catch(() => null) - : null; - - return { - software: { - name: "calckey", - version: config.version, - repository: meta.repositoryUrl, - homepage: "https://calckey.cloud", - }, - protocols: ["activitypub"], - services: { - inbound: [] as string[], - outbound: ["atom1.0", "rss2.0"], - }, - openRegistrations: !meta.disableRegistration, - usage: { - users: { total, activeHalfyear, activeMonth }, - localPosts, - localComments: 0, - }, - metadata: { - nodeName: meta.name, - nodeDescription: meta.description, - maintainer: { - name: meta.maintainerName, - email: meta.maintainerEmail, - }, - langs: meta.langs, - tosUrl: meta.ToSUrl, - repositoryUrl: meta.repositoryUrl, - feedbackUrl: meta.feedbackUrl, - disableRegistration: meta.disableRegistration, - disableLocalTimeline: meta.disableLocalTimeline, - disableRecommendedTimeline: meta.disableRecommendedTimeline, - disableGlobalTimeline: meta.disableGlobalTimeline, - emailRequiredForSignup: meta.emailRequiredForSignup, - enableHcaptcha: meta.enableHcaptcha, - enableRecaptcha: meta.enableRecaptcha, - maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, - maxCaptionTextLength: MAX_CAPTION_TEXT_LENGTH, - enableTwitterIntegration: meta.enableTwitterIntegration, - enableGithubIntegration: meta.enableGithubIntegration, - enableDiscordIntegration: meta.enableDiscordIntegration, - enableEmail: meta.enableEmail, - enableServiceWorker: meta.enableServiceWorker, - proxyAccountName: proxyAccount ? proxyAccount.username : null, - themeColor: meta.themeColor || "#31748f", - }, - }; -}; - -const cache = new Cache>>(1000 * 60 * 10); - -router.get(nodeinfo2_1path, async (ctx) => { - const base = await cache.fetch(null, () => nodeinfo2()); - - ctx.body = { version: "2.1", ...base }; - ctx.set("Cache-Control", "public, max-age=600"); -}); - -router.get(nodeinfo2_0path, async (ctx) => { - const base = await cache.fetch(null, () => nodeinfo2()); - - // @ts-ignore - base.software.repository = undefined; - - ctx.body = { version: "2.0", ...base }; - ctx.set("Cache-Control", "public, max-age=600"); -}); - -export default router; diff --git a/packages/backend/src/server/well-known.ts b/packages/backend/src/server/well-known.ts index 5af3b2c84b..4af469d98a 100644 --- a/packages/backend/src/server/well-known.ts +++ b/packages/backend/src/server/well-known.ts @@ -1,34 +1,33 @@ import Router from "@koa/router"; import config from "@/config/index.js"; -import * as Acct from "@/misc/acct.js"; -import { links } from "./nodeinfo.js"; -import { escapeAttribute, escapeValue } from "@/prelude/xml.js"; -import { Users } from "@/models/index.js"; -import type { User } from "@/models/entities/user.js"; -import type { FindOptionsWhere } from "typeorm"; -import { IsNull } from "typeorm"; +import {escapeAttribute, escapeValue} from "@/prelude/xml.js"; // Init router const router = new Router(); const XRD = ( - ...x: { - element: string; - value?: string; - attributes?: Record; - }[] + ...x: { + element: string; + value?: string; + attributes?: Record; + }[] ) => - `${x - .map( - ({ element, value, attributes }) => - `<${Object.entries( - (typeof attributes === "object" && attributes) || {}, - ).reduce((a, [k, v]) => `${a} ${k}="${escapeAttribute(v)}"`, element)}${ - typeof value === "string" ? `>${escapeValue(value)}`, - ) - .reduce((a, c) => a + c, "")}`; + `${x + .map( + ({ element, value, attributes }) => + `<${Object.entries( + (typeof attributes === "object" && attributes) || {} + ).reduce( + (a, [k, v]) => `${a} ${k}="${escapeAttribute(v)}"`, + element + )}${ + typeof value === "string" + ? `>${escapeValue(value)}` + ) + .reduce((a, c) => a + c, "")}`; const allPath = "/.well-known/(.*)"; const webFingerPath = "/.well-known/webfinger"; @@ -36,156 +35,68 @@ const jrd = "application/jrd+json"; const xrd = "application/xrd+xml"; router.use(allPath, async (ctx, next) => { - ctx.set({ - "Access-Control-Allow-Headers": "Accept", - "Access-Control-Allow-Methods": "GET, OPTIONS", - "Access-Control-Allow-Origin": "*", - "Access-Control-Expose-Headers": "Vary", - }); - await next(); + ctx.set({ + "Access-Control-Allow-Headers": "Accept", + "Access-Control-Allow-Methods": "GET, OPTIONS", + "Access-Control-Allow-Origin": "*", + "Access-Control-Expose-Headers": "Vary", + }); + await next(); }); router.options(allPath, async (ctx) => { - ctx.status = 204; + ctx.status = 204; }); router.get("/.well-known/host-meta", async (ctx) => { - ctx.set("Content-Type", xrd); - ctx.body = XRD({ - element: "Link", - attributes: { - rel: "lrdd", - type: xrd, - template: `${config.url}${webFingerPath}?resource={uri}`, - }, - }); + ctx.set("Content-Type", xrd); + ctx.body = XRD({ + element: "Link", + attributes: { + rel: "lrdd", + type: xrd, + template: `${config.url}${webFingerPath}?resource={uri}`, + }, + }); }); router.get("/.well-known/host-meta.json", async (ctx) => { - ctx.set("Content-Type", jrd); - ctx.body = { - links: [ - { - rel: "lrdd", - type: jrd, - template: `${config.url}${webFingerPath}?resource={uri}`, - }, - ], - }; + ctx.set("Content-Type", jrd); + ctx.body = { + links: [ + { + rel: "lrdd", + type: jrd, + template: `${config.url}${webFingerPath}?resource={uri}`, + }, + ], + }; }); if (config.twa != null) { - router.get("/.well-known/assetlinks.json", async (ctx) => { - ctx.set("Content-Type", "application/json"); - ctx.body = [ - { - relation: ["delegate_permission/common.handle_all_urls"], - target: { - namespace: config.twa.nameSpace, - package_name: config.twa.packageName, - sha256_cert_fingerprints: config.twa.sha256CertFingerprints, - }, - }, - ]; - }); + router.get("/.well-known/assetlinks.json", async (ctx) => { + ctx.set("Content-Type", "application/json"); + ctx.body = [ + { + relation: ["delegate_permission/common.handle_all_urls"], + target: { + namespace: config.twa.nameSpace, + package_name: config.twa.packageName, + sha256_cert_fingerprints: config.twa.sha256CertFingerprints, + }, + }, + ]; + }); } -router.get("/.well-known/nodeinfo", async (ctx) => { - ctx.body = { links }; -}); - /* TODO router.get('/.well-known/change-password', async ctx => { }); */ -router.get(webFingerPath, async (ctx) => { - const fromId = (id: User["id"]): FindOptionsWhere => ({ - id, - host: IsNull(), - isSuspended: false, - }); - - const generateQuery = (resource: string): FindOptionsWhere | number => - resource.startsWith(`${config.url.toLowerCase()}/users/`) - ? fromId(resource.split("/").pop()!) - : fromAcct( - Acct.parse( - resource.startsWith(`${config.url.toLowerCase()}/@`) - ? resource.split("/").pop()! - : resource.startsWith("acct:") - ? resource.slice("acct:".length) - : resource, - ), - ); - - const fromAcct = (acct: Acct.Acct): FindOptionsWhere | number => - !acct.host || acct.host === config.host.toLowerCase() - ? { - usernameLower: acct.username, - host: IsNull(), - isSuspended: false, - } - : 422; - - if (typeof ctx.query.resource !== "string") { - ctx.status = 400; - return; - } - - const query = generateQuery(ctx.query.resource.toLowerCase()); - - if (typeof query === "number") { - ctx.status = query; - return; - } - - const user = await Users.findOneBy(query); - - if (user == null) { - ctx.status = 404; - return; - } - - const subject = `acct:${user.username}@${config.host}`; - const self = { - rel: "self", - type: "application/activity+json", - href: `${config.url}/users/${user.id}`, - }; - const profilePage = { - rel: "http://webfinger.net/rel/profile-page", - type: "text/html", - href: `${config.url}/@${user.username}`, - }; - const subscribe = { - rel: "http://ostatus.org/schema/1.0/subscribe", - template: `${config.url}/authorize-follow?acct={uri}`, - }; - - if (ctx.accepts(jrd, xrd) === xrd) { - ctx.body = XRD( - { element: "Subject", value: subject }, - { element: "Link", attributes: self }, - { element: "Link", attributes: profilePage }, - { element: "Link", attributes: subscribe }, - ); - ctx.type = xrd; - } else { - ctx.body = { - subject, - links: [self, profilePage, subscribe], - }; - ctx.type = jrd; - } - - ctx.vary("Accept"); - ctx.set("Cache-Control", "public, max-age=180"); -}); - // Return 404 for other .well-known router.all(allPath, async (ctx) => { - ctx.status = 404; + ctx.status = 404; }); export default router;