mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Add local nostr-tools fallback for restricted domains
This commit is contained in:
1 parent
c4cc89af29
commit
4f75f2dff4
4 files changed
+242
-28
No files matched your search
+96
-2
@@ -217,6 +217,76 @@ async function ensureNostrTools() {
|
||||
return cachedNostrTools || null;
|
||||
}
|
||||
|
||||
function isSimplePoolConstructor(candidate) {
|
||||
if (typeof candidate !== "function") {
|
||||
return false;
|
||||
}
|
||||
|
||||
const prototype = candidate.prototype;
|
||||
if (!prototype || typeof prototype !== "object") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return typeof prototype.sub === "function" && typeof prototype.close === "function";
|
||||
}
|
||||
|
||||
function unwrapSimplePool(candidate) {
|
||||
if (!candidate) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isSimplePoolConstructor(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
|
||||
if (typeof candidate === "object") {
|
||||
if (isSimplePoolConstructor(candidate.SimplePool)) {
|
||||
return candidate.SimplePool;
|
||||
}
|
||||
if (isSimplePoolConstructor(candidate.default)) {
|
||||
return candidate.default;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function resolveSimplePoolConstructor(tools, scope = globalScope) {
|
||||
const candidates = [
|
||||
tools?.SimplePool,
|
||||
tools?.pool?.SimplePool,
|
||||
tools?.pool,
|
||||
tools?.SimplePool?.SimplePool,
|
||||
tools?.SimplePool?.default,
|
||||
tools?.pool?.default,
|
||||
tools?.default?.SimplePool,
|
||||
tools?.default?.pool?.SimplePool,
|
||||
tools?.default?.pool,
|
||||
];
|
||||
|
||||
if (scope && typeof scope === "object") {
|
||||
candidates.push(scope?.SimplePool);
|
||||
candidates.push(scope?.pool?.SimplePool);
|
||||
candidates.push(scope?.pool);
|
||||
const scopedTools =
|
||||
scope?.NostrTools && scope.NostrTools !== tools ? scope.NostrTools : null;
|
||||
if (scopedTools) {
|
||||
candidates.push(scopedTools.SimplePool);
|
||||
candidates.push(scopedTools.pool?.SimplePool);
|
||||
candidates.push(scopedTools.pool);
|
||||
}
|
||||
}
|
||||
|
||||
for (const candidate of candidates) {
|
||||
const resolved = unwrapSimplePool(candidate);
|
||||
if (resolved) {
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
let ingestLocalViewEventRef = null;
|
||||
|
||||
async function loadIngestLocalViewEvent() {
|
||||
@@ -4292,10 +4362,34 @@ class NostrClient {
|
||||
}
|
||||
|
||||
const tools = await ensureNostrTools();
|
||||
const SimplePool = tools?.SimplePool;
|
||||
const SimplePool = resolveSimplePoolConstructor(tools);
|
||||
if (typeof SimplePool !== "function") {
|
||||
const error = new Error("NostrTools SimplePool is unavailable.");
|
||||
if (isDevMode) {
|
||||
if (tools && typeof tools === "object") {
|
||||
const availableKeys = Object.keys(tools).join(", ");
|
||||
console.warn(
|
||||
"[nostr] NostrTools helpers did not expose SimplePool. Available keys:",
|
||||
availableKeys
|
||||
);
|
||||
} else {
|
||||
console.warn(
|
||||
"[nostr] NostrTools helpers were unavailable. Check that nostr-tools bundles can load on this domain."
|
||||
);
|
||||
}
|
||||
if (nostrToolsBootstrapFailure) {
|
||||
console.warn(
|
||||
"[nostr] nostr-tools bootstrap failure details:",
|
||||
nostrToolsBootstrapFailure
|
||||
);
|
||||
}
|
||||
}
|
||||
const error = new Error(
|
||||
"NostrTools SimplePool is unavailable. Verify that nostr-tools resources can load on this domain."
|
||||
);
|
||||
error.code = "nostr-simplepool-unavailable";
|
||||
if (nostrToolsBootstrapFailure) {
|
||||
error.bootstrapFailure = nostrToolsBootstrapFailure;
|
||||
}
|
||||
this.poolPromise = null;
|
||||
throw error;
|
||||
}
|
||||
|
||||
+114
-26
@@ -1,7 +1,38 @@
|
||||
const REMOTE_IMPORT_TIMEOUT = 4500;
|
||||
const LOCAL_IMPORT_TIMEOUT = 2500;
|
||||
const SCRIPT_FALLBACK_TIMEOUT = 6000;
|
||||
const CDN_BUNDLE_URL = "https://cdn.jsdelivr.net/npm/[email protected]/lib/nostr.bundle.min.js";
|
||||
const CDN_BUNDLE_URL =
|
||||
"https://cdn.jsdelivr.net/npm/[email protected]/lib/nostr.bundle.min.js";
|
||||
const LOCAL_BUNDLE_RELATIVE_URL = "../vendor/nostr-tools.bundle.min.js";
|
||||
|
||||
const moduleUrl =
|
||||
typeof import.meta !== "undefined" && import.meta?.url ? import.meta.url : null;
|
||||
|
||||
const resolveRelativeUrl = (relativePath) => {
|
||||
if (!relativePath) {
|
||||
return relativePath;
|
||||
}
|
||||
if (/^[a-zA-Z][a-zA-Z\d+.-]*:/.test(relativePath)) {
|
||||
return relativePath;
|
||||
}
|
||||
if (moduleUrl) {
|
||||
try {
|
||||
return new URL(relativePath, moduleUrl).href;
|
||||
} catch (error) {
|
||||
// Fall through to other resolution strategies
|
||||
}
|
||||
}
|
||||
if (typeof window !== "undefined" && window?.location?.href) {
|
||||
try {
|
||||
return new URL(relativePath, window.location.href).href;
|
||||
} catch (error) {
|
||||
return relativePath;
|
||||
}
|
||||
}
|
||||
return relativePath;
|
||||
};
|
||||
|
||||
const LOCAL_BUNDLE_URL = resolveRelativeUrl(LOCAL_BUNDLE_RELATIVE_URL);
|
||||
|
||||
let bootstrapPromise = null;
|
||||
|
||||
@@ -137,6 +168,60 @@ const ensureGlobalReadyPromise = (scope, promise) => {
|
||||
}
|
||||
};
|
||||
|
||||
const loadScriptBundle = (scope, url, label) => {
|
||||
if (!scope?.document) {
|
||||
return Promise.resolve({
|
||||
label,
|
||||
ok: false,
|
||||
timedOut: false,
|
||||
duration: 0,
|
||||
error: new Error("Document is unavailable for script loading."),
|
||||
});
|
||||
}
|
||||
|
||||
return withTimeout(
|
||||
() =>
|
||||
new Promise((resolve, reject) => {
|
||||
const { document } = scope;
|
||||
const target = document.head || document.body || document.documentElement;
|
||||
if (!target) {
|
||||
reject(new Error("Unable to locate a DOM target for script injection."));
|
||||
return;
|
||||
}
|
||||
|
||||
const script = document.createElement("script");
|
||||
script.async = true;
|
||||
script.src = url;
|
||||
script.crossOrigin = "anonymous";
|
||||
|
||||
const cleanup = () => {
|
||||
script.onload = null;
|
||||
script.onerror = null;
|
||||
if (script.parentNode) {
|
||||
script.parentNode.removeChild(script);
|
||||
}
|
||||
};
|
||||
|
||||
script.onload = () => {
|
||||
cleanup();
|
||||
resolve(scope?.NostrTools || null);
|
||||
};
|
||||
script.onerror = (event) => {
|
||||
cleanup();
|
||||
if (event?.error instanceof Error) {
|
||||
reject(event.error);
|
||||
} else {
|
||||
reject(new Error(`nostr-tools bundle failed to load: ${url}`));
|
||||
}
|
||||
};
|
||||
|
||||
target.appendChild(script);
|
||||
}),
|
||||
SCRIPT_FALLBACK_TIMEOUT,
|
||||
label
|
||||
);
|
||||
};
|
||||
|
||||
export function bootstrapNostrTools() {
|
||||
if (bootstrapPromise) {
|
||||
return bootstrapPromise;
|
||||
@@ -256,38 +341,41 @@ export function bootstrapNostrTools() {
|
||||
!!scope.document && (resolvedModules.length === 0 || allDynamicTimedOut);
|
||||
|
||||
if (shouldAttemptScriptFallback) {
|
||||
const scriptLoadResult = await withTimeout(
|
||||
() =>
|
||||
new Promise((resolve, reject) => {
|
||||
const script = scope.document.createElement("script");
|
||||
script.src = CDN_BUNDLE_URL;
|
||||
script.async = true;
|
||||
script.onload = () => resolve(scope?.NostrTools || null);
|
||||
script.onerror = () =>
|
||||
reject(new Error("nostr-tools CDN bundle failed to load"));
|
||||
scope.document.head.appendChild(script);
|
||||
}),
|
||||
SCRIPT_FALLBACK_TIMEOUT,
|
||||
"cdn-bundle"
|
||||
);
|
||||
const scriptSources = [
|
||||
LOCAL_BUNDLE_URL
|
||||
? { url: LOCAL_BUNDLE_URL, label: "local-bundle" }
|
||||
: null,
|
||||
{ url: CDN_BUNDLE_URL, label: "cdn-bundle" },
|
||||
].filter(Boolean);
|
||||
|
||||
attempts.push({
|
||||
target: scriptLoadResult.label,
|
||||
ok: scriptLoadResult.ok,
|
||||
timedOut: !!scriptLoadResult.timedOut,
|
||||
duration: scriptLoadResult.duration,
|
||||
error: scriptLoadResult.ok
|
||||
? null
|
||||
: toSerializableError(scriptLoadResult.error),
|
||||
});
|
||||
for (const source of scriptSources) {
|
||||
const scriptLoadResult = await loadScriptBundle(
|
||||
scope,
|
||||
source.url,
|
||||
source.label
|
||||
);
|
||||
|
||||
attempts.push({
|
||||
target: scriptLoadResult.label,
|
||||
ok: scriptLoadResult.ok,
|
||||
timedOut: !!scriptLoadResult.timedOut,
|
||||
duration: scriptLoadResult.duration,
|
||||
error: scriptLoadResult.ok
|
||||
? null
|
||||
: toSerializableError(scriptLoadResult.error),
|
||||
});
|
||||
|
||||
if (!scriptLoadResult.ok) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (scriptLoadResult.ok) {
|
||||
const extracted = extractToolsFromModule(scriptLoadResult.value);
|
||||
if (extracted && Object.keys(extracted).length > 0) {
|
||||
resolvedModules.push({ source: "cdn-bundle", tools: extracted });
|
||||
resolvedModules.push({ source: source.label, tools: extracted });
|
||||
if (!resolvedNip04 && hasWorkingNip04(extracted?.nip04)) {
|
||||
resolvedNip04 = extracted.nip04;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <https://unlicense.org>
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Minified by jsDelivr using Terser v5.37.0.
|
||||
* Original file: /npm/[email protected]/lib/nostr.bundle.js
|
||||
*
|
||||
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
|
||||
*/
|
||||
"use strict";var NostrTools=(()=>{var t=Object.defineProperty,e=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,r=Object.prototype.hasOwnProperty,o=(e,n)=>{for(var r in n)t(e,r,{get:n[r],enumerable:!0})},i={};function s(t){if(!Number.isSafeInteger(t)||t<0)throw new Error(`Wrong positive integer: ${t}`)}function a(t,...e){if(!(t instanceof Uint8Array))throw new Error("Expected Uint8Array");if(e.length>0&&!e.includes(t.length))throw new Error(`Expected Uint8Array of length ${e}, not of length=${t.length}`)}function c(t,e=!0){if(t.destroyed)throw new Error("Hash instance has been destroyed");if(e&&t.finished)throw new Error("Hash#digest() has already been called")}o(i,{Relay:()=>Pr,SimplePool:()=>qr,finalizeEvent:()=>qe,fj:()=>xr,generateSecretKey:()=>Pe,getEventHash:()=>$e,getFilterLimit:()=>vr,getPublicKey:()=>Ce,kinds:()=>je,matchFilter:()=>br,matchFilters:()=>mr,mergeFilters:()=>Er,nip04:()=>Ro,nip05:()=>Oi,nip10:()=>Ci,nip11:()=>Mi,nip13:()=>Di,nip18:()=>Wi,nip19:()=>Mr,nip21:()=>Yi,nip25:()=>es,nip27:()=>os,nip28:()=>cs,nip30:()=>ps,nip39:()=>Es,nip42:()=>Lr,nip44:()=>As,nip47:()=>oa,nip57:()=>ca,nip59:()=>pa,nip98:()=>Ua,parseReferences:()=>Oo,serializeEvent:()=>Ne,sortEvents:()=>de,utils:()=>Se,validateEvent:()=>fe,verifiedSymbol:()=>le,verifyEvent:()=>Me});var u="object"==typeof globalThis&&"crypto"in globalThis?globalThis.crypto:void 0,l=t=>t instanceof Uint8Array,h=t=>new DataView(t.buffer,t.byteOffset,t.byteLength),f=(t,e)=>t<<32-e|t>>>e;if(!(68===new Uint8Array(new Uint32Array([287454020]).buffer)[0]))throw new Error("Non little-endian hardware is not supported");function d(t){if("string"==typeof t&&(t=function(t){if("string"!=typeof t)throw new Error("utf8ToBytes expected string, got "+typeof t);return new Uint8Array((new TextEncoder).encode(t))}(t)),!l(t))throw new Error("expected Uint8Array, got "+typeof t);return t}var p=class{clone(){return this._cloneInto()}};function g(t){const e=e=>t().update(d(e)).digest(),n=t();return e.outputLen=n.outputLen,e.blockLen=n.blockLen,e.create=()=>t(),e}function y(t=32){if(u&&"function"==typeof u.getRandomValues)return u.getRandomValues(new Uint8Array(t));throw new Error("crypto.getRandomValues must be defined")}var w=class extends p{constructor(t,e,n,r){super(),this.blockLen=t,this.outputLen=e,this.padOffset=n,this.isLE=r,this.finished=!1,this.length=0,this.pos=0,this.destroyed=!1,this.buffer=new Uint8Array(t),this.view=h(this.buffer)}update(t){c(this);const{view:e,buffer:n,blockLen:r}=this,o=(t=d(t)).length;for(let i=0;i<o;){const s=Math.min(r-this.pos,o-i);if(s!==r)n.set(t.subarray(i,i+s),this.pos),this.pos+=s,i+=s,this.pos===r&&(this.process(e,0),this.pos=0);else{const e=h(t);for(;r<=o-i;i+=r)this.process(e,i)}}return this.length+=t.length,this.roundClean(),this}digestInto(t){c(this),function(t,e){a(t);const n=e.outputLen;if(t.length<n)throw new Error(`digestInto() expects output buffer of length at least ${n}`)}(t,this),this.finished=!0;const{buffer:e,view:n,blockLen:r,isLE:o}=this;let{pos:i}=this;e[i++]=128,this.buffer.subarray(i).fill(0),this.padOffset>r-i&&(this.process(n,0),i=0);for(let t=i;t<r;t++)e[t]=0;!function(t,e,n,r){if("function"==typeof t.setBigUint64)return t.setBigUint64(e,n,r);const o=BigInt(32),i=BigInt(4294967295),s=Number(n>>o&i),a=Number(n&i),c=r?4:0,u=r?0:4;t.setUint32(e+c,s,r),t.setUint32(e+u,a,r)}(n,r-8,BigInt(8*this.length),o),this.process(n,0);const s=h(t),u=this.outputLen;if(u%4)throw new Error("_sha2: outputLen should be aligned to 32bit");const l=u/4,f=this.get();if(l>f.length)throw new Error("_sha2: outputLen bigger than state");for(let t=0;t<l;t++)s.setUint32(4*t,f[t],o)}digest(){const{buffer:t,outputLen:e}=this;this.digestInto(t);const n=t.slice(0,e);return this.destroy(),n}_cloneInto(t){t||(t=new this.constructor),t.set(...this.get());const{blockLen:e,buffer:n,length:r,finished:o,destroyed:i,pos:s}=this;return t.length=r,t.pos=s,t.finished=o,t.destroyed=i,r%e&&t.buffer.set(n),t}},b=(t,e,n)=>t&e^t&n^e&n,m=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),E=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),v=new Uint32Array(64),x=class extends w{constructor(){super(64,32,8,!1),this.A=0|E[0],this.B=0|E[1],this.C=0|E[2],this.D=0|E[3],this.E=0|E[4],this.F=0|E[5],this.G=0|E[6],this.H=0|E[7]}get(){const{A:t,B:e,C:n,DLine truncated
|
||||
//# sourceMappingURL=/sm/f29f5f5418a4e9d4df57df00b6b51f97de02afef7a8d582c6c8814bdab32efb1.map
|
||||
Reference in new issue
Block a user