chore(license): relicense artwork and move non-free media out (#3173)

This commit is contained in:
Hampus authored and GitHub committed 2026-10-03 17:53:42 +02:00
1 parent 71b7cffabc
commit e7347b582c
145 files changed
+806 -3424

No files matched your search

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

@@ -76,7 +76,7 @@ describe('Attachment Decay', () => {
const channel = await createChannel(harness, account.token, guild.id, 'test-channel');
const channelId = guild.system_channel_id ?? channel.id;
const file1Data = loadFixture('yeah.png');
const file2Data = loadFixture('thisisfine.gif');
const file2Data = loadFixture('animated.gif');
const {response, json} = await sendMessageWithAttachments(
harness,
account.token,
@@ -258,7 +258,7 @@ describe('Attachment Decay', () => {
const channel = await createChannel(harness, account.token, guild.id, 'test-channel');
const channelId = guild.system_channel_id ?? channel.id;
const smallFile = loadFixture('yeah.png');
const largeFile = loadFixture('thisisfine.gif');
const largeFile = loadFixture('animated.gif');
const smallResult = await sendMessageWithAttachments(
harness,
account.token,
@@ -327,17 +327,17 @@ describe('Attachment Upload Validation', () => {
const channel = await createChannel(harness, account.token, guild.id, 'test-channel');
const channelId = guild.system_channel_id ?? channel.id;
const file1Data = loadFixture('yeah.png');
const file2Data = loadFixture('thisisfine.gif');
const file2Data = loadFixture('animated.gif');
const payload = {
content: 'Ordered files test',
attachments: [
{id: 0, filename: 'yeah.png', description: 'First file', title: 'First'},
{id: 1, filename: 'thisisfine.gif', description: 'Second file', title: 'Second'},
{id: 1, filename: 'animated.gif', description: 'Second file', title: 'Second'},
],
};
const {response, json} = await sendMessageWithAttachments(harness, account.token, channelId, payload, [
{index: 0, filename: 'yeah.png', data: file1Data},
{index: 1, filename: 'thisisfine.gif', data: file2Data},
{index: 1, filename: 'animated.gif', data: file2Data},
]);
expect(response.status).toBe(200);
expect(json.attachments).toBeDefined();
@@ -346,7 +346,7 @@ describe('Attachment Upload Validation', () => {
expect(json.attachments![0].filename).toBe('yeah.png');
expect(json.attachments![0].description).toBe('First file');
expect(json.attachments![0].title).toBe('First');
expect(json.attachments![1].filename).toBe('thisisfine.gif');
expect(json.attachments![1].filename).toBe('animated.gif');
expect(json.attachments![1].description).toBe('Second file');
expect(json.attachments![1].title).toBe('Second');
});
@@ -356,17 +356,17 @@ describe('Attachment Upload Validation', () => {
const channel = await createChannel(harness, account.token, guild.id, 'test-channel');
const channelId = guild.system_channel_id ?? channel.id;
const file1Data = loadFixture('yeah.png');
const file2Data = loadFixture('thisisfine.gif');
const file2Data = loadFixture('animated.gif');
const payload = {
content: 'Sparse IDs test',
attachments: [
{id: 2, filename: 'yeah.png', description: 'ID is 2', title: 'Two'},
{id: 5, filename: 'thisisfine.gif', description: 'ID is 5', title: 'Five'},
{id: 5, filename: 'animated.gif', description: 'ID is 5', title: 'Five'},
],
};
const {response, json} = await sendMessageWithAttachments(harness, account.token, channelId, payload, [
{index: 2, filename: 'yeah.png', data: file1Data},
{index: 5, filename: 'thisisfine.gif', data: file2Data},
{index: 5, filename: 'animated.gif', data: file2Data},
]);
expect(response.status).toBe(200);
expect(json.attachments).toBeDefined();
@@ -472,7 +472,7 @@ describe('Attachment Upload Validation', () => {
const channel = await createChannel(harness, account.token, guild.id, 'test-channel');
const channelId = guild.system_channel_id ?? channel.id;
const file1Data = loadFixture('yeah.png');
const file2Data = loadFixture('thisisfine.gif');
const file2Data = loadFixture('animated.gif');
const payload = {
content: 'Mixed metadata test',
attachments: [
@@ -485,13 +485,13 @@ describe('Attachment Upload Validation', () => {
},
{
id: 1,
filename: 'thisisfine.gif',
filename: 'animated.gif',
},
],
};
const {response, json} = await sendMessageWithAttachments(harness, account.token, channelId, payload, [
{index: 0, filename: 'yeah.png', data: file1Data},
{index: 1, filename: 'thisisfine.gif', data: file2Data},
{index: 1, filename: 'animated.gif', data: file2Data},
]);
expect(response.status).toBe(200);
expect(json.attachments).toBeDefined();
@@ -76,7 +76,7 @@ export async function sendWithImage(
filenames.map((filename, index) => ({
index,
filename,
data: loadFixture(filename.endsWith('.gif') ? 'thisisfine.gif' : 'yeah.png'),
data: loadFixture(filename.endsWith('.gif') ? 'animated.gif' : 'yeah.png'),
})),
);
if (response.status !== 200) {
@@ -86,25 +86,25 @@ describe('Embed Attachment URL Resolution', () => {
const channel = await createChannel(harness, account.token, guild.id, 'test-channel');
const channelId = guild.system_channel_id ?? channel.id;
const file1Data = loadFixture('yeah.png');
const file2Data = loadFixture('thisisfine.gif');
const file2Data = loadFixture('animated.gif');
const payload = {
content: 'Both image and thumbnail',
attachments: [
{id: 0, filename: 'yeah.png'},
{id: 1, filename: 'thisisfine.gif'},
{id: 1, filename: 'animated.gif'},
],
embeds: [
{
title: 'Complete Embed',
description: 'This embed uses both image and thumbnail',
image: {url: 'attachment://thisisfine.gif'},
image: {url: 'attachment://animated.gif'},
thumbnail: {url: 'attachment://yeah.png'},
},
],
};
const {response, json} = await sendMessageWithAttachments(harness, account.token, channelId, payload, [
{index: 0, filename: 'yeah.png', data: file1Data},
{index: 1, filename: 'thisisfine.gif', data: file2Data},
{index: 1, filename: 'animated.gif', data: file2Data},
]);
expect(response.status).toBe(200);
expect(json.embeds).toBeDefined();
@@ -576,12 +576,12 @@ describe('Embed Attachment URL Resolution', () => {
const channel = await createChannel(harness, account.token, guild.id, 'test-channel');
const channelId = guild.system_channel_id ?? channel.id;
const file1Data = loadFixture('yeah.png');
const file2Data = loadFixture('thisisfine.gif');
const file2Data = loadFixture('animated.gif');
const payload = {
content: 'Multiple embeds with different attachments',
attachments: [
{id: 0, filename: 'yeah.png'},
{id: 1, filename: 'thisisfine.gif'},
{id: 1, filename: 'animated.gif'},
],
embeds: [
{
@@ -592,19 +592,19 @@ describe('Embed Attachment URL Resolution', () => {
{
title: 'Second Embed',
description: 'Uses GIF',
image: {url: 'attachment://thisisfine.gif'},
image: {url: 'attachment://animated.gif'},
},
],
};
const {response, json} = await sendMessageWithAttachments(harness, account.token, channelId, payload, [
{index: 0, filename: 'yeah.png', data: file1Data},
{index: 1, filename: 'thisisfine.gif', data: file2Data},
{index: 1, filename: 'animated.gif', data: file2Data},
]);
expect(response.status).toBe(200);
expect(json.embeds).toBeDefined();
expect(json.embeds).toHaveLength(2);
expect(json.embeds![0].image?.url).toContain('yeah.png');
expect(json.embeds![1].image?.url).toContain('thisisfine.gif');
expect(json.embeds![1].image?.url).toContain('animated.gif');
});
it('should resolve multiple files referenced by embeds', async () => {
const account = await createTestAccount(harness);
Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

File diff suppressed because it is too large. Load diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

@@ -113,13 +113,13 @@ describe('Favorite Meme Limits', () => {
attachment_id: message1.attachments[0].id,
name: 'PNG Meme',
});
const message2 = await createMessageWithImageAttachment(harness, account.token, channel.id, 'thisisfine.gif');
const message2 = await createMessageWithImageAttachment(harness, account.token, channel.id, 'animated.gif');
const meme2 = await createFavoriteMemeFromMessage(harness, account.token, channel.id, message2.id, {
attachment_id: message2.attachments[0].id,
name: 'GIF Meme',
});
expect(meme2.id).toBeTruthy();
expect(meme2.filename).toBe('thisisfine.gif');
expect(meme2.filename).toBe('animated.gif');
});
test('should return error for invalid attachment id', async () => {
const account = await createTestAccountForAttachmentTests(harness);
@@ -244,7 +244,7 @@ describe('Favorite Meme Operations', () => {
attachment_id: message1.attachments[0].id,
name: 'First Meme',
});
const message2 = await createMessageWithImageAttachment(harness, account.token, channel.id, 'thisisfine.gif');
const message2 = await createMessageWithImageAttachment(harness, account.token, channel.id, 'animated.gif');
await createFavoriteMemeFromMessage(harness, account.token, channel.id, message2.id, {
attachment_id: message2.attachments[0].id,
name: 'Second Meme',
+11 -18
View File
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import fs from 'node:fs/promises';
import {stripOwnAttachmentSignature} from '@app/api/attachment/AttachmentUrls';
import type {ChannelID, GuildID, MessageID, UserID, WebhookID, WebhookToken} from '@app/api/BrandedTypes';
import {createChannelID, createGuildID, createWebhookID, createWebhookToken} from '@app/api/BrandedTypes';
import {Config} from '@app/api/Config';
import type {IChannelRepository} from '@app/api/channel/IChannelRepository';
import type {MessageRequest, MessageUpdateRequest} from '@app/api/channel/MessageTypes';
import {withChannelFollowLock} from '@app/api/channel/services/ChannelFollowers';
@@ -29,7 +29,6 @@ import type {RequestCache} from '@app/api/middleware/RequestCacheMiddleware';
import type {Channel} from '@app/api/models/Channel';
import type {Message} from '@app/api/models/Message';
import type {Webhook} from '@app/api/models/Webhook';
import {resolveAssetPath} from '@app/api/utils/AssetPaths';
import * as RandomUtils from '@app/api/utils/RandomUtils';
import type {IWebhookRepository} from '@app/api/webhook/IWebhookRepository';
import {transform as GitHubTransform} from '@app/api/webhook/transformers/GitHubTransformer';
@@ -117,6 +116,10 @@ interface WebhookExecuteInstatusParams extends WebhookTokenParams {
}
const WEBHOOK_AVATAR_MISSING_CACHE_VALUE = '__fluxer_webhook_avatar_missing__';
const HOSTED_WEBHOOK_AVATAR_URLS = {
github: 'https://fluxer.app/static/img/app-webhook-github.2d0319169a3aee33.webp',
instatus: 'https://fluxer.app/static/img/app-webhook-instatus.22ad5aee16da872c.webp',
} as const;
export class WebhookService {
private static readonly NO_ALLOWED_MENTIONS: AllowedMentionsRequest = {parse: []};
@@ -744,32 +747,22 @@ export class WebhookService {
}
private async getGitHubWebhookAvatar(webhookId: WebhookID): Promise<string | null> {
return this.getStaticWebhookAvatar({webhookId, provider: 'github'});
return this.getHostedWebhookAvatar({webhookId, provider: 'github'});
}
private async getInstatusWebhookAvatar(webhookId: WebhookID): Promise<string | null> {
return this.getStaticWebhookAvatar({webhookId, provider: 'instatus'});
return this.getHostedWebhookAvatar({webhookId, provider: 'instatus'});
}
private async getStaticWebhookAvatar({
private async getHostedWebhookAvatar({
webhookId,
provider,
}: {
webhookId: WebhookID;
provider: 'github' | 'instatus';
provider: keyof typeof HOSTED_WEBHOOK_AVATAR_URLS;
}): Promise<string | null> {
const cacheKey = `webhook:${webhookId}:avatar:${provider}`;
const avatarCache = await this.cacheService.get<string | null>(cacheKey);
if (avatarCache) return avatarCache;
const avatarFile = await fs.readFile(resolveAssetPath('assets', `${provider}.webp`));
const avatar = await this.avatarService.uploadAvatar({
prefix: 'avatars',
entityId: webhookId,
errorPath: 'avatar',
base64Image: avatarFile.toString('base64'),
});
await this.cacheService.set(cacheKey, avatar, seconds('1 day'));
return avatar;
if (Config.instance.selfHosted) return null;
return this.getWebhookAvatar({webhookId, avatarUrl: HOSTED_WEBHOOK_AVATAR_URLS[provider]});
}
private getWebhookMetadata(webhook: Webhook): Record<string, string> | undefined {
@@ -35,7 +35,7 @@ describe('Webhook emoji bypass', () => {
user.token,
guildId,
'animated',
'thisisfine.gif',
'animated.gif',
'image/gif',
);
const webhook = await createWebhook(harness, channelId, user.token, 'Emoji Test Webhook');