forked from FoundKeyGang/FoundKey
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:
parent
7ee6a09cf2
commit
563f3672a9
8 changed files with 32 additions and 78 deletions
24
packages/backend/migration/1668374092227-forceEnablePush.js
Normal file
24
packages/backend/migration/1668374092227-forceEnablePush.js
Normal 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -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',
|
||||||
},
|
},
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue