mirror of
https://github.com/chmouel/liseur-sync.git
synced 2026-10-16 11:22:01 +00:00
fix: Protect offline storage state
This commit is contained in:
parent
bcbf0b382e
commit
940c942196
4 changed files with 42 additions and 5 deletions
|
|
@ -13,6 +13,8 @@ import {
|
|||
|
||||
const buttons = [...document.querySelectorAll("[data-offline-book]")];
|
||||
if (buttons.length) {
|
||||
const offlineCapable = globalThis.isSecureContext &&
|
||||
!!globalThis.navigator?.serviceWorker && !!globalThis.navigator?.locks;
|
||||
const prefix = deploymentPrefix();
|
||||
const csrf = document.querySelector('input[name="csrf"]')?.value || "";
|
||||
const auth = readerAuth({
|
||||
|
|
@ -47,6 +49,11 @@ if (buttons.length) {
|
|||
};
|
||||
|
||||
for (const button of buttons) {
|
||||
if (!offlineCapable) {
|
||||
button.disabled = true;
|
||||
say(button, "Offline reading requires a secure browser connection.", true);
|
||||
continue;
|
||||
}
|
||||
activeAccount(storagePartition())
|
||||
.then(account => account && updateReadyState(button, account))
|
||||
.catch(error => console.warn("offline download state could not be loaded", error));
|
||||
|
|
@ -81,6 +88,7 @@ if (buttons.length) {
|
|||
await removeBookSnapshots({
|
||||
partition,
|
||||
account: identity.account,
|
||||
epoch: context.epoch,
|
||||
bookID: button.dataset.offlineBook,
|
||||
});
|
||||
button.dataset.offlineReady = "";
|
||||
|
|
|
|||
|
|
@ -478,12 +478,13 @@ export async function updateOfflineAnnotation({
|
|||
}
|
||||
|
||||
export async function removeOfflineAnnotation({
|
||||
partition = storagePartition(), account, epoch, bookID, id,
|
||||
partition = storagePartition(), account, epoch, bookID, id, removeAnnotation = true,
|
||||
} = {}) {
|
||||
if (!partition || !account || !bookID || !id) return;
|
||||
return withDB(async db => {
|
||||
await guardedWork(db, [ANNOTATIONS, OUTBOX], { partition, account, epoch }, tx => {
|
||||
tx.objectStore(ANNOTATIONS).delete(keyForAnnotation({ partition, account, bookID, id }));
|
||||
if (removeAnnotation)
|
||||
tx.objectStore(ANNOTATIONS).delete(keyForAnnotation({ partition, account, bookID, id }));
|
||||
const outbox = tx.objectStore(OUTBOX);
|
||||
const cursorRequest = outbox.index("account").openCursor(IDBKeyRange.bound(
|
||||
[partition, account, "", 0],
|
||||
|
|
@ -1015,11 +1016,15 @@ export function localPublicationRequest(snapshot, resources, path) {
|
|||
return Promise.resolve({ ok: false, status: 404, url: clean });
|
||||
}
|
||||
|
||||
export async function removeBookSnapshots({ partition = storagePartition(), account, bookID } = {}) {
|
||||
export async function removeBookSnapshots({
|
||||
partition = storagePartition(), account, epoch, bookID,
|
||||
} = {}) {
|
||||
const selectedAccount = account || await activeAccount(partition);
|
||||
if (!selectedAccount) return;
|
||||
return withDB(async db => {
|
||||
await transactionWork(db, [SNAPSHOTS, RESOURCES], "readwrite", tx => {
|
||||
await guardedWork(db, [SNAPSHOTS, RESOURCES], {
|
||||
partition, account: selectedAccount, epoch,
|
||||
}, tx => {
|
||||
const snapshots = tx.objectStore(SNAPSHOTS);
|
||||
const resources = tx.objectStore(RESOURCES);
|
||||
let records;
|
||||
|
|
@ -1041,6 +1046,26 @@ export async function removeBookSnapshots({ partition = storagePartition(), acco
|
|||
});
|
||||
}
|
||||
|
||||
async function removeStagingSnapshots(context, bookID) {
|
||||
return withDB(async db => {
|
||||
await guardedWork(db, [SNAPSHOTS, RESOURCES], context, tx => {
|
||||
const snapshots = tx.objectStore(SNAPSHOTS);
|
||||
const resources = tx.objectStore(RESOURCES);
|
||||
const request = snapshots.index("book").getAll([
|
||||
context.partition, context.account, bookID,
|
||||
]);
|
||||
request.onsuccess = () => {
|
||||
for (const snapshot of request.result) {
|
||||
if (snapshot.state !== "staging") continue;
|
||||
for (const href of snapshot.resourceHrefs || [])
|
||||
resources.delete([snapshot.key, href]);
|
||||
snapshots.delete(snapshot.key);
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export async function downloadPublication({
|
||||
request,
|
||||
|
|
@ -1089,6 +1114,7 @@ export async function downloadPublication({
|
|||
author: (manifest.metadata?.author || {}).name || "",
|
||||
createdAt: Date.now(),
|
||||
};
|
||||
await removeStagingSnapshots(context, bookID);
|
||||
await putStagingSnapshot(snapshot);
|
||||
const queue = [...plan.resources.values()];
|
||||
const seen = new Set(queue.map(resource => resource.href));
|
||||
|
|
|
|||
|
|
@ -99,7 +99,9 @@ async function render() {
|
|||
remove.addEventListener("click", async () => {
|
||||
remove.disabled = true;
|
||||
try {
|
||||
await removeBookSnapshots({ partition, account, bookID: snapshot.bookID });
|
||||
await removeBookSnapshots({
|
||||
partition, account, epoch: context.epoch, bookID: snapshot.bookID,
|
||||
});
|
||||
notifyOfflineChange();
|
||||
await render();
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -588,6 +588,7 @@ async function handleAnnotationConflict(local, server, record = null) {
|
|||
account: offlineAccount,
|
||||
bookID: cfg.bookID,
|
||||
id: server.id,
|
||||
removeAnnotation: false,
|
||||
});
|
||||
} else {
|
||||
await updateOfflineAnnotation({
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue