Tie push subscriptions to current session
If a user logs out from a device the expectation should be that device no longer having any association with the user's account. Any existing push notifications should thefore be removed on server. For this reason tie push notifications to a session, and remove them when the session is deleted.
This commit is contained in:
parent
150cb82f5c
commit
52dfde95d1
7 changed files with 39 additions and 15 deletions
|
@ -8,9 +8,9 @@
|
|||
</nav>
|
||||
<div class="account">
|
||||
<template v-if="session?.account">
|
||||
{{ session?.account.name || "anonymous" }}
|
||||
(s:{{ session?.id }} a:{{ session?.account.id }})
|
||||
{{ session?.account.type }}
|
||||
{{ session.account.name || "anonymous" }}
|
||||
(s:{{ session.id }} a:{{ session.account.id }}{{ session.push ? " push" : null }})
|
||||
{{ session.account.type }}
|
||||
<button type="button" @click="logOut">Log out</button>
|
||||
</template>
|
||||
<template v-else>
|
||||
|
|
|
@ -99,12 +99,14 @@ async function getSubscription(
|
|||
const unsupported = ref<boolean | undefined>(undefined);
|
||||
const subscription = ref<PushSubscription | null>(null);
|
||||
const runtimeConfig = useRuntimeConfig();
|
||||
const { refresh: refreshSession } = useAccountSession();
|
||||
|
||||
function onClick() {
|
||||
async function onClick() {
|
||||
if (!subscription.value)
|
||||
registerAndSubscribe(runtimeConfig.public.vapidPublicKey, (subs) => { subscription.value = subs })
|
||||
await registerAndSubscribe(runtimeConfig.public.vapidPublicKey, (subs) => { subscription.value = subs })
|
||||
else
|
||||
unsubscribe(subscription.value, () => { subscription.value = null })
|
||||
await unsubscribe(subscription.value, () => { subscription.value = null })
|
||||
refreshSession();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
import { readAccounts } from "~/server/database";
|
||||
import { readAccounts, readSubscriptions } from "~/server/database";
|
||||
import { AccountSession } from "~/shared/types/account";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
export default defineEventHandler(async (event): Promise<AccountSession | undefined> => {
|
||||
const session = await getAccountSession(event);
|
||||
if (!session)
|
||||
return;
|
||||
const accounts = await readAccounts();
|
||||
const subscriptions = await readSubscriptions();
|
||||
const push = Boolean(
|
||||
subscriptions.find(sub => sub.type === "push" && sub.sessionId === session.id)
|
||||
);
|
||||
|
||||
return {
|
||||
id: session.id,
|
||||
account: accounts.find(account => account.id === session.accountId)!,
|
||||
} satisfies AccountSession;
|
||||
push,
|
||||
};
|
||||
})
|
||||
|
|
|
@ -2,12 +2,17 @@ import { readSubscriptions, writeSubscriptions } from "~/server/database";
|
|||
import { Subscription } from "~/shared/types/account";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const session = await requireAccountSession(event);
|
||||
const body: { subscription: PushSubscriptionJSON } = await readBody(event);
|
||||
const subscriptions = await readSubscriptions();
|
||||
const existingIndex = subscriptions.findIndex(
|
||||
sub => sub.type === "push" && sub.push.endpoint === body.subscription.endpoint
|
||||
sub => sub.type === "push" && sub.sessionId === session.id
|
||||
);
|
||||
const subscription: Subscription = { type: "push", push: body.subscription };
|
||||
const subscription: Subscription = {
|
||||
type: "push",
|
||||
sessionId: session.id,
|
||||
push: body.subscription
|
||||
};
|
||||
if (existingIndex !== -1) {
|
||||
subscriptions[existingIndex] = subscription;
|
||||
} else {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { readSubscriptions, writeSubscriptions } from "~/server/database";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const body: { subscription: PushSubscriptionJSON } = await readBody(event);
|
||||
const session = await requireAccountSession(event);
|
||||
const subscriptions = await readSubscriptions();
|
||||
const existingIndex = subscriptions.findIndex(
|
||||
sub => sub.type === "push" && sub.push.endpoint === body.subscription.endpoint
|
||||
sub => sub.type === "push" && sub.sessionId === session.id
|
||||
);
|
||||
if (existingIndex !== -1) {
|
||||
subscriptions.splice(existingIndex, 1);
|
||||
|
@ -13,4 +13,4 @@ export default defineEventHandler(async (event) => {
|
|||
}
|
||||
await writeSubscriptions(subscriptions);
|
||||
return { message: "Existing subscription removed."};
|
||||
})
|
||||
});
|
||||
|
|
|
@ -1,7 +1,16 @@
|
|||
import type { H3Event } from "h3";
|
||||
import { nextSessionId, readSessions, writeSessions } from "~/server/database";
|
||||
import { nextSessionId, readSessions, readSubscriptions, writeSessions, writeSubscriptions } from "~/server/database";
|
||||
import { Session } from "~/shared/types/account";
|
||||
|
||||
async function removeSessionSubscription(sessionId: number) {
|
||||
const subscriptions = await readSubscriptions();
|
||||
const index = subscriptions.findIndex(subscription => subscription.sessionId === sessionId);
|
||||
if (index !== -1) {
|
||||
subscriptions.splice(index, 1);
|
||||
await writeSubscriptions(subscriptions);
|
||||
}
|
||||
}
|
||||
|
||||
async function clearAccountSessionInternal(event: H3Event, sessions: Session[]) {
|
||||
const existingSessionCookie = await getSignedCookie(event, "session");
|
||||
if (existingSessionCookie) {
|
||||
|
@ -9,6 +18,7 @@ async function clearAccountSessionInternal(event: H3Event, sessions: Session[])
|
|||
const sessionIndex = sessions.findIndex(session => session.id === sessionId);
|
||||
if (sessionIndex !== -1) {
|
||||
sessions.splice(sessionIndex, 1);
|
||||
await removeSessionSubscription(sessionId);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
2
shared/types/account.d.ts
vendored
2
shared/types/account.d.ts
vendored
|
@ -7,6 +7,7 @@ export interface Account {
|
|||
|
||||
export interface Subscription {
|
||||
type: "push",
|
||||
sessionId: number,
|
||||
push: PushSubscriptionJSON,
|
||||
}
|
||||
|
||||
|
@ -18,4 +19,5 @@ export interface Session {
|
|||
export interface AccountSession {
|
||||
id: number,
|
||||
account: Account,
|
||||
push: boolean,
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue