diff --git a/locales/index.d.ts b/locales/index.d.ts index d641a6d3a6..897f2cc7aa 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -12011,6 +12011,20 @@ export interface Locale extends ILocale { */ "parentDefault": string; }; + /** + * Generate Keys + */ + "genKeys": string; + "_genKeysDialog": { + /** + * Are you sure that you want to generate new keys? This will stop push notifications for all users who have already enabled them. + */ + "text": string; + /** + * Generate new keys + */ + "title": string; + }; /** * ID */ diff --git a/packages/backend/src/server/api/endpoint-list.ts b/packages/backend/src/server/api/endpoint-list.ts index 1866ee5da8..6dce7f1a3d 100644 --- a/packages/backend/src/server/api/endpoint-list.ts +++ b/packages/backend/src/server/api/endpoint-list.ts @@ -59,6 +59,7 @@ export * as 'admin/federation/refresh-remote-instance-metadata' from './endpoint export * as 'admin/federation/remove-all-following' from './endpoints/admin/federation/remove-all-following.js'; export * as 'admin/federation/update-instance' from './endpoints/admin/federation/update-instance.js'; export * as 'admin/forward-abuse-user-report' from './endpoints/admin/forward-abuse-user-report.js'; +export * as 'admin/gen-vapid-keys' from './endpoints/admin/gen-vapid-keys.js'; export * as 'admin/get-index-stats' from './endpoints/admin/get-index-stats.js'; export * as 'admin/get-table-stats' from './endpoints/admin/get-table-stats.js'; export * as 'admin/get-user-ips' from './endpoints/admin/get-user-ips.js'; diff --git a/packages/backend/src/server/api/endpoints/admin/gen-vapid-keys.ts b/packages/backend/src/server/api/endpoints/admin/gen-vapid-keys.ts new file mode 100644 index 0000000000..5695866265 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/gen-vapid-keys.ts @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: marie and sharkey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import webpush from 'web-push'; +const { generateVAPIDKeys } = webpush; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { ModerationLogService } from '@/core/ModerationLogService.js'; + +export const meta = { + tags: ['admin'], + + requireCredential: true, + requireModerator: true, + kind: 'write:admin:meta', +} as const; + +export const paramDef = {} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + private moderationLogService: ModerationLogService, + ) { + super(meta, paramDef, async (ps, me) => { + const keys = await generateVAPIDKeys(); + + return { public: keys.publicKey, private: keys.privateKey }; + }); + } +} diff --git a/packages/frontend/src/pages/admin/settings.vue b/packages/frontend/src/pages/admin/settings.vue index cd05b43be8..0e9c0a7d38 100644 --- a/packages/frontend/src/pages/admin/settings.vue +++ b/packages/frontend/src/pages/admin/settings.vue @@ -138,6 +138,8 @@ SPDX-License-Identifier: AGPL-3.0-only + + {{ i18n.ts.genKeys }} @@ -434,6 +436,18 @@ function chooseProxyAccount() { }); } +async function genKeys() { + if (serviceWorkerForm.savedState.swPrivateKey) { + const result = await os.confirm({ type: 'warning', title: i18n.ts._genKeysDialog.title, text: i18n.ts._genKeysDialog.text }); + if (result.canceled) return; + } + + const keys = await os.apiWithDialog('admin/gen-vapid-keys', {}); + + serviceWorkerForm.state.swPublicKey = keys.public; + serviceWorkerForm.state.swPrivateKey = keys.private; +} + const headerTabs = computed(() => []); definePageMetadata(() => ({ diff --git a/packages/misskey-js/src/autogen/apiClientJSDoc.ts b/packages/misskey-js/src/autogen/apiClientJSDoc.ts index c8f8dec044..f4120b3afc 100644 --- a/packages/misskey-js/src/autogen/apiClientJSDoc.ts +++ b/packages/misskey-js/src/autogen/apiClientJSDoc.ts @@ -548,6 +548,17 @@ declare module '../api.js' { credential?: string | null, ): Promise>; + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:meta* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + /** * No description provided. * diff --git a/packages/misskey-js/src/autogen/endpoint.ts b/packages/misskey-js/src/autogen/endpoint.ts index 7e6508ab37..c8000fc1d0 100644 --- a/packages/misskey-js/src/autogen/endpoint.ts +++ b/packages/misskey-js/src/autogen/endpoint.ts @@ -658,6 +658,7 @@ export type Endpoints = { 'admin/federation/remove-all-following': { req: AdminFederationRemoveAllFollowingRequest; res: EmptyResponse }; 'admin/federation/update-instance': { req: AdminFederationUpdateInstanceRequest; res: EmptyResponse }; 'admin/forward-abuse-user-report': { req: AdminForwardAbuseUserReportRequest; res: EmptyResponse }; + 'admin/gen-vapid-keys': { req: EmptyRequest; res: EmptyResponse }; 'admin/get-index-stats': { req: EmptyRequest; res: AdminGetIndexStatsResponse }; 'admin/get-table-stats': { req: EmptyRequest; res: AdminGetTableStatsResponse }; 'admin/get-user-ips': { req: AdminGetUserIpsRequest; res: AdminGetUserIpsResponse }; diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index 3d6bcab8c7..9ae318fc2f 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -459,6 +459,15 @@ export type paths = { */ post: operations['admin___forward-abuse-user-report']; }; + '/admin/gen-vapid-keys': { + /** + * admin/gen-vapid-keys + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:meta* + */ + post: operations['admin___gen-vapid-keys']; + }; '/admin/get-index-stats': { /** * admin/get-index-stats @@ -8306,6 +8315,50 @@ export type operations = { }; }; }; + /** + * admin/gen-vapid-keys + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *write:admin:meta* + */ + 'admin___gen-vapid-keys': { + responses: { + /** @description OK (without any results) */ + 204: { + content: never; + }; + /** @description Client error */ + 400: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; /** * admin/get-index-stats * @description No description provided. diff --git a/sharkey-locales/en-US.yml b/sharkey-locales/en-US.yml index 5baa7d53f4..cb98083be4 100644 --- a/sharkey-locales/en-US.yml +++ b/sharkey-locales/en-US.yml @@ -448,4 +448,9 @@ _defaultCWPriority: defaultParent: "Use Default, then Parent (use the default CW, and append the inherited CW)" parentDefault: "Use Parent, then Default (use the inherited CW, and append the default CW)" +genKeys: "Generate Keys" +_genKeysDialog: + text: "Are you sure that you want to generate new keys? This will stop push notifications for all users who have already enabled them." + title: "Generate new keys" + id: "ID"