server: always enable push notifications

The thing that previously presumably hindered this was that the VAPID
keys had to be set up. Previously admins had to do this, but this is a bad
idea for multiple reasons:
1) The meaning of "public key" and "private key" was not well documented
in the settings.
2) Giving out a private key over the API, even just for admins, sounds
like a bad idea.

Co-authored-by: Francis Dinh <normandy@biribiri.dev>
This commit is contained in:
Johann150 2022-11-16 20:57:27 +01:00
parent 7ee6a09cf2
commit 563f3672a9
Signed by untrusted user: Johann150
GPG key ID: 9EE6577A2A06F8F1
8 changed files with 32 additions and 78 deletions

View file

@ -0,0 +1,24 @@
import push from 'web-push';
export class forceEnablePush1668374092227 {
name = 'forceEnablePush1668374092227';
async up(queryRunner) {
// set VAPID keys if not yet set
const { publicKey, privateKey } = push.generateVAPIDKeys();
await queryRunner.query(`UPDATE "meta" SET "swPublicKey" = $1, "swPrivateKey" = $2 WHERE "swPublicKey" IS NULL OR "swPrivateKey" IS NULL`, [publicKey, privateKey]);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableServiceWorker"`);
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "swPublicKey" SET NOT NULL`);
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "swPrivateKey" SET NOT NULL`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "swPrivateKey" DROP NOT NULL`);
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "swPublicKey" DROP NOT NULL`);
await queryRunner.query(`ALTER TABLE "meta" ADD "enableServiceWorker" boolean NOT NULL DEFAULT false`);
// since VAPID keys are set and the service worker may have been enabled before, make sure it is now enabled
await queryRunner.query(`UPDATE "meta" SET "enableServiceWorker" = true`);
// can't unset the VAPID keys because we do not know if we set them in the migration
}
}

View file

@ -236,22 +236,15 @@ export class Meta {
}) })
public smtpPass: string | null; public smtpPass: string | null;
@Column('boolean', { @Column('varchar', {
default: false, length: 128,
}) })
public enableServiceWorker: boolean; public swPublicKey: string;
@Column('varchar', { @Column('varchar', {
length: 128, length: 128,
nullable: true,
}) })
public swPublicKey: string | null; public swPrivateKey: string;
@Column('varchar', {
length: 128,
nullable: true,
})
public swPrivateKey: string | null;
@Column('boolean', { @Column('boolean', {
default: false, default: false,

View file

@ -48,7 +48,7 @@ export const meta = {
}, },
swPublickey: { swPublickey: {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: false,
}, },
bannerUrl: { bannerUrl: {
type: 'string', type: 'string',
@ -114,10 +114,6 @@ export const meta = {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
}, },
enableServiceWorker: {
type: 'boolean',
optional: false, nullable: false,
},
translatorAvailable: { translatorAvailable: {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
@ -219,10 +215,6 @@ export const meta = {
type: 'string', type: 'string',
optional: true, nullable: true, optional: true, nullable: true,
}, },
swPrivateKey: {
type: 'string',
optional: true, nullable: true,
},
useObjectStorage: { useObjectStorage: {
type: 'boolean', type: 'boolean',
optional: true, nullable: false, optional: true, nullable: false,
@ -339,7 +331,6 @@ export default define(meta, paramDef, async (ps, me) => {
enableTwitterIntegration: instance.enableTwitterIntegration, enableTwitterIntegration: instance.enableTwitterIntegration,
enableGithubIntegration: instance.enableGithubIntegration, enableGithubIntegration: instance.enableGithubIntegration,
enableDiscordIntegration: instance.enableDiscordIntegration, enableDiscordIntegration: instance.enableDiscordIntegration,
enableServiceWorker: instance.enableServiceWorker,
pinnedPages: instance.pinnedPages, pinnedPages: instance.pinnedPages,
pinnedClipId: instance.pinnedClipId, pinnedClipId: instance.pinnedClipId,
cacheRemoteFiles: instance.cacheRemoteFiles, cacheRemoteFiles: instance.cacheRemoteFiles,
@ -364,7 +355,6 @@ export default define(meta, paramDef, async (ps, me) => {
smtpPort: instance.smtpPort, smtpPort: instance.smtpPort,
smtpUser: instance.smtpUser, smtpUser: instance.smtpUser,
smtpPass: instance.smtpPass, smtpPass: instance.smtpPass,
swPrivateKey: instance.swPrivateKey,
useObjectStorage: instance.useObjectStorage, useObjectStorage: instance.useObjectStorage,
objectStorageBaseUrl: instance.objectStorageBaseUrl, objectStorageBaseUrl: instance.objectStorageBaseUrl,
objectStorageBucket: instance.objectStorageBucket, objectStorageBucket: instance.objectStorageBucket,

View file

@ -77,9 +77,6 @@ export const paramDef = {
smtpPort: { type: 'integer', nullable: true }, smtpPort: { type: 'integer', nullable: true },
smtpUser: { type: 'string', nullable: true }, smtpUser: { type: 'string', nullable: true },
smtpPass: { type: 'string', nullable: true }, smtpPass: { type: 'string', nullable: true },
enableServiceWorker: { type: 'boolean' },
swPublicKey: { type: 'string', nullable: true },
swPrivateKey: { type: 'string', nullable: true },
tosUrl: { type: 'string', nullable: true }, tosUrl: { type: 'string', nullable: true },
useObjectStorage: { type: 'boolean' }, useObjectStorage: { type: 'boolean' },
objectStorageBaseUrl: { type: 'string', nullable: true }, objectStorageBaseUrl: { type: 'string', nullable: true },
@ -298,18 +295,6 @@ export default define(meta, paramDef, async (ps, me) => {
set.smtpPass = ps.smtpPass; set.smtpPass = ps.smtpPass;
} }
if (ps.enableServiceWorker !== undefined) {
set.enableServiceWorker = ps.enableServiceWorker;
}
if (ps.swPublicKey !== undefined) {
set.swPublicKey = ps.swPublicKey;
}
if (ps.swPrivateKey !== undefined) {
set.swPrivateKey = ps.swPrivateKey;
}
if (ps.tosUrl !== undefined) { if (ps.tosUrl !== undefined) {
set.ToSUrl = ps.tosUrl; set.ToSUrl = ps.tosUrl;
} }

View file

@ -182,10 +182,6 @@ export const meta = {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
}, },
enableServiceWorker: {
type: 'boolean',
optional: false, nullable: false,
},
translatorAvailable: { translatorAvailable: {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
@ -240,7 +236,8 @@ export const meta = {
}, },
serviceWorker: { serviceWorker: {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: true, nullable: false,
default: true,
}, },
miauth: { miauth: {
type: 'boolean', type: 'boolean',
@ -321,8 +318,6 @@ export default define(meta, paramDef, async (ps, me) => {
enableGithubIntegration: instance.enableGithubIntegration, enableGithubIntegration: instance.enableGithubIntegration,
enableDiscordIntegration: instance.enableDiscordIntegration, enableDiscordIntegration: instance.enableDiscordIntegration,
enableServiceWorker: instance.enableServiceWorker,
translatorAvailable: translatorAvailable(instance), translatorAvailable: translatorAvailable(instance),
pinnedPages: instance.pinnedPages, pinnedPages: instance.pinnedPages,
@ -346,7 +341,7 @@ export default define(meta, paramDef, async (ps, me) => {
twitter: instance.enableTwitterIntegration, twitter: instance.enableTwitterIntegration,
github: instance.enableGithubIntegration, github: instance.enableGithubIntegration,
discord: instance.enableDiscordIntegration, discord: instance.enableDiscordIntegration,
serviceWorker: instance.enableServiceWorker, serviceWorker: true,
miauth: true, miauth: true,
}, },
}; };

View file

@ -101,7 +101,6 @@ const nodeinfo2 = async (): Promise<NodeInfo2Base> => {
enableGithubIntegration: meta.enableGithubIntegration, enableGithubIntegration: meta.enableGithubIntegration,
enableDiscordIntegration: meta.enableDiscordIntegration, enableDiscordIntegration: meta.enableDiscordIntegration,
enableEmail: meta.enableEmail, enableEmail: meta.enableEmail,
enableServiceWorker: meta.enableServiceWorker,
proxyAccountName: proxyAccount?.username ?? null, proxyAccountName: proxyAccount?.username ?? null,
themeColor: meta.themeColor || '#86b300', themeColor: meta.themeColor || '#86b300',
}, },

View file

@ -40,8 +40,6 @@ function truncateNotification(notification: Packed<'Notification'>): any {
export async function pushNotification<T extends keyof pushNotificationsTypes>(userId: string, type: T, body: pushNotificationsTypes[T]) { export async function pushNotification<T extends keyof pushNotificationsTypes>(userId: string, type: T, body: pushNotificationsTypes[T]) {
const meta = await fetchMeta(); const meta = await fetchMeta();
if (!meta.enableServiceWorker || meta.swPublicKey == null || meta.swPrivateKey == null) return;
// Register key pair information // Register key pair information
push.setVapidDetails(config.url, push.setVapidDetails(config.url,
meta.swPublicKey, meta.swPublicKey,

View file

@ -107,27 +107,6 @@
</FormInput> </FormInput>
</FormSplit> </FormSplit>
</FormSection> </FormSection>
<FormSection>
<template #label>ServiceWorker</template>
<FormSwitch v-model="enableServiceWorker" class="_formBlock">
<template #label>{{ i18n.ts.enableServiceworker }}</template>
<template #caption>{{ i18n.ts.serviceworkerInfo }}</template>
</FormSwitch>
<template v-if="enableServiceWorker">
<FormInput v-model="swPublicKey" class="_formBlock">
<template #prefix><i class="fas fa-key"></i></template>
<template #label>Public key</template>
</FormInput>
<FormInput v-model="swPrivateKey" class="_formBlock">
<template #prefix><i class="fas fa-key"></i></template>
<template #label>Private key</template>
</FormInput>
</template>
</FormSection>
</div> </div>
</FormSuspense> </FormSuspense>
</MkSpacer> </MkSpacer>
@ -167,9 +146,6 @@ let localDriveCapacityMb: any = $ref(0);
let remoteDriveCapacityMb: any = $ref(0); let remoteDriveCapacityMb: any = $ref(0);
let enableRegistration: boolean = $ref(false); let enableRegistration: boolean = $ref(false);
let emailRequiredForSignup: boolean = $ref(false); let emailRequiredForSignup: boolean = $ref(false);
let enableServiceWorker: boolean = $ref(false);
let swPublicKey: any = $ref(null);
let swPrivateKey: any = $ref(null);
async function init(): Promise<void> { async function init(): Promise<void> {
const meta = await os.api('admin/meta'); const meta = await os.api('admin/meta');
@ -192,9 +168,6 @@ async function init(): Promise<void> {
remoteDriveCapacityMb = meta.driveCapacityPerRemoteUserMb; remoteDriveCapacityMb = meta.driveCapacityPerRemoteUserMb;
enableRegistration = !meta.disableRegistration; enableRegistration = !meta.disableRegistration;
emailRequiredForSignup = meta.emailRequiredForSignup; emailRequiredForSignup = meta.emailRequiredForSignup;
enableServiceWorker = meta.enableServiceWorker;
swPublicKey = meta.swPublickey;
swPrivateKey = meta.swPrivateKey;
} }
function save(): void { function save(): void {
@ -218,9 +191,6 @@ function save(): void {
remoteDriveCapacityMb: parseInt(remoteDriveCapacityMb, 10), remoteDriveCapacityMb: parseInt(remoteDriveCapacityMb, 10),
disableRegistration: !enableRegistration, disableRegistration: !enableRegistration,
emailRequiredForSignup, emailRequiredForSignup,
enableServiceWorker,
swPublicKey,
swPrivateKey,
}).then(() => { }).then(() => {
fetchInstance(); fetchInstance();
}); });