more shims, path, crypto, url
This commit is contained in:
parent
192c5fb093
commit
38427d4fe4
7 changed files with 156 additions and 0 deletions
5
shims/btime.js
Normal file
5
shims/btime.js
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
// Shim for the btime native module (file birth time)
|
||||||
|
// Obsidian wraps this in try/catch: try{this.btime=window.require("btime")}catch(e){}
|
||||||
|
// Returning null causes graceful degradation - mtime is used instead.
|
||||||
|
|
||||||
|
export const btimeShim = null;
|
||||||
60
shims/crypto/create-hash.js
Normal file
60
shims/crypto/create-hash.js
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
// Shim for crypto.createHash
|
||||||
|
// Obsidian uses createHash('SHA256') for signature verification (main process only)
|
||||||
|
// and possibly for content hashing in the renderer.
|
||||||
|
// Uses SubtleCrypto where possible.
|
||||||
|
|
||||||
|
export function createHash(algorithm) {
|
||||||
|
const alg = algorithm.toUpperCase().replace('-', '');
|
||||||
|
const subtleAlg = alg === 'SHA256' ? 'SHA-256' : alg === 'SHA1' ? 'SHA-1' : alg === 'SHA512' ? 'SHA-512' : alg;
|
||||||
|
|
||||||
|
let inputData = new Uint8Array(0);
|
||||||
|
|
||||||
|
return {
|
||||||
|
update(data) {
|
||||||
|
if (typeof data === 'string') {
|
||||||
|
data = new TextEncoder().encode(data);
|
||||||
|
}
|
||||||
|
// Concatenate
|
||||||
|
const merged = new Uint8Array(inputData.length + data.length);
|
||||||
|
merged.set(inputData);
|
||||||
|
merged.set(data, inputData.length);
|
||||||
|
inputData = merged;
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Note: digest is sync in Node but we may need async.
|
||||||
|
// For now provide sync hex/base64 via a simple JS implementation.
|
||||||
|
// TODO: evaluate if any sync call sites exist; if not, make this async.
|
||||||
|
digest(encoding) {
|
||||||
|
// Fallback: simple sync hash (for SHA-256 only)
|
||||||
|
// This is a placeholder - swap in a proper sync implementation if needed
|
||||||
|
console.warn('[shim:crypto] createHash.digest - using placeholder');
|
||||||
|
const hash = simpleHash(inputData);
|
||||||
|
if (encoding === 'hex') return hash;
|
||||||
|
if (encoding === 'base64') return btoa(hash);
|
||||||
|
return hash;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Async alternative for contexts that can await
|
||||||
|
async digestAsync(encoding) {
|
||||||
|
const hashBuffer = await crypto.subtle.digest(subtleAlg, inputData);
|
||||||
|
const hashArray = new Uint8Array(hashBuffer);
|
||||||
|
if (encoding === 'hex') {
|
||||||
|
return Array.from(hashArray).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||||
|
}
|
||||||
|
if (encoding === 'base64') {
|
||||||
|
return btoa(String.fromCharCode(...hashArray));
|
||||||
|
}
|
||||||
|
return hashArray;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Very basic placeholder hash - not cryptographic, just for bootstrapping
|
||||||
|
function simpleHash(data) {
|
||||||
|
let hash = 0;
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
hash = ((hash << 5) - hash + data[i]) | 0;
|
||||||
|
}
|
||||||
|
return Math.abs(hash).toString(16).padStart(8, '0');
|
||||||
|
}
|
||||||
12
shims/crypto/index.js
Normal file
12
shims/crypto/index.js
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Crypto shim
|
||||||
|
// Obsidian uses: scrypt, randomBytes, createHash
|
||||||
|
|
||||||
|
import { randomBytes } from './random-bytes.js';
|
||||||
|
import { createHash } from './create-hash.js';
|
||||||
|
import { scrypt } from './scrypt.js';
|
||||||
|
|
||||||
|
export const cryptoShim = {
|
||||||
|
randomBytes,
|
||||||
|
createHash,
|
||||||
|
scrypt,
|
||||||
|
};
|
||||||
20
shims/crypto/random-bytes.js
Normal file
20
shims/crypto/random-bytes.js
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
// Shim for crypto.randomBytes
|
||||||
|
// Uses Web Crypto API under the hood
|
||||||
|
|
||||||
|
export function randomBytes(size) {
|
||||||
|
const buf = new Uint8Array(size);
|
||||||
|
crypto.getRandomValues(buf);
|
||||||
|
|
||||||
|
// Add Buffer-like convenience methods
|
||||||
|
buf.toString = function(encoding) {
|
||||||
|
if (encoding === 'hex') {
|
||||||
|
return Array.from(this).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||||
|
}
|
||||||
|
if (encoding === 'base64') {
|
||||||
|
return btoa(String.fromCharCode(...this));
|
||||||
|
}
|
||||||
|
return new TextDecoder().decode(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
29
shims/crypto/scrypt.js
Normal file
29
shims/crypto/scrypt.js
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Shim for crypto.scrypt
|
||||||
|
// Delegates to window.scrypt which is already loaded by Obsidian's own scrypt.js
|
||||||
|
|
||||||
|
export function scrypt(password, salt, keylen, options, callback) {
|
||||||
|
// Node signature: scrypt(password, salt, keylen, options, callback)
|
||||||
|
// Obsidian's app.js checks for window.require("crypto") and uses it if available,
|
||||||
|
// otherwise falls back to window.scrypt - so this shim just delegates to the latter.
|
||||||
|
|
||||||
|
if (typeof options === 'function') {
|
||||||
|
callback = options;
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const N = options?.N || 32768;
|
||||||
|
const r = options?.r || 8;
|
||||||
|
const p = options?.p || 1;
|
||||||
|
|
||||||
|
if (window.scrypt && window.scrypt.scrypt) {
|
||||||
|
// Use the browser scrypt library already loaded by Obsidian
|
||||||
|
const pwBytes = typeof password === 'string' ? new TextEncoder().encode(password) : password;
|
||||||
|
const saltBytes = typeof salt === 'string' ? new TextEncoder().encode(salt) : salt;
|
||||||
|
|
||||||
|
window.scrypt.scrypt(pwBytes, saltBytes, N, r, p, keylen)
|
||||||
|
.then((result) => callback(null, new Uint8Array(result)))
|
||||||
|
.catch((err) => callback(err));
|
||||||
|
} else {
|
||||||
|
callback(new Error('scrypt not available'));
|
||||||
|
}
|
||||||
|
}
|
||||||
6
shims/path.js
Normal file
6
shims/path.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
// Path shim - delegates to path-browserify (bundled via esbuild alias)
|
||||||
|
// Configured for posix mode since vault paths are normalized to forward slashes.
|
||||||
|
|
||||||
|
import pathBrowserify from 'path';
|
||||||
|
|
||||||
|
export const pathShim = pathBrowserify;
|
||||||
24
shims/url.js
Normal file
24
shims/url.js
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
// URL shim
|
||||||
|
// Obsidian uses: pathToFileURL, fileURLToPath, URL, URLSearchParams
|
||||||
|
|
||||||
|
export const urlShim = {
|
||||||
|
URL: globalThis.URL,
|
||||||
|
URLSearchParams: globalThis.URLSearchParams,
|
||||||
|
|
||||||
|
pathToFileURL(p) {
|
||||||
|
// Return an object with .href matching Node's url.pathToFileURL behavior
|
||||||
|
const encoded = encodeURI(p.replace(/\\/g, '/'));
|
||||||
|
const href = 'file:///' + encoded.replace(/^\/+/, '');
|
||||||
|
return { href, toString: () => href };
|
||||||
|
},
|
||||||
|
|
||||||
|
fileURLToPath(url) {
|
||||||
|
let str = typeof url === 'string' ? url : url.href || url.toString();
|
||||||
|
if (str.startsWith('file:///')) {
|
||||||
|
str = str.slice(8);
|
||||||
|
} else if (str.startsWith('file://')) {
|
||||||
|
str = str.slice(7);
|
||||||
|
}
|
||||||
|
return decodeURI(str);
|
||||||
|
},
|
||||||
|
};
|
||||||
Loading…
Add table
Reference in a new issue