Merge branch 'main' into snug.moe

This commit is contained in:
vib 2023-05-31 18:37:21 +03:00
commit c4a330dd9e
19 changed files with 131 additions and 99 deletions

View File

@ -20,10 +20,11 @@ export async function checkWordMute(note: NoteLike, me: UserLike | null | undefi
const text = ((note.cw ?? '') + '\n' + (note.text ?? '')).trim();
if (text === '') return false;
const textLower = text.toLowerCase();
const matched = mutedWords.some(filter => {
if (Array.isArray(filter)) {
return filter.every(keyword => text.includes(keyword));
return filter.every(keyword => textLower.includes(keyword.toLowerCase()));
} else {
// represents RegExp
const regexp = filter.match(/^\/(.+)\/(.*)$/);

View File

@ -10,52 +10,49 @@ const logger = queueLogger.createSubLogger('check-expired');
export async function checkExpired(job: Bull.Job<Record<string, unknown>>, done: any): Promise<void> {
logger.info('Checking expired data...');
const expiredMutings = await Mutings.createQueryBuilder('muting')
.where('muting.expiresAt IS NOT NULL')
.andWhere('muting.expiresAt < :now', { now: new Date() })
.innerJoinAndSelect('muting.mutee', 'mutee')
.getMany();
if (expiredMutings.length > 0) {
await Mutings.delete({
id: In(expiredMutings.map(m => m.id)),
});
for (const m of expiredMutings) {
publishUserEvent(m.muterId, 'unmute', m.mutee!);
}
}
const OlderThan = (millis: number) => {
return LessThan(new Date(new Date().getTime() - millis));
};
await Signins.delete({
createdAt: OlderThan(2 * MONTH),
});
await Promise.all([
Mutings.createQueryBuilder('muting')
.where('muting.expiresAt IS NOT NULL')
.andWhere('muting.expiresAt < :now', { now: new Date() })
.innerJoinAndSelect('muting.mutee', 'mutee')
.getMany()
.then(async (expiredMutings) => {
if (expiredMutings.length > 0) {
await Mutings.delete({
id: In(expiredMutings.map(m => m.id)),
});
await AttestationChallenges.delete({
createdAt: OlderThan(5 * MINUTE),
});
await PasswordResetRequests.delete({
// this timing should be the same as in @/server/api/endpoints/reset-password.ts
createdAt: OlderThan(30 * MINUTE),
});
await AuthSessions.delete({
createdAt: OlderThan(15 * MINUTE),
});
await Notifications.delete({
isRead: true,
createdAt: OlderThan(3 * MONTH),
});
await Users.delete({
// delete users where the deletion status reference count has come down to zero
isDeleted: 0,
});
for (const m of expiredMutings) {
publishUserEvent(m.muterId, 'unmute', m.mutee!);
}
}
}),
Signins.delete({
createdAt: OlderThan(2 * MONTH),
}),
AttestationChallenges.delete({
createdAt: OlderThan(5 * MINUTE),
}),
PasswordResetRequests.delete({
// this timing should be the same as in @/server/api/endpoints/reset-password.ts
createdAt: OlderThan(30 * MINUTE),
}),
AuthSessions.delete({
createdAt: OlderThan(15 * MINUTE),
}),
Notifications.delete({
isRead: true,
createdAt: OlderThan(3 * MONTH),
}),
Users.delete({
// delete users where the deletion status reference count has come down to zero
isDeleted: 0,
}),
]);
logger.succ('Deleted expired data.');

View File

@ -62,7 +62,7 @@ export function validateNote(object: IObject): Error | null {
/**
* Function to process the content of a note, reusable in createNote and updateNote.
*/
async function processContent(note: IPost, quoteUri: string | null):
async function processContent(actor: IRemoteUser, note: IPost, quoteUri: string | null, resolver: Resolver):
Promise<{
cw: string | null,
files: DriveFile[],
@ -78,10 +78,10 @@ async function processContent(note: IPost, quoteUri: string | null):
const limit = promiseLimit(2);
const attachments = toArray(note.attachment);
const files = note.attachment
const files = attachments
// If the note is marked as sensitive, the images should be marked sensitive too.
.map(attach => attach.sensitive |= note.sensitive)
? (await Promise.all(note.attachment.map(x => limit(() => resolveImage(actor, x, resolver)) as Promise<DriveFile>)))
? (await Promise.all(attachments.map(x => limit(() => resolveImage(actor, x, resolver)) as Promise<DriveFile>)))
.filter(image => image != null)
: [];
@ -258,7 +258,7 @@ export async function createNote(value: string | IObject, resolver: Resolver, si
const poll = await extractPollFromQuestion(note, resolver).catch(() => undefined);
const processedContent = await processContent(note, quote?.uri);
const processedContent = await processContent(actor, note, quote?.uri, resolver);
if (isTalk) {
for (const recipient of visibleUsers) {

View File

@ -4,6 +4,7 @@ import { toPuny } from '@/misc/convert-host.js';
import { Emojis } from '@/models/index.js';
import { Emoji } from '@/models/entities/emoji.js';
import { apLogger } from '@/remote/activitypub/logger.js';
import { genId } from '@/misc/gen-id.js';
export function extractApHashtags(tags: IObject | IObject[] | null | undefined): string[] {
if (tags == null) return [];

View File

@ -17,27 +17,56 @@ export const renderActivity = (x: any): IActivity | null => {
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1',
{
xsd: 'http://www.w3.org/2001/XMLSchema#',
// as non-standards
manuallyApprovesFollowers: 'as:manuallyApprovesFollowers',
sensitive: 'as:sensitive',
manuallyApprovesFollowers: {
'@id': 'as:manuallyApprovesFollowers',
'@type': 'xsd:boolean',
},
sensitive: {
'@id': 'as:sensitive',
'@type': 'xsd:boolean',
},
Hashtag: 'as:Hashtag',
// Mastodon
toot: 'http://joinmastodon.org/ns#',
Emoji: 'toot:Emoji',
featured: 'toot:featured',
discoverable: 'toot:discoverable',
featured: {
'@id': 'toot:featured',
'@type': '@id',
},
discoverable: {
'@id': 'toot:discoverable',
'@type': 'xsd:boolean',
},
// Fedibird
fedibird: 'http://fedibird.com/ns#',
quoteUri: 'fedibird:quoteUri',
quoteUri: {
'@id': 'http://fedibird.com/ns#quoteUri',
'@type': '@id',
},
// schema
schema: 'http://schema.org#',
PropertyValue: 'schema:PropertyValue',
value: 'schema:value',
schema: 'http://schema.org/',
PropertyValue: {
'@id': 'schema:PropertyValue',
'@context': {
'value': 'schema:value',
'name': 'schema:name',
},
},
// Misskey
misskey: 'https://misskey-hub.net/ns#',
'_misskey_quote': 'misskey:_misskey_quote',
'_misskey_talk': 'misskey:_misskey_talk',
'isCat': 'misskey:isCat',
'_misskey_quote': {
'@id': 'misskey:_misskey_quote',
'@type': '@id',
},
'_misskey_talk': {
'@id': 'misskey:_misskey_talk',
'@type': 'xsd:boolean',
},
'isCat': {
'@id': 'misskey:isCat',
'@type': 'xsd:boolean',
},
// vcard
vcard: 'http://www.w3.org/2006/vcard/ns#',
},

View File

@ -31,13 +31,13 @@ export default class Logger {
* @param color Log message color
* @param store Whether to store messages
*/
constructor(domain: string, color?: KEYWORD, store = true, minLevel: Level = LOG_LEVELS.info) {
constructor(domain: string, color?: KEYWORD, store = true, minLevel?: Level) {
this.domain = {
name: domain,
color,
};
this.store = store;
this.minLevel = minLevel;
this.minLevel = minLevel ?? envOption.logLevel;
}
/**
@ -47,7 +47,7 @@ export default class Logger {
* @param store Whether to store messages
* @returns A Logger instance whose parent logger is this instance.
*/
public createSubLogger(domain: string, color?: KEYWORD, store = true, minLevel: Level = LOG_LEVELS.info): Logger {
public createSubLogger(domain: string, color?: KEYWORD, store = true, minLevel?: Level): Logger {
const logger = new Logger(domain, color, store, minLevel);
logger.parentLogger = this;
return logger;

View File

@ -4,11 +4,12 @@ import * as assert from 'assert';
import * as childProcess from 'child_process';
import { async, signup, request, post, startServer, shutdownServer } from './utils.js';
describe('API visibility', () => {
describe('API visibility', function() {
this.timeout(20*60*1000);
let p: childProcess.ChildProcess;
before(async () => {
this.timeout(0);
p = await startServer();
});

View File

@ -4,14 +4,15 @@ import * as assert from 'assert';
import * as childProcess from 'child_process';
import { async, signup, request, post, react, uploadFile, startServer, shutdownServer } from './utils.js';
describe('API', () => {
describe('API', function() {
this.timeout(20*60*1000);
let p: childProcess.ChildProcess;
let alice: any;
let bob: any;
let carol: any;
before(async function() {
this.timeout(0);
before(async () => {
p = await startServer();
alice = await signup({ username: 'alice' });
bob = await signup({ username: 'bob' });

View File

@ -4,7 +4,9 @@ import * as assert from 'assert';
import * as childProcess from 'child_process';
import { async, signup, request, post, startServer, shutdownServer } from './utils.js';
describe('Block', () => {
describe('Block', function() {
this.timeout(20*60*1000);
let p: childProcess.ChildProcess;
// alice blocks bob
@ -13,8 +15,6 @@ describe('Block', () => {
let carol: any;
before(async () => {
this.timeout(0);
p = await startServer();
alice = await signup({ username: 'alice' });
bob = await signup({ username: 'bob' });

View File

@ -16,14 +16,15 @@ const AP = 'application/activity+json; charset=utf-8';
const JSON = 'application/json; charset=utf-8';
const HTML = 'text/html; charset=utf-8';
describe('Fetch resource', () => {
describe('Fetch resource', function() {
this.timeout(20*60*1000);
let p: childProcess.ChildProcess;
let alice: any;
let alicesPost: any;
before(async () => {
this.timeout(0);
p = await startServer();
alice = await signup({ username: 'alice' });
alicesPost = await post(alice, {

View File

@ -4,7 +4,9 @@ import * as assert from 'assert';
import * as childProcess from 'child_process';
import { async, signup, request, post, react, connectStream, startServer, shutdownServer, simpleGet } from './utils.js';
describe('FF visibility', () => {
describe('FF visibility', function() {
this.timeout(20*60*1000);
let p: childProcess.ChildProcess;
let alice: any;
@ -12,8 +14,6 @@ describe('FF visibility', () => {
let follower: any;
before(async () => {
this.timeout(0);
p = await startServer();
alice = await signup({ username: 'alice' });
bob = await signup({ username: 'bob' });

View File

@ -4,7 +4,9 @@ import * as assert from 'assert';
import * as childProcess from 'child_process';
import { async, signup, request, post, react, startServer, shutdownServer, waitFire } from './utils.js';
describe('Mute', () => {
describe('Mute', function() {
this.timeout(20*60*1000);
let p: childProcess.ChildProcess;
// alice mutes carol
@ -13,8 +15,6 @@ describe('Mute', () => {
let carol: any;
before(async () => {
this.timeout(0);
p = await startServer();
alice = await signup({ username: 'alice' });
bob = await signup({ username: 'bob' });

View File

@ -5,7 +5,9 @@ import * as childProcess from 'child_process';
import { Note } from '../src/models/entities/note.js';
import { async, signup, request, post, uploadUrl, startServer, shutdownServer, initTestDb, api } from './utils.js';
describe('Note', () => {
describe('Note', function() {
this.timeout(20*60*1000);
let p: childProcess.ChildProcess;
let Notes: any;
@ -13,8 +15,6 @@ describe('Note', () => {
let bob: any;
before(async () => {
this.timeout(0);
p = await startServer();
const connection = await initTestDb(true);
Notes = connection.getRepository(Note);

View File

@ -5,7 +5,9 @@ import * as childProcess from 'child_process';
import * as sinon from 'sinon';
import { async, signup, startServer, shutdownServer, initTestDb } from '../utils.js';
describe('Creating a block activity', () => {
describe('Creating a block activity', function() {
this.timeout(20*60*1000);
let p: childProcess.ChildProcess;
// alice blocks bob
@ -14,8 +16,6 @@ describe('Creating a block activity', () => {
let carol: any;
before(async () => {
this.timeout(0);
await initTestDb();
p = await startServer();
alice = await signup({ username: 'alice' });

View File

@ -24,7 +24,9 @@ describe('Streaming', () => {
});
};
describe('Streaming', () => {
describe('Streaming', function() {
this.timeout(20*60*1000);
// Local users
let ayano: any;
let kyoko: any;
@ -38,8 +40,6 @@ describe('Streaming', () => {
let list: any;
before(async () => {
this.timeout(0);
p = await startServer();
const connection = await initTestDb(true);
Followings = connection.getRepository(Following);
@ -410,7 +410,7 @@ describe('Streaming', () => {
let fooCount = 0;
let barCount = 0;
let fooBarCount = 0;
const ws = await connectStream(chitose, 'hashtag', ({ type, body }) => {
if (type == 'note') {
if (body.text === '#foo') fooCount++;
@ -422,19 +422,19 @@ describe('Streaming', () => {
['foo', 'bar'],
],
});
post(chitose, {
text: '#foo',
});
post(chitose, {
text: '#bar',
});
post(chitose, {
text: '#foo #bar',
});
setTimeout(() => {
assert.strictEqual(fooCount, 0);
assert.strictEqual(barCount, 0);

View File

@ -4,7 +4,9 @@ import * as assert from 'assert';
import * as childProcess from 'child_process';
import { async, signup, request, post, react, connectStream, startServer, shutdownServer } from './utils.js';
describe('Note thread mute', () => {
describe('Note thread mute', function() {
this.timeout(20*60*1000);
let p: childProcess.ChildProcess;
let alice: any;
@ -12,8 +14,6 @@ describe('Note thread mute', () => {
let carol: any;
before(async () => {
this.timeout(0);
p = await startServer();
alice = await signup({ username: 'alice' });
bob = await signup({ username: 'bob' });

View File

@ -4,7 +4,9 @@ import * as assert from 'assert';
import * as childProcess from 'child_process';
import { async, signup, request, post, uploadUrl, startServer, shutdownServer } from './utils.js';
describe('users/notes', () => {
describe('users/notes', function() {
this.timeout(20*60*1000);
let p: childProcess.ChildProcess;
let alice: any;
@ -13,8 +15,6 @@ describe('users/notes', () => {
let jpgPngNote: any;
before(async () => {
this.timeout(0);
p = await startServer();
alice = await signup({ username: 'alice' });
const jpg = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg');

View File

@ -10,7 +10,7 @@ import * as foundkey from 'foundkey-js';
import fetch from 'node-fetch';
import FormData from 'form-data';
import { DataSource } from 'typeorm';
import loadConfig from '../src/config/load.js';
import { loadConfig } from '../src/config/load.js';
import { entities } from '../src/db/postgre.js';
import got from 'got';

View File

@ -6,6 +6,7 @@ export function checkWordMute(note: Record<string, any>, me: Record<string, any>
const text = ((note.cw ?? '') + '\n' + (note.text ?? '')).trim();
if (text === '') return false;
const textLower = text.toLowerCase();
const matched = mutedWords.some(filter => {
if (Array.isArray(filter)) {
@ -13,7 +14,7 @@ export function checkWordMute(note: Record<string, any>, me: Record<string, any>
const filteredFilter = filter.filter(keyword => keyword !== '');
if (filteredFilter.length === 0) return false;
return filteredFilter.every(keyword => text.includes(keyword));
return filteredFilter.every(keyword => textLower.includes(keyword.toLowerCase()));
} else {
// represents RegExp
const regexp = filter.match(/^\/(.+)\/(.*)$/);