diff --git a/src/client/components/form/suspense.vue b/src/client/components/form/suspense.vue index 562fe23e06..6a8282733f 100644 --- a/src/client/components/form/suspense.vue +++ b/src/client/components/form/suspense.vue @@ -5,9 +5,9 @@ <MkLoading/> </div> </div> - <div v-else-if="resolved"> + <FormGroup v-else-if="resolved" class="_formItem"> <slot :result="result"></slot> - </div> + </FormGroup> <div class="_formItem" v-else> <div class="_formPanel"> error! @@ -20,8 +20,13 @@ <script lang="ts"> import { defineComponent, PropType, ref, watch } from 'vue'; import './form.scss'; +import FormGroup from './group.vue'; export default defineComponent({ + components: { + FormGroup, + }, + props: { p: { type: Function as PropType<() => Promise<any>>, diff --git a/src/client/pages/instance-info.vue b/src/client/pages/instance-info.vue index 326b30c7c9..a3cd402993 100644 --- a/src/client/pages/instance-info.vue +++ b/src/client/pages/instance-info.vue @@ -14,6 +14,10 @@ </FormKeyValueView> </FormGroup> + <FormTextarea readonly :value="instance.description"> + <span>{{ $ts.description }}</span> + </FormTextarea> + <FormGroup> <FormKeyValueView> <template #key>{{ $ts.software }}</template> @@ -99,6 +103,27 @@ <FormLink :to="`https://${host}/.well-known/host-meta.json`" external>host-meta.json</FormLink> <FormLink :to="`https://${host}/.well-known/nodeinfo`" external>nodeinfo</FormLink> </FormGroup> + <FormSuspense :p="dnsPromiseFactory" v-slot="{ result: dns }"> + <FormGroup> + <template #label>DNS</template> + <FormKeyValueView v-for="record in dns.a" :key="record"> + <template #key>A</template> + <template #value><span class="_monospace">{{ record }}</span></template> + </FormKeyValueView> + <FormKeyValueView v-for="record in dns.aaaa" :key="record"> + <template #key>AAAA</template> + <template #value><span class="_monospace">{{ record }}</span></template> + </FormKeyValueView> + <FormKeyValueView v-for="record in dns.cname" :key="record"> + <template #key>CNAME</template> + <template #value><span class="_monospace">{{ record }}</span></template> + </FormKeyValueView> + <FormKeyValueView v-for="record in dns.txt"> + <template #key>TXT</template> + <template #value><span class="_monospace">{{ record[0] }}</span></template> + </FormKeyValueView> + </FormGroup> + </FormSuspense> </FormGroup> </FormBase> </template> @@ -167,6 +192,9 @@ export default defineComponent({ }], }, instance: null, + dnsPromiseFactory: () => os.api('federation/dns', { + host: this.host + }), now: null, canvas: null, chart: null, diff --git a/src/client/pages/user-ap-info.vue b/src/client/pages/user-ap-info.vue index 7520540c2d..648ecdb10a 100644 --- a/src/client/pages/user-ap-info.vue +++ b/src/client/pages/user-ap-info.vue @@ -22,7 +22,7 @@ </FormKeyValueView> <FormKeyValueView> <template #key>Shared Inbox</template> - <template #value><span class="_monospace">{{ ap.sharedInbox }}</span></template> + <template #value><span class="_monospace">{{ ap.sharedInbox || ap.endpoints.sharedInbox }}</span></template> </FormKeyValueView> <FormKeyValueView> <template #key>Outbox</template> diff --git a/src/client/pages/user-info.vue b/src/client/pages/user-info.vue index 1d714cac33..06f2e4270d 100644 --- a/src/client/pages/user-info.vue +++ b/src/client/pages/user-info.vue @@ -18,6 +18,13 @@ </FormKeyValueView> </FormGroup> + <FormGroup> + <FormKeyValueView> + <template #key>{{ $ts.updatedAt }}</template> + <template #value><MkTime v-if="user.lastFetchedAt" mode="detail" :time="user.lastFetchedAt"/><span v-else>N/A</span></template> + </FormKeyValueView> + </FormGroup> + <FormObjectView tall :value="user"> <span>Raw</span> </FormObjectView> diff --git a/src/models/repositories/user.ts b/src/models/repositories/user.ts index 203b878fbb..a3b4c69f43 100644 --- a/src/models/repositories/user.ts +++ b/src/models/repositories/user.ts @@ -198,6 +198,7 @@ export class UserRepository extends Repository<User> { uri: user.uri, createdAt: user.createdAt.toISOString(), updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null, + lastFetchedAt: user.lastFetchedAt?.toISOString(), bannerUrl: user.bannerUrl, bannerBlurhash: user.bannerBlurhash, bannerColor: null, // 後方互換性のため diff --git a/src/server/api/endpoints/federation/dns.ts b/src/server/api/endpoints/federation/dns.ts new file mode 100644 index 0000000000..a188f46ac1 --- /dev/null +++ b/src/server/api/endpoints/federation/dns.ts @@ -0,0 +1,43 @@ +import { promises as dns } from 'dns'; +import $ from 'cafy'; +import define from '../../define'; +import { Instances } from '../../../../models'; +import { toPuny } from '@/misc/convert-host'; + +const resolver = new dns.Resolver(); +resolver.setServers(['1.1.1.1']); + +export const meta = { + tags: ['federation'], + + requireCredential: false as const, + + params: { + host: { + validator: $.str + } + }, +}; + +export default define(meta, async (ps, me) => { + const instance = await Instances.findOneOrFail({ host: toPuny(ps.host) }); + + const [ + resolved4, + resolved6, + resolvedCname, + resolvedTxt, + ] = await Promise.all([ + resolver.resolve4(instance.host).catch(() => []), + resolver.resolve6(instance.host).catch(() => []), + resolver.resolveCname(instance.host).catch(() => []), + resolver.resolveTxt(instance.host).catch(() => []), + ]); + + return { + a: resolved4, + aaaa: resolved6, + cname: resolvedCname, + txt: resolvedTxt, + }; +});