diff --git a/.config/ci.yml b/.config/ci.yml
index fcf15a293d..180b16cbb1 100644
--- a/.config/ci.yml
+++ b/.config/ci.yml
@@ -222,10 +222,12 @@ checkActivityPubGetSignature: false
# downloadTimeout: 30
# maxFileSize: 262144000
-# enable stripe identity for ID verification
-# stripeVerify: true
-# stripeKey: sk_
-# stripeHookKey: whsec_
+# Stripe identity for ID verification
+stripeAgeCheck:
+ enabled: false
+ required: false
+ key: sk_
+ hookKey: whsec_
# Upload or download file size limits (bytes)
#maxFileSize: 262144000
diff --git a/.config/docker_example.yml b/.config/docker_example.yml
index 3604361083..363a465a01 100644
--- a/.config/docker_example.yml
+++ b/.config/docker_example.yml
@@ -300,6 +300,7 @@ checkActivityPubGetSignature: false
# Stripe identity for ID verification
stripeAgeCheck:
enabled: false
+ required: false
key: sk_
hookKey: whsec_
diff --git a/.config/example.yml b/.config/example.yml
index b58cd53429..62bcc1939c 100644
--- a/.config/example.yml
+++ b/.config/example.yml
@@ -315,6 +315,7 @@ checkActivityPubGetSignature: false
# Stripe identity for ID verification
stripeAgeCheck:
enabled: false
+ required: false
key: sk_
hookKey: whsec_
diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts
index 837817dc7c..629a4815f8 100644
--- a/packages/backend/src/config.ts
+++ b/packages/backend/src/config.ts
@@ -110,6 +110,7 @@ type Source = {
stripeAgeCheck: {
enabled: boolean;
+ required: boolean;
key: string;
hookKey: string;
};
@@ -205,6 +206,7 @@ export type Config = {
stripeAgeCheck: {
enabled: boolean | undefined;
+ required: boolean | undefined;
key: string;
hookKey: string;
};
@@ -478,6 +480,6 @@ function applyEnvOverrides(config: Source) {
_apply_top([['outgoingAddress', 'outgoingAddressFamily', 'proxy', 'proxySmtp', 'mediaProxy', 'proxyRemoteFiles', 'videoThumbnailGenerator']]);
_apply_top([['maxFileSize', 'maxNoteLength', 'pidFile']]);
_apply_top(['import', ['downloadTimeout', 'maxFileSize']]);
- _apply_top(['stripeAgeCheck', ['enabled', 'key', 'hookKey']]);
+ _apply_top(['stripeAgeCheck', ['enabled', 'required', 'key', 'hookKey']]);
_apply_top([['signToActivityPubGet', 'checkActivityPubGetSignature']]);
}
diff --git a/packages/backend/src/core/entities/MetaEntityService.ts b/packages/backend/src/core/entities/MetaEntityService.ts
index 3128b762f4..08583361c8 100644
--- a/packages/backend/src/core/entities/MetaEntityService.ts
+++ b/packages/backend/src/core/entities/MetaEntityService.ts
@@ -165,6 +165,7 @@ export class MetaEntityService {
turnstile: instance.enableTurnstile,
objectStorage: instance.useObjectStorage,
serviceWorker: instance.enableServiceWorker,
+ idRequired: this.config.stripeAgeCheck.enabled && this.config.stripeAgeCheck.required ? true : false,
miauth: true,
},
};
diff --git a/packages/backend/src/models/json-schema/meta.ts b/packages/backend/src/models/json-schema/meta.ts
index 1d620f16fd..2ae33c5a8c 100644
--- a/packages/backend/src/models/json-schema/meta.ts
+++ b/packages/backend/src/models/json-schema/meta.ts
@@ -316,6 +316,10 @@ export const packedMetaDetailedOnlySchema = {
type: 'boolean',
optional: false, nullable: false,
},
+ idRequired: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
miauth: {
type: 'boolean',
optional: true, nullable: false,
diff --git a/packages/frontend/src/components/MkVisitorDashboard.vue b/packages/frontend/src/components/MkVisitorDashboard.vue
index 6fb3304468..94c58e3c27 100644
--- a/packages/frontend/src/components/MkVisitorDashboard.vue
+++ b/packages/frontend/src/components/MkVisitorDashboard.vue
@@ -41,7 +41,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
{{ i18n.ts.letsLookAtTimeline }}
diff --git a/packages/frontend/src/pages/welcome.entrance.a.vue b/packages/frontend/src/pages/welcome.entrance.a.vue
index 0d132e6a86..83496882ef 100644
--- a/packages/frontend/src/pages/welcome.entrance.a.vue
+++ b/packages/frontend/src/pages/welcome.entrance.a.vue
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
diff --git a/packages/frontend/src/router/definition.ts b/packages/frontend/src/router/definition.ts
index aa7084dc7b..292c51e64a 100644
--- a/packages/frontend/src/router/definition.ts
+++ b/packages/frontend/src/router/definition.ts
@@ -7,6 +7,7 @@ import { App, AsyncComponentLoader, defineAsyncComponent, provide } from 'vue';
import type { RouteDef } from '@/nirax.js';
import { IRouter, Router } from '@/nirax.js';
import { $i, iAmModerator } from '@/account.js';
+import { fetchInstance } from '@/instance.js';
import MkLoading from '@/pages/_loading_.vue';
import MkError from '@/pages/_error_.vue';
import { setMainRouter } from '@/router/main.js';
@@ -17,6 +18,8 @@ const page = (loader: AsyncComponentLoader
) => defineAsyncComponent({
errorComponent: MkError,
});
+const instanceMeta = await fetchInstance();
+
const routes: RouteDef[] = [{
path: '/@:initUser/pages/:initPageName/view-source',
component: page(() => import('@/pages/page-editor/page-editor.vue')),
@@ -52,7 +55,7 @@ const routes: RouteDef[] = [{
path: '/settings',
component: page(() => import('@/pages/settings/index.vue')),
loginRequired: true,
- idRequired: true,
+ idRequired: $i && $i.idCheckRequired ? true : false,
children: [{
path: '/profile',
name: 'profile',
@@ -218,7 +221,6 @@ const routes: RouteDef[] = [{
path: '/theme-editor',
component: page(() => import('@/pages/theme-editor.vue')),
loginRequired: true,
- idRequired: true,
}, {
path: '/roles/:role',
component: page(() => import('@/pages/role.vue')),
@@ -255,17 +257,14 @@ const routes: RouteDef[] = [{
path: '/lookup',
component: page(() => import('@/pages/lookup.vue')),
loginRequired: true,
- idRequired: true,
}, {
path: '/share',
component: page(() => import('@/pages/share.vue')),
loginRequired: true,
- idRequired: true,
}, {
path: '/api-console',
component: page(() => import('@/pages/api-console.vue')),
loginRequired: true,
- idRequired: true,
}, {
path: '/scratchpad',
component: page(() => import('@/pages/scratchpad.vue')),
@@ -340,11 +339,11 @@ const routes: RouteDef[] = [{
}, {
path: '/channels/:channelId',
component: page(() => import('@/pages/channel.vue')),
- idRequired: true,
+ idRequired: $i && $i.idCheckRequired || !$i && instanceMeta.features.idRequired ? true : false,
}, {
path: '/channels',
component: page(() => import('@/pages/channels.vue')),
- idRequired: true,
+ idRequired: $i && $i.idCheckRequired || !$i && instanceMeta.features.idRequired ? true : false,
}, {
path: '/custom-emojis-manager',
component: page(() => import('@/pages/custom-emojis-manager.vue')),
@@ -566,12 +565,12 @@ const routes: RouteDef[] = [{
path: '/timeline/list/:listId',
component: page(() => import('@/pages/user-list-timeline.vue')),
loginRequired: true,
- idRequired: true,
+ idRequired: $i && $i.idCheckRequired || !$i && instanceMeta.features.idRequired ? true : false,
}, {
path: '/timeline/antenna/:antennaId',
component: page(() => import('@/pages/antenna-timeline.vue')),
loginRequired: true,
- idRequired: true,
+ idRequired: $i && $i.idCheckRequired || !$i && instanceMeta.features.idRequired ? true : false,
}, {
path: '/clicker',
component: page(() => import('@/pages/clicker.vue')),
@@ -595,7 +594,7 @@ const routes: RouteDef[] = [{
}, {
path: '/timeline',
component: page(() => import('@/pages/timeline.vue')),
- idRequired: true,
+ idRequired: $i && $i.idCheckRequired || !$i && instanceMeta.features.idRequired ? true : false,
}, {
name: 'index',
path: '/',
@@ -613,7 +612,7 @@ const routes: RouteDef[] = [{
}];
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')));
}
/**
diff --git a/packages/frontend/src/scripts/confirm-id.ts b/packages/frontend/src/scripts/confirm-id.ts
index 8bc8773f12..f60b79fdae 100644
--- a/packages/frontend/src/scripts/confirm-id.ts
+++ b/packages/frontend/src/scripts/confirm-id.ts
@@ -5,9 +5,25 @@
import { defineAsyncComponent } from 'vue';
import { $i } from '@/account.js';
+import { i18n } from '@/i18n.js';
import { popup } from '@/os.js';
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;
const { dispose } = popup(defineAsyncComponent(() => import('@/components/SkStripeIdDialog.vue')), {
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 34b987a38a..a48d890a39 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -5117,6 +5117,7 @@ export type components = {
recaptcha: boolean;
objectStorage: boolean;
serviceWorker: boolean;
+ idRequired: boolean;
/** @default true */
miauth?: boolean;
};