1
1
mirror of https://github.com/kokonect-link/cherrypick synced 2025-01-19 08:13:14 +09:00

fix: emoji stealer

This commit is contained in:
paring 2023-08-12 23:03:29 +09:00 committed by NoriDev
parent e757f716a6
commit 3903474f12
5 changed files with 129 additions and 32 deletions

View File

@ -39,6 +39,7 @@ import * as ep___admin_emoji_addAliasesBulk from './endpoints/admin/emoji/add-al
import * as ep___admin_emoji_add from './endpoints/admin/emoji/add.js';
import * as ep___admin_emoji_adds from './endpoints/admin/emoji/adds.js';
import * as ep___admin_emoji_copy from './endpoints/admin/emoji/copy.js';
import * as ep___admin_emoji_steal from './endpoints/admin/emoji/steal.js';
import * as ep___admin_emoji_deleteBulk from './endpoints/admin/emoji/delete-bulk.js';
import * as ep___admin_emoji_delete from './endpoints/admin/emoji/delete.js';
import * as ep___admin_emoji_importZip from './endpoints/admin/emoji/import-zip.js';
@ -430,6 +431,7 @@ const $admin_emoji_addAliasesBulk: Provider = { provide: 'ep:admin/emoji/add-ali
const $admin_emoji_add: Provider = { provide: 'ep:admin/emoji/add', useClass: ep___admin_emoji_add.default };
const $admin_emoji_adds: Provider = { provide: 'ep:admin/emoji/adds', useClass: ep___admin_emoji_adds.default };
const $admin_emoji_copy: Provider = { provide: 'ep:admin/emoji/copy', useClass: ep___admin_emoji_copy.default };
const $admin_emoji_steal: Provider = { provide: 'ep:admin/emoji/steal', useClass: ep___admin_emoji_steal.default };
const $admin_emoji_deleteBulk: Provider = { provide: 'ep:admin/emoji/delete-bulk', useClass: ep___admin_emoji_deleteBulk.default };
const $admin_emoji_delete: Provider = { provide: 'ep:admin/emoji/delete', useClass: ep___admin_emoji_delete.default };
const $admin_emoji_importZip: Provider = { provide: 'ep:admin/emoji/import-zip', useClass: ep___admin_emoji_importZip.default };
@ -826,6 +828,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$admin_emoji_add,
$admin_emoji_adds,
$admin_emoji_copy,
$admin_emoji_steal,
$admin_emoji_deleteBulk,
$admin_emoji_delete,
$admin_emoji_importZip,
@ -1215,6 +1218,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention
$admin_emoji_add,
$admin_emoji_adds,
$admin_emoji_copy,
$admin_emoji_steal,
$admin_emoji_deleteBulk,
$admin_emoji_delete,
$admin_emoji_importZip,

View File

@ -38,6 +38,7 @@ import * as ep___admin_emoji_addAliasesBulk from './endpoints/admin/emoji/add-al
import * as ep___admin_emoji_add from './endpoints/admin/emoji/add.js';
import * as ep___admin_emoji_adds from './endpoints/admin/emoji/adds.js';
import * as ep___admin_emoji_copy from './endpoints/admin/emoji/copy.js';
import * as ep___admin_emoji_steal from './endpoints/admin/emoji/steal.js';
import * as ep___admin_emoji_deleteBulk from './endpoints/admin/emoji/delete-bulk.js';
import * as ep___admin_emoji_delete from './endpoints/admin/emoji/delete.js';
import * as ep___admin_emoji_importZip from './endpoints/admin/emoji/import-zip.js';
@ -427,6 +428,7 @@ const eps = [
['admin/emoji/add', ep___admin_emoji_add],
['admin/emoji/adds', ep___admin_emoji_adds],
['admin/emoji/copy', ep___admin_emoji_copy],
['admin/emoji/steal', ep___admin_emoji_steal],
['admin/emoji/delete-bulk', ep___admin_emoji_deleteBulk],
['admin/emoji/delete', ep___admin_emoji_delete],
['admin/emoji/import-zip', ep___admin_emoji_importZip],

View File

@ -0,0 +1,112 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey, cherrypick contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { EmojisRepository } from '@/models/index.js';
import { IdService } from '@/core/IdService.js';
import type { DriveFile } from '@/models/entities/DriveFile.js';
import { DI } from '@/di-symbols.js';
import { DriveService } from '@/core/DriveService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js';
import { ApiError } from '../../../error.js';
import {IsNull} from "typeorm";
export const meta = {
tags: ['admin'],
requireCredential: true,
requireRolePolicy: 'canManageCustomEmojis',
errors: {
noSuchEmoji: {
message: 'No such emoji.',
code: 'NO_SUCH_EMOJI',
id: 'e2785b66-dca3-4087-9cac-b93c541cc425',
},
localEmojiAlreadyExists: {
message: 'Local emoji already exists.',
code: 'LOCAL_EMOJI_ALREADY_EXISTS',
id: 'c7262375-102c-41c6-be6b-4f81166a8a5b',
},
},
res: {
type: 'object',
optional: false, nullable: false,
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
name: { type: 'string' },
host: { type: 'string' },
},
required: ['name', 'host'],
} as const;
@Injectable()
// eslint-disable-next-line import/no-default-export
export default class extends Endpoint<typeof meta, typeof paramDef> {
constructor(
@Inject(DI.emojisRepository)
private emojisRepository: EmojisRepository,
private emojiEntityService: EmojiEntityService,
private idService: IdService,
private globalEventService: GlobalEventService,
private driveService: DriveService,
) {
super(meta, paramDef, async (ps, me) => {
const emoji = await this.emojisRepository.findOneBy({ name: ps.name, host: ps.host });
const localEmoji = await this.emojisRepository.findOneBy({ name: ps.name, host: IsNull() });
if (emoji == null) {
throw new ApiError(meta.errors.noSuchEmoji);
}
if (localEmoji != null) {
throw new ApiError(meta.errors.localEmojiAlreadyExists);
}
let driveFile: DriveFile;
try {
driveFile = await this.driveService.uploadFromUrl({ url: emoji.originalUrl, user: null, force: true });
} catch (e) {
throw new ApiError();
}
const copied = await this.emojisRepository.insert({
id: this.idService.genId(),
updatedAt: new Date(),
name: emoji.name,
host: null,
aliases: [],
originalUrl: driveFile.url,
publicUrl: driveFile.webpublicUrl ?? driveFile.url,
type: driveFile.webpublicType ?? driveFile.type,
license: emoji.license,
}).then(x => this.emojisRepository.findOneByOrFail(x.identifiers[0]));
this.globalEventService.publishBroadcastStream('emojiAdded', {
emoji: await this.emojiEntityService.packDetailed(copied.id),
});
return {
id: copied.id,
};
});
}
}

View File

@ -58,6 +58,7 @@ export type Endpoints = {
'admin/emoji/adds': { req: TODO; res: TODO; };
'admin/emoji/copy': { req: TODO; res: TODO; };
'admin/emoji/list-remote': { req: TODO; res: TODO; };
'admin/emoji/steal': { req: TODO; res: TODO; };
'admin/emoji/list': { req: TODO; res: TODO; };
'admin/emoji/remove': { req: TODO; res: TODO; };
'admin/emoji/update': { req: TODO; res: TODO; };

View File

@ -92,7 +92,16 @@ function onClick(ev: MouseEvent) {
copyToClipboard(`:${props.name}:`);
os.success();
},
}, ...(props.menuReaction && react ? [{
}, ...(props.host && $i && ($i.isAdmin || $i.policies.canManageCustomEmojis) ? [{
text: i18n.ts.import,
icon: 'ti ti-plus',
action: async () => {
await os.apiWithDialog('admin/emoji/steal', {
name: customEmojiName.value,
host: props.host,
});
},
}] : []), ...(props.menuReaction && react ? [{
text: i18n.ts.doReaction,
icon: 'ti ti-plus',
action: () => {
@ -123,37 +132,6 @@ onUnmounted(() => {
window.removeEventListener('touchend', resetTimer);
}
});
const onContextMenu = (e: MouseEvent) => {
if (props.host && $i && ($i.isAdmin || $i.policies.canManageCustomEmojis)) {
os.contextMenu([
{
text: i18n.ts.import,
icon: 'ti ti-plus',
action: async () => {
const id = ((await os.api('admin/emoji/list-remote', {
host: props.host,
name: props.name
})) as { id: string }[])[0]?.id
const localId = ((await os.api('admin/emoji/list', {
name: props.name
})) as { id: string }[])[0]?.id
if (localId) {
await os.alert({ type: 'error', title: 'Emoji already exists' })
return
}
if (!id) {
await os.alert({ type: 'error', title: 'Emoji not found' })
return
}
await os.apiWithDialog('admin/emoji/copy', {
emojiId: id,
});
}
}
], e)
}
}
</script>
<style lang="scss" module>