From 713ede123d120665c4fd331028fb338df7fa282b Mon Sep 17 00:00:00 2001 From: WardPearce Date: Sat, 14 Feb 2026 04:08:48 +1300 Subject: [PATCH] Implemented Materialious subscription storage --- materialious/src/lib/api/backend.ts | 244 ++++++++++++++++++ materialious/src/lib/api/index.ts | 31 +++ .../src/lib/api/youtubejs/subscriptions.ts | 26 +- materialious/src/lib/backend.ts | 139 ---------- .../lib/components/settings/Interface.svelte | 4 +- materialious/src/lib/server/database.ts | 90 ++++--- materialious/src/lib/server/misc.ts | 11 + materialious/src/lib/server/user.ts | 20 +- materialious/src/lib/store.ts | 4 +- materialious/src/routes/(app)/+layout.svelte | 11 +- .../routes/(app)/internal/login/+page.svelte | 2 +- materialious/src/routes/+layout.ts | 4 +- .../src/routes/api/user/create/+server.ts | 11 +- .../src/routes/api/user/login/+server.ts | 11 +- .../routes/api/user/subscriptions/+server.ts | 10 + .../api/user/subscriptions/[id]/+server.ts | 47 ++++ 16 files changed, 447 insertions(+), 218 deletions(-) create mode 100644 materialious/src/lib/api/backend.ts delete mode 100644 materialious/src/lib/backend.ts create mode 100644 materialious/src/lib/server/misc.ts create mode 100644 materialious/src/routes/api/user/subscriptions/+server.ts create mode 100644 materialious/src/routes/api/user/subscriptions/[id]/+server.ts diff --git a/materialious/src/lib/api/backend.ts b/materialious/src/lib/api/backend.ts new file mode 100644 index 00000000..37aa39a5 --- /dev/null +++ b/materialious/src/lib/api/backend.ts @@ -0,0 +1,244 @@ +import sodium from 'libsodium-wrappers-sumo'; +import { rawMasterKeyStore } from '../store'; +import { get } from 'svelte/store'; +import { parseChannelRSS } from './youtubejs/subscriptions'; +import type { Subscription } from './model'; +import { getChannelYTjs } from './youtubejs/channel'; +import type { ChannelSubscriptions } from '$lib/dexie'; + +async function getInternalAuthorId(authorId: string, rawKey: Uint8Array): Promise { + await sodium.ready; + return sodium.to_base64( + sodium.crypto_generichash(sodium.crypto_generichash_BYTES, authorId, rawKey) + ); +} + +async function getRawKey(): Promise { + const rawMasterKey = get(rawMasterKeyStore); + if (!rawMasterKey) return; + + await sodium.ready; + + return sodium.from_base64(rawMasterKey); +} + +export async function getSubscriptionsBackend(): Promise { + const resp = await fetch(`/api/user/subscriptions`, { + method: 'GET', + credentials: 'same-origin' + }); + + if (!resp.ok) return []; + + const subscriptions: ChannelSubscriptions[] = []; + + const respJson = await resp.json(); + + for (const sub of respJson.subscriptions) { + subscriptions.push({ + channelName: (await decryptWithMasterKey(sub.channelNameNonce, sub.channelNameCipher)) ?? '', + channelId: (await decryptWithMasterKey(sub.channelIdNonce, sub.channelIdCipher)) ?? '', + lastRSSFetch: new Date(sub.lastRSSFetch) + }); + } + + return subscriptions; +} + +export async function updateRSSLastUpdated(authorId: string) { + const rawKey = await getRawKey(); + if (!rawKey) return false; + + const internalAuthorId = await getInternalAuthorId(authorId, rawKey); + + await fetch(`/api/user/subscriptions/${internalAuthorId}`, { + method: 'PATCH', + credentials: 'same-origin' + }); +} + +export async function amSubscribedBackend(authorId: string): Promise { + const rawKey = await getRawKey(); + if (!rawKey) return false; + + const internalAuthorId = await getInternalAuthorId(authorId, rawKey); + + const resp = await fetch(`/api/user/subscriptions/${internalAuthorId}`, { + method: 'GET', + credentials: 'same-origin' + }); + if (!resp.ok) return false; + + const respJson = await resp.json(); + + return respJson.amSubscribed; +} + +export async function deleteUnsubscribeBackend(authorId: string) { + const rawKey = await getRawKey(); + if (!rawKey) return false; + + const internalAuthorId = await getInternalAuthorId(authorId, rawKey); + + await fetch(`/api/user/subscriptions/${internalAuthorId}`, { + method: 'DELETE', + credentials: 'same-origin' + }); +} + +export async function postSubscribeBackend(authorId: string) { + const rawKey = await getRawKey(); + if (!rawKey) return; + + const internalAuthorId = await getInternalAuthorId(authorId, rawKey); + + const channel = await getChannelYTjs(authorId); + + const channelId = await encryptWithMasterKey(authorId); + const channelName = await encryptWithMasterKey(channel.author); + + const resp = await fetch(`/api/user/subscriptions/${internalAuthorId}`, { + method: 'POST', + body: JSON.stringify({ + channelIdCipher: channelId?.cipher, + channelIdNonce: channelId?.nonce, + channelNameCipher: channelName?.cipher, + channelNameNonce: channelName?.nonce + }), + credentials: 'same-origin' + }); + + if (resp.ok) parseChannelRSS(authorId); +} + +export async function createUserBackend(username: string, rawPassword: string): Promise { + await sodium.ready; + + const passwordSalt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES); + const loginHash = sodium.crypto_pwhash( + 32, + rawPassword, + passwordSalt, + sodium.crypto_pwhash_OPSLIMIT_SENSITIVE, + sodium.crypto_pwhash_MEMLIMIT_SENSITIVE, + sodium.crypto_pwhash_ALG_DEFAULT + ); + + const decryptionKeySalt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES); + const rawDecryptionKey = sodium.crypto_pwhash( + 32, + rawPassword, + decryptionKeySalt, + sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, + sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE, + sodium.crypto_pwhash_ALG_DEFAULT + ); + + const rawDecryptionMasterKey = sodium.randombytes_buf(sodium.crypto_secretbox_KEYBYTES); + const decryptionMasterKeyNonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES); + + const masterKeyCipher = sodium.crypto_secretbox_easy( + rawDecryptionMasterKey, + decryptionMasterKeyNonce, + rawDecryptionKey + ); + + const userCreateResp = await fetch('/api/user/create', { + method: 'POST', + body: JSON.stringify({ + username: username, + password: { + hash: sodium.to_base64(loginHash), + salt: sodium.to_base64(passwordSalt) + }, + decryptionKeySalt: sodium.to_base64(decryptionKeySalt), + masterKey: { + cipher: sodium.to_base64(masterKeyCipher), + nonce: sodium.to_base64(decryptionMasterKeyNonce) + } + }), + credentials: 'same-origin' + }); + + if (!userCreateResp.ok) return false; + + rawMasterKeyStore.set(sodium.to_base64(rawDecryptionMasterKey)); + + return true; +} + +export async function loginUserBackend(username: string, rawPassword: string): Promise { + await sodium.ready; + + const passwordSaltsResp = await fetch(`/api/user/${username}/public`); + if (!passwordSaltsResp.ok) return false; + + const passwordSalts = await passwordSaltsResp.json(); + + const loginHash = sodium.crypto_pwhash( + 32, + rawPassword, + sodium.from_base64(passwordSalts.passwordSalt), + sodium.crypto_pwhash_OPSLIMIT_SENSITIVE, + sodium.crypto_pwhash_MEMLIMIT_SENSITIVE, + sodium.crypto_pwhash_ALG_DEFAULT + ); + + const loginResp = await fetch('/api/user/login', { + method: 'POST', + body: JSON.stringify({ + username, + passwordHash: sodium.to_base64(loginHash) + }), + credentials: 'same-origin' + }); + + if (!loginResp.ok) return false; + + const loginJson = await loginResp.json(); + + const rawDecryptionKey = sodium.crypto_pwhash( + sodium.crypto_secretbox_KEYBYTES, + rawPassword, + sodium.from_base64(passwordSalts.decryptionKeySalt), + sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, + sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE, + sodium.crypto_pwhash_ALG_DEFAULT + ); + + const rawDecryptionMasterKey = sodium.crypto_secretbox_open_easy( + sodium.from_base64(loginJson.masterKeyCipher), + sodium.from_base64(loginJson.masterKeyNonce), + rawDecryptionKey + ); + + rawMasterKeyStore.set(sodium.to_base64(rawDecryptionMasterKey)); + + return true; +} + +async function encryptWithMasterKey( + text: string +): Promise<{ nonce: string; cipher: string } | undefined> { + await sodium.ready; + const rawKey = await getRawKey(); + if (!rawKey) return; + + const nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES); + const cipher = sodium.crypto_secretbox_easy(new TextEncoder().encode(text), nonce, rawKey); + + return { + nonce: sodium.to_base64(nonce), + cipher: sodium.to_base64(cipher) + }; +} + +async function decryptWithMasterKey(nonce: string, cipher: string): Promise { + await sodium.ready; + const rawKey = await getRawKey(); + if (!rawKey) return; + + return new TextDecoder().decode( + sodium.crypto_secretbox_open_easy(sodium.from_base64(cipher), sodium.from_base64(nonce), rawKey) + ); +} diff --git a/materialious/src/lib/api/index.ts b/materialious/src/lib/api/index.ts index d278654f..853f61e9 100644 --- a/materialious/src/lib/api/index.ts +++ b/materialious/src/lib/api/index.ts @@ -8,6 +8,7 @@ import { interfaceRegionStore, playerYouTubeJsAlways, playerYouTubeJsFallback, + rawMasterKeyStore, returnYTDislikesInstanceStore, synciousInstanceStore } from '../store'; @@ -45,6 +46,13 @@ import { postSubscribeYTjs } from './youtubejs/subscriptions'; import { getPlaylistYTjs } from './youtubejs/playlist'; +import { isOwnBackend } from '$lib/shared'; +import { + amSubscribedBackend, + deleteUnsubscribeBackend, + getSubscriptionsBackend, + postSubscribeBackend +} from './backend'; export function buildPath(path: string): URL { return new URL(`${get(instanceStore)}/api/v1/${path}`); @@ -278,6 +286,15 @@ export async function getSubscriptions( bypassYTBackend: boolean = false ): Promise { if (isYTBackend() && !bypassYTBackend) { + if (isOwnBackend()?.internalAuth && get(rawMasterKeyStore)) { + return (await getSubscriptionsBackend()).map((sub) => { + return { + author: sub.channelName, + authorId: sub.channelId + }; + }); + } + return getSubscriptionsYTjs(); } const resp = await fetchErrorHandle( @@ -291,6 +308,10 @@ export async function amSubscribed( fetchOptions: RequestInit = {} ): Promise { if (isYTBackend()) { + if (isOwnBackend()?.internalAuth && get(rawMasterKeyStore)) { + return amSubscribedBackend(authorId); + } + return amSubscribedYTjs(authorId); } @@ -312,6 +333,10 @@ export async function postSubscribe( bypassYTBackend: boolean = false ) { if (isYTBackend() && !bypassYTBackend) { + if (isOwnBackend()?.internalAuth && get(rawMasterKeyStore)) { + return postSubscribeBackend(authorId); + } + return postSubscribeYTjs(authorId); } @@ -326,6 +351,12 @@ export async function postSubscribe( export async function deleteUnsubscribe(authorId: string, fetchOptions: RequestInit = {}) { if (isYTBackend()) { + // deleteUnsubscribeYTjs still should run + // as cleans feeds of that channel. + if (isOwnBackend()?.internalAuth && get(rawMasterKeyStore)) { + deleteUnsubscribeBackend(authorId); + } + return deleteUnsubscribeYTjs(authorId); } diff --git a/materialious/src/lib/api/youtubejs/subscriptions.ts b/materialious/src/lib/api/youtubejs/subscriptions.ts index 807765d7..3a7bcb6f 100644 --- a/materialious/src/lib/api/youtubejs/subscriptions.ts +++ b/materialious/src/lib/api/youtubejs/subscriptions.ts @@ -1,5 +1,4 @@ -import { localDb } from '$lib/dexie'; -import { clearCaches } from '$lib/misc'; +import { localDb, type ChannelSubscriptions } from '$lib/dexie'; import { cleanNumber } from '$lib/numbers'; import { relativeTimestamp } from '$lib/time'; import { get } from 'svelte/store'; @@ -8,8 +7,10 @@ import { getChannelYTjs } from './channel'; import { engineCooldownYTStore, engineCullYTStore, - engineMaxConcurrentChannelsStore + engineMaxConcurrentChannelsStore, + rawMasterKeyStore } from '$lib/store'; +import { getSubscriptionsBackend, updateRSSLastUpdated } from '../backend'; export async function getSubscriptionsYTjs(): Promise { const subscriptions: Subscription[] = []; @@ -54,7 +55,6 @@ export async function postSubscribeYTjs( export async function deleteUnsubscribeYTjs(authorId: string) { await localDb.channelSubscriptions.where('channelId').equals(authorId).delete(); await localDb.subscriptionFeed.where('authorId').equals(authorId).delete(); - clearCaches(); } export async function parseChannelRSS(channelId: string): Promise { @@ -132,14 +132,24 @@ export async function parseChannelRSS(channelId: string): Promise { // Continue regardless of error } - await localDb.channelSubscriptions.where('channelId').equals(channelId).modify({ - lastRSSFetch: new Date() - }); + if (!get(rawMasterKeyStore)) { + await localDb.channelSubscriptions.where('channelId').equals(channelId).modify({ + lastRSSFetch: new Date() + }); + } else { + await updateRSSLastUpdated(authorId); + } } } export async function getFeedYTjs(maxResults: number, page: number): Promise { - const channelSubscriptions = await localDb.channelSubscriptions.toArray(); + let channelSubscriptions: ChannelSubscriptions[]; + + if (!get(rawMasterKeyStore)) { + channelSubscriptions = await localDb.channelSubscriptions.toArray(); + } else { + channelSubscriptions = await getSubscriptionsBackend(); + } const toUpdatePromises: Promise[] = []; diff --git a/materialious/src/lib/backend.ts b/materialious/src/lib/backend.ts deleted file mode 100644 index 44a236dc..00000000 --- a/materialious/src/lib/backend.ts +++ /dev/null @@ -1,139 +0,0 @@ -import sodium from 'libsodium-wrappers-sumo'; -import { rawSubscriptionKeyStore } from './store'; -import { get } from 'svelte/store'; - -export async function postSubscribeBackend(authorId: string) { - const rawSubscriptionKey = get(rawSubscriptionKeyStore); - - if (!rawSubscriptionKey) return; - - await sodium.ready; - - const rawKey = sodium.from_base64(rawSubscriptionKeyStore); - - const internalAuthorId = sodium.crypto_generichash( - sodium.crypto_generichash_BYTES, - authorId, - rawKey - ); - - const textEncoder = new TextEncoder(); - - const channelIdNonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES); - const channelIdCipher = sodium.crypto_secretbox_easy( - textEncoder.encode(authorId), - channelIdNonce, - rawKey - ); - - const channelNameNonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES); - const channelNameCipher = sodium.crypto_secretbox_easy( - textEncoder.encode(authorId), - channelNameNonce, - rawKey - ); -} - -export async function createUserBackend(username: string, rawPassword: string): Promise { - await sodium.ready; - - const passwordSalt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES); - const loginHash = sodium.crypto_pwhash( - 32, - rawPassword, - passwordSalt, - sodium.crypto_pwhash_OPSLIMIT_SENSITIVE, - sodium.crypto_pwhash_MEMLIMIT_SENSITIVE, - sodium.crypto_pwhash_ALG_DEFAULT - ); - - const decryptionKeySalt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES); - const rawDecryptionKey = sodium.crypto_pwhash( - 32, - rawPassword, - decryptionKeySalt, - sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, - sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE, - sodium.crypto_pwhash_ALG_DEFAULT - ); - - const rawDecryptionMasterKey = sodium.randombytes_buf(sodium.crypto_secretbox_KEYBYTES); - const decryptionMasterKeyNonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES); - - const masterKeyCipher = sodium.crypto_secretbox_easy( - rawDecryptionMasterKey, - decryptionMasterKeyNonce, - rawDecryptionKey - ); - - const userCreateResp = await fetch('/api/user/create', { - method: 'POST', - body: JSON.stringify({ - username: username, - password: { - hash: sodium.to_base64(loginHash), - salt: sodium.to_base64(passwordSalt) - }, - decryptionKeySalt: sodium.to_base64(decryptionKeySalt), - masterKey: { - cipher: sodium.to_base64(masterKeyCipher), - nonce: sodium.to_base64(decryptionMasterKeyNonce) - } - }) - }); - - if (!userCreateResp.ok) return false; - - rawSubscriptionKeyStore.set(sodium.to_base64(rawDecryptionMasterKey)); - - return true; -} - -export async function loginUserBackend(username: string, rawPassword: string): Promise { - await sodium.ready; - - const passwordSaltsResp = await fetch(`/api/user/${username}/public`); - if (!passwordSaltsResp.ok) return false; - - const passwordSalts = await passwordSaltsResp.json(); - - const loginHash = sodium.crypto_pwhash( - 32, - rawPassword, - sodium.from_base64(passwordSalts.passwordSalt), - sodium.crypto_pwhash_OPSLIMIT_SENSITIVE, - sodium.crypto_pwhash_MEMLIMIT_SENSITIVE, - sodium.crypto_pwhash_ALG_DEFAULT - ); - - const loginResp = await fetch('/api/user/login', { - method: 'POST', - body: JSON.stringify({ - username, - passwordHash: sodium.to_base64(loginHash) - }) - }); - - if (!loginResp.ok) return false; - - const loginJson = await loginResp.json(); - - const rawDecryptionKey = sodium.crypto_pwhash( - sodium.crypto_secretbox_KEYBYTES, - rawPassword, - sodium.from_base64(passwordSalts.decryptionKeySalt), - sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE, - sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE, - sodium.crypto_pwhash_ALG_DEFAULT - ); - - const rawDecryptionMasterKey = sodium.crypto_secretbox_open_easy( - sodium.from_base64(loginJson.masterKeyCipher), - sodium.from_base64(loginJson.masterKeyNonce), - rawDecryptionKey - ); - - rawSubscriptionKeyStore.set(sodium.to_base64(rawDecryptionMasterKey)); - - return true; -} diff --git a/materialious/src/lib/components/settings/Interface.svelte b/materialious/src/lib/components/settings/Interface.svelte index 29505abc..3ec993e7 100644 --- a/materialious/src/lib/components/settings/Interface.svelte +++ b/materialious/src/lib/components/settings/Interface.svelte @@ -32,7 +32,7 @@ interfaceRegionStore, interfaceSearchHistoryEnabled, interfaceSearchSuggestionsStore, - rawSubscriptionKeyStore, + rawMasterKeyStore, searchHistoryStore, themeColorStore } from '../../store'; @@ -92,7 +92,7 @@ async function setBackend(event: Event) { if (isOwnBackend()?.internalAuth) { - rawSubscriptionKeyStore.set(undefined); + rawMasterKeyStore.set(undefined); fetch('/api/user/logout', { method: 'DELETE' }); } diff --git a/materialious/src/lib/server/database.ts b/materialious/src/lib/server/database.ts index 6d18510d..938f1dbb 100644 --- a/materialious/src/lib/server/database.ts +++ b/materialious/src/lib/server/database.ts @@ -17,42 +17,54 @@ export interface UserTableModel extends Model { masterKeyNonce: string; } -export const UserTable = sequelize.define('User', { - id: { - type: DataTypes.UUIDV4, - allowNull: false, - primaryKey: true +export const UserTable = sequelize.define( + 'User', + { + id: { + type: DataTypes.UUIDV4, + allowNull: false, + primaryKey: true, + unique: true + }, + username: { + type: DataTypes.STRING, + allowNull: false, + unique: true + }, + passwordHash: { + type: DataTypes.STRING, + allowNull: false + }, + passwordSalt: { + type: DataTypes.STRING, + allowNull: false + }, + created: { + type: DataTypes.DATE, + allowNull: false + }, + decryptionKeySalt: { + type: DataTypes.STRING, + allowNull: false + }, + masterKeyCipher: { + type: DataTypes.STRING, + allowNull: false + }, + masterKeyNonce: { + type: DataTypes.STRING, + allowNull: false + } }, - username: { - type: DataTypes.STRING, - allowNull: false, - unique: true - }, - passwordHash: { - type: DataTypes.STRING, - allowNull: false - }, - passwordSalt: { - type: DataTypes.STRING, - allowNull: false - }, - created: { - type: DataTypes.DATE, - allowNull: false - }, - decryptionKeySalt: { - type: DataTypes.STRING, - allowNull: false - }, - masterKeyCipher: { - type: DataTypes.STRING, - allowNull: false - }, - masterKeyNonce: { - type: DataTypes.STRING, - allowNull: false + { + indexes: [ + { + unique: true, + fields: ['id', 'username'] + } + ] } -}); +); export interface ChannelSubscriptionModel { id: string; // Hashed authId with subscription key on client. @@ -89,13 +101,7 @@ export const ChannelSubscriptionTable = sequelize.define('Subscriptions', { lastRSSFetch: { type: DataTypes.DATE, allowNull: false - }, - userId: { - type: DataTypes.UUIDV4, - references: { - model: 'User', - key: 'id' - }, - allowNull: false } }); + +UserTable.hasMany(ChannelSubscriptionTable); diff --git a/materialious/src/lib/server/misc.ts b/materialious/src/lib/server/misc.ts new file mode 100644 index 00000000..e3872590 --- /dev/null +++ b/materialious/src/lib/server/misc.ts @@ -0,0 +1,11 @@ +import type { Cookies } from '@sveltejs/kit'; +import { sign } from 'cookie-signature'; +import { env } from '$env/dynamic/private'; + +export function setAuthCookie(id: string, cookies: Cookies) { + cookies.set('userid', sign(id, env.COOKIE_SECRET), { + httpOnly: true, + path: '/api/user', + maxAge: 60 * 60 * 24 * 60 // 60 days + }); +} diff --git a/materialious/src/lib/server/user.ts b/materialious/src/lib/server/user.ts index be41f2db..98c4f294 100644 --- a/materialious/src/lib/server/user.ts +++ b/materialious/src/lib/server/user.ts @@ -38,10 +38,22 @@ export class User { await UserTable.destroy(this.userWhere); } + async subscriptionRssUpdated(id: string) { + await ChannelSubscriptionTable.update( + { lastRSSFetch: new Date() }, + { + where: { + id: id, + UserId: this.id + } + } + ); + } + async addSubscription(subscription: Omit) { await ChannelSubscriptionTable.create({ ...subscription, - userId: this.id + UserId: this.id }); } @@ -64,7 +76,7 @@ export class User { } async subscriptions(): Promise { - const subscriptions = await UserTable.findAll({ + const subscriptions = await ChannelSubscriptionTable.findAll({ where: { userId: this.data.id } @@ -90,7 +102,7 @@ export type CreateUser = { }; export async function createUser(user: CreateUser): Promise { - const id = crypto.randomUUID(); + const id = crypto.randomUUID().toString(); const createdUser = { id, @@ -155,7 +167,7 @@ export async function authenticateUser(username: string, passwordHash: string): textEncoder.encode(userModel.passwordHash) ) ) { - return new User(userModel as UserTableModel); + return new User(userModel); } throw error(404); diff --git a/materialious/src/lib/store.ts b/materialious/src/lib/store.ts index 3c4b7e66..af2f01d9 100644 --- a/materialious/src/lib/store.ts +++ b/materialious/src/lib/store.ts @@ -333,10 +333,10 @@ export const engineFallbacksStore: Writable = persist( 'engineFallbacks' ); -export const rawSubscriptionKeyStore: Writable = persist( +export const rawMasterKeyStore: Writable = persist( writable(), createStorage(), - 'rawSubscriptionKey' + 'rawMasterKey' ); export const syncPartyPeerStore: Writable = writable(null); diff --git a/materialious/src/routes/(app)/+layout.svelte b/materialious/src/routes/(app)/+layout.svelte index 7714b5a9..ffd9bdc0 100644 --- a/materialious/src/routes/(app)/+layout.svelte +++ b/materialious/src/routes/(app)/+layout.svelte @@ -25,7 +25,7 @@ isAndroidTvStore, playerState, playertheatreModeIsActive, - rawSubscriptionKeyStore, + rawMasterKeyStore, syncPartyPeerStore, themeColorStore } from '$lib/store'; @@ -40,7 +40,7 @@ import { _ } from '$lib/i18n'; import { get } from 'svelte/store'; import { pwaInfo } from 'virtual:pwa-info'; - import { isYTBackend, clearCaches, truncate } from '$lib/misc'; + import { isYTBackend, truncate } from '$lib/misc'; import Author from '$lib/components/Author.svelte'; import Toast from '$lib/components/Toast.svelte'; import { isOwnBackend } from '$lib/shared'; @@ -189,12 +189,11 @@ function logout() { if (isOwnBackend()?.internalAuth && isYTBackend()) { - rawSubscriptionKeyStore.set(undefined); + rawMasterKeyStore.set(undefined); fetch('/api/user/logout', { method: 'DELETE' }); } authStore.set(null); - clearCaches(); goto(resolve('/', {})); } @@ -273,7 +272,7 @@ class:hide={$playertheatreModeIsActive} > @@ -382,7 +381,7 @@ {#if showLogin} - {#if !isLoggedIn && !$rawSubscriptionKeyStore} + {#if !isLoggedIn && !$rawMasterKeyStore}