mirror of
https://github.com/ancsemi/Haven.git
synced 2026-10-26 16:45:16 +00:00
Let new accounts send picker GIFs; allow klipy.com on the link allowlist
This commit is contained in:
1 parent
86041b72e7
commit
fba21ccf89
3 files changed
+67
-2
No files matched your search
+9
-1
@@ -142,6 +142,9 @@ const extractUrls = rules.extractUrls;
|
||||
// Content check
|
||||
// ══════════════════════════════════════════════════════════════════════
|
||||
|
||||
// The image hosts the GIF picker's services send from (server.js fetchGifs).
|
||||
const GIF_HOSTS = ['giphy.com', 'tenor.com', 'klipy.com'];
|
||||
|
||||
// ctx: { userId, isAdmin, effectiveLevel, createdAt, surface, markdown }
|
||||
// markdown: the text is a chat message, so bare addresses inside code do not count.
|
||||
// surface is one of 'message' | 'edit' | 'dm' | 'profile' | 'channel'.
|
||||
@@ -195,8 +198,13 @@ function checkText(text, ctx = {}) {
|
||||
// Independent of the allowlist and deliberately blunt. The register ->
|
||||
// post-link -> get-banned -> re-register loop is the pattern this exists
|
||||
// to break, and it does not care which domain was used.
|
||||
// GIFs from the GIF picker are links too, to the GIF services' own image
|
||||
// hosts. A new member trying the picker was struck, then muted (the wait is
|
||||
// for links people paste, not for GIFs), so a message whose only links are
|
||||
// those is let through. The domain rules below still apply to it.
|
||||
const gifOnly = links.every(l => GIF_HOSTS.some(h => l.host === h || String(l.host).endsWith('.' + h)));
|
||||
const minHours = parseInt(s.automod_link_min_account_hours, 10);
|
||||
if (Number.isFinite(minHours) && minHours > 0 && ctx.createdAt) {
|
||||
if (!gifOnly && Number.isFinite(minHours) && minHours > 0 && ctx.createdAt) {
|
||||
const ageMs = Date.now() - new Date(String(ctx.createdAt).replace(' ', 'T') + 'Z').getTime();
|
||||
if (Number.isFinite(ageMs) && ageMs < minHours * 3600 * 1000) {
|
||||
const hoursLeft = Math.max(1, Math.ceil((minHours * 3600 * 1000 - ageMs) / 3600000));
|
||||
|
||||
+14
-1
@@ -589,7 +589,7 @@ function initDatabase() {
|
||||
const starter = [
|
||||
'youtube.com', 'youtu.be', 'twitch.tv', 'x.com', 'twitter.com', 'bsky.app',
|
||||
'reddit.com', 'github.com', 'gitlab.com', 'stackoverflow.com', 'wikipedia.org',
|
||||
'imgur.com', 'giphy.com', 'tenor.com', 'spotify.com', 'soundcloud.com',
|
||||
'imgur.com', 'giphy.com', 'tenor.com', 'klipy.com', 'spotify.com', 'soundcloud.com',
|
||||
'steamcommunity.com', 'steampowered.com', 'last.fm', 'archive.org',
|
||||
'haven-app.com'
|
||||
];
|
||||
@@ -617,6 +617,19 @@ function initDatabase() {
|
||||
} catch (err) {
|
||||
console.error('automod: adding haven-app.com to the allowlist failed:', err.message);
|
||||
}
|
||||
// KLIPY became a GIF picker choice after the allowlist was seeded, so its
|
||||
// GIFs were blocked on allowlist servers. Added once, the same way.
|
||||
try {
|
||||
const added = db.prepare("SELECT value FROM server_settings WHERE key = 'automod_klipy_v4270'").get();
|
||||
if (!added || added.value !== 'true') {
|
||||
db.prepare(
|
||||
"INSERT OR IGNORE INTO automod_domains (domain, mode, include_subdomains, note) VALUES ('klipy.com', 'allow', 1, 'Seeded default')"
|
||||
).run();
|
||||
db.prepare("INSERT OR REPLACE INTO server_settings (key, value) VALUES ('automod_klipy_v4270', 'true')").run();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('automod: adding klipy.com to the allowlist failed:', err.message);
|
||||
}
|
||||
|
||||
// ── Migration: turn the safe protections on, once (v3.43.0) ──
|
||||
// The seeds above are INSERT OR IGNORE, so they only reach brand-new
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* The new-account link wait is for links people paste. A GIF sent from the
|
||||
* GIF picker is a link to the GIF service's image host, and a new member who
|
||||
* tried the picker used to be struck and then muted for it.
|
||||
*
|
||||
* node --test test/automodGifNewAccount.integration.test.js
|
||||
*/
|
||||
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert');
|
||||
const { createHarness, wait } = require('./socketServerHarness');
|
||||
|
||||
const h = createHarness(3505, 'automod-gif');
|
||||
|
||||
test.before(() => h.start());
|
||||
test.after(() => h.stop());
|
||||
|
||||
test('a new account can send GIFs but not other links', async () => {
|
||||
const admin = await h.register('admin');
|
||||
const bob = await h.register('bob');
|
||||
const A = await h.connect(admin.token);
|
||||
const B = await h.connect(bob.token);
|
||||
|
||||
A.emit('update-server-setting', { key: 'automod_enabled', value: 'true' });
|
||||
A.emit('update-server-setting', { key: 'automod_link_min_account_hours', value: '24' });
|
||||
const made = h.next(A, 'channels-list', (chs) => Array.isArray(chs) && chs.some((c) => c.name === 'chat'));
|
||||
A.emit('create-channel', { name: 'chat' });
|
||||
const chat = (await made).find((c) => c.name === 'chat');
|
||||
B.emit('join-channel', { code: chat.code });
|
||||
await wait(300);
|
||||
B.emit('enter-channel', { code: chat.code });
|
||||
await wait(200);
|
||||
|
||||
const gif = 'https://media4.giphy.com/media/abc123/giphy.gif';
|
||||
const got = h.next(B, 'new-message', (d) => d && d.message && d.message.content === gif);
|
||||
B.emit('send-message', { code: chat.code, content: gif });
|
||||
assert.ok(await got, 'the GIF went through');
|
||||
|
||||
const refused = h.next(B, 'new-message', (d) => d && d.message && d.message.content.includes('example.org'), 1500);
|
||||
B.emit('send-message', { code: chat.code, content: 'look https://example.org/page' });
|
||||
assert.strictEqual(await refused, null, 'a pasted link still waits');
|
||||
});
|
||||
Reference in new issue
Block a user