@learncard/network-plugin 2.13.16 → 2.13.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lcn-plugin.cjs.development.cjs +75 -13
- package/dist/lcn-plugin.cjs.development.cjs.map +3 -3
- package/dist/lcn-plugin.cjs.production.min.cjs +34 -34
- package/dist/lcn-plugin.cjs.production.min.cjs.map +3 -3
- package/dist/lcn-plugin.esm.js +75 -13
- package/dist/lcn-plugin.esm.js.map +3 -3
- package/dist/plugin.d.ts +26 -6
- package/dist/plugin.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/plugin.ts +172 -32
package/dist/lcn-plugin.esm.js
CHANGED
|
@@ -17528,6 +17528,56 @@ mustache.Writer = Writer;
|
|
|
17528
17528
|
var mustache_default = mustache;
|
|
17529
17529
|
|
|
17530
17530
|
// src/plugin.ts
|
|
17531
|
+
var LEARNCARD_DOMAIN_SUFFIXES = [".learncard.com", ".learncard.app", ".learncard.ai"];
|
|
17532
|
+
var isLearnCardDomain = /* @__PURE__ */ __name((host) => {
|
|
17533
|
+
return LEARNCARD_DOMAIN_SUFFIXES.some(
|
|
17534
|
+
(suffix) => host === suffix.replace(/^\./, "") || host.endsWith(suffix)
|
|
17535
|
+
);
|
|
17536
|
+
}, "isLearnCardDomain");
|
|
17537
|
+
var isLocalhostHost = /* @__PURE__ */ __name((host) => {
|
|
17538
|
+
const lower = host.toLowerCase();
|
|
17539
|
+
return lower === "localhost" || lower === "127.0.0.1";
|
|
17540
|
+
}, "isLocalhostHost");
|
|
17541
|
+
var validateFederationUrl = /* @__PURE__ */ __name((userProvidedUrl, config2) => {
|
|
17542
|
+
let parsed;
|
|
17543
|
+
try {
|
|
17544
|
+
parsed = new URL(userProvidedUrl);
|
|
17545
|
+
} catch {
|
|
17546
|
+
throw new Error(`Invalid federation endpoint URL: ${userProvidedUrl}`);
|
|
17547
|
+
}
|
|
17548
|
+
if (config2.serviceOrigin) {
|
|
17549
|
+
const endpointOrigin = parsed.origin;
|
|
17550
|
+
if (endpointOrigin === config2.serviceOrigin) {
|
|
17551
|
+
return parsed.href;
|
|
17552
|
+
}
|
|
17553
|
+
}
|
|
17554
|
+
const host = parsed.hostname.toLowerCase();
|
|
17555
|
+
const isLocalhost = isLocalhostHost(host);
|
|
17556
|
+
if (isLocalhost) {
|
|
17557
|
+
if (!config2.allowLocalhostFederation) {
|
|
17558
|
+
throw new Error(
|
|
17559
|
+
`Localhost federation is disabled. Set allowLocalhostFederation: true for development.`
|
|
17560
|
+
);
|
|
17561
|
+
}
|
|
17562
|
+
if (parsed.protocol === "https:") {
|
|
17563
|
+
parsed.protocol = "http:";
|
|
17564
|
+
}
|
|
17565
|
+
return parsed.href;
|
|
17566
|
+
}
|
|
17567
|
+
if (parsed.protocol !== "https:") {
|
|
17568
|
+
throw new Error(`Federation requires HTTPS for non-localhost hosts: ${userProvidedUrl}`);
|
|
17569
|
+
}
|
|
17570
|
+
if (config2.trustedFederationHosts !== void 0) {
|
|
17571
|
+
const trustedHosts = new Set(config2.trustedFederationHosts);
|
|
17572
|
+
const allowAnyHost = trustedHosts.has("*");
|
|
17573
|
+
if (!allowAnyHost && !isLearnCardDomain(host) && !trustedHosts.has(host)) {
|
|
17574
|
+
throw new Error(
|
|
17575
|
+
`Federation host '${host}' is not trusted. Add it to trustedFederationHosts or use '*' to allow any host.`
|
|
17576
|
+
);
|
|
17577
|
+
}
|
|
17578
|
+
}
|
|
17579
|
+
return parsed.href;
|
|
17580
|
+
}, "validateFederationUrl");
|
|
17531
17581
|
var uint8ArrayToBase64Url = /* @__PURE__ */ __name((bytes) => {
|
|
17532
17582
|
let binary = "";
|
|
17533
17583
|
for (let i = 0; i < bytes.length; i += 1) binary += String.fromCharCode(bytes[i]);
|
|
@@ -17621,8 +17671,20 @@ var issueCredentialWithNetworkStatus = /* @__PURE__ */ __name(async (learnCard,
|
|
|
17621
17671
|
}, "issueCredentialWithNetworkStatus");
|
|
17622
17672
|
async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, options) {
|
|
17623
17673
|
const apiToken = typeof apiTokenOrOptions === "string" ? apiTokenOrOptions : void 0;
|
|
17624
|
-
const
|
|
17625
|
-
const
|
|
17674
|
+
const resolvedOptions = (typeof apiTokenOrOptions === "object" ? apiTokenOrOptions : options) ?? {};
|
|
17675
|
+
const {
|
|
17676
|
+
guardianApprovalGetter,
|
|
17677
|
+
extraHeaders,
|
|
17678
|
+
trustedFederationHosts,
|
|
17679
|
+
allowLocalhostFederation
|
|
17680
|
+
} = resolvedOptions;
|
|
17681
|
+
const serviceUrl = new URL(url2);
|
|
17682
|
+
const serviceIsLocalhost = isLocalhostHost(serviceUrl.hostname);
|
|
17683
|
+
const federationConfig = {
|
|
17684
|
+
trustedFederationHosts,
|
|
17685
|
+
allowLocalhostFederation: allowLocalhostFederation ?? serviceIsLocalhost,
|
|
17686
|
+
serviceOrigin: serviceUrl.origin
|
|
17687
|
+
};
|
|
17626
17688
|
let did = "";
|
|
17627
17689
|
try {
|
|
17628
17690
|
const idPlane = learnCard?.id;
|
|
@@ -17691,8 +17753,8 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
|
|
|
17691
17753
|
}
|
|
17692
17754
|
}, "getBoostTemplateForIssuance");
|
|
17693
17755
|
const getInboxEndpointForDid = /* @__PURE__ */ __name(async (_learnCard, recipientDid) => {
|
|
17694
|
-
const
|
|
17695
|
-
const serviceDomain = `${
|
|
17756
|
+
const serviceUrl2 = new URL(url2);
|
|
17757
|
+
const serviceDomain = `${serviceUrl2.hostname}${serviceUrl2.port ? `%3A${serviceUrl2.port}` : ""}`;
|
|
17696
17758
|
const localServiceDid = `did:web:${serviceDomain}`;
|
|
17697
17759
|
const getInferredServiceDid = /* @__PURE__ */ __name((did2) => {
|
|
17698
17760
|
if (!did2.startsWith("did:web:")) return null;
|
|
@@ -17713,12 +17775,12 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
|
|
|
17713
17775
|
}), "getInboxService");
|
|
17714
17776
|
const inferredServiceDid = getInferredServiceDid(recipientDid);
|
|
17715
17777
|
if (inferredServiceDid === localServiceDid) {
|
|
17716
|
-
return `${
|
|
17778
|
+
return `${serviceUrl2.origin}/api/inbox/receive`;
|
|
17717
17779
|
}
|
|
17718
17780
|
const didDoc = await _learnCard.invoke.resolveDid(recipientDid);
|
|
17719
17781
|
const inboxService = getInboxService(didDoc);
|
|
17720
17782
|
if ((inboxService?.serviceDid || inferredServiceDid) === localServiceDid) {
|
|
17721
|
-
return `${
|
|
17783
|
+
return `${serviceUrl2.origin}/api/inbox/receive`;
|
|
17722
17784
|
}
|
|
17723
17785
|
if (!inboxService?.serviceEndpoint) {
|
|
17724
17786
|
throw new Error(
|
|
@@ -17880,7 +17942,8 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
|
|
|
17880
17942
|
return client.profileManager.updateProfileManager.mutate(manager);
|
|
17881
17943
|
}, "updateProfileManagerProfile"),
|
|
17882
17944
|
deleteProfile: /* @__PURE__ */ __name(async () => {
|
|
17883
|
-
|
|
17945
|
+
await initialQuery;
|
|
17946
|
+
if (!apiToken) await ensureUser();
|
|
17884
17947
|
const result = await client.profile.deleteProfile.mutate();
|
|
17885
17948
|
if (result) {
|
|
17886
17949
|
userData = void 0;
|
|
@@ -18031,11 +18094,10 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
|
|
|
18031
18094
|
proofFormat: "jwt",
|
|
18032
18095
|
challenge: `inbox-federation-${crypto.randomUUID()}`
|
|
18033
18096
|
});
|
|
18034
|
-
|
|
18035
|
-
if (receiveUrl.includes("localhost")) {
|
|
18036
|
-
receiveUrl = receiveUrl.replace("https://", "http://");
|
|
18037
|
-
}
|
|
18097
|
+
const receiveUrl = validateFederationUrl(inboxEndpoint, federationConfig);
|
|
18038
18098
|
const response = await fetch(receiveUrl, {
|
|
18099
|
+
// A redirect must not bypass endpoint validation or forward credentials.
|
|
18100
|
+
redirect: "error",
|
|
18039
18101
|
method: "POST",
|
|
18040
18102
|
headers: {
|
|
18041
18103
|
"Content-Type": "application/json",
|
|
@@ -18510,8 +18572,8 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
|
|
|
18510
18572
|
const isDid = recipient.startsWith("did:");
|
|
18511
18573
|
const isEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(recipient);
|
|
18512
18574
|
const isPhone = /^\+?[\d\s-]{10,}$/.test(recipient.replace(/[\s-]/g, ""));
|
|
18513
|
-
const
|
|
18514
|
-
const serviceDomain = `${
|
|
18575
|
+
const serviceUrl2 = new URL(url2);
|
|
18576
|
+
const serviceDomain = `${serviceUrl2.hostname}${serviceUrl2.port ? `%3A${serviceUrl2.port}` : ""}`;
|
|
18515
18577
|
const recipientDomain = recipient.startsWith("did:web:") ? recipient.split(":")[2] : void 0;
|
|
18516
18578
|
const isRemoteDidWebRecipient = recipient.startsWith("did:web:") && recipientDomain !== serviceDomain;
|
|
18517
18579
|
if (isRemoteDidWebRecipient && input.templateUri) {
|