Skip to content

Instantly share code, notes, and snippets.

@CypherpunkSamurai
Last active March 20, 2022 20:34
Show Gist options
  • Select an option

  • Save CypherpunkSamurai/bf434491b9ca79cb620717cf74cfb243 to your computer and use it in GitHub Desktop.

Select an option

Save CypherpunkSamurai/bf434491b9ca79cb620717cf74cfb243 to your computer and use it in GitHub Desktop.
Obisidian.md Custom Commit System

Obsidian Commit System

This was a POC of a custom commit system leveraging SHA hashes like Github. Initially SHA1 was used to make using Github API easier, later on project shifted motives towards Dropbox integration.

Please remove unused Dropbox Code before using, or just use the functions required.

This is an old piece of snippet from August 2021. If anyone wants to borrow the code feel free, just link to this gist in the credits and that'd do :P

Commit Function - L180

Credits

Cypherpunk Samurai - Me :P

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();
}));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment