summaryrefslogtreecommitdiff
path: root/packages/client/src/pages
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2022-07-02 15:12:11 +0900
committerGitHub <noreply@github.com>2022-07-02 15:12:11 +0900
commiteccc90c843f63b2dc08d8fbf80e4f54a601e477d (patch)
treea26e23b56d711806862bdfaafeb9b826d25465a8 /packages/client/src/pages
parentrefactor(client): refactoring (diff)
downloadsharkey-eccc90c843f63b2dc08d8fbf80e4f54a601e477d.tar.gz
sharkey-eccc90c843f63b2dc08d8fbf80e4f54a601e477d.tar.bz2
sharkey-eccc90c843f63b2dc08d8fbf80e4f54a601e477d.zip
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
Diffstat (limited to 'packages/client/src/pages')
-rw-r--r--packages/client/src/pages/admin-file.vue26
-rw-r--r--packages/client/src/pages/admin/security.vue15
-rw-r--r--packages/client/src/pages/user-info.vue47
3 files changed, 81 insertions, 7 deletions
diff --git a/packages/client/src/pages/admin-file.vue b/packages/client/src/pages/admin-file.vue
index 7bfbed35f0..f96a41a7ea 100644
--- a/packages/client/src/pages/admin-file.vue
+++ b/packages/client/src/pages/admin-file.vue
@@ -1,7 +1,7 @@
<template>
<MkStickyContainer>
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
- <MkSpacer v-if="file" :content-max="500" :margin-min="16" :margin-max="32">
+ <MkSpacer v-if="file" :content-max="600" :margin-min="16" :margin-max="32">
<div v-if="tab === 'overview'" class="cxqhhsmd _formRoot">
<a class="_formBlock thumbnail" :href="file.url" target="_blank">
<MkDriveFileThumbnail class="thumbnail" :file="file" fit="contain"/>
@@ -39,6 +39,20 @@
<MkButton danger @click="del"><i class="fas fa-trash-alt"></i> {{ i18n.ts.delete }}</MkButton>
</div>
</div>
+ <div v-else-if="tab === 'ip' && info" class="_formRoot">
+ <MkInfo v-if="!iAmAdmin" warn>{{ i18n.ts.requireAdminForView }}</MkInfo>
+ <MkKeyValue v-if="info.requestIp" class="_formBlock _monospace" :copy="info.requestIp" oneline>
+ <template #key>IP</template>
+ <template #value>{{ info.requestIp }}</template>
+ </MkKeyValue>
+ <FormSection v-if="info.requestHeaders">
+ <template #label>Headers</template>
+ <MkKeyValue v-for="(v, k) in info.requestHeaders" :key="k" class="_formBlock _monospace">
+ <template #key>{{ k }}</template>
+ <template #value>{{ v }}</template>
+ </MkKeyValue>
+ </FormSection>
+ </div>
<div v-else-if="tab === 'raw'" class="_formRoot">
<MkObjectView v-if="info" tall :value="info">
</MkObjectView>
@@ -54,13 +68,15 @@ import MkSwitch from '@/components/form/switch.vue';
import MkObjectView from '@/components/object-view.vue';
import MkDriveFileThumbnail from '@/components/drive-file-thumbnail.vue';
import MkKeyValue from '@/components/key-value.vue';
-import FormLink from '@/components/form/link.vue';
+import FormSection from '@/components/form/section.vue';
import MkUserCardMini from '@/components/user-card-mini.vue';
+import MkInfo from '@/components/ui/info.vue';
import bytes from '@/filters/bytes';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { acct } from '@/filters/user';
+import { iAmAdmin, iAmModerator } from '@/account';
let tab = $ref('overview');
let file: any = $ref(null);
@@ -108,7 +124,11 @@ const headerTabs = $computed(() => [{
key: 'overview',
title: i18n.ts.overview,
icon: 'fas fa-info-circle',
-}, {
+}, iAmModerator ? {
+ key: 'ip',
+ title: 'IP',
+ icon: 'fas fa-bars-staggered',
+} : null, {
key: 'raw',
title: 'Raw data',
icon: 'fas fa-code',
diff --git a/packages/client/src/pages/admin/security.vue b/packages/client/src/pages/admin/security.vue
index ec11e42a7d..76fa9d21eb 100644
--- a/packages/client/src/pages/admin/security.vue
+++ b/packages/client/src/pages/admin/security.vue
@@ -15,6 +15,18 @@
</FormFolder>
<FormFolder class="_formBlock">
+ <template #label>Log IP address</template>
+ <template v-if="enableIpLogging" #suffix>Enabled</template>
+ <template v-else #suffix>Disabled</template>
+
+ <div class="_formRoot">
+ <FormSwitch v-model="enableIpLogging" class="_formBlock" @update:modelValue="save">
+ <template #label>Enable</template>
+ </FormSwitch>
+ </div>
+ </FormFolder>
+
+ <FormFolder class="_formBlock">
<template #label>Summaly Proxy</template>
<div class="_formRoot">
@@ -51,17 +63,20 @@ import { definePageMetadata } from '@/scripts/page-metadata';
let summalyProxy: string = $ref('');
let enableHcaptcha: boolean = $ref(false);
let enableRecaptcha: boolean = $ref(false);
+let enableIpLogging: boolean = $ref(false);
async function init() {
const meta = await os.api('admin/meta');
summalyProxy = meta.summalyProxy;
enableHcaptcha = meta.enableHcaptcha;
enableRecaptcha = meta.enableRecaptcha;
+ enableIpLogging = meta.enableIpLogging;
}
function save() {
os.apiWithDialog('admin/update-meta', {
summalyProxy,
+ enableIpLogging,
}).then(() => {
fetchInstance();
});
diff --git a/packages/client/src/pages/user-info.vue b/packages/client/src/pages/user-info.vue
index cfea2637b7..f9edd208ab 100644
--- a/packages/client/src/pages/user-info.vue
+++ b/packages/client/src/pages/user-info.vue
@@ -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>