feat: Log user ips (#8872)

* wip

* store ip and headers

* Update admin-file.vue

* require admin for view ip/headers

* IP (recent) 消した

* admin必須

* opt in

* clean ips periodically

* respect logging setting in drive/files/create
This commit is contained in:
syuilo
2022-07-02 15:12:11 +09:00
committed by GitHub
parent ded0f6f0df
commit eccc90c843
29 changed files with 371 additions and 73 deletions

View File

@@ -27,6 +27,12 @@
<template #key>ID</template>
<template #value><span class="_monospace">{{ user.id }}</span></template>
</MkKeyValue>
<!-- 要る
<MkKeyValue v-if="ips.length > 0" :copy="user.id" oneline style="margin: 1em 0;">
<template #key>IP (recent)</template>
<template #value><span class="_monospace">{{ ips[0].ip }}</span></template>
</MkKeyValue>
-->
<MkKeyValue oneline style="margin: 1em 0;">
<template #key>{{ i18n.ts.createdAt }}</template>
<template #value><span class="_monospace"><MkTime :time="user.createdAt" :mode="'detail'"/></span></template>
@@ -92,8 +98,18 @@
<div v-else-if="tab === 'files'" class="_formRoot">
<MkFileListForAdmin :pagination="filesPagination" view-mode="grid"/>
</div>
<div v-else-if="tab === 'ip'" class="_formRoot">
<MkInfo v-if="!iAmAdmin" warn>{{ i18n.ts.requireAdminForView }}</MkInfo>
<MkInfo v-else>The date is the IP address was first acknowledged.</MkInfo>
<template v-if="iAmAdmin && ips">
<div v-for="record in ips" :key="record.ip" class="_monospace" :class="$style.ip" style="margin: 1em 0;">
<span class="date">{{ record.createdAt }}</span>
<span class="ip">{{ record.ip }}</span>
</div>
</template>
</div>
<div v-else-if="tab === 'ap'" class="_formRoot">
<MkObjectView v-if="ap" tall :value="user">
<MkObjectView v-if="ap" tall :value="ap">
</MkObjectView>
</div>
<div v-else-if="tab === 'raw'" class="_formRoot">
@@ -122,6 +138,7 @@ import MkKeyValue from '@/components/key-value.vue';
import MkSelect from '@/components/form/select.vue';
import FormSuspense from '@/components/form/suspense.vue';
import MkFileListForAdmin from '@/components/file-list-for-admin.vue';
import MkInfo from '@/components/ui/info.vue';
import * as os from '@/os';
import number from '@/filters/number';
import bytes from '@/filters/bytes';
@@ -129,7 +146,7 @@ import { url } from '@/config';
import { userPage, acct } from '@/filters/user';
import { definePageMetadata } from '@/scripts/page-metadata';
import { i18n } from '@/i18n';
import { iAmModerator } from '@/account';
import { iAmAdmin, iAmModerator } from '@/account';
const props = defineProps<{
userId: string;
@@ -140,6 +157,7 @@ let chartSrc = $ref('per-user-notes');
let user = $ref<null | misskey.entities.UserDetailed>();
let init = $ref();
let info = $ref();
let ips = $ref(null);
let ap = $ref(null);
let moderator = $ref(false);
let silenced = $ref(false);
@@ -158,9 +176,12 @@ function createFetcher() {
userId: props.userId,
}), os.api('admin/show-user', {
userId: props.userId,
})]).then(([_user, _info]) => {
}), iAmAdmin ? os.api('admin/get-user-ips', {
userId: props.userId,
}) : Promise.resolve(null)]).then(([_user, _info, _ips]) => {
user = _user;
info = _info;
ips = _ips;
moderator = info.isModerator;
silenced = info.isSilenced;
suspended = info.isSuspended;
@@ -300,7 +321,11 @@ const headerTabs = $computed(() => [{
key: 'ap',
title: 'AP',
icon: 'fas fa-share-alt',
}, {
}, iAmModerator ? {
key: 'ip',
title: 'IP',
icon: 'fas fa-bars-staggered',
} : null, {
key: 'raw',
title: 'Raw',
icon: 'fas fa-code',
@@ -362,3 +387,17 @@ definePageMetadata(computed(() => ({
}
}
</style>
<style lang="scss" module>
.ip {
display: flex;
> :global(.date) {
opacity: 0.7;
}
> :global(.ip) {
margin-left: auto;
}
}
</style>