From what I see, Obsidian API doesn’t allow to hook into the file system events.
However, we can try to patch it in some way
import { DataAdapter, DataWriteOptions, ListedFiles, Plugin, Stat } from 'obsidian';
export class EncryptionPlugin extends Plugin {
override onload(): void {
this.app.vault.adapter = new EncryptionAdapter(this.app.vault.adapter);
}
override onunload(): void {
this.app.vault.adapter = (this.app.vault.adapter as EncryptionAdapter).internalAdapter;
}
}
class EncryptionAdapter extends DataAdapterDecorator {
override async read(normalizedPath: string): Promise<string> {
const encrypted = await super.read(normalizedPath);
return await this.decrypt(encrypted);
}
override async readBinary(normalizedPath: string): Promise<ArrayBuffer> {
const encryptedBinary = await super.readBinary(normalizedPath);
return await this.decryptBinary(encryptedBinary);
}
override async write(normalizedPath: string, data: string, options?: DataWriteOptions | undefined): Promise<void> {
const encryptedData = await this.encrypt(data);
await super.write(normalizedPath, encryptedData, options);
}
override async writeBinary(normalizedPath: string, data: ArrayBuffer, options?: DataWriteOptions | undefined): Promise<void> {
const encryptedData = await this.encryptBinary(data);
await super.writeBinary(normalizedPath, encryptedData, options);
}
override async append(normalizedPath: string, data: string, options?: DataWriteOptions | undefined): Promise<void> {
await this.process(normalizedPath, (content) => content + data, options);
}
override async process(normalizedPath: string, fn: (data: string) => string, options?: DataWriteOptions | undefined): Promise<string> {
const content = await this.read(normalizedPath);
const newContent = fn(content);
await this.write(normalizedPath, newContent, options);
return newContent;
}
async decrypt(encrypted: string): Promise<string> {
// TODO
return encrypted;
}
async decryptBinary(encryptedBinary: ArrayBuffer): Promise<ArrayBuffer> {
// TODO
return encryptedBinary;
}
async encrypt(decrypted: string): Promise<string> {
// TODO
return decrypted;
}
async encryptBinary(decryptedBinary: ArrayBuffer): Promise<ArrayBuffer> {
// TODO
return decryptedBinary;
}
}
class DataAdapterDecorator implements DataAdapter {
internalAdapter: DataAdapter;
constructor (internalAdapter: DataAdapter) {
this.internalAdapter = internalAdapter;
}
getName(): string {
return this.internalAdapter.getName();
}
exists(normalizedPath: string, sensitive?: boolean | undefined): Promise<boolean> {
return this.internalAdapter.exists(normalizedPath, sensitive);
}
stat(normalizedPath: string): Promise<Stat | null> {
return this.internalAdapter.stat(normalizedPath);
}
list(normalizedPath: string): Promise<ListedFiles> {
return this.internalAdapter.list(normalizedPath);
}
read(normalizedPath: string): Promise<string> {
return this.internalAdapter.read(normalizedPath);
}
readBinary(normalizedPath: string): Promise<ArrayBuffer> {
return this.internalAdapter.readBinary(normalizedPath);
}
write(normalizedPath: string, data: string, options?: DataWriteOptions | undefined): Promise<void> {
return this.internalAdapter.write(normalizedPath, data, options);
}
writeBinary(normalizedPath: string, data: ArrayBuffer, options?: DataWriteOptions | undefined): Promise<void> {
return this.internalAdapter.writeBinary(normalizedPath, data, options);
}
append(normalizedPath: string, data: string, options?: DataWriteOptions | undefined): Promise<void> {
return this.internalAdapter.append(normalizedPath, data, options);
}
process(normalizedPath: string, fn: (data: string) => string, options?: DataWriteOptions | undefined): Promise<string> {
return this.internalAdapter.process(normalizedPath, fn, options);
}
getResourcePath(normalizedPath: string): string {
return this.internalAdapter.getResourcePath(normalizedPath);
}
mkdir(normalizedPath: string): Promise<void> {
return this.internalAdapter.mkdir(normalizedPath);
}
trashSystem(normalizedPath: string): Promise<boolean> {
return this.internalAdapter.trashSystem(normalizedPath);
}
trashLocal(normalizedPath: string): Promise<void> {
return this.internalAdapter.trashLocal(normalizedPath);
}
rmdir(normalizedPath: string, recursive: boolean): Promise<void> {
return this.internalAdapter.rmdir(normalizedPath, recursive);
}
remove(normalizedPath: string): Promise<void> {
return this.internalAdapter.remove(normalizedPath);
}
rename(normalizedPath: string, normalizedNewPath: string): Promise<void> {
return this.internalAdapter.rename(normalizedPath, normalizedNewPath);
}
copy(normalizedPath: string, normalizedNewPath: string): Promise<void> {
return this.internalAdapter.copy(normalizedPath, normalizedNewPath);
}
}