sharing v1

This commit is contained in:
Maxime Cannoodt 2022-06-19 22:49:37 +02:00
parent 1000c4efc0
commit 07f4800d34
4 changed files with 69 additions and 29 deletions

47
main.ts
View File

@ -1,51 +1,46 @@
import { App, MarkdownView, Plugin, PluginSettingTab, Setting } from "obsidian"; import { App, MarkdownView, Plugin, PluginSettingTab, Setting } from "obsidian";
import { encryptMarkdown } from "src/encryption"; import { encryptMarkdown } from "src/encryption";
import { NoteSharingService } from "src/NoteSharingService";
// Remember to rename these classes and interfaces! // Remember to rename these classes and interfaces!
interface MyPluginSettings { interface MyPluginSettings {
mySetting: string; serverUrl: string;
} }
const DEFAULT_SETTINGS: MyPluginSettings = { const DEFAULT_SETTINGS: MyPluginSettings = {
mySetting: "default", serverUrl: "http://localhost:8080",
}; };
export default class MyPlugin extends Plugin { export default class MyPlugin extends Plugin {
settings: MyPluginSettings; settings: MyPluginSettings;
noteSharingService: NoteSharingService;
async onload() { async onload() {
await this.loadSettings(); await this.loadSettings();
this.noteSharingService = new NoteSharingService(
this.settings.serverUrl
);
// This adds a settings tab so the user can configure various aspects of the plugin
this.addSettingTab(new SettingsTab(this.app, this));
// This adds a complex command that can check whether the current state of the app allows execution of the command // This adds a complex command that can check whether the current state of the app allows execution of the command
this.addCommand({ this.addCommand({
id: "open-sample-modal-complex", id: "obsidian-note-sharing-share-note",
name: "Open sample modal (complex)", name: "Create share link",
checkCallback: (checking: boolean) => { checkCallback: (checking: boolean) => {
// Conditions to check // Conditions to check
const markdownView = const markdownView =
this.app.workspace.getActiveViewOfType(MarkdownView); this.app.workspace.getActiveViewOfType(MarkdownView);
if (markdownView) { if (markdownView) {
// If checking is true, we're simply "checking" if the command can be run.
// If checking is false, then we want to actually perform the operation.
if (!checking) { if (!checking) {
this.shareNote(markdownView); this.noteSharingService.shareNote(markdownView);
} }
// This command will only show up in Command Palette when the check function returns true
return true; return true;
} }
}, },
}); });
// This adds a settings tab so the user can configure various aspects of the plugin
this.addSettingTab(new SampleSettingTab(this.app, this));
}
// ENCRYPT AND SHARE MD NOTE
private shareNote(mdView: MarkdownView) {
const cryptData = encryptMarkdown(mdView);
console.log(cryptData);
} }
onunload() {} onunload() {}
@ -60,10 +55,11 @@ export default class MyPlugin extends Plugin {
async saveSettings() { async saveSettings() {
await this.saveData(this.settings); await this.saveData(this.settings);
this.noteSharingService.serverUrl = this.settings.serverUrl;
} }
} }
class SampleSettingTab extends PluginSettingTab { class SettingsTab extends PluginSettingTab {
plugin: MyPlugin; plugin: MyPlugin;
constructor(app: App, plugin: MyPlugin) { constructor(app: App, plugin: MyPlugin) {
@ -76,18 +72,17 @@ class SampleSettingTab extends PluginSettingTab {
containerEl.empty(); containerEl.empty();
containerEl.createEl("h2", { text: "Settings for my awesome plugin." }); containerEl.createEl("h2", { text: "Obsidian Note Sharing" });
new Setting(containerEl) new Setting(containerEl)
.setName("Setting #1") .setName("Server URL")
.setDesc("It's a secret") .setDesc("Server URL hosting the encrypted notes.")
.addText((text) => .addText((text) =>
text text
.setPlaceholder("Enter your secret") .setPlaceholder("enter URL")
.setValue(this.plugin.settings.mySetting) .setValue(this.plugin.settings.serverUrl)
.onChange(async (value) => { .onChange(async (value) => {
console.log("Secret: " + value); this.plugin.settings.serverUrl = value;
this.plugin.settings.mySetting = value;
await this.plugin.saveSettings(); await this.plugin.saveSettings();
}) })
); );

View File

@ -1,6 +1,6 @@
{ {
"id": "obsidian-sample-plugin", "id": "obsidian-sample-plugin",
"name": "Obsidian Note Sharing (working title)", "name": "Obsidian Note Sharing",
"version": "1.0.1", "version": "1.0.1",
"minAppVersion": "0.12.0", "minAppVersion": "0.12.0",
"description": "This is a sample plugin for Obsidian. This plugin demonstrates some of the capabilities of the Obsidian API.", "description": "This is a sample plugin for Obsidian. This plugin demonstrates some of the capabilities of the Obsidian API.",

45
src/NoteSharingService.ts Normal file
View File

@ -0,0 +1,45 @@
import { MarkdownView, requestUrl } from "obsidian";
import { encryptMarkdown } from "./encryption";
export class NoteSharingService {
private _url: string;
constructor(serverUrl: string) {
this.serverUrl = serverUrl;
}
/**
* @param mdView Markdown file to share.
* @returns link to shared note with attached decryption key.
*/
public async shareNote(mdView: MarkdownView): Promise<string> {
const cryptData = encryptMarkdown(mdView);
let url = await this.postNote(cryptData.ciphertext, cryptData.hmac);
url += `#${cryptData.key}`;
console.log(`Note shared: ${url}`);
return url;
}
private async postNote(ciphertext: string, hmac: string): Promise<string> {
const res = await requestUrl({
url: `${this._url}/note`,
method: "POST",
contentType: "application/json",
body: JSON.stringify({ ciphertext, hmac }),
});
if (res.status == 200 && res.json != null) {
const id = res.json.id;
return `${this._url}/note/${id}`;
}
throw Error("Did not get expected response from server on note POST.");
}
public set serverUrl(newUrl: string) {
newUrl = newUrl.replace(/([^:]\/)\/+/g, "$1");
if (newUrl[newUrl.length - 1] == "/") {
newUrl = newUrl.substring(0, newUrl.length - 1);
}
this._url = newUrl;
}
}

View File

@ -1,13 +1,13 @@
import { MarkdownView, moment } from "obsidian"; import { MarkdownView, moment } from "obsidian";
import { generateKey, encryptString } from "./crypto"; import { generateKey, encryptString } from "./crypto";
interface encryptedMarkdown { export interface EncryptedMarkdown {
ciphertext: string; ciphertext: string;
hmac: string; hmac: string;
key: string; key: string;
} }
export function encryptMarkdown(mdView: MarkdownView): encryptedMarkdown { export function encryptMarkdown(mdView: MarkdownView): EncryptedMarkdown {
const plaintext = mdView.getViewData(); const plaintext = mdView.getViewData();
const key = generateKey(moment.now() + plaintext); const key = generateKey(moment.now() + plaintext);
const { ciphertext, hmac } = encryptString(plaintext, key); const { ciphertext, hmac } = encryptString(plaintext, key);