upd: add required boolean, hide timelines on required ID

Blocks guest timeline on sidebar and on welcome page if ID Verification is required
Blocks guests from going to timeline view, channels, antennas and lists
This commit is contained in:
Marie 2024-09-12 00:41:56 +02:00
parent c3e2ca9314
commit 53d17b21f3
No known key found for this signature in database
GPG Key ID: 7ADF6C9CD9A28555
11 changed files with 45 additions and 18 deletions

View File

@ -222,10 +222,12 @@ checkActivityPubGetSignature: false
# downloadTimeout: 30 # downloadTimeout: 30
# maxFileSize: 262144000 # maxFileSize: 262144000
# enable stripe identity for ID verification # Stripe identity for ID verification
# stripeVerify: true stripeAgeCheck:
# stripeKey: sk_ enabled: false
# stripeHookKey: whsec_ required: false
key: sk_
hookKey: whsec_
# Upload or download file size limits (bytes) # Upload or download file size limits (bytes)
#maxFileSize: 262144000 #maxFileSize: 262144000

View File

@ -300,6 +300,7 @@ checkActivityPubGetSignature: false
# Stripe identity for ID verification # Stripe identity for ID verification
stripeAgeCheck: stripeAgeCheck:
enabled: false enabled: false
required: false
key: sk_ key: sk_
hookKey: whsec_ hookKey: whsec_

View File

@ -315,6 +315,7 @@ checkActivityPubGetSignature: false
# Stripe identity for ID verification # Stripe identity for ID verification
stripeAgeCheck: stripeAgeCheck:
enabled: false enabled: false
required: false
key: sk_ key: sk_
hookKey: whsec_ hookKey: whsec_

View File

@ -110,6 +110,7 @@ type Source = {
stripeAgeCheck: { stripeAgeCheck: {
enabled: boolean; enabled: boolean;
required: boolean;
key: string; key: string;
hookKey: string; hookKey: string;
}; };
@ -205,6 +206,7 @@ export type Config = {
stripeAgeCheck: { stripeAgeCheck: {
enabled: boolean | undefined; enabled: boolean | undefined;
required: boolean | undefined;
key: string; key: string;
hookKey: string; hookKey: string;
}; };
@ -478,6 +480,6 @@ function applyEnvOverrides(config: Source) {
_apply_top([['outgoingAddress', 'outgoingAddressFamily', 'proxy', 'proxySmtp', 'mediaProxy', 'proxyRemoteFiles', 'videoThumbnailGenerator']]); _apply_top([['outgoingAddress', 'outgoingAddressFamily', 'proxy', 'proxySmtp', 'mediaProxy', 'proxyRemoteFiles', 'videoThumbnailGenerator']]);
_apply_top([['maxFileSize', 'maxNoteLength', 'pidFile']]); _apply_top([['maxFileSize', 'maxNoteLength', 'pidFile']]);
_apply_top(['import', ['downloadTimeout', 'maxFileSize']]); _apply_top(['import', ['downloadTimeout', 'maxFileSize']]);
_apply_top(['stripeAgeCheck', ['enabled', 'key', 'hookKey']]); _apply_top(['stripeAgeCheck', ['enabled', 'required', 'key', 'hookKey']]);
_apply_top([['signToActivityPubGet', 'checkActivityPubGetSignature']]); _apply_top([['signToActivityPubGet', 'checkActivityPubGetSignature']]);
} }

View File

@ -165,6 +165,7 @@ export class MetaEntityService {
turnstile: instance.enableTurnstile, turnstile: instance.enableTurnstile,
objectStorage: instance.useObjectStorage, objectStorage: instance.useObjectStorage,
serviceWorker: instance.enableServiceWorker, serviceWorker: instance.enableServiceWorker,
idRequired: this.config.stripeAgeCheck.enabled && this.config.stripeAgeCheck.required ? true : false,
miauth: true, miauth: true,
}, },
}; };

View File

@ -316,6 +316,10 @@ export const packedMetaDetailedOnlySchema = {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
}, },
idRequired: {
type: 'boolean',
optional: false, nullable: false,
},
miauth: { miauth: {
type: 'boolean', type: 'boolean',
optional: true, nullable: false, optional: true, nullable: false,

View File

@ -41,7 +41,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div :class="$style.statsItemCount"><MkNumber :value="stats.originalNotesCount"/></div> <div :class="$style.statsItemCount"><MkNumber :value="stats.originalNotesCount"/></div>
</div> </div>
</div> </div>
<div v-if="instance.policies.ltlAvailable" :class="[$style.tl, $style.panel]"> <div v-if="instance.policies.ltlAvailable && !instance.features?.idRequired" :class="[$style.tl, $style.panel]">
<div :class="$style.tlHeader">{{ i18n.ts.letsLookAtTimeline }}</div> <div :class="$style.tlHeader">{{ i18n.ts.letsLookAtTimeline }}</div>
<div :class="$style.tlBody"> <div :class="$style.tlBody">
<MkTimeline src="local"/> <MkTimeline src="local"/>

View File

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<div v-if="meta" class="rsqzvsbo"> <div v-if="meta" class="rsqzvsbo">
<MkFeaturedPhotos class="bg"/> <MkFeaturedPhotos class="bg"/>
<XTimeline class="tl"/> <XTimeline v-if="!meta.features!.idRequired" class="tl"/>
<div class="shape1"></div> <div class="shape1"></div>
<div class="shape2"></div> <div class="shape2"></div>
<div class="logo-wrapper"> <div class="logo-wrapper">

View File

@ -7,6 +7,7 @@ import { App, AsyncComponentLoader, defineAsyncComponent, provide } from 'vue';
import type { RouteDef } from '@/nirax.js'; import type { RouteDef } from '@/nirax.js';
import { IRouter, Router } from '@/nirax.js'; import { IRouter, Router } from '@/nirax.js';
import { $i, iAmModerator } from '@/account.js'; import { $i, iAmModerator } from '@/account.js';
import { fetchInstance } from '@/instance.js';
import MkLoading from '@/pages/_loading_.vue'; import MkLoading from '@/pages/_loading_.vue';
import MkError from '@/pages/_error_.vue'; import MkError from '@/pages/_error_.vue';
import { setMainRouter } from '@/router/main.js'; import { setMainRouter } from '@/router/main.js';
@ -17,6 +18,8 @@ const page = (loader: AsyncComponentLoader<any>) => defineAsyncComponent({
errorComponent: MkError, errorComponent: MkError,
}); });
const instanceMeta = await fetchInstance();
const routes: RouteDef[] = [{ const routes: RouteDef[] = [{
path: '/@:initUser/pages/:initPageName/view-source', path: '/@:initUser/pages/:initPageName/view-source',
component: page(() => import('@/pages/page-editor/page-editor.vue')), component: page(() => import('@/pages/page-editor/page-editor.vue')),
@ -52,7 +55,7 @@ const routes: RouteDef[] = [{
path: '/settings', path: '/settings',
component: page(() => import('@/pages/settings/index.vue')), component: page(() => import('@/pages/settings/index.vue')),
loginRequired: true, loginRequired: true,
idRequired: true, idRequired: $i && $i.idCheckRequired ? true : false,
children: [{ children: [{
path: '/profile', path: '/profile',
name: 'profile', name: 'profile',
@ -218,7 +221,6 @@ const routes: RouteDef[] = [{
path: '/theme-editor', path: '/theme-editor',
component: page(() => import('@/pages/theme-editor.vue')), component: page(() => import('@/pages/theme-editor.vue')),
loginRequired: true, loginRequired: true,
idRequired: true,
}, { }, {
path: '/roles/:role', path: '/roles/:role',
component: page(() => import('@/pages/role.vue')), component: page(() => import('@/pages/role.vue')),
@ -255,17 +257,14 @@ const routes: RouteDef[] = [{
path: '/lookup', path: '/lookup',
component: page(() => import('@/pages/lookup.vue')), component: page(() => import('@/pages/lookup.vue')),
loginRequired: true, loginRequired: true,
idRequired: true,
}, { }, {
path: '/share', path: '/share',
component: page(() => import('@/pages/share.vue')), component: page(() => import('@/pages/share.vue')),
loginRequired: true, loginRequired: true,
idRequired: true,
}, { }, {
path: '/api-console', path: '/api-console',
component: page(() => import('@/pages/api-console.vue')), component: page(() => import('@/pages/api-console.vue')),
loginRequired: true, loginRequired: true,
idRequired: true,
}, { }, {
path: '/scratchpad', path: '/scratchpad',
component: page(() => import('@/pages/scratchpad.vue')), component: page(() => import('@/pages/scratchpad.vue')),
@ -340,11 +339,11 @@ const routes: RouteDef[] = [{
}, { }, {
path: '/channels/:channelId', path: '/channels/:channelId',
component: page(() => import('@/pages/channel.vue')), component: page(() => import('@/pages/channel.vue')),
idRequired: true, idRequired: $i && $i.idCheckRequired || !$i && instanceMeta.features.idRequired ? true : false,
}, { }, {
path: '/channels', path: '/channels',
component: page(() => import('@/pages/channels.vue')), component: page(() => import('@/pages/channels.vue')),
idRequired: true, idRequired: $i && $i.idCheckRequired || !$i && instanceMeta.features.idRequired ? true : false,
}, { }, {
path: '/custom-emojis-manager', path: '/custom-emojis-manager',
component: page(() => import('@/pages/custom-emojis-manager.vue')), component: page(() => import('@/pages/custom-emojis-manager.vue')),
@ -566,12 +565,12 @@ const routes: RouteDef[] = [{
path: '/timeline/list/:listId', path: '/timeline/list/:listId',
component: page(() => import('@/pages/user-list-timeline.vue')), component: page(() => import('@/pages/user-list-timeline.vue')),
loginRequired: true, loginRequired: true,
idRequired: true, idRequired: $i && $i.idCheckRequired || !$i && instanceMeta.features.idRequired ? true : false,
}, { }, {
path: '/timeline/antenna/:antennaId', path: '/timeline/antenna/:antennaId',
component: page(() => import('@/pages/antenna-timeline.vue')), component: page(() => import('@/pages/antenna-timeline.vue')),
loginRequired: true, loginRequired: true,
idRequired: true, idRequired: $i && $i.idCheckRequired || !$i && instanceMeta.features.idRequired ? true : false,
}, { }, {
path: '/clicker', path: '/clicker',
component: page(() => import('@/pages/clicker.vue')), component: page(() => import('@/pages/clicker.vue')),
@ -595,7 +594,7 @@ const routes: RouteDef[] = [{
}, { }, {
path: '/timeline', path: '/timeline',
component: page(() => import('@/pages/timeline.vue')), component: page(() => import('@/pages/timeline.vue')),
idRequired: true, idRequired: $i && $i.idCheckRequired || !$i && instanceMeta.features.idRequired ? true : false,
}, { }, {
name: 'index', name: 'index',
path: '/', path: '/',
@ -613,7 +612,7 @@ const routes: RouteDef[] = [{
}]; }];
function createRouterImpl(path: string): IRouter { function createRouterImpl(path: string): IRouter {
return new Router(routes, path, !!$i, $i?.idCheckRequired!, page(() => import('@/pages/not-found.vue'))); return new Router(routes, path, !!$i, $i?.idCheckRequired! || !$i && instanceMeta.features.idRequired, page(() => import('@/pages/not-found.vue')));
} }
/** /**

View File

@ -5,9 +5,25 @@
import { defineAsyncComponent } from 'vue'; import { defineAsyncComponent } from 'vue';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
import { i18n } from '@/i18n.js';
import { popup } from '@/os.js'; import { popup } from '@/os.js';
export function confirmId(path?: string) { export function confirmId(path?: string) {
if (!$i) {
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {
autoSet: true,
message: i18n.ts.signinRequired,
}, {
cancelled: () => {
if (path) {
window.location.href = path;
}
},
closed: () => dispose(),
});
return new Error('User Account required for id verification');
};
if ($i && !$i.idCheckRequired) return; if ($i && !$i.idCheckRequired) return;
const { dispose } = popup(defineAsyncComponent(() => import('@/components/SkStripeIdDialog.vue')), { const { dispose } = popup(defineAsyncComponent(() => import('@/components/SkStripeIdDialog.vue')), {

View File

@ -5117,6 +5117,7 @@ export type components = {
recaptcha: boolean; recaptcha: boolean;
objectStorage: boolean; objectStorage: boolean;
serviceWorker: boolean; serviceWorker: boolean;
idRequired: boolean;
/** @default true */ /** @default true */
miauth?: boolean; miauth?: boolean;
}; };