Skip to content

Commit

Permalink
twemojiをセルフホスティングしないようにする (#120)
Browse files Browse the repository at this point in the history
* twemojiをセルフホスティングしないようにする

* fix test
  • Loading branch information
adzukimame authored Oct 17, 2024
1 parent d1f7088 commit 30e5564
Show file tree
Hide file tree
Showing 7 changed files with 24 additions and 83 deletions.
1 change: 0 additions & 1 deletion packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@
"@bull-board/api": "5.21.1",
"@bull-board/fastify": "5.21.1",
"@bull-board/ui": "5.21.1",
"@discordapp/twemoji": "15.0.3",
"@fastify/accepts": "4.3.0",
"@fastify/cookie": "9.3.1",
"@fastify/cors": "9.0.1",
Expand Down
6 changes: 5 additions & 1 deletion packages/backend/src/server/SecurityHeaderService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export class SecurityHeaderService {
const imgSrc = [
'\'self\'', 'data:', 'blob:',
'https://xn--931a.moe/assets/',
'https://cdn.jsdelivr.net/gh/jdecked/[email protected]/assets/',
...(this.config.externalMediaProxyEnabled ? [mediaProxyOrigin] : []),
...(this.config.contentSecurityPolicy?.imgAndMediaSrc ?? []),
].join(' ');
Expand Down Expand Up @@ -190,9 +191,12 @@ export class SecurityHeaderService {
case '/assets/*':
case '/apple-touch-icon.png':
case '/fluent-emoji/:path(.*)':
reply.header('Content-Security-Policy', this.selfHostedMediaPolicy);
break;

case '/twemoji/:path(.*)':
case '/twemoji-badge/:path(.*)':
reply.header('Content-Security-Policy', this.selfHostedMediaPolicy);
reply.header('Content-Security-Policy', this.strictestPolicy);
break;

case '/favicon.ico':
Expand Down
42 changes: 6 additions & 36 deletions packages/backend/src/server/web/ClientServerService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { createBullBoard } from '@bull-board/api';
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter.js';
import { FastifyAdapter } from '@bull-board/fastify';
import ms from 'ms';
import sharp from 'sharp';
import pug from 'pug';
import { In, IsNull } from 'typeorm';
import fastifyStatic from '@fastify/static';
Expand Down Expand Up @@ -454,9 +453,9 @@ export class ClientServerService {
return;
}

return await reply.sendFile(path, `${_dirname}/../../../node_modules/@discordapp/twemoji/dist/svg/`, {
maxAge: ms('30 days'),
});
reply.header('Cache-Control', 'public, max-age=31536000, immutable');

return reply.redirect(`https://cdn.jsdelivr.net/gh/jdecked/[email protected]/assets/svg/${path}`, 301);
});

fastify.get<{ Params: { path: string } }>('/twemoji-badge/:path(.*)', async (request, reply) => {
Expand All @@ -467,38 +466,9 @@ export class ClientServerService {
return;
}

const mask = await sharp(
`${_dirname}/../../../node_modules/@discordapp/twemoji/dist/svg/${path.replace('.png', '')}.svg`,
{ density: 1000 },
)
.resize(488, 488)
.greyscale()
.normalise()
.linear(1.75, -(128 * 1.75) + 128) // 1.75x contrast
.flatten({ background: '#000' })
.extend({
top: 12,
bottom: 12,
left: 12,
right: 12,
background: '#000',
})
.toColorspace('b-w')
.png()
.toBuffer();

const buffer = await sharp({
create: { width: 512, height: 512, channels: 4, background: { r: 0, g: 0, b: 0, alpha: 0 } },
})
.pipelineColorspace('b-w')
.boolean(mask, 'eor')
.resize(96, 96)
.png()
.toBuffer();

reply.header('Cache-Control', 'max-age=2592000');
reply.header('Content-Type', 'image/png');
return buffer;
reply.header('Cache-Control', 'public, max-age=31536000, immutable');

return reply.redirect(`https://cdn.jsdelivr.net/gh/jdecked/[email protected]/assets/72x72/${path}`, 301);
});

// ServiceWorker
Expand Down
16 changes: 12 additions & 4 deletions packages/backend/test/e2e/fetch-resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,6 @@ describe('Webリソース', () => {
{ path: '/favicon.ico', type: 'image/vnd.microsoft.icon' },
{ path: '/opensearch.xml', type: 'application/opensearchdescription+xml' },
{ path: '/apple-touch-icon.png', type: 'image/png' },
{ path: '/twemoji/2764.svg', type: 'image/svg+xml' },
{ path: '/twemoji/2764-fe0f-200d-1f525.svg', type: 'image/svg+xml' },
{ path: '/twemoji-badge/2764.png', type: 'image/png' },
{ path: '/twemoji-badge/2764-fe0f-200d-1f525.png', type: 'image/png' },
{ path: '/fluent-emoji/2764.png', type: 'image/png' },
{ path: '/fluent-emoji/2764-fe0f-200d-1f525.png', type: 'image/png' },
])('$path', (p) => {
Expand All @@ -121,6 +117,18 @@ describe('Webリソース', () => {
// こういったアサーションはフロントエンドE2EやAPI Endpointのテストで担保する。
});

describe.each([
{ path: '/twemoji/2764.svg', type: 'image/svg+xml' },
{ path: '/twemoji/2764-fe0f-200d-1f525.svg', type: 'image/svg+xml' },
{ path: '/twemoji-badge/2764.png', type: 'image/png' },
{ path: '/twemoji-badge/2764-fe0f-200d-1f525.png', type: 'image/png' },
])('$path', (p) => {
test('のGETリクエストがリダイレクトされる', async () => {
const res = await simpleGet(p.path);
assert.strictEqual(res.status, 301);
});
});

describe.each([
{ path: '/twemoji/2764.png' },
{ path: '/twemoji/2764-fe0f-200d-1f525.png' },
Expand Down
2 changes: 0 additions & 2 deletions packages/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
"lint": "pnpm typecheck && pnpm eslint"
},
"dependencies": {
"@discordapp/twemoji": "15.0.3",
"@github/webauthn-json": "2.1.1",
"@koozaki/romaji-conv": "2.0.29",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
Expand All @@ -27,7 +26,6 @@
"@rollup/pluginutils": "5.1.0",
"@syuilo/aiscript": "0.19.0",
"@tabler/icons-webfont": "3.3.0",
"@twemoji/parser": "15.1.1",
"@vitejs/plugin-vue": "5.1.0",
"@vue/compiler-sfc": "3.4.37",
"aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.11",
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/scripts/emoji-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/

const twemojiSvgBase = '/twemoji';
const twemojiSvgBase = 'https://cdn.jsdelivr.net/gh/jdecked/twemoji@15.1.0/assets/svg';
const fluentEmojiPngBase = '/fluent-emoji';

export function char2twemojiFilePath(char: string): string {
Expand Down
38 changes: 0 additions & 38 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 30e5564

Please sign in to comment.