Revert disable post import for security reasons

Signed-off-by: limepotato <limepot@protonmail.ch>
This commit is contained in:
Crimekillz 2024-03-26 12:40:19 +01:00 committed by limepotato
parent a26bf77440
commit d8f732c0ef
4 changed files with 149 additions and 2 deletions

View file

@ -11,5 +11,41 @@ export async function importCkPost(
job: Bull.Job<DbUserImportMastoPostJobData>, job: Bull.Job<DbUserImportMastoPostJobData>,
done: any, done: any,
): Promise<void> { ): Promise<void> {
const user = await Users.findOneBy({ id: job.data.user.id });
if (user == null) {
done();
return;
}
const post = job.data.post;
if (post.replyId != null) {
done();
return;
}
if (post.renoteId != null) {
done();
return;
}
if (post.visibility !== "public") {
done();
return;
}
const { text, cw, localOnly, createdAt } = Post.parse(post);
const note = await create(user, {
createdAt: createdAt,
files: undefined,
poll: undefined,
text: text || undefined,
reply: null,
renote: null,
cw: cw,
localOnly,
visibility: "hidden",
visibleUsers: [],
channel: null,
apMentions: new Array(0),
apHashtags: undefined,
apEmojis: undefined,
});
logger.succ("Imported");
done(); done();
} }

View file

@ -15,5 +15,77 @@ export async function importMastoPost(
job: Bull.Job<DbUserImportMastoPostJobData>, job: Bull.Job<DbUserImportMastoPostJobData>,
done: any, done: any,
): Promise<void> { ): Promise<void> {
const user = await Users.findOneBy({ id: job.data.user.id });
if (user == null) {
done();
return;
}
const post = job.data.post;
let reply: Note | null = null;
job.progress(20);
if (post.object.inReplyTo != null) {
reply = await resolveNote(post.object.inReplyTo);
}
job.progress(40);
if (post.directMessage) {
done();
return;
}
if (job.data.signatureCheck) {
if (!post.signature) {
done();
return;
}
}
job.progress(60);
let text;
try {
text = await htmlToMfm(post.object.content, post.object.tag);
} catch (e) {
throw e;
}
job.progress(80);
let files: DriveFile[] = (post.object.attachment || [])
.map((x: any) => x?.driveFile)
.filter((x: any) => x);
if (files.length == 0) {
const urls = post.object.attachment
.map((x: any) => x.url)
.filter((x: String) => x.startsWith("http"));
files = [];
for (const url of urls) {
try {
const file = await uploadFromUrl({
url: url,
user: user,
});
files.push(file);
} catch (e) {
logger.error(`Skipped adding file to drive: ${url}`);
}
}
}
const note = await create(user, {
createdAt: new Date(post.object.published),
files: files.length == 0 ? undefined : files,
poll: undefined,
text: text || undefined,
reply,
renote: null,
cw: post.object.sensitive ? post.object.summary : undefined,
localOnly: false,
visibility: "hidden",
visibleUsers: [],
channel: null,
apMentions: new Array(0),
apHashtags: undefined,
apEmojis: undefined,
});
job.progress(100);
done(); done();
logger.succ("Imported");
} }

View file

@ -1,6 +1,9 @@
import define from "../../define.js"; import define from "../../define.js";
import { createImportPostsJob } from "@/queue/index.js";
import { ApiError } from "../../error.js"; import { ApiError } from "../../error.js";
import { DriveFiles } from "@/models/index.js";
import { DAY } from "@/const.js"; import { DAY } from "@/const.js";
import { fetchMeta } from "@/misc/fetch-meta.js";
export const meta = { export const meta = {
secure: true, secure: true,
@ -23,7 +26,7 @@ export const meta = {
}, },
importsDisabled: { importsDisabled: {
message: "Post imports are disabled for security reasons.", message: "Post imports are disabled.",
code: "IMPORTS_DISABLED", code: "IMPORTS_DISABLED",
id: " bc9227e4-fb82-11ed-be56-0242ac120002", id: " bc9227e4-fb82-11ed-be56-0242ac120002",
}, },
@ -40,5 +43,13 @@ export const paramDef = {
} as const; } as const;
export default define(meta, paramDef, async (ps, user) => { export default define(meta, paramDef, async (ps, user) => {
throw new ApiError(meta.errors.importsDisabled); const file = await DriveFiles.findOneBy({ id: ps.fileId });
const instanceMeta = await fetchMeta();
if (instanceMeta.experimentalFeatures?.postImports === false)
throw new ApiError(meta.errors.importsDisabled);
if (file == null) throw new ApiError(meta.errors.noSuchFile);
if (file.size === 0) throw new ApiError(meta.errors.emptyFile);
createImportPostsJob(user, file.id, ps.signatureCheck);
}); });

View file

@ -16,6 +16,24 @@
{{ i18n.ts.export }}</MkButton {{ i18n.ts.export }}</MkButton
> >
</FormFolder> </FormFolder>
<FormFolder class="_formBlock">
<template #label>{{ i18n.ts.import }}</template>
<template #icon
><i class="ph-upload-simple ph-bold ph-lg"></i
></template>
<FormRadios v-model="importType" class="_formBlock">
<option value="iceshrimp">Iceshrimp/Misskey</option>
<option value="mastodon">Mastodon/Akkoma/Pleroma</option>
</FormRadios>
<MkButton
primary
:class="$style.button"
inline
@click="importPosts($event)"
><i class="ph-upload-simple ph-bold ph-lg"></i>
{{ i18n.ts.import }}</MkButton
>
</FormFolder>
</FormSection> </FormSection>
<FormSection> <FormSection>
<template #label>{{ <template #label>{{
@ -195,6 +213,16 @@ const exportNotes = () => {
os.api("i/export-notes", {}).then(onExportSuccess).catch(onError); os.api("i/export-notes", {}).then(onExportSuccess).catch(onError);
}; };
const importPosts = async (ev) => {
const file = await selectFile(ev.currentTarget ?? ev.target);
os.api("i/import-posts", {
fileId: file.id,
signatureCheck: false,
})
.then(onImportSuccess)
.catch(onError);
};
const exportFollowing = () => { const exportFollowing = () => {
os.api("i/export-following", { os.api("i/export-following", {
excludeMuting: excludeMutingUsers.value, excludeMuting: excludeMutingUsers.value,