|
import { App, Editor, MarkdownView, Modal, Notice, Platform, Plugin, PluginSettingTab, Setting } from 'obsidian'; |
|
|
|
const axios = require('axios'); |
|
var Hashes = require('jshashes'); |
|
|
|
// import { Dropbox, DropboxAuth, files } from 'dropbox'; |
|
import { Dropbox, DropboxAuth, files } from "./assets/Dropbox-sdk.js"; |
|
import gen_crypto_random_string from 'crypto-random-string'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
interface MyPluginSettings { |
|
mySetting: string; |
|
} |
|
|
|
const DEFAULT_SETTINGS: MyPluginSettings = { |
|
mySetting: 'default' |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
type accessTokenStore = { |
|
access_token: string; |
|
refresh_token: string; |
|
}; |
|
|
|
|
|
|
|
|
|
// ####################### |
|
// |
|
// |
|
// Functions |
|
// |
|
// |
|
// ######################## |
|
|
|
|
|
// monkeyPatchConsole(this); |
|
const monkeyPatchConsole = (plugin: Plugin) => { |
|
// if (!Platform.isMobile) { |
|
// return; |
|
// } |
|
const logFile = `${plugin.manifest.dir}/logs.txt`; |
|
const logs: string[] = []; |
|
const logMessages = (prefix: string) => (...messages: unknown[]) => { |
|
logs.push(`\n[${prefix}]`); |
|
for (const message of messages) { |
|
logs.push(String(message)); |
|
} |
|
plugin.app.vault.adapter.write(logFile, logs.join(" ")); |
|
}; |
|
|
|
console.debug = logMessages("debug"); |
|
console.error = logMessages("error"); |
|
console.info = logMessages("info"); |
|
console.log = logMessages("log"); |
|
console.warn = logMessages("warn"); |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ############################## |
|
// |
|
// |
|
// Plugin |
|
// |
|
// |
|
// ############################## |
|
|
|
|
|
|
|
export default class MyPlugin extends Plugin { |
|
settings: MyPluginSettings; |
|
|
|
vault_metadata_file: string = "vault.meta"; |
|
|
|
|
|
obsidian_protocol_scheme = "obsidian"; |
|
obsidian_protocol_address = "dropboxauth"; |
|
|
|
dropbox_client: Dropbox; |
|
dropbox_client_id = ''; |
|
dropbox_client_secret = ''; |
|
dropbox_auth_redirect_uri = `${this.obsidian_protocol_scheme}://${this.obsidian_protocol_address}`; |
|
|
|
dropbox_access_token: string; |
|
dropbox_access_token_file: string = `${this.manifest.dir}/dropbox_access_token.json`; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async onload(): Promise<void> { |
|
await this.loadSettings(); |
|
monkeyPatchConsole(this); |
|
|
|
// register protocol handler |
|
this.register_protocol_handlers(); |
|
|
|
let ribbonIconEl = this.addRibbonIcon('dice', 'Sample Plugin', async (evt: MouseEvent) => { |
|
// new Notice("Clicked Ribbon Button!"); |
|
// new Notice("Commiting Changes."); |
|
// let commit_hash = await this.commit(); |
|
// if (commit_hash !== null) { |
|
// new Notice(`Commit Hash: ${commit_hash}`); |
|
// } |
|
|
|
await this.dropbox_client_new(); |
|
await this.dropbox_gen_auth(); |
|
|
|
|
|
|
|
}); // Ribbon Button Click Handler |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ============ |
|
// |
|
// Functions |
|
// |
|
// ============ |
|
|
|
async dropbox_client_new():Promise<void> { |
|
const dropboxconfig = { |
|
fetch, |
|
clientId: this.dropbox_client_id, |
|
clientSecret: this.dropbox_client_secret, |
|
}; |
|
this.dropbox_client = new Dropbox(dropboxconfig); |
|
return; |
|
} |
|
|
|
|
|
|
|
register_protocol_handlers():void { |
|
this.registerObsidianProtocolHandler( |
|
this.obsidian_protocol_address, |
|
async (params) => { |
|
await this.dropbox_handle_auth(params); |
|
} |
|
); |
|
} |
|
|
|
async local_commit_changes():Promise<string> { |
|
/* |
|
------------------------------------------------------ |
|
Commit changes to a local commit meta file |
|
|
|
|
|
Return: |
|
:string |
|
commit hash - if new commit |
|
null - if no new commit |
|
|
|
------------------------------------------------------ |
|
*/ |
|
|
|
// List of Files |
|
const fileList = this.app.vault.getFiles(); |
|
|
|
// List of Hashes |
|
let hashList = []; |
|
if (fileList.length > 0) { |
|
let counter = 0; |
|
for (var file of fileList) { |
|
if (this.app.vault.adapter.exists(file.path)) { |
|
// new Notice(file.path); |
|
let fileContents; |
|
if (file.extension !== "md" && file.extension !== "txt" && file.extension !== "mdx") { |
|
if (file.name != "vault.meta") { |
|
// File is not a Note |
|
fileContents = await this.app.vault.adapter.readBinary(file.path); |
|
} |
|
} else { |
|
fileContents = await this.app.vault.adapter.read(file.path); |
|
} |
|
var SHA1 = await new Hashes.SHA1().hex(fileContents); |
|
hashList.push({file: file.path, hash: SHA1}); |
|
// new Notice(SHA1); |
|
} |
|
} |
|
} |
|
|
|
|
|
// Commit Changes |
|
var commit_hash = await new Hashes.SHA1().hex(JSON.stringify(hashList)); |
|
|
|
// Check if Commit hash matches old hash |
|
let recent_commit = await this.get_recent_local_commit(); |
|
|
|
// Else Commit |
|
if (recent_commit !== commit_hash || recent_commit == null) { |
|
var vault_name = await this.app.vault.getName(); |
|
var VaultJSON = JSON.stringify({vault_name: vault_name, commit_hash: commit_hash, files: hashList}); |
|
// Save Commit |
|
await this.app.vault.adapter.write(this.vault_metadata_file, VaultJSON); |
|
// Return Commit Hash |
|
return commit_hash; |
|
} else { |
|
// No New Changes |
|
new Notice(`No New Changes.\n\nLast Commit: ${recent_commit}`) |
|
// Return null |
|
return null; |
|
} |
|
|
|
} |
|
|
|
async get_recent_local_commit():Promise<string> { |
|
/* |
|
------------------------------------------------------ |
|
Reads the recent commit and returns hash |
|
|
|
------------------------------------------------------ |
|
*/ |
|
if (await this.app.vault.adapter.exists(this.vault_metadata_file)) { |
|
let meta = await this.app.vault.adapter.read(this.vault_metadata_file); |
|
let commit_hash = await JSON.parse(meta)["commit_hash"]; |
|
return commit_hash; |
|
} else { |
|
return null; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
async dropbox_gen_auth():Promise<void> { |
|
/* |
|
------------------------------------------------------ |
|
Generates a new Dropbox OAuth url and opens it in browser |
|
|
|
------------------------------------------------------ |
|
*/ |
|
|
|
// Generate Cryptographically Secures Code Verifiers |
|
const verifier = gen_crypto_random_string({length: 43, type: 'base64'}); |
|
this.dropbox_client.auth.codeChallenge = verifier; |
|
this.dropbox_client.auth.codeVerifier = "S256"; |
|
// Generate OAuth URL |
|
const authUrl = await this.dropbox_client.auth.getAuthenticationUrl(this.dropbox_auth_redirect_uri, null, 'code', 'offline', null, 'none', true) |
|
// Open the OAuth URL in browser |
|
window.location.assign(authUrl); |
|
return; |
|
} |
|
|
|
|
|
|
|
|
|
async dropbox_handle_auth(params: any):Promise<any> { |
|
/* |
|
------------------------------------------------------ |
|
Handles Dropbox OAuth response |
|
|
|
Args: |
|
params - obsidian protocol handler parameters |
|
------------------------------------------------------ |
|
*/ |
|
|
|
if (params.code) { |
|
new Notice("Dropbox OAuth Recieved...."); |
|
// Get the verifier |
|
const verifier = this.dropbox_client.auth.codeVerifier; |
|
new Notice(verifier); |
|
//await this.dropbox_client.setCodeVerifier(verifier); |
|
// Token |
|
new Notice("Getting Access token...."); |
|
const access_token = await this.dropbox_client.getAccessTokenFromCode( |
|
this.dropbox_auth_redirect_uri, |
|
params.code |
|
); |
|
new Notice("Now Saving Access token...."); |
|
await this.app.vault.adapter.write( |
|
this.dropbox_access_token_file, |
|
JSON.stringify(access_token) |
|
); |
|
} |
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ================ |
|
// |
|
// Plugin |
|
// |
|
// ================ |
|
|
|
async loadSettings() { |
|
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); |
|
} |
|
|
|
async saveSettings() { |
|
await this.saveData(this.settings); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SampleModal extends Modal { |
|
constructor(app: App) { |
|
super(app); |
|
} |
|
|
|
onOpen() { |
|
let {contentEl} = this; |
|
contentEl.setText('Woah!'); |
|
} |
|
|
|
onClose() { |
|
let {contentEl} = this; |
|
contentEl.empty(); |
|
} |
|
} |
|
|
|
class SampleSettingTab extends PluginSettingTab { |
|
plugin: MyPlugin; |
|
|
|
constructor(app: App, plugin: MyPlugin) { |
|
super(app, plugin); |
|
this.plugin = plugin; |
|
} |
|
|
|
display(): void { |
|
let {containerEl} = this; |
|
|
|
containerEl.empty(); |
|
|
|
containerEl.createEl('h2', {text: 'Settings for my awesome plugin.'}); |
|
|
|
new Setting(containerEl) |
|
.setName('Setting #1') |
|
.setDesc('It\'s a secret') |
|
.addText(text => text |
|
.setPlaceholder('Enter your secret') |
|
.setValue(this.plugin.settings.mySetting) |
|
.onChange(async (value) => { |
|
console.log('Secret: ' + value); |
|
this.plugin.settings.mySetting = value; |
|
await this.plugin.saveSettings(); |
|
})); |
|
} |
|
} |