diff options
Diffstat (limited to 'src/server')
22 files changed, 194 insertions, 35 deletions
diff --git a/src/server/api/common/signin.ts b/src/server/api/common/signin.ts index 0f4ee4ca11..37229ad1bc 100644 --- a/src/server/api/common/signin.ts +++ b/src/server/api/common/signin.ts @@ -2,6 +2,9 @@ import * as Koa from 'koa'; import config from '../../../config'; import { ILocalUser } from '../../../models/entities/user'; +import { Signins } from '../../../models'; +import { genId } from '../../../misc/gen-id'; +import { publishMainStream } from '../../../services/stream'; export default function(ctx: Koa.BaseContext, user: ILocalUser, redirect = false) { if (redirect) { @@ -24,4 +27,19 @@ export default function(ctx: Koa.BaseContext, user: ILocalUser, redirect = false ctx.body = { i: user.token }; ctx.status = 200; } + + (async () => { + // Append signin history + const record = await Signins.save({ + id: genId(), + createdAt: new Date(), + userId: user.id, + ip: ctx.ip, + headers: ctx.headers, + success: true + }); + + // Publish signin event + publishMainStream(user.id, 'signin', await Signins.pack(record)); + })(); } diff --git a/src/server/api/endpoints/admin/emoji/add.ts b/src/server/api/endpoints/admin/emoji/add.ts index 5ba00afde8..8c21b1c73e 100644 --- a/src/server/api/endpoints/admin/emoji/add.ts +++ b/src/server/api/endpoints/admin/emoji/add.ts @@ -4,6 +4,7 @@ import { detectUrlMine } from '../../../../../misc/detect-url-mine'; import { Emojis } from '../../../../../models'; import { genId } from '../../../../../misc/gen-id'; import { getConnection } from 'typeorm'; +import { insertModerationLog } from '../../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -31,7 +32,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const type = await detectUrlMine(ps.url); const emoji = await Emojis.save({ @@ -46,6 +47,10 @@ export default define(meta, async (ps) => { await getConnection().queryResultCache!.remove(['meta_emojis']); + insertModerationLog(me, 'addEmoji', { + emojiId: emoji.id + }); + return { id: emoji.id }; diff --git a/src/server/api/endpoints/admin/emoji/remove.ts b/src/server/api/endpoints/admin/emoji/remove.ts index 3ebf933bc6..92c5f5f8c6 100644 --- a/src/server/api/endpoints/admin/emoji/remove.ts +++ b/src/server/api/endpoints/admin/emoji/remove.ts @@ -3,6 +3,7 @@ import define from '../../../define'; import { ID } from '../../../../../misc/cafy-id'; import { Emojis } from '../../../../../models'; import { getConnection } from 'typeorm'; +import { insertModerationLog } from '../../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -21,7 +22,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const emoji = await Emojis.findOne(ps.id); if (emoji == null) throw new Error('emoji not found'); @@ -29,4 +30,8 @@ export default define(meta, async (ps) => { await Emojis.delete(emoji.id); await getConnection().queryResultCache!.remove(['meta_emojis']); + + insertModerationLog(me, 'removeEmoji', { + emoji: emoji + }); }); diff --git a/src/server/api/endpoints/admin/queue/clear.ts b/src/server/api/endpoints/admin/queue/clear.ts index f0fd00f1ad..03c1ae8463 100644 --- a/src/server/api/endpoints/admin/queue/clear.ts +++ b/src/server/api/endpoints/admin/queue/clear.ts @@ -1,5 +1,6 @@ import define from '../../../define'; import { destroy } from '../../../../../queue'; +import { insertModerationLog } from '../../../../../services/insert-moderation-log'; export const meta = { tags: ['admin'], @@ -10,8 +11,8 @@ export const meta = { params: {} }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { destroy(); - return; + insertModerationLog(me, 'clearQueue'); }); diff --git a/src/server/api/endpoints/admin/show-moderation-logs.ts b/src/server/api/endpoints/admin/show-moderation-logs.ts new file mode 100644 index 0000000000..bc67b3e55b --- /dev/null +++ b/src/server/api/endpoints/admin/show-moderation-logs.ts @@ -0,0 +1,35 @@ +import $ from 'cafy'; +import { ID } from '../../../../misc/cafy-id'; +import define from '../../define'; +import { ModerationLogs } from '../../../../models'; +import { makePaginationQuery } from '../../common/make-pagination-query'; + +export const meta = { + tags: ['admin'], + + requireCredential: true, + requireModerator: true, + + params: { + limit: { + validator: $.optional.num.range(1, 100), + default: 10 + }, + + sinceId: { + validator: $.optional.type(ID), + }, + + untilId: { + validator: $.optional.type(ID), + }, + } +}; + +export default define(meta, async (ps) => { + const query = makePaginationQuery(ModerationLogs.createQueryBuilder('report'), ps.sinceId, ps.untilId); + + const reports = await query.take(ps.limit!).getMany(); + + return await ModerationLogs.packMany(reports); +}); diff --git a/src/server/api/endpoints/admin/show-users.ts b/src/server/api/endpoints/admin/show-users.ts index 8733d87a38..89e0cf1e2a 100644 --- a/src/server/api/endpoints/admin/show-users.ts +++ b/src/server/api/endpoints/admin/show-users.ts @@ -49,6 +49,16 @@ export const meta = { 'remote', ]), default: 'local' + }, + + username: { + validator: $.optional.str, + default: null + }, + + hostname: { + validator: $.optional.str, + default: null } } }; @@ -70,6 +80,14 @@ export default define(meta, async (ps, me) => { case 'remote': query.andWhere('user.host IS NOT NULL'); break; } + if (ps.username) { + query.andWhere('user.usernameLower like :username', { username: ps.username.toLowerCase() + '%' }); + } + + if (ps.hostname) { + query.andWhere('user.host like :hostname', { hostname: '%' + ps.hostname.toLowerCase() + '%' }); + } + switch (ps.sort) { case '+follower': query.orderBy('user.followersCount', 'DESC'); break; case '-follower': query.orderBy('user.followersCount', 'ASC'); break; diff --git a/src/server/api/endpoints/admin/silence-user.ts b/src/server/api/endpoints/admin/silence-user.ts index 83aa88012a..8cc84aa1cc 100644 --- a/src/server/api/endpoints/admin/silence-user.ts +++ b/src/server/api/endpoints/admin/silence-user.ts @@ -2,6 +2,7 @@ import $ from 'cafy'; import { ID } from '../../../../misc/cafy-id'; import define from '../../define'; import { Users } from '../../../../models'; +import { insertModerationLog } from '../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -25,7 +26,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const user = await Users.findOne(ps.userId as string); if (user == null) { @@ -39,4 +40,8 @@ export default define(meta, async (ps) => { await Users.update(user.id, { isSilenced: true }); + + insertModerationLog(me, 'silence', { + targetId: user.id, + }); }); diff --git a/src/server/api/endpoints/admin/suspend-user.ts b/src/server/api/endpoints/admin/suspend-user.ts index fa4d378708..6ba0d91505 100644 --- a/src/server/api/endpoints/admin/suspend-user.ts +++ b/src/server/api/endpoints/admin/suspend-user.ts @@ -4,6 +4,8 @@ import define from '../../define'; import deleteFollowing from '../../../../services/following/delete'; import { Users, Followings } from '../../../../models'; import { User } from '../../../../models/entities/user'; +import { insertModerationLog } from '../../../../services/insert-moderation-log'; +import { doPostSuspend } from '../../../../services/suspend-user'; export const meta = { desc: { @@ -27,7 +29,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const user = await Users.findOne(ps.userId as string); if (user == null) { @@ -46,7 +48,14 @@ export default define(meta, async (ps) => { isSuspended: true }); - unFollowAll(user); + insertModerationLog(me, 'suspend', { + targetId: user.id, + }); + + (async () => { + await doPostSuspend(user).catch(e => {}); + await unFollowAll(user).catch(e => {}); + })(); }); async function unFollowAll(follower: User) { diff --git a/src/server/api/endpoints/admin/unsilence-user.ts b/src/server/api/endpoints/admin/unsilence-user.ts index f9b173366b..607c9b699a 100644 --- a/src/server/api/endpoints/admin/unsilence-user.ts +++ b/src/server/api/endpoints/admin/unsilence-user.ts @@ -2,6 +2,7 @@ import $ from 'cafy'; import { ID } from '../../../../misc/cafy-id'; import define from '../../define'; import { Users } from '../../../../models'; +import { insertModerationLog } from '../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -25,7 +26,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const user = await Users.findOne(ps.userId as string); if (user == null) { @@ -35,4 +36,8 @@ export default define(meta, async (ps) => { await Users.update(user.id, { isSilenced: false }); + + insertModerationLog(me, 'unsilence', { + targetId: user.id, + }); }); diff --git a/src/server/api/endpoints/admin/unsuspend-user.ts b/src/server/api/endpoints/admin/unsuspend-user.ts index 08dae034d3..237585e276 100644 --- a/src/server/api/endpoints/admin/unsuspend-user.ts +++ b/src/server/api/endpoints/admin/unsuspend-user.ts @@ -2,6 +2,8 @@ import $ from 'cafy'; import { ID } from '../../../../misc/cafy-id'; import define from '../../define'; import { Users } from '../../../../models'; +import { insertModerationLog } from '../../../../services/insert-moderation-log'; +import { doPostUnsuspend } from '../../../../services/unsuspend-user'; export const meta = { desc: { @@ -25,7 +27,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const user = await Users.findOne(ps.userId as string); if (user == null) { @@ -35,4 +37,10 @@ export default define(meta, async (ps) => { await Users.update(user.id, { isSuspended: false }); + + insertModerationLog(me, 'unsuspend', { + targetId: user.id, + }); + + doPostUnsuspend(user); }); diff --git a/src/server/api/endpoints/admin/update-meta.ts b/src/server/api/endpoints/admin/update-meta.ts index 8e98d203ff..834faa42b9 100644 --- a/src/server/api/endpoints/admin/update-meta.ts +++ b/src/server/api/endpoints/admin/update-meta.ts @@ -2,6 +2,7 @@ import $ from 'cafy'; import define from '../../define'; import { getConnection } from 'typeorm'; import { Meta } from '../../../../models/entities/meta'; +import { insertModerationLog } from '../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -401,7 +402,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const set = {} as Partial<Meta>; if (ps.announcements) { @@ -653,4 +654,6 @@ export default define(meta, async (ps) => { await transactionalEntityManager.save(Meta, set); } }); + + insertModerationLog(me, 'updateMeta'); }); diff --git a/src/server/api/endpoints/admin/vacuum.ts b/src/server/api/endpoints/admin/vacuum.ts index 6990706282..4921e228e5 100644 --- a/src/server/api/endpoints/admin/vacuum.ts +++ b/src/server/api/endpoints/admin/vacuum.ts @@ -1,6 +1,7 @@ import $ from 'cafy'; import define from '../../define'; import { getConnection } from 'typeorm'; +import { insertModerationLog } from '../../../../services/insert-moderation-log'; export const meta = { tags: ['admin'], @@ -18,7 +19,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const params: string[] = []; if (ps.full) { @@ -30,4 +31,6 @@ export default define(meta, async (ps) => { } getConnection().query('VACUUM ' + params.join(' ')); + + insertModerationLog(me, 'vacuum', ps); }); diff --git a/src/server/api/endpoints/federation/instances.ts b/src/server/api/endpoints/federation/instances.ts index 3c4e0037d6..bc0eb9a1d7 100644 --- a/src/server/api/endpoints/federation/instances.ts +++ b/src/server/api/endpoints/federation/instances.ts @@ -43,12 +43,12 @@ export default define(meta, async (ps, me) => { switch (ps.sort) { case '+notes': query.orderBy('instance.notesCount', 'DESC'); break; case '-notes': query.orderBy('instance.notesCount', 'ASC'); break; - case '+usersCount': query.orderBy('instance.usersCount', 'DESC'); break; - case '-usersCount': query.orderBy('instance.usersCount', 'ASC'); break; - case '+followingCount': query.orderBy('instance.followingCount', 'DESC'); break; - case '-followingCount': query.orderBy('instance.followingCount', 'ASC'); break; - case '+followersCount': query.orderBy('instance.followersCount', 'DESC'); break; - case '-followersCount': query.orderBy('instance.followersCount', 'ASC'); break; + case '+users': query.orderBy('instance.usersCount', 'DESC'); break; + case '-users': query.orderBy('instance.usersCount', 'ASC'); break; + case '+following': query.orderBy('instance.followingCount', 'DESC'); break; + case '-following': query.orderBy('instance.followingCount', 'ASC'); break; + case '+followers': query.orderBy('instance.followersCount', 'DESC'); break; + case '-followers': query.orderBy('instance.followersCount', 'ASC'); break; case '+caughtAt': query.orderBy('instance.caughtAt', 'DESC'); break; case '-caughtAt': query.orderBy('instance.caughtAt', 'ASC'); break; case '+lastCommunicatedAt': query.orderBy('instance.lastCommunicatedAt', 'DESC'); break; diff --git a/src/server/api/endpoints/hashtags/users.ts b/src/server/api/endpoints/hashtags/users.ts index 59210f4604..28a78ff8e6 100644 --- a/src/server/api/endpoints/hashtags/users.ts +++ b/src/server/api/endpoints/hashtags/users.ts @@ -59,7 +59,7 @@ export const meta = { export default define(meta, async (ps, me) => { const query = Users.createQueryBuilder('user') - .where(':tag = ANY(user.tags)', { tag: ps.tag }); + .where(':tag = ANY(user.tags)', { tag: ps.tag.toLowerCase() }); const recent = new Date(Date.now() - (1000 * 60 * 60 * 24 * 5)); diff --git a/src/server/api/endpoints/i/delete-account.ts b/src/server/api/endpoints/i/delete-account.ts index 8ec85c9f41..b4950cb1fb 100644 --- a/src/server/api/endpoints/i/delete-account.ts +++ b/src/server/api/endpoints/i/delete-account.ts @@ -3,6 +3,7 @@ import * as bcrypt from 'bcryptjs'; import define from '../../define'; import { Users, UserProfiles } from '../../../../models'; import { ensure } from '../../../../prelude/ensure'; +import { doPostSuspend } from '../../../../services/suspend-user'; export const meta = { requireCredential: true, @@ -26,5 +27,8 @@ export default define(meta, async (ps, user) => { throw new Error('incorrect password'); } + // 物理削除する前にDelete activityを送信する + await doPostSuspend(user).catch(e => {}); + await Users.delete(user.id); }); diff --git a/src/server/api/endpoints/i/update.ts b/src/server/api/endpoints/i/update.ts index a454cdb940..149081e50b 100644 --- a/src/server/api/endpoints/i/update.ts +++ b/src/server/api/endpoints/i/update.ts @@ -77,6 +77,13 @@ export const meta = { } }, + fields: { + validator: $.optional.arr($.object()).range(1, 4), + desc: { + 'ja-JP': 'プロフィール補足情報' + } + }, + isLocked: { validator: $.optional.bool, desc: { @@ -226,6 +233,14 @@ export default define(meta, async (ps, user, app) => { profileUpdates.pinnedPageId = null; } + if (ps.fields) { + profileUpdates.fields = ps.fields + .filter(x => typeof x.name === 'string' && x.name !== '' && typeof x.value === 'string' && x.value !== '') + .map(x => { + return { name: x.name, value: x.value }; + }); + } + //#region emojis/tags let emojis = [] as string[]; diff --git a/src/server/api/private/signin.ts b/src/server/api/private/signin.ts index eb267aa604..de0e35f500 100644 --- a/src/server/api/private/signin.ts +++ b/src/server/api/private/signin.ts @@ -1,7 +1,6 @@ import * as Koa from 'koa'; import * as bcrypt from 'bcryptjs'; import * as speakeasy from 'speakeasy'; -import { publishMainStream } from '../../../services/stream'; import signin from '../common/signin'; import config from '../../../config'; import { Users, Signins, UserProfiles, UserSecurityKeys, AttestationChallenges } from '../../../models'; @@ -53,34 +52,30 @@ export default async (ctx: Koa.BaseContext) => { // Compare password const same = await bcrypt.compare(password, profile.password!); - async function fail(status?: number, failure?: {error: string}) { + async function fail(status?: number, failure?: { error: string }) { // Append signin history - const record = await Signins.save({ + await Signins.save({ id: genId(), createdAt: new Date(), userId: user.id, ip: ctx.ip, headers: ctx.headers, - success: !!(status || failure) + success: false }); - // Publish signin event - publishMainStream(user.id, 'signin', await Signins.pack(record)); - - if (status && failure) { - ctx.throw(status, failure); - } + ctx.throw(status || 500, failure || { error: 'someting happened' }); } if (!profile.twoFactorEnabled) { if (same) { signin(ctx, user); + return; } else { await fail(403, { error: 'incorrect password' }); + return; } - return; } if (token) { @@ -169,6 +164,7 @@ export default async (ctx: Koa.BaseContext) => { if (isValid) { signin(ctx, user); + return; } else { await fail(403, { error: 'invalid challenge data' @@ -191,6 +187,7 @@ export default async (ctx: Koa.BaseContext) => { await fail(403, { error: 'no keys found' }); + return; } // 32 byte challenge @@ -219,6 +216,5 @@ export default async (ctx: Koa.BaseContext) => { ctx.status = 200; return; } - - await fail(); + // never get here }; diff --git a/src/server/api/private/signup.ts b/src/server/api/private/signup.ts index ca197a6611..026fe7485b 100644 --- a/src/server/api/private/signup.ts +++ b/src/server/api/private/signup.ts @@ -5,7 +5,7 @@ import generateUserToken from '../common/generate-native-user-token'; import config from '../../../config'; import { fetchMeta } from '../../../misc/fetch-meta'; import * as recaptcha from 'recaptcha-promise'; -import { Users, RegistrationTickets } from '../../../models'; +import { Users, Signins, RegistrationTickets } from '../../../models'; import { genId } from '../../../misc/gen-id'; import { usersChart } from '../../../services/chart'; import { User } from '../../../models/entities/user'; @@ -104,6 +104,13 @@ export default async (ctx: Koa.BaseContext) => { // Start transaction await getConnection().transaction(async transactionalEntityManager => { + const exist = await transactionalEntityManager.findOne(User, { + usernameLower: username.toLowerCase(), + host: null + }); + + if (exist) throw 'already registered'; + account = await transactionalEntityManager.save(new User({ id: genId(), createdAt: new Date(), @@ -130,6 +137,16 @@ export default async (ctx: Koa.BaseContext) => { usersChart.update(account, true); + // Append signin history + await Signins.save({ + id: genId(), + createdAt: new Date(), + userId: account.id, + ip: ctx.ip, + headers: ctx.headers, + success: true + }); + const res = await Users.pack(account, account, { detail: true, includeSecrets: true diff --git a/src/server/proxy/proxy-media.ts b/src/server/proxy/proxy-media.ts index eadfab54a3..415eef6c34 100644 --- a/src/server/proxy/proxy-media.ts +++ b/src/server/proxy/proxy-media.ts @@ -33,7 +33,7 @@ export async function proxyMedia(ctx: Koa.BaseContext) { }; } - ctx.set('Content-Type', type); + ctx.set('Content-Type', image.type); ctx.set('Cache-Control', 'max-age=31536000, immutable'); ctx.body = image.data; } catch (e) { diff --git a/src/server/web/index.ts b/src/server/web/index.ts index 8cf6a75208..6c41bbde46 100644 --- a/src/server/web/index.ts +++ b/src/server/web/index.ts @@ -156,11 +156,17 @@ router.get('/@:user', async (ctx, next) => { if (user != null) { const profile = await UserProfiles.findOne(user.id).then(ensure); const meta = await fetchMeta(); + const me = profile.fields + ? profile.fields + .filter(filed => filed.value != null && filed.value.match(/^https?:/)) + .map(field => field.value) + : []; + await ctx.render('user', { - user, profile, + user, profile, me, instanceName: meta.name || 'Misskey' }); - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.set('Cache-Control', 'public, max-age=30'); } else { // リモートユーザーなので await next(); diff --git a/src/server/web/views/base.pug b/src/server/web/views/base.pug index 733a306d56..16bea853e7 100644 --- a/src/server/web/views/base.pug +++ b/src/server/web/views/base.pug @@ -44,3 +44,4 @@ html <svg viewBox="0 0 50 50"> <path fill=#fb4e4e d="M25.251,6.461c-10.318,0-18.683,8.365-18.683,18.683h4.068c0-8.071,6.543-14.615,14.615-14.615V6.461z" /> </svg> + block content diff --git a/src/server/web/views/user.pug b/src/server/web/views/user.pug index 9b257afb7b..6ff86b09be 100644 --- a/src/server/web/views/user.pug +++ b/src/server/web/views/user.pug @@ -36,3 +36,8 @@ block meta link(rel='alternate' href=user.uri type='application/activity+json') if profile.url link(rel='alternate' href=profile.url type='text/html') + +block content + div#me + each m in me + a(rel='me' href=`${m}`) #{m} |