fix: URLs to internal resources should not be sent to Iframely
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
import Router from "koa-router";
|
import Router from "koa-router";
|
||||||
import parseDocumentSlug from "@shared/utils/parseDocumentSlug";
|
import parseDocumentSlug from "@shared/utils/parseDocumentSlug";
|
||||||
import parseMentionUrl from "@shared/utils/parseMentionUrl";
|
import parseMentionUrl from "@shared/utils/parseMentionUrl";
|
||||||
import { NotFoundError } from "@server/errors";
|
import { isInternalUrl } from "@shared/utils/urls";
|
||||||
|
import { NotFoundError, ValidationError } from "@server/errors";
|
||||||
import auth from "@server/middlewares/authentication";
|
import auth from "@server/middlewares/authentication";
|
||||||
import { rateLimiter } from "@server/middlewares/rateLimiter";
|
import { rateLimiter } from "@server/middlewares/rateLimiter";
|
||||||
import validate from "@server/middlewares/validate";
|
import validate from "@server/middlewares/validate";
|
||||||
@@ -26,12 +27,16 @@ router.post(
|
|||||||
const { user: actor } = ctx.state.auth;
|
const { user: actor } = ctx.state.auth;
|
||||||
const urlObj = new URL(url);
|
const urlObj = new URL(url);
|
||||||
|
|
||||||
|
// Mentions
|
||||||
if (urlObj.protocol === "mention:") {
|
if (urlObj.protocol === "mention:") {
|
||||||
|
if (!documentId) {
|
||||||
|
throw ValidationError("Document ID is required to unfurl a mention");
|
||||||
|
}
|
||||||
const { modelId: userId } = parseMentionUrl(url);
|
const { modelId: userId } = parseMentionUrl(url);
|
||||||
|
|
||||||
const [user, document] = await Promise.all([
|
const [user, document] = await Promise.all([
|
||||||
User.findByPk(userId),
|
User.findByPk(userId),
|
||||||
Document.findByPk(documentId!, {
|
Document.findByPk(documentId, {
|
||||||
userId: actor.id,
|
userId: actor.id,
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
@@ -48,20 +53,25 @@ router.post(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const previewDocumentId = parseDocumentSlug(url);
|
// Internal resources
|
||||||
if (previewDocumentId) {
|
if (isInternalUrl(url)) {
|
||||||
const document = previewDocumentId
|
const previewDocumentId = parseDocumentSlug(url);
|
||||||
? await Document.findByPk(previewDocumentId, { userId: actor.id })
|
if (previewDocumentId) {
|
||||||
: undefined;
|
const document = previewDocumentId
|
||||||
if (!document) {
|
? await Document.findByPk(previewDocumentId, { userId: actor.id })
|
||||||
throw NotFoundError("Document does not exist");
|
: undefined;
|
||||||
}
|
if (!document) {
|
||||||
authorize(actor, "read", document);
|
throw NotFoundError("Document does not exist");
|
||||||
|
}
|
||||||
|
authorize(actor, "read", document);
|
||||||
|
|
||||||
ctx.body = presentDocument(document, actor);
|
ctx.body = presentDocument(document, actor);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
return (ctx.response.status = 204);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// External resources
|
||||||
if (resolvers.Iframely) {
|
if (resolvers.Iframely) {
|
||||||
const data = await resolvers.Iframely.unfurl(url);
|
const data = await resolvers.Iframely.unfurl(url);
|
||||||
return data.error
|
return data.error
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import escapeRegExp from "lodash/escapeRegExp";
|
import escapeRegExp from "lodash/escapeRegExp";
|
||||||
import env from "../env";
|
import env from "../env";
|
||||||
import { parseDomain } from "./domains";
|
import { getBaseDomain, parseDomain } from "./domains";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepends the CDN url to the given path (If a CDN is configured).
|
* Prepends the CDN url to the given path (If a CDN is configured).
|
||||||
@@ -15,10 +15,6 @@ export function cdnPath(path: string): string {
|
|||||||
/**
|
/**
|
||||||
* Returns true if the given string is a link to inside the application.
|
* Returns true if the given string is a link to inside the application.
|
||||||
*
|
*
|
||||||
* Important Note: If this is called server-side, it will always return false.
|
|
||||||
* The reason this is in a shared util is because it's used in an editor plugin
|
|
||||||
* which is also in the shared code
|
|
||||||
*
|
|
||||||
* @param url The url to check.
|
* @param url The url to check.
|
||||||
* @returns True if the url is internal, false otherwise.
|
* @returns True if the url is internal, false otherwise.
|
||||||
*/
|
*/
|
||||||
@@ -36,10 +32,10 @@ export function isInternalUrl(href: string) {
|
|||||||
const outline =
|
const outline =
|
||||||
typeof window !== "undefined"
|
typeof window !== "undefined"
|
||||||
? parseDomain(window.location.href)
|
? parseDomain(window.location.href)
|
||||||
: undefined;
|
: parseDomain(env.URL);
|
||||||
|
|
||||||
const domain = parseDomain(href);
|
const domain = parseDomain(href);
|
||||||
return outline?.host === domain.host;
|
|
||||||
|
return outline.host === domain.host || domain.host.endsWith(getBaseDomain());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user