Consolidate Persimmons source
This commit is contained in:
1 parent
5b7e15ebd6
commit
40f4edd363
1 file changed
+78
@@ -0,0 +1,78 @@
|
|||||||
|
import {runJuice, juiceRequest, giteaToken} from './juice.mjs';
|
||||||
|
import {vaultUnlocked, vaultUsername, useVaultCredential} from './vault-worker.mjs';
|
||||||
|
import {CONNECTION} from './connection-state.mjs';
|
||||||
|
import {vaultRequest} from './human-api.mjs';
|
||||||
|
|
||||||
|
function trustedPage(message, sender, type) {
|
||||||
|
return sender.origin === 'https://persimmons.app' &&
|
||||||
|
new URL(sender.url).origin === sender.origin && sender.frameId === 0 &&
|
||||||
|
message?.type === type;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function connectionStatus(message, sender) {
|
||||||
|
if (!trustedPage(message, sender, 'persimmons.connection.v1')) return null;
|
||||||
|
const result = {connected: false, version: chrome.runtime.getManifest().version};
|
||||||
|
if (!/^[a-z0-9][a-z0-9_.-]{0,99}$/.test(message.owner)) return result;
|
||||||
|
const hint = (await chrome.storage.local.get(CONNECTION))[CONNECTION];
|
||||||
|
if (hint?.owner !== message.owner ||
|
||||||
|
!await chrome.permissions.contains({origins: ['https://persimmons.app/*']})) return result;
|
||||||
|
try {
|
||||||
|
const data = await vaultRequest('GET', hint.owner);
|
||||||
|
const storageId = `human-vault:https://persimmons.app:${hint.owner}`;
|
||||||
|
result.connected = true;
|
||||||
|
result.initialized = !!(await chrome.storage.local.get(storageId))[storageId];
|
||||||
|
result.unlocked = vaultUnlocked(hint.owner);
|
||||||
|
result.empty = data.items.length === 0;
|
||||||
|
} catch {}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
export async function vaultInventory(message, sender) {
|
||||||
|
if (!trustedPage(message, sender, 'persimmons.inventory.v1')) return null;
|
||||||
|
if (!/^[a-z0-9][a-z0-9_.-]{0,99}$/.test(message.owner)) return null;
|
||||||
|
const hint = (await chrome.storage.local.get(CONNECTION))[CONNECTION];
|
||||||
|
if (hint?.owner !== message.owner || !vaultUnlocked(message.owner) ||
|
||||||
|
!await chrome.permissions.contains({origins: ['https://persimmons.app/*']})) return null;
|
||||||
|
try {
|
||||||
|
const data = await vaultRequest('GET', hint.owner);
|
||||||
|
const items = [];
|
||||||
|
for (const metadata of data.items) {
|
||||||
|
const full = await vaultRequest('GET', hint.owner, metadata.id);
|
||||||
|
const username = await vaultUsername(hint.owner, full.item);
|
||||||
|
if (typeof username === 'string' && username) {
|
||||||
|
items.push({id: metadata.id, origin: metadata.origin, username});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {items};
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function liveJuice(owner) {
|
||||||
|
const hint = (await chrome.storage.local.get(CONNECTION))[CONNECTION];
|
||||||
|
if (hint?.owner !== owner || !await chrome.permissions.contains({origins: ['https://persimmons.app/*']})) throw new Error();
|
||||||
|
await vaultRequest('GET', owner);
|
||||||
|
}
|
||||||
|
let juiceBusy = false;
|
||||||
|
export async function juiceMessage(message, sender) {
|
||||||
|
if (juiceBusy) return {ok: false, message: 'A Juice operation is already running.'};
|
||||||
|
juiceBusy = true;
|
||||||
|
try {
|
||||||
|
return await runJuice(message, sender, {
|
||||||
|
live: liveJuice,
|
||||||
|
unlocked: async owner => {
|
||||||
|
if (!vaultUnlocked(owner) || !(await chrome.storage.local.get(`human-vault:https://persimmons.app:${owner}`))[`human-vault:https://persimmons.app:${owner}`]) throw new Error();
|
||||||
|
},
|
||||||
|
source: async (owner, id) => (await vaultRequest('GET', owner, id)).item,
|
||||||
|
use: useVaultCredential, request: juiceRequest, provider: giteaToken,
|
||||||
|
id: () => crypto.randomUUID().replaceAll('-', '')
|
||||||
|
});
|
||||||
|
} finally { juiceBusy = false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// External responses contain only status, operation IDs and safe username metadata.
|
||||||
|
chrome.runtime.onMessageExternal.addListener((message, sender, reply) => {
|
||||||
|
const work = message?.type === 'persimmons.juice.v1' ? juiceMessage(message, sender) : message?.type === 'persimmons.inventory.v1' ? vaultInventory(message, sender) : connectionStatus(message, sender);
|
||||||
|
work.then(reply, () => reply(null));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
Reference in new issue
Block a user