feat: add 3 new plugin hooks : onBeforeBlobUpload, onBeforeDraftAutoSave, onBeforeEditDraft (#586)
Co-authored-by: Linus Rath <minipixxelinfo@gmail.com>
This commit is contained in:
co-authored by
Linus Rath
parent
782974ecdb
commit
752e71198c
@@ -60,6 +60,7 @@ const PERMISSION_LABELS: Record<string, { title: string; body: string }> = {
|
||||
'crypto:full': { title: 'Full cryptographic access (high risk)', body: 'Runs with full cryptographic access in a privileged, same-origin context. It can read your message bodies and private keys, store key material, and sign/encrypt on your behalf. Only enable plugins you fully trust — this is comparable to a full-access browser extension.' },
|
||||
'email:raw-send': { title: 'Send raw messages', body: 'Submit fully-formed (e.g. signed or encrypted) messages on your behalf.' },
|
||||
'email:blob-read': { title: 'Read raw message content', body: 'Fetch the raw bytes of your messages and attachments (needed to decrypt and verify them).' },
|
||||
'email:blob-write': { title: 'Alterate raw message content', body: 'get the raw file content before it is uploaded to alterate it just before is is sended to server. (needed to encrypt)' },
|
||||
'email:render-takeover': { title: 'Replace rendered email content', body: 'Replace the displayed content of an opened message (e.g. to show decrypted text and a signature-verification badge).' },
|
||||
'calendar:read': { title: 'Read your calendar', body: 'Access events, calendars, RSVPs, and reminders.' },
|
||||
'calendar:write': { title: 'Modify your calendar', body: 'Create, edit, or delete events.' },
|
||||
|
||||
@@ -9,6 +9,8 @@ import { useAuthStore } from '@/stores/auth-store';
|
||||
import { useEmailStore } from '@/stores/email-store';
|
||||
import { apiFetch } from '../browser-navigation';
|
||||
import { awaitDialog } from './host-dialog';
|
||||
import { fileStorage} from '../plugin-storage'
|
||||
import { generateUUID } from '../utils';
|
||||
|
||||
/**
|
||||
* Methods only callable from the privileged (same-origin) tier. These expose
|
||||
@@ -19,6 +21,8 @@ import { awaitDialog } from './host-dialog';
|
||||
const PRIVILEGED_ONLY_METHODS = new Set<string>([
|
||||
'jmap.fetchBlob',
|
||||
'jmap.sendRaw',
|
||||
'upfiles.get',
|
||||
'upfiles.set',
|
||||
]);
|
||||
|
||||
const PERM_PER_METHOD: Record<string, Permission | null> = {
|
||||
@@ -38,6 +42,11 @@ const PERM_PER_METHOD: Record<string, Permission | null> = {
|
||||
// jmap (privileged-tier only; see PRIVILEGED_ONLY_METHODS)
|
||||
'jmap.fetchBlob': 'email:blob-read',
|
||||
'jmap.sendRaw': 'email:raw-send',
|
||||
// uploaded files (privileged-tier only) :
|
||||
// Used only to get a file before it is uploaded to alterate it.
|
||||
// To just read, use jmap.fetchBlob.
|
||||
'upfiles.get' : 'email:blob-write',
|
||||
'upfiles.save' : 'email:blob-write',
|
||||
// admin
|
||||
'admin.getConfig': 'admin:config',
|
||||
'admin.getAllConfig': 'admin:config',
|
||||
@@ -263,6 +272,19 @@ async function doJmapSendRaw(
|
||||
);
|
||||
}
|
||||
|
||||
// ─── Uploaded files in IndexedDB (privileged tier) ──────────────────────────
|
||||
|
||||
async function getFile(fileID:string): Promise<File | null> {
|
||||
return await fileStorage.getFile(fileID)
|
||||
}
|
||||
|
||||
async function saveFile(formerFileID:string, file: File): Promise<string> {
|
||||
const fileId = generateUUID();
|
||||
await fileStorage.saveFile(fileId, file);
|
||||
await fileStorage.deleteFile(formerFileID);
|
||||
return fileId;
|
||||
}
|
||||
|
||||
// ─── admin config (same as before) ────────────────────────────
|
||||
|
||||
async function adminGetAll(pluginId: string): Promise<Record<string, unknown>> {
|
||||
@@ -335,6 +357,8 @@ export async function dispatchApiCall(
|
||||
args[1] as string,
|
||||
args[2] as { delayedUntil?: string; envelopeRecipients?: string[] } | undefined,
|
||||
);
|
||||
case 'upfiles.get' : return getFile(args[0] as string);
|
||||
case 'upfiles.save' : return saveFile(args[0] as string, args[1] as File);
|
||||
|
||||
case 'admin.getConfig': return adminGet(plugin.id, args[0] as string);
|
||||
case 'admin.getAllConfig': return adminGetAll(plugin.id);
|
||||
|
||||
@@ -189,6 +189,16 @@ function buildPluginApi(manifest: PluginManifest) {
|
||||
opts?: { delayedUntil?: string; envelopeRecipients?: string[] },
|
||||
) => callApi('jmap.sendRaw', [rawBytes, identityId, opts]),
|
||||
},
|
||||
/**
|
||||
* Used to alterate files before they are uploaded to server.
|
||||
* Edited files are saved on indexedDB and remove once the upload to server begins.
|
||||
*/
|
||||
upfiles: {
|
||||
save: (formerFileId:string, file:File) =>
|
||||
callApi('upfiles.save', [formerFileId, file]) as Promise<string>,
|
||||
get: (fileId:string) =>
|
||||
callApi('upfiles.get', [fileId]) as Promise<File>,
|
||||
},
|
||||
toast: {
|
||||
success: (m: string) => { void callApi('toast.success', [m]); },
|
||||
error: (m: string) => { void callApi('toast.error', [m]); },
|
||||
|
||||
Reference in New Issue
Block a user