@idos-network/client 3.0.0 → 4.0.0

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/README.md CHANGED
@@ -49,9 +49,12 @@ const profile = loggedInClient.user;
49
49
 
50
50
  // Now we can filer over users credentials (no access to them)
51
51
  const credentials = await loggedInClient.filterCredentials({
52
- credentialLevelOrHigherFilter: {
53
- userLevel: "basic",
54
- requiredAddons: ["email", "liveness"],
52
+ acceptedIssuers: [{ authPublicKey: "ISSUER_AUTH_PUBLIC_KEY" }],
53
+ // Accepted sources per claim; a self-attested ("MANUAL") email is fine here.
54
+ claimsFilter: {
55
+ identity: ["VERIFIED"],
56
+ liveness: ["LIVENESS"],
57
+ email: ["VERIFIED", "MANUAL"],
55
58
  },
56
59
  });
57
60
 
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Addon, BaseLevel, recordFilter } from "@idos-network/credentials/utils";
1
+ import { Addon, BaseLevel, Claim, ClaimRequirements, ClaimSource, ClaimSources, Claims, recordFilter } from "@idos-network/credentials/utils";
2
2
  import { KwilActionClient, Wallet, signNearMessage } from "@idos-network/kwil-infra";
3
3
  import { AddAttributeInput, AddWalletInput, AddWalletMessageInput, DelegatedWriteGrantBaseParams, GetAccessGrantsGrantedInput, GetWalletsOutput, SharePreliminaryCredentialInput, WalletType, idOSCredential, idOSCredentialListItem, idOSDelegatedWriteGrant, idOSGrant, idOSUser, idOSUserAttribute, idOSWallet, toDelegatedWriteGrantBaseParams } from "@idos-network/kwil-infra/actions";
4
4
  import { KwilSigner } from "@idos-network/kwil-js";
@@ -173,10 +173,13 @@ export declare class idOSClientLoggedIn implements Omit<Properties<idOSClientWit
173
173
  pick: Parameters<typeof recordFilter>[1];
174
174
  omit: Parameters<typeof recordFilter>[2];
175
175
  };
176
+ /** @deprecated The level leaves out self-attested data. Use `claimsFilter` instead. */
176
177
  credentialLevelOrHigherFilter?: {
177
178
  userLevel: BaseLevel;
178
179
  requiredAddons: Addon[];
179
180
  };
181
+ /** Accepted sources per claim, e.g. `{ email: ["VERIFIED", "MANUAL"] }`. See `matchClaims`. */
182
+ claimsFilter?: ClaimRequirements;
180
183
  }): Promise<idOSCredentialListItem[]>;
181
184
  requestAccessGrant(credentialId: string, { consumerEncryptionPublicKey, consumerAuthPublicKey, lockedUntil }: {
182
185
  consumerEncryptionPublicKey: string;
@@ -195,5 +198,5 @@ export declare function createIDOSClient(params: {
195
198
  enclaveOptions: Omit<IframeEnclave["options"], "mode">;
196
199
  }): idOSClientConfiguration<IframeEnclave>;
197
200
  //#endregion
198
- export { type DelegatedWriteGrantBaseParams, type idOSCredential, type idOSCredentialListItem, type idOSDelegatedWriteGrant, type idOSGrant, type idOSUser, type idOSUserAttribute, type idOSWallet, signNearMessage, toDelegatedWriteGrantBaseParams };
201
+ export { type Claim, type ClaimRequirements, type ClaimSource, type ClaimSources, type Claims, type DelegatedWriteGrantBaseParams, type idOSCredential, type idOSCredentialListItem, type idOSDelegatedWriteGrant, type idOSGrant, type idOSUser, type idOSUserAttribute, type idOSWallet, signNearMessage, toDelegatedWriteGrantBaseParams };
199
202
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/enclave/iframe-enclave.ts","../src/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/enclave/iframe-enclave.ts","../src/index.ts"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{buildEphemeralSignedCredentialContentReference as e,buildPreliminaryIDOSCredential as t,mapPreliminaryToIDOSCredential as n,matchLevelOrHigher as r,recordFilter as i}from"@idos-network/credentials/utils";import{createClientKwilSigner as a,createKgwAuthenticatedBlobGateway as o,createNodeKwilClient as s,createWebKwilClient as c,isMmTokenAuth as l,mmTokenCredentialContentUri as u,signNearMessage as d}from"@idos-network/kwil-infra";import{addAttribute as f,addWallet as p,addWalletMessage as m,addWallets as h,createPreliminaryCredential as ee,dwgMessage as te,getAccessGrantsGrantedCount as ne,getAccessGrantsOwned as re,getAttributes as g,getCredentialOwned as ie,getCredentialShared as _,getCredentials as ae,getGrants as oe,getUser as se,getWallets as ce,hasProfile as v,removeCredential as le,removeWallet as ue,revokeAccessGrant as de,sharePreliminaryCredential as y,toDelegatedWriteGrantBaseParams as b}from"@idos-network/kwil-infra/actions";import{NodeKwil as x}from"@idos-network/kwil-js";import{BlobGateway as S,createBlobContentReference as fe,requireAccessTokenForUkycContent as C,resolveCredentialEncryptedContent as pe}from"@idos-network/utils/blob-gateway";import{base64Decode as w,base64Encode as T,hexEncodeSha256Hash as E,utf8Decode as D}from"@idos-network/utils/codecs";import{LocalStorageStore as me,MemoryStore as O}from"@idos-network/utils/store";import k from"tiny-invariant";import{BaseProvider as he}from"@idos-network/enclave";var A=class extends he{container;iframe;hostUrl;bound=!1;constructor(e){if(super(e),!this.options.container)throw Error(`container is required`);this.container=this.options.container,this.hostUrl=new URL(this.options.url??`https://enclave.idos.network`),this.iframe=document.createElement(`iframe`),this.iframe.id=`idos-enclave-iframe`}async load(){await this.createAndLoadIframe(),await this.requestToEnclave(`load`),await this.reconfigure(),await this.bindMessageListener()}async reset(){throw Error(`Embedding pages cannot reset enclave storage`)}async reconfigure(e={}){super.reconfigure(e),await this.requestToEnclave(`reconfigure`,this.options)}async confirm(e){this.showEnclave();try{return await this.requestToEnclave(`confirm`,e)}catch(e){return console.error(e),!1}finally{this.hideEnclave()}}async filterCredentials(e,t){return await this.requestToEnclave(`filterCredentials`,e,t)}async encrypt(e,t){return this.requestToEnclave(`encrypt`,e,t)}async decrypt(e,t){return this.requestToEnclave(`decrypt`,e,t)}async backupUserEncryptionProfile(){this.showEnclave();try{await this.requestToEnclave(`backupUserEncryptionProfile`)}catch(e){console.error(e)}finally{this.hideEnclave()}}async ensureUserEncryptionProfile(){this.showEnclave();try{return await this.requestToEnclave(`ensureUserEncryptionProfile`)}finally{this.hideEnclave()}}async addAddressMessageToSign(e,t,n){return this.requestToEnclave(`addAddressMessageToSign`,e,t,n)}async removeAddressMessageToSign(e,t,n){return this.requestToEnclave(`removeAddressMessageToSign`,e,t,n)}async addAddressToMpcSecret(e,t,n){return this.requestToEnclave(`addAddressToMpcSecret`,e,t,n)}async removeAddressFromMpcSecret(e,t,n){return this.requestToEnclave(`removeAddressFromMpcSecret`,e,t,n)}async createAndLoadIframe(){let e=document.querySelector(this.container);if(!e)throw Error(`Can't find container with selector ${this.container}`);let t=[`publickey-credentials-get`,`storage-access`],n=[`forms`,`modals`,`popups`,`popups-to-escape-sandbox`,`same-origin`,`scripts`].map(e=>`allow-${e}`),r={"aspect-ratio":`4/1`,"background-color":`transparent`,border:`none`,display:`block`,overflow:`hidden`,width:`100%`};this.iframe.allow=t.join(`; `),this.iframe.referrerPolicy=`origin`,this.iframe.sandbox.add(...n),this.iframe.src=this.hostUrl.toString();for(let[e,t]of Object.entries(r))this.iframe.style.setProperty(e,t);let i;for(;i=document.getElementById(this.iframe.id);)console.log(`reinstalling idOS iframe...`),e.removeChild(i);return e.appendChild(this.iframe),new Promise(e=>this.iframe.addEventListener(`load`,()=>{e()},{once:!0}))}showEnclave(){this.iframe.parentElement.classList.add(`visible`)}hideEnclave(){this.iframe.parentElement.classList.remove(`visible`)}async requestToEnclave(e,...t){return new Promise((n,r)=>{let{port1:i,port2:a}=new MessageChannel;i.onmessage=({data:e})=>{i.close(),e.error?r(e.error):n(e.result)},this.iframe.contentWindow.postMessage({method:e,data:t},this.hostUrl.origin,[a])})}bindMessageListener(){this.bound||window.addEventListener(`message`,this.onMessage.bind(this)),this.bound=!0}async onMessage(e){if(!e||!e.data||typeof e.data!=`object`||e.data.type!==`idOS:signTypedData`||e.origin!==this.hostUrl.origin)return;let t=e.data.payload,n=await this.signTypedData(t.domain,t.types,t.value);await this.requestToEnclave(`signTypedDataResponse`,n)}};function j(){return typeof window<`u`}function ge(e){return e.client instanceof x}function M(e){return j()?new S({url:e,fetchFn:(e,t)=>fetch(e,{...t,credentials:`include`})}):new S({url:e})}function N(e,t){return ge(e.kwilClient)?o({url:e.blobGateway.url,kwilClient:e.kwilClient,signer:t}):l(t)?e.blobGateway.withAccessToken(t.accessToken):e.blobGateway}function P(e,t,n){if(e===`MM`)return u(t,n)}const F="This idOS client is stale: another signer was set or it was logged out. Use the client returned by the latest `withUserSigner()`.",I=new WeakMap,L=new WeakMap,R=new WeakMap,z=new WeakMap,B=new WeakMap,V=new WeakSet;function H(e){return I.get(e)??e}function U(e,t){if(e.signer!==t)throw Error(F)}function W(e,t){let n=H(e),r=t?L.get(n)?.get(t):void 0;if(r)return r;let i=()=>U(n,t),a={get signer(){return i(),n.signer},get client(){return i(),n.client},call:async(...e)=>(i(),n.call(...e)),execute:async(...e)=>(i(),n.execute(...e)),waitForTx:async e=>(i(),n.waitForTx(e)),setSigner:e=>{i(),n.setSigner(e)}};if(I.set(a,n),t){let e=L.get(n)??new WeakMap;e.set(t,a),L.set(n,e)}return a}function G(e){return e&&R.get(e)||e}function K(e,t,n){let r=G(e),i=n?z.get(r)?.get(n):void 0;if(i)return i;let a=new Proxy(r,{get(e,r){if(r===`then`||typeof r==`symbol`)return;let i=Reflect.get(e,r,e);return typeof i==`function`?(...r)=>(U(t,n),i.apply(e,r)):(U(t,n),i)}});if(R.set(a,r),n){let e=z.get(r)??new WeakMap;e.set(n,a),z.set(r,e)}return a}function q(e,t){let n=H(e),r=(B.get(n)??Promise.resolve()).then(t,t);return B.set(n,r.then(()=>void 0,()=>void 0)),r}function J(){return new Proxy({},{get(e,t){if(t!==`signer`&&t!==`then`&&typeof t!=`symbol`){if(t===`client`)throw Error(F);return t===`setSigner`?()=>{throw Error(F)}:async()=>{throw Error(F)}}}})}function _e(e,t){return new Z(e,J(),J(),M(t))}function Y(e,t,n,r,i){let a=H(t);return q(a,async()=>{let t=a.signer;return t!==void 0&&t!==n||(t===n&&(a.setSigner(void 0),V.add(a)),V.has(a)&&(await r.reset(),V.delete(a)),a.signer!==void 0&&a.signer!==n)?_e(e,i):new Z(e,a,r,M(i))})}var X=class{state;chainId;nodeUrl;blobGatewayUrl;enclaveOptions;store;enclaveProvider;constructor(e){this.state=`configuration`,this.chainId=e.chainId,this.nodeUrl=e.nodeUrl,this.blobGatewayUrl=e.blobGatewayUrl,this.enclaveOptions=e.enclaveOptions,this.store=e.store??(j()?new me:new O),this.enclaveProvider=e.enclaveProvider?new e.enclaveProvider({...e.enclaveOptions,store:this.store}):new A(e.enclaveOptions)}async createClient(){return Z.fromConfig(this)}},Z=class e{state;store;kwilClient;enclaveProvider;blobGateway;constructor(e,t,n,r){this.state=`idle`,this.store=e,this.kwilClient=t,this.enclaveProvider=n,this.blobGateway=r}static async fromConfig(t){let n=await(j()?c:s)({nodeUrl:t.nodeUrl,chainId:t.chainId});await t.enclaveProvider.load();let r=t.blobGatewayUrl??t.nodeUrl;return new e(t.store,n,t.enclaveProvider,M(r))}async addressHasProfile(e){return v(this.kwilClient,{address:e}).then(e=>e.has_profile)}async withUserSigner(e){let t=e,[n,r,i,o]=await a(this.store,this.kwilClient,t);if(o===`NEAR`){let e=t;t={signMessage:async t=>({signedMessage:await d(e,t)})}}return q(this.kwilClient,async()=>(this.kwilClient.setSigner(n),new Q(this,t,n,r,i,o,N(this,n))))}async logOut(){return this}},Q=class{state;store;#e;#t;signer;kwilSigner;walletIdentifier;walletPublicKey;walletType;blobGateway;constructor(e,t,n,r,i,a,o){this.state=`with-user-signer`,this.store=e.store,this.#e=e.kwilClient,this.#t=e.enclaveProvider,this.signer=t,this.kwilSigner=n,this.walletIdentifier=r,this.walletPublicKey=i,this.walletType=a,this.blobGateway=o,this.#t.setSigner(this.signer)}get kwilClient(){return W(this.#e,this.kwilSigner)}get enclaveProvider(){return K(this.#t,this.#e,this.kwilSigner)}async logOut(){return Y(this.store,this.#e,this.kwilSigner,this.#t,this.blobGateway.url)}async hasProfile(){return v(this.kwilClient,{address:this.walletIdentifier}).then(e=>e.has_profile)}async createUserEncryptionProfile(e,t){return await q(this.#e,async()=>{U(this.#e,this.kwilSigner),await this.enclaveProvider.reconfigure({mode:`new`,userId:e,walletAddress:this.walletIdentifier,walletPublicKey:this.walletPublicKey,walletType:this.walletType,encryptionPasswordStore:t,expectedUserEncryptionPublicKey:void 0}),U(this.#e,this.kwilSigner)}),U(this.#e,this.kwilSigner),this.enclaveProvider.ensureUserEncryptionProfile()}async logIn(){if(!await this.hasProfile())throw Error(`User does not have a profile`);let e=await se(this.kwilClient);return q(this.#e,async()=>(U(this.#e,this.kwilSigner),await this.enclaveProvider.reconfigure({mode:`existing`,userId:e.id,expectedUserEncryptionPublicKey:e.recipient_encryption_public_key,walletAddress:this.walletIdentifier,walletType:this.walletType,encryptionPasswordStore:e.encryption_password_store,walletPublicKey:this.walletPublicKey}),U(this.#e,this.kwilSigner),new $(this,e)))}},$=class{state;store;#e;#t;signer;kwilSigner;walletIdentifier;walletPublicKey;walletType;user;blobGateway;constructor(e,t){this.state=`logged-in`,this.store=e.store,this.#e=H(e.kwilClient),this.#t=G(e.enclaveProvider),this.signer=e.signer,this.kwilSigner=e.kwilSigner,this.walletIdentifier=e.walletIdentifier,this.walletPublicKey=e.walletPublicKey,this.walletType=e.walletType,this.user=t,this.blobGateway=e.blobGateway}get kwilClient(){return W(this.#e,this.kwilSigner)}get enclaveProvider(){return K(this.#t,this.#e,this.kwilSigner)}async logOut(){return Y(this.store,this.#e,this.kwilSigner,this.#t,this.blobGateway.url)}async requestDWGMessage(e){return te(this.kwilClient,e).then(e=>e.message)}async createCredential(e,r,i){let a=crypto.randomUUID(),o={...await t({publicNotes:e,plaintextContent:r,recipientEncryptionPublicKey:w(this.user.recipient_encryption_public_key),issuerSigningSecretKey:i,contentUri:P(this.walletType,this.kwilSigner,a)}),id:a};C(o.contentUri,this.blobGateway.hasAccessToken);let s=crypto.randomUUID(),c={request_id:s,credential_id:o.id,issuer_auth_public_key:o.issuerAuthPublicKey,encryptor_public_key:o.encryptorPublicKey,content_uri:o.contentUri,content_size:o.contentSize,content_hash:E(r),public_notes:o.publicNotes,public_notes_signature:o.publicNotesSignature,broader_signature:o.broaderSignature};return await ee(this.kwilClient,c),await this.blobGateway.uploadCredentialBlobs({requestId:s,original:o.encryptedContent}),n(o)}async removeCredential(e){let t=await this.getCredentialById(e);k(t,`"idOSCredential" with id ${e} not found`);let n=t.content_uri??null;return C(n,this.blobGateway.hasAccessToken),await le(this.kwilClient,{id:e}),n&&await this.blobGateway.deleteCredentialBlob({credentialId:e}),{id:e}}async getCredentialById(e){return ie(this.kwilClient,{id:e}).then(e=>e[0])}async shareCredential(e){return await y(this.kwilClient,e),e}async getAllCredentials(){return ae(this.kwilClient)}async getAccessGrantsOwned(){return re(this.kwilClient)}async getAttributes(){return g(this.kwilClient)}async createAttribute(e){return await f(this.kwilClient,e),e}async getCredentialContentSha256Hash(e){let t=await this.getCredentialById(e);k(t,`"idOSCredential" with id ${e} not found`);let n=await this.#r(t);return E(n)}async getCredentialContent(e){let t=await this.getCredentialById(e);k(t,`"idOSCredential" with id ${e} not found`);let n=await this.#r(t);return D(n)}async getCredentialWithEncryptedContent(e){let t=await this.getCredentialById(e);return k(t,`"idOSCredential" with id ${e} not found`),this.#n(t)}async getCredentialSharedContent(e){let t=await this.getCredentialShared(e);k(t,`Shared credential with id ${e} not found`);let n=await this.#r(t);return D(n)}async getGrants(e){return{grants:await oe(this.kwilClient,e),totalCount:await this.getGrantsCount()}}async addWallets(e){return await h(this.kwilClient,e),e}async getGrantsCount(){return ne(this.kwilClient,{user_id:null}).then(e=>e.count)}async getCredentialShared(e){return _(this.kwilClient,{id:e}).then(e=>e[0])}async revokeAccessGrant(e){return await de(this.kwilClient,{id:e}),{id:e}}async addWalletMessage(e){return(await m(this.kwilClient,e)).message}async addWallet(e){if(await p(this.kwilClient,e),this.user.encryption_password_store!==`mpc`)return console.log(`MPC is not enabled or the user is not using MPC`),e;if(!e.wallet_type)throw Error(`Wallet type is required for MPC users`);let t=await this.enclaveProvider.addAddressMessageToSign(e.address,e.public_key??void 0,e.wallet_type),n=await this.enclaveProvider.signTypedData(t.domain,t.types,t.value),r=await this.enclaveProvider.addAddressToMpcSecret(this.user.id,t.value,n);return r!==`success`&&console.error(`Failed to add wallet to MPC: ${r}`),e}async getWallets(){return ce(this.kwilClient)}async removeWallet(e){let t=(await this.getWallets()).find(t=>t.id===e);if(!t)throw Error(`Wallet with id ${e} not found`);if(await ue(this.kwilClient,{id:e}),this.user.encryption_password_store!==`mpc`)return console.log(`MPC is not enabled or the user is not using MPC`),{id:e};let n=await this.enclaveProvider.removeAddressMessageToSign(t.address,t.public_key??void 0,t.wallet_type),r=await this.enclaveProvider.signTypedData(n.domain,n.types,n.value),i=await this.enclaveProvider.removeAddressFromMpcSecret(t.user_id,n.value,r);return i!==`success`&&console.error(`Failed to add wallet to MPC: ${i}`),{id:e}}async removeWallets(e){for(let t of e)await this.removeWallet(t);return e}async filterCredentials(e){let t=(await this.getAllCredentials()).filter(e=>!e.original_id&&!!e.public_notes).filter(t=>e.acceptedIssuers?.some(e=>e.authPublicKey===t.issuer_auth_public_key)),n=e.publicNotesFieldFilters,a=e.credentialLevelOrHigherFilter,o=e.privateFieldFilters;if(a&&(t=t.filter(e=>{let t;try{t=JSON.parse(e.public_notes)}catch{throw Error(`Credential ${e.id} has non-JSON public notes.`)}return r(a.userLevel,a.requiredAddons,t.level)})),n&&(Object.keys(n.pick).length>0||Object.keys(n.omit).length>0)&&(t=t.filter(e=>{let t;try{t=JSON.parse(e.public_notes)}catch{throw Error(`Credential ${e.id} has non-JSON public notes.`)}return i(t,n.pick,n.omit)})),o&&(Object.keys(o.pick).length>0||Object.keys(o.omit).length>0)){let e=await Promise.all(t.map(e=>this.getCredentialById(e.id)));k(e.every(e=>e!==void 0),`Some credentials could not be fetched in full form for private field filtering`);let n=await this.enclaveProvider.filterCredentials(await Promise.all(e.map(e=>this.#n(e))),o);t=t.filter(e=>n.some(t=>t.id===e.id))}return t}async requestAccessGrant(t,{consumerEncryptionPublicKey:n,consumerAuthPublicKey:r,lockedUntil:i=0}){let a=await this.getCredentialById(t);k(a,`"idOSCredential" with id ${t} not found`);let o=await this.#r(a),s=E(o);await this.enclaveProvider.ensureUserEncryptionProfile();let{content:c,encryptorPublicKey:l}=await this.enclaveProvider.encrypt(o,w(n)),u=crypto.randomUUID(),d=P(this.walletType,this.kwilSigner,u);C(d,this.blobGateway.hasAccessToken);let f=d?{uri:d,size:c.byteLength}:await fe(c),p=e(``,f.uri),m=/^[0-9a-fA-F]{64}$/.test(r)?r.toLowerCase():r,h={...p,request_id:crypto.randomUUID(),copy_id:u,original_id:a.id,content_uri:f.uri,content_size:f.size,encryptor_public_key:T(l),grantee_wallet_identifier:m,locked_until:i,content_hash:s};return await this.shareCredential(h),await this.blobGateway.uploadCredentialBlobs({requestId:h.request_id,copy:c}),h}async#n(e){return e.content?e:{...e,content:T(await this.#i(e)),content_uri:null,content_size:null}}async#r(e){return await this.enclaveProvider.ensureUserEncryptionProfile(),this.enclaveProvider.decrypt(await this.#i(e),w(e.encryptor_public_key))}async#i(e){return pe(e,this.blobGateway)}};function ve(e){return new X({nodeUrl:e.nodeUrl,blobGatewayUrl:e.blobGatewayUrl,enclaveOptions:e.enclaveOptions})}export{A as IframeEnclave,ve as createIDOSClient,X as idOSClientConfiguration,Z as idOSClientIdle,$ as idOSClientLoggedIn,Q as idOSClientWithUserSigner,d as signNearMessage,b as toDelegatedWriteGrantBaseParams};
1
+ import{buildEphemeralSignedCredentialContentReference as e,buildPreliminaryIDOSCredential as t,mapPreliminaryToIDOSCredential as n,matchClaims as r,matchLevelOrHigher as i,recordFilter as a}from"@idos-network/credentials/utils";import{createClientKwilSigner as o,createKgwAuthenticatedBlobGateway as s,createNodeKwilClient as c,createWebKwilClient as l,isMmTokenAuth as u,mmTokenStorageId as d,signNearMessage as f}from"@idos-network/kwil-infra";import{addAttribute as p,addWallet as m,addWalletMessage as h,addWallets as ee,createPreliminaryCredential as g,credentialBroaderMessage as _,dwgMessage as te,getAccessGrantsGrantedCount as ne,getAccessGrantsOwned as re,getAttributes as ie,getCredentialOwned as ae,getCredentialShared as oe,getCredentials as se,getGrants as ce,getUser as le,getWallets as v,hasProfile as y,removeCredential as b,removeWallet as ue,revokeAccessGrant as de,sharePreliminaryCredential as fe,toDelegatedWriteGrantBaseParams as pe}from"@idos-network/kwil-infra/actions";import{NodeKwil as me}from"@idos-network/kwil-js";import{BlobGateway as x,BlobGatewayUploadOutcomeUnknownError as S,createBlobContentReference as he,createUkycContentReference as ge,requireAccessTokenForUkycContent as C,resolveCredentialEncryptedContent as _e}from"@idos-network/utils/blob-gateway";import{base64Decode as w,base64Encode as T,hexEncodeSha256Hash as E,utf8Decode as D}from"@idos-network/utils/codecs";import{LocalStorageStore as ve,MemoryStore as ye}from"@idos-network/utils/store";import O from"tiny-invariant";import{BaseProvider as be}from"@idos-network/enclave";var k=class extends be{container;iframe;hostUrl;bound=!1;constructor(e){if(super(e),!this.options.container)throw Error(`container is required`);this.container=this.options.container,this.hostUrl=new URL(this.options.url??`https://enclave.idos.network`),this.iframe=document.createElement(`iframe`),this.iframe.id=`idos-enclave-iframe`}async load(){await this.createAndLoadIframe(),await this.requestToEnclave(`load`),await this.reconfigure(),await this.bindMessageListener()}async reset(){throw Error(`Embedding pages cannot reset enclave storage`)}async reconfigure(e={}){super.reconfigure(e),await this.requestToEnclave(`reconfigure`,this.options)}async confirm(e){this.showEnclave();try{return await this.requestToEnclave(`confirm`,e)}catch(e){return console.error(e),!1}finally{this.hideEnclave()}}async filterCredentials(e,t){return await this.requestToEnclave(`filterCredentials`,e,t)}async encrypt(e,t){return this.requestToEnclave(`encrypt`,e,t)}async decrypt(e,t){return this.requestToEnclave(`decrypt`,e,t)}async backupUserEncryptionProfile(){this.showEnclave();try{await this.requestToEnclave(`backupUserEncryptionProfile`)}catch(e){console.error(e)}finally{this.hideEnclave()}}async ensureUserEncryptionProfile(){this.showEnclave();try{return await this.requestToEnclave(`ensureUserEncryptionProfile`)}finally{this.hideEnclave()}}async addAddressMessageToSign(e,t,n){return this.requestToEnclave(`addAddressMessageToSign`,e,t,n)}async removeAddressMessageToSign(e,t,n){return this.requestToEnclave(`removeAddressMessageToSign`,e,t,n)}async addAddressToMpcSecret(e,t,n){return this.requestToEnclave(`addAddressToMpcSecret`,e,t,n)}async removeAddressFromMpcSecret(e,t,n){return this.requestToEnclave(`removeAddressFromMpcSecret`,e,t,n)}async createAndLoadIframe(){let e=document.querySelector(this.container);if(!e)throw Error(`Can't find container with selector ${this.container}`);let t=[`publickey-credentials-get`,`storage-access`],n=[`forms`,`modals`,`popups`,`popups-to-escape-sandbox`,`same-origin`,`scripts`].map(e=>`allow-${e}`),r={"aspect-ratio":`4/1`,"background-color":`transparent`,border:`none`,display:`block`,overflow:`hidden`,width:`100%`};this.iframe.allow=t.join(`; `),this.iframe.referrerPolicy=`origin`,this.iframe.sandbox.add(...n),this.iframe.src=this.hostUrl.toString();for(let[e,t]of Object.entries(r))this.iframe.style.setProperty(e,t);let i;for(;i=document.getElementById(this.iframe.id);)console.log(`reinstalling idOS iframe...`),e.removeChild(i);return e.appendChild(this.iframe),new Promise(e=>this.iframe.addEventListener(`load`,()=>{e()},{once:!0}))}showEnclave(){this.iframe.parentElement.classList.add(`visible`)}hideEnclave(){this.iframe.parentElement.classList.remove(`visible`)}async requestToEnclave(e,...t){return new Promise((n,r)=>{let{port1:i,port2:a}=new MessageChannel;i.onmessage=({data:e})=>{i.close(),e.error?r(e.error):n(e.result)},this.iframe.contentWindow.postMessage({method:e,data:t},this.hostUrl.origin,[a])})}bindMessageListener(){this.bound||window.addEventListener(`message`,this.onMessage.bind(this)),this.bound=!0}async onMessage(e){if(!e||!e.data||typeof e.data!=`object`||e.data.type!==`idOS:signTypedData`||e.origin!==this.hostUrl.origin)return;let t=e.data.payload,n=await this.signTypedData(t.domain,t.types,t.value);await this.requestToEnclave(`signTypedDataResponse`,n)}};function A(){return typeof window<`u`}function j(e){return e.client instanceof me}function M(e){return A()?new x({url:e,fetchFn:(e,t)=>fetch(e,{...t,credentials:`include`})}):new x({url:e})}function xe(e,t){return j(e.kwilClient)?s({url:e.blobGateway.url,kwilClient:e.kwilClient,signer:t}):u(t)?e.blobGateway.withAccessToken(t.accessToken):e.blobGateway}function N(e,t){if(e===`MM`)return d(t)}function Se(e,t){return e.byteLength===t.byteLength&&e.every((e,n)=>e===t[n])}const P="This idOS client is stale: another signer was set or it was logged out. Use the client returned by the latest `withUserSigner()`.",F=new WeakMap,I=new WeakMap,L=new WeakMap,R=new WeakMap,z=new WeakMap,B=new WeakSet;function V(e){return F.get(e)??e}function H(e,t){if(e.signer!==t)throw Error(P)}function U(e,t){let n=V(e),r=t?I.get(n)?.get(t):void 0;if(r)return r;let i=()=>H(n,t),a={get signer(){return i(),n.signer},get client(){return i(),n.client},call:async(...e)=>(i(),n.call(...e)),execute:async(...e)=>(i(),n.execute(...e)),waitForTx:async e=>(i(),n.waitForTx(e)),setSigner:e=>{i(),n.setSigner(e)}};if(F.set(a,n),t){let e=I.get(n)??new WeakMap;e.set(t,a),I.set(n,e)}return a}function W(e){return e&&L.get(e)||e}function G(e,t,n){let r=W(e),i=n?R.get(r)?.get(n):void 0;if(i)return i;let a=new Proxy(r,{get(e,r){if(r===`then`||typeof r==`symbol`)return;let i=Reflect.get(e,r,e);return typeof i==`function`?(...r)=>(H(t,n),i.apply(e,r)):(H(t,n),i)}});if(L.set(a,r),n){let e=R.get(r)??new WeakMap;e.set(n,a),R.set(r,e)}return a}function K(e,t){let n=V(e),r=(z.get(n)??Promise.resolve()).then(t,t);return z.set(n,r.then(()=>void 0,()=>void 0)),r}function q(){return new Proxy({},{get(e,t){if(t!==`signer`&&t!==`then`&&typeof t!=`symbol`){if(t===`client`)throw Error(P);return t===`setSigner`?()=>{throw Error(P)}:async()=>{throw Error(P)}}}})}function Ce(e,t){return new X(e,q(),q(),M(t))}function J(e,t,n,r,i){let a=V(t);return K(a,async()=>{let t=a.signer;return t!==void 0&&t!==n||(t===n&&(a.setSigner(void 0),B.add(a)),B.has(a)&&(await r.reset(),B.delete(a)),a.signer!==void 0&&a.signer!==n)?Ce(e,i):new X(e,a,r,M(i))})}var Y=class{state;chainId;nodeUrl;blobGatewayUrl;enclaveOptions;store;enclaveProvider;constructor(e){this.state=`configuration`,this.chainId=e.chainId,this.nodeUrl=e.nodeUrl,this.blobGatewayUrl=e.blobGatewayUrl,this.enclaveOptions=e.enclaveOptions,this.store=e.store??(A()?new ve:new ye),this.enclaveProvider=e.enclaveProvider?new e.enclaveProvider({...e.enclaveOptions,store:this.store}):new k(e.enclaveOptions)}async createClient(){return X.fromConfig(this)}},X=class e{state;store;kwilClient;enclaveProvider;blobGateway;constructor(e,t,n,r){this.state=`idle`,this.store=e,this.kwilClient=t,this.enclaveProvider=n,this.blobGateway=r}static async fromConfig(t){let n=await(A()?l:c)({nodeUrl:t.nodeUrl,chainId:t.chainId});await t.enclaveProvider.load();let r=t.blobGatewayUrl??t.nodeUrl;return new e(t.store,n,t.enclaveProvider,M(r))}async addressHasProfile(e){return y(this.kwilClient,{address:e}).then(e=>{if(!e)throw Error(`has_profile returned no rows`);return e.has_profile})}async withUserSigner(e){let t=e,[n,r,i,a]=await o(this.store,this.kwilClient,t);if(a===`NEAR`){let e=t;t={signMessage:async t=>({signedMessage:await f(e,t)})}}return K(this.kwilClient,async()=>(this.kwilClient.setSigner(n),new Z(this,t,n,r,i,a,xe(this,n))))}async logOut(){return this}},Z=class{state;store;#e;#t;signer;kwilSigner;walletIdentifier;walletPublicKey;walletType;blobGateway;constructor(e,t,n,r,i,a,o){this.state=`with-user-signer`,this.store=e.store,this.#e=e.kwilClient,this.#t=e.enclaveProvider,this.signer=t,this.kwilSigner=n,this.walletIdentifier=r,this.walletPublicKey=i,this.walletType=a,this.blobGateway=o,this.#t.setSigner(this.signer)}get kwilClient(){return U(this.#e,this.kwilSigner)}get enclaveProvider(){return G(this.#t,this.#e,this.kwilSigner)}async logOut(){return J(this.store,this.#e,this.kwilSigner,this.#t,this.blobGateway.url)}async hasProfile(){let e=this.walletIdentifier;if(this.walletType===`NEAR`){if(!this.walletPublicKey)throw Error(`NEAR wallet public key is required`);e=this.walletPublicKey}return y(this.kwilClient,{address:e}).then(e=>{if(!e)throw Error(`has_profile returned no rows`);return e.has_profile})}async createUserEncryptionProfile(e,t){return await K(this.#e,async()=>{H(this.#e,this.kwilSigner),await this.enclaveProvider.reconfigure({mode:`new`,userId:e,walletAddress:this.walletIdentifier,walletPublicKey:this.walletPublicKey,walletType:this.walletType,encryptionPasswordStore:t,expectedUserEncryptionPublicKey:void 0}),H(this.#e,this.kwilSigner)}),H(this.#e,this.kwilSigner),this.enclaveProvider.ensureUserEncryptionProfile()}async logIn(){if(!await this.hasProfile())throw Error(`User does not have a profile`);let e=await le(this.kwilClient);return K(this.#e,async()=>(H(this.#e,this.kwilSigner),await this.enclaveProvider.reconfigure({mode:`existing`,userId:e.id,expectedUserEncryptionPublicKey:e.recipient_encryption_public_key,walletAddress:this.walletIdentifier,walletType:this.walletType,encryptionPasswordStore:e.encryption_password_store,walletPublicKey:this.walletPublicKey}),H(this.#e,this.kwilSigner),new $(this,e)))}};function Q(e){if(e.walletType===`NEAR`){if(!e.walletPublicKey)throw Error(`NEAR wallet public key is required`);return e.walletPublicKey}return e.walletIdentifier}var $=class{state;store;#e;#t;signer;kwilSigner;walletIdentifier;walletPublicKey;walletType;user;blobGateway;constructor(e,t){this.state=`logged-in`,this.store=e.store,this.#e=V(e.kwilClient),this.#t=W(e.enclaveProvider),this.signer=e.signer,this.kwilSigner=e.kwilSigner,this.walletIdentifier=e.walletIdentifier,this.walletPublicKey=e.walletPublicKey,this.walletType=e.walletType,this.user=t,this.blobGateway=e.blobGateway}get kwilClient(){return U(this.#e,this.kwilSigner)}get enclaveProvider(){return G(this.#t,this.#e,this.kwilSigner)}async logOut(){return J(this.store,this.#e,this.kwilSigner,this.#t,this.blobGateway.url)}async requestDWGMessage(e){return te(this.kwilClient,e).then(e=>{if(!e)throw Error(`dwg_message returned no rows`);return e.message})}async createCredential(e,r,i){let a=crypto.randomUUID(),o={...await t({publicNotes:e,plaintextContent:r,recipientEncryptionPublicKey:w(this.user.recipient_encryption_public_key),broaderMessageFor:(e,t)=>_(this.kwilClient,{public_notes_signature:e,content_uri:t,recipient_wallet:Q(this)}).then(e=>e.message),issuerSigningSecretKey:i,ukycStorageId:N(this.walletType,this.kwilSigner)}),id:a};C(o.contentUri,this.blobGateway.hasAccessToken);let s=crypto.randomUUID(),c={request_id:s,credential_id:o.id,issuer_auth_public_key:o.issuerAuthPublicKey,encryptor_public_key:o.encryptorPublicKey,content_uri:o.contentUri,content_size:o.contentSize,content_hash:E(r),public_notes:o.publicNotes,public_notes_signature:o.publicNotesSignature,broader_signature:o.broaderSignature};return await g(this.kwilClient,c),await this.#n({requestId:s,credentialIds:[o.id],original:o.encryptedContent}),n(o)}async#n(e){try{await this.blobGateway.uploadCredentialBlobs(e)}catch(t){if(!(t instanceof S))throw t;let n=await this.getCredentialById(e.credentialIds[0]).catch(()=>void 0);if(!n?.content_uri)throw t;let r=new AbortController,i=setTimeout(()=>r.abort(),6e4),a=await this.blobGateway.fetchBlob({credentialId:n.id,contentUri:n.content_uri,expectedSize:n.content_size,signal:r.signal}).catch(()=>void 0).finally(()=>clearTimeout(i)),o=e.original??e.copy;if(!a||!Se(a,o))throw t}}async removeCredential(e){let t=await this.getCredentialById(e);O(t,`"idOSCredential" with id ${e} not found`);let n=t.content_uri??null;return C(n,this.blobGateway.hasAccessToken),await b(this.kwilClient,{id:e}),n&&await this.blobGateway.deleteCredentialBlob({credentialId:e}),{id:e}}async getCredentialById(e){return ae(this.kwilClient,{id:e}).then(e=>e[0])}async shareCredential(e){return await fe(this.kwilClient,e),e}async getAllCredentials(){return se(this.kwilClient)}async getAccessGrantsOwned(){return re(this.kwilClient)}async getAttributes(){return ie(this.kwilClient)}async createAttribute(e){return await p(this.kwilClient,e),e}async getCredentialContentSha256Hash(e){let t=await this.getCredentialById(e);O(t,`"idOSCredential" with id ${e} not found`);let n=await this.#i(t);return E(n)}async getCredentialContent(e){let t=await this.getCredentialById(e);O(t,`"idOSCredential" with id ${e} not found`);let n=await this.#i(t);return D(n)}async getCredentialWithEncryptedContent(e){let t=await this.getCredentialById(e);return O(t,`"idOSCredential" with id ${e} not found`),this.#r(t)}async getCredentialSharedContent(e){let t=await this.getCredentialShared(e);O(t,`Shared credential with id ${e} not found`);let n=await this.#i(t);return D(n)}async getGrants(e){return{grants:await ce(this.kwilClient,e),totalCount:await this.getGrantsCount()}}async addWallets(e){return await ee(this.kwilClient,e),e}async getGrantsCount(){return ne(this.kwilClient,{user_id:null}).then(e=>{if(!e)throw Error(`get_access_grants_granted_count returned no rows`);return e.count})}async getCredentialShared(e){return oe(this.kwilClient,{id:e}).then(e=>e[0])}async revokeAccessGrant(e){return await de(this.kwilClient,{id:e}),{id:e}}async addWalletMessage(e){return(await h(this.kwilClient,e)).message}async addWallet(e){if(await m(this.kwilClient,e),this.user.encryption_password_store!==`mpc`)return console.log(`MPC is not enabled or the user is not using MPC`),e;if(!e.wallet_type)throw Error(`Wallet type is required for MPC users`);let t=await this.enclaveProvider.addAddressMessageToSign(e.address,e.public_key??void 0,e.wallet_type),n=await this.enclaveProvider.signTypedData(t.domain,t.types,t.value),r=await this.enclaveProvider.addAddressToMpcSecret(this.user.id,t.value,n);return r!==`success`&&console.error(`Failed to add wallet to MPC: ${r}`),e}async getWallets(){return v(this.kwilClient)}async removeWallet(e){let t=(await this.getWallets()).find(t=>t.id===e);if(!t)throw Error(`Wallet with id ${e} not found`);if(await ue(this.kwilClient,{id:e}),this.user.encryption_password_store!==`mpc`)return console.log(`MPC is not enabled or the user is not using MPC`),{id:e};let n=await this.enclaveProvider.removeAddressMessageToSign(t.address,t.public_key??void 0,t.wallet_type),r=await this.enclaveProvider.signTypedData(n.domain,n.types,n.value),i=await this.enclaveProvider.removeAddressFromMpcSecret(t.user_id,n.value,r);return i!==`success`&&console.error(`Failed to add wallet to MPC: ${i}`),{id:e}}async removeWallets(e){for(let t of e)await this.removeWallet(t);return e}async filterCredentials(e){let t=(await this.getAllCredentials()).filter(e=>!e.original_id&&!!e.public_notes).filter(t=>e.acceptedIssuers?.some(e=>e.authPublicKey===t.issuer_auth_public_key)),n=e.publicNotesFieldFilters,o=e.credentialLevelOrHigherFilter,s=e.privateFieldFilters,c=e.claimsFilter;if(c&&(t=t.filter(e=>{let t;try{t=JSON.parse(e.public_notes)}catch{throw Error(`Credential ${e.id} has non-JSON public notes.`)}return r(c,t)})),o&&(t=t.filter(e=>{let t;try{t=JSON.parse(e.public_notes)}catch{throw Error(`Credential ${e.id} has non-JSON public notes.`)}return i(o.userLevel,o.requiredAddons,t.level)})),n&&(Object.keys(n.pick).length>0||Object.keys(n.omit).length>0)&&(t=t.filter(e=>{let t;try{t=JSON.parse(e.public_notes)}catch{throw Error(`Credential ${e.id} has non-JSON public notes.`)}return a(t,n.pick,n.omit)})),s&&(Object.keys(s.pick).length>0||Object.keys(s.omit).length>0)){let e=await Promise.all(t.map(e=>this.getCredentialById(e.id)));O(e.every(e=>e!==void 0),`Some credentials could not be fetched in full form for private field filtering`);let n=await this.enclaveProvider.filterCredentials(await Promise.all(e.map(e=>this.#r(e))),s);t=t.filter(e=>n.some(t=>t.id===e.id))}return t}async requestAccessGrant(t,{consumerEncryptionPublicKey:n,consumerAuthPublicKey:r,lockedUntil:i=0}){let a=await this.getCredentialById(t);O(a,`"idOSCredential" with id ${t} not found`);let o=await this.#i(a),s=E(o);await this.enclaveProvider.ensureUserEncryptionProfile();let{content:c,encryptorPublicKey:l}=await this.enclaveProvider.encrypt(o,w(n)),u=crypto.randomUUID(),d=N(this.walletType,this.kwilSigner),f=d?ge(d,c):await he(c);C(f.uri,this.blobGateway.hasAccessToken);let p=await e(``,f.uri,(e,t)=>_(this.kwilClient,{public_notes_signature:e,content_uri:t,recipient_wallet:Q(this)}).then(e=>e.message)),m=/^[0-9a-fA-F]{64}$/.test(r)?r.toLowerCase():r,h={...p,request_id:crypto.randomUUID(),copy_id:u,original_id:a.id,content_uri:f.uri,content_size:f.size,encryptor_public_key:T(l),grantee_wallet_identifier:m,locked_until:i,content_hash:s};return await this.shareCredential(h),await this.#n({requestId:h.request_id,credentialIds:[u],copy:c}),h}async#r(e){return e.content?e:{...e,content:T(await this.#a(e)),content_uri:null,content_size:null}}async#i(e){return await this.enclaveProvider.ensureUserEncryptionProfile(),this.enclaveProvider.decrypt(await this.#a(e),w(e.encryptor_public_key))}async#a(e){return _e(e,this.blobGateway)}};function we(e){return new Y({nodeUrl:e.nodeUrl,blobGatewayUrl:e.blobGatewayUrl,enclaveOptions:e.enclaveOptions})}export{k as IframeEnclave,we as createIDOSClient,Y as idOSClientConfiguration,X as idOSClientIdle,$ as idOSClientLoggedIn,Z as idOSClientWithUserSigner,f as signNearMessage,pe as toDelegatedWriteGrantBaseParams};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["createAttribute","requestAddWalletMessage"],"sources":["../src/enclave/iframe-enclave.ts","../src/index.ts"],"sourcesContent":["import type { idOSCredentialRecord as idOSCredential } from \"@idos-network/credentials/types\";\nimport type {\n AddAddressMessageToSign,\n AddAddressSignatureMessage,\n RemoveAddressMessageToSign,\n RemoveAddressSignatureMessage,\n} from \"@idos-network/enclave/mpc\";\n\nimport {\n BaseProvider,\n type EnclaveOptions,\n type PublicEncryptionProfile,\n} from \"@idos-network/enclave\";\n\nimport type { BaseProviderMethodArgs, BaseProviderMethodReturn } from \"./helpers\";\n\nexport interface IframeEnclaveOptions extends EnclaveOptions {\n container: string;\n url?: string;\n throwOnUserCancelUnlock?: boolean;\n}\n\nexport class IframeEnclave extends BaseProvider<IframeEnclaveOptions> {\n private container: string;\n private iframe: HTMLIFrameElement;\n private hostUrl: URL;\n private bound = false;\n\n constructor(options: IframeEnclaveOptions) {\n super(options);\n\n if (!this.options.container) {\n throw new Error(\"container is required\");\n }\n\n this.container = this.options.container;\n this.hostUrl = new URL(this.options.url ?? \"https://enclave.idos.network\");\n this.iframe = document.createElement(\"iframe\");\n this.iframe.id = \"idos-enclave-iframe\";\n }\n\n /** @see parent method */\n async load(): Promise<void> {\n // First we have to create and load the iframe\n await this.createAndLoadIframe();\n\n // Load the enclave from the store (trigger load() method in the iframe)\n await this.requestToEnclave(\"load\");\n\n // Pass current options\n await this.reconfigure();\n\n // Bind the message listener to the iframe (in case iframe -> enclave comm)\n await this.bindMessageListener();\n }\n\n /**\n * Embedding pages cannot reset enclave storage. The iframe rejects `reset`\n * because it deletes every idOS-* key with no origin check.\n */\n async reset(): Promise<void> {\n throw new Error(\"Embedding pages cannot reset enclave storage\");\n }\n\n /** @override parent method to call iframe */\n async reconfigure(options: Omit<IframeEnclaveOptions, \"container\" | \"url\"> = {}): Promise<void> {\n super.reconfigure(options);\n await this.requestToEnclave(\"reconfigure\", this.options);\n }\n\n /** @override parent method to call iframe */\n async confirm(message: string): Promise<boolean> {\n this.showEnclave();\n\n try {\n return await this.requestToEnclave(\"confirm\", message);\n } catch (error) {\n console.error(error);\n return false;\n } finally {\n this.hideEnclave();\n }\n }\n\n /** @override parent method to call iframe */\n async filterCredentials(\n credentials: idOSCredential[],\n privateFieldFilters: { pick: Record<string, unknown[]>; omit: Record<string, unknown[]> },\n ): Promise<idOSCredential[]> {\n return await this.requestToEnclave(\"filterCredentials\", credentials, privateFieldFilters);\n }\n\n /** @override parent method to call iframe */\n async encrypt(\n message: Uint8Array,\n receiverPublicKey: Uint8Array,\n ): Promise<{ content: Uint8Array; encryptorPublicKey: Uint8Array }> {\n return this.requestToEnclave(\"encrypt\", message, receiverPublicKey);\n }\n\n /** @override parent method to call iframe */\n async decrypt(\n message: Uint8Array,\n senderPublicKey: Uint8Array,\n ): Promise<Uint8Array<ArrayBufferLike>> {\n return this.requestToEnclave(\"decrypt\", message, senderPublicKey);\n }\n\n /** @override parent method to call iframe */\n async backupUserEncryptionProfile(): Promise<void> {\n this.showEnclave();\n\n try {\n await this.requestToEnclave(\"backupUserEncryptionProfile\");\n } catch (error) {\n console.error(error);\n } finally {\n this.hideEnclave();\n }\n }\n\n /** @override parent method to call iframe */\n async ensureUserEncryptionProfile(): Promise<PublicEncryptionProfile> {\n this.showEnclave();\n\n try {\n return await this.requestToEnclave(\"ensureUserEncryptionProfile\");\n } finally {\n this.hideEnclave();\n }\n }\n\n async addAddressMessageToSign(\n address: string,\n publicKey: string | undefined,\n addressToAddType: string,\n ): Promise<AddAddressMessageToSign> {\n return this.requestToEnclave(\"addAddressMessageToSign\", address, publicKey, addressToAddType);\n }\n\n async removeAddressMessageToSign(\n address: string,\n publicKey: string | undefined,\n addressToRemoveType: string,\n ): Promise<RemoveAddressMessageToSign> {\n return this.requestToEnclave(\n \"removeAddressMessageToSign\",\n address,\n publicKey,\n addressToRemoveType,\n );\n }\n\n async addAddressToMpcSecret(\n userId: string,\n message: AddAddressSignatureMessage,\n signature: string,\n ): Promise<string> {\n return this.requestToEnclave(\"addAddressToMpcSecret\", userId, message, signature);\n }\n\n async removeAddressFromMpcSecret(\n userId: string,\n message: RemoveAddressSignatureMessage,\n signature: string,\n ): Promise<string> {\n return this.requestToEnclave(\"removeAddressFromMpcSecret\", userId, message, signature);\n }\n\n private async createAndLoadIframe(): Promise<void> {\n const container = document.querySelector(this.container);\n\n if (!container) {\n throw new Error(`Can't find container with selector ${this.container}`);\n }\n\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy#directives\n const permissionsPolicies = [\"publickey-credentials-get\", \"storage-access\"];\n\n // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox\n const liftedSandboxRestrictions = [\n \"forms\",\n \"modals\",\n \"popups\",\n \"popups-to-escape-sandbox\",\n \"same-origin\",\n \"scripts\",\n ].map((toLift) => `allow-${toLift}`);\n\n // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#referrerpolicy\n const referrerPolicy = \"origin\";\n\n const styles = {\n \"aspect-ratio\": \"4/1\",\n \"background-color\": \"transparent\",\n border: \"none\",\n display: \"block\",\n overflow: \"hidden\",\n width: \"100%\",\n };\n\n this.iframe.allow = permissionsPolicies.join(\"; \");\n this.iframe.referrerPolicy = referrerPolicy;\n this.iframe.sandbox.add(...liftedSandboxRestrictions);\n this.iframe.src = this.hostUrl.toString();\n for (const [k, v] of Object.entries(styles)) {\n this.iframe.style.setProperty(k, v);\n }\n\n let el: HTMLElement | null;\n // oxlint-disable-next-line no-cond-assign -- it's on purpose\n while ((el = document.getElementById(this.iframe.id))) {\n console.log(\"reinstalling idOS iframe...\");\n container.removeChild(el);\n }\n container.appendChild(this.iframe);\n\n return new Promise((resolve) =>\n this.iframe.addEventListener(\n \"load\",\n () => {\n resolve();\n },\n { once: true },\n ),\n );\n }\n\n private showEnclave(): void {\n // oxlint-disable-next-line typescript/no-non-null-assertion -- Make the explosion visible.\n this.iframe.parentElement!.classList.add(\"visible\");\n }\n\n private hideEnclave(): void {\n // oxlint-disable-next-line typescript/no-non-null-assertion -- Make the explosion visible.\n this.iframe.parentElement!.classList.remove(\"visible\");\n }\n\n private async requestToEnclave<TMethod extends keyof BaseProviderMethodArgs>(\n method: TMethod,\n ...args: BaseProviderMethodArgs[TMethod]\n ): Promise<BaseProviderMethodReturn[TMethod]> {\n return new Promise((resolve, reject) => {\n const { port1, port2 } = new MessageChannel();\n\n port1.onmessage = ({ data }) => {\n port1.close();\n // oxlint-disable-next-line no-unused-expressions\n data.error ? reject(data.error) : resolve(data.result);\n };\n\n // oxlint-disable-next-line typescript/no-non-null-assertion -- Make the explosion visible.\n this.iframe.contentWindow!.postMessage(\n {\n method,\n data: args,\n },\n this.hostUrl.origin,\n [port2],\n );\n });\n }\n\n private bindMessageListener(): void {\n if (!this.bound) window.addEventListener(\"message\", this.onMessage.bind(this));\n this.bound = true;\n }\n\n private async onMessage(message: MessageEvent): Promise<void> {\n // We can't be sure about the message and the content\n // so we have to validate it carefully.\n if (!message || !message.data || typeof message.data !== \"object\") return;\n\n if (message.data.type !== \"idOS:signTypedData\" || message.origin !== this.hostUrl.origin)\n return;\n\n const payload = message.data.payload;\n const signature = await this.signTypedData(payload.domain, payload.types, payload.value);\n await this.requestToEnclave(\"signTypedDataResponse\", signature);\n }\n}\n","import type {\n BaseProvider,\n EncryptionPasswordStore,\n PublicEncryptionProfile,\n} from \"@idos-network/enclave\";\n\nimport {\n buildEphemeralSignedCredentialContentReference,\n buildPreliminaryIDOSCredential,\n mapPreliminaryToIDOSCredential,\n matchLevelOrHigher,\n type PreliminaryIDOSCredential,\n recordFilter,\n type BaseLevel,\n type Addon,\n} from \"@idos-network/credentials/utils\";\nimport {\n createClientKwilSigner,\n createKgwAuthenticatedBlobGateway,\n createNodeKwilClient,\n createWebKwilClient,\n isMmTokenAuth,\n type KwilActionClient,\n mmTokenCredentialContentUri,\n signNearMessage,\n type Wallet,\n} from \"@idos-network/kwil-infra\";\nimport {\n type AddAttributeInput,\n type AddWalletInput,\n type AddWalletMessageInput,\n addWallet,\n addWalletMessage as requestAddWalletMessage,\n addWallets,\n addAttribute as createAttribute,\n createPreliminaryCredential,\n type CreatePreliminaryCredentialInput,\n dwgMessage,\n type GetAccessGrantsGrantedInput,\n type GetWalletsOutput,\n getAccessGrantsGrantedCount,\n getAccessGrantsOwned,\n getAttributes,\n getCredentialOwned,\n getCredentialShared,\n getCredentials,\n getGrants,\n getUser,\n getWallets,\n hasProfile,\n type idOSCredential,\n type idOSCredentialListItem,\n type idOSDelegatedWriteGrant,\n type DelegatedWriteGrantBaseParams,\n toDelegatedWriteGrantBaseParams,\n type idOSGrant,\n type idOSUser,\n type idOSUserAttribute,\n type idOSWallet,\n removeCredential,\n removeWallet,\n revokeAccessGrant,\n type SharePreliminaryCredentialInput,\n sharePreliminaryCredential,\n type WalletType,\n} from \"@idos-network/kwil-infra/actions\";\nimport { NodeKwil, type KwilSigner } from \"@idos-network/kwil-js\";\nimport {\n BlobGateway,\n createBlobContentReference,\n requireAccessTokenForUkycContent,\n resolveCredentialEncryptedContent,\n} from \"@idos-network/utils/blob-gateway\";\nimport {\n base64Decode,\n base64Encode,\n hexEncodeSha256Hash,\n utf8Decode,\n} from \"@idos-network/utils/codecs\";\nimport { LocalStorageStore, MemoryStore, type Store } from \"@idos-network/utils/store\";\nimport invariant from \"tiny-invariant\";\n\nimport { IframeEnclave } from \"./enclave/iframe-enclave\";\nexport { IframeEnclave };\n\ntype Properties<T> = {\n // oxlint-disable-next-line typescript/no-restricted-types -- All functions are to be removed.\n [K in keyof T as Exclude<T[K], Function> extends never ? never : K]: T[K];\n};\n\nfunction isBrowserRuntime(): boolean {\n return typeof window !== \"undefined\";\n}\n\nfunction usesNodeKwil(kwilClient: KwilActionClient): boolean {\n return kwilClient.client instanceof NodeKwil;\n}\n\nfunction idleBlobGateway(url: string): BlobGateway {\n if (!isBrowserRuntime()) {\n return new BlobGateway({ url });\n }\n\n return new BlobGateway({\n url,\n // Browser blob reads need the KGW HttpOnly session cookie. That only works if the\n // blob gateway is covered by the cookie's Domain (typically same host as nodeUrl/KGW).\n fetchFn: (input, init) => fetch(input, { ...init, credentials: \"include\" }),\n });\n}\n\nfunction blobGatewayForSigner(idle: idOSClientIdle, kwilSigner: KwilSigner): BlobGateway {\n if (usesNodeKwil(idle.kwilClient)) {\n return createKgwAuthenticatedBlobGateway({\n url: idle.blobGateway.url,\n kwilClient: idle.kwilClient,\n signer: kwilSigner,\n });\n }\n\n return isMmTokenAuth(kwilSigner)\n ? idle.blobGateway.withAccessToken(kwilSigner.accessToken)\n : idle.blobGateway;\n}\n\nfunction contentUriForWallet(\n walletType: WalletType,\n kwilSigner: KwilSigner,\n credentialId: string,\n): string | undefined {\n if (walletType !== \"MM\") {\n return undefined;\n }\n return mmTokenCredentialContentUri(kwilSigner, credentialId);\n}\n\nconst STALE_CLIENT =\n \"This idOS client is stale: another signer was set or it was logged out. Use the client returned by the latest `withUserSigner()`.\";\n\n// Wrappers from one idle client share its Kwil client and enclave. `rawOf` unwraps the\n// guard below; `turns` keeps signer replacement and enclave reconfiguration from interleaving.\nconst rawOf = new WeakMap<KwilActionClient, KwilActionClient>();\nconst boundOf = new WeakMap<KwilActionClient, WeakMap<KwilSigner, KwilActionClient>>();\nconst rawEnclaveOf = new WeakMap<BaseProvider, BaseProvider>();\nconst boundEnclaveOf = new WeakMap<BaseProvider, WeakMap<KwilSigner, BaseProvider>>();\nconst turns = new WeakMap<KwilActionClient, Promise<void>>();\nconst resetPending = new WeakSet<KwilActionClient>();\n\nfunction sharedKwilClient(kwilClient: KwilActionClient): KwilActionClient {\n return rawOf.get(kwilClient) ?? kwilClient;\n}\n\nfunction assertSigner(kwilClient: KwilActionClient, kwilSigner: KwilSigner): void {\n if (kwilClient.signer !== kwilSigner) throw new Error(STALE_CLIENT);\n}\n\n// shortcut: guards call/execute/waitForTx/setSigner only; wrap any new KwilActionClient method here.\nfunction boundKwilClient(kwilClient: KwilActionClient, kwilSigner: KwilSigner): KwilActionClient {\n const raw = sharedKwilClient(kwilClient);\n const cached = kwilSigner ? boundOf.get(raw)?.get(kwilSigner) : undefined;\n if (cached) return cached;\n\n const guard = (): void => assertSigner(raw, kwilSigner);\n const bound = {\n get signer() {\n guard();\n return raw.signer;\n },\n get client() {\n guard();\n return raw.client;\n },\n call: async (...args: Parameters<KwilActionClient[\"call\"]>) => {\n guard();\n return raw.call(...args);\n },\n execute: async (...args: Parameters<KwilActionClient[\"execute\"]>) => {\n guard();\n return raw.execute(...args);\n },\n waitForTx: async (txHash: string) => {\n guard();\n return raw.waitForTx(txHash);\n },\n setSigner: (signer: KwilSigner | undefined) => {\n guard();\n raw.setSigner(signer);\n },\n } as KwilActionClient;\n\n rawOf.set(bound, raw);\n if (kwilSigner) {\n const bySigner = boundOf.get(raw) ?? new WeakMap<KwilSigner, KwilActionClient>();\n bySigner.set(kwilSigner, bound);\n boundOf.set(raw, bySigner);\n }\n return bound;\n}\n\nfunction sharedEnclave(enclave: BaseProvider): BaseProvider {\n return (enclave && rawEnclaveOf.get(enclave)) || enclave;\n}\n\nfunction boundEnclave(\n enclave: BaseProvider,\n kwilClient: KwilActionClient,\n kwilSigner: KwilSigner,\n): BaseProvider {\n const raw = sharedEnclave(enclave);\n const cached = kwilSigner ? boundEnclaveOf.get(raw)?.get(kwilSigner) : undefined;\n if (cached) return cached;\n\n const bound = new Proxy(raw, {\n get(target, prop) {\n if (prop === \"then\" || typeof prop === \"symbol\") return undefined;\n const value = Reflect.get(target, prop, target);\n if (typeof value !== \"function\") {\n assertSigner(kwilClient, kwilSigner);\n return value;\n }\n return (...args: unknown[]) => {\n assertSigner(kwilClient, kwilSigner);\n return value.apply(target, args);\n };\n },\n }) as BaseProvider;\n\n rawEnclaveOf.set(bound, raw);\n if (kwilSigner) {\n const bySigner = boundEnclaveOf.get(raw) ?? new WeakMap<KwilSigner, BaseProvider>();\n bySigner.set(kwilSigner, bound);\n boundEnclaveOf.set(raw, bySigner);\n }\n return bound;\n}\n\nfunction exclusive<T>(kwilClient: KwilActionClient, run: () => Promise<T>): Promise<T> {\n const raw = sharedKwilClient(kwilClient);\n const previous = turns.get(raw) ?? Promise.resolve();\n const result = previous.then(run, run);\n turns.set(\n raw,\n result.then(\n () => undefined,\n () => undefined,\n ),\n );\n return result;\n}\n\n// `setSigner` is synchronous on the real clients. A rejected promise here is not awaited\n// by `withUserSigner` or the enclave constructor, and Node can terminate on it.\nfunction detachedSurface<T extends object>(): T {\n return new Proxy({} as T, {\n get(_target, prop) {\n if (prop === \"signer\") return undefined;\n if (prop === \"then\" || typeof prop === \"symbol\") return undefined;\n if (prop === \"client\") throw new Error(STALE_CLIENT);\n if (prop === \"setSigner\") {\n return () => {\n throw new Error(STALE_CLIENT);\n };\n }\n return async () => {\n throw new Error(STALE_CLIENT);\n };\n },\n });\n}\n\nfunction staleIdle(store: Store, blobUrl: string): idOSClientIdle {\n return new idOSClientIdle(\n store,\n detachedSurface<KwilActionClient>(),\n detachedSurface<BaseProvider>(),\n idleBlobGateway(blobUrl),\n );\n}\n\n// A replaced signer keeps the session. The signer that actually logged out must finish\n// `reset` on a later attempt; success is only returned once that reset completes.\nfunction finishLogOut(\n store: Store,\n kwilClient: KwilActionClient,\n kwilSigner: KwilSigner,\n enclaveProvider: BaseProvider,\n blobUrl: string,\n): Promise<idOSClientIdle> {\n const raw = sharedKwilClient(kwilClient);\n return exclusive(raw, async () => {\n const current = raw.signer;\n if (current !== undefined && current !== kwilSigner) return staleIdle(store, blobUrl);\n\n if (current === kwilSigner) {\n raw.setSigner(undefined);\n resetPending.add(raw);\n }\n\n if (resetPending.has(raw)) {\n await enclaveProvider.reset();\n resetPending.delete(raw);\n }\n\n // A signer installed while `reset` was in progress must not ride back on this idle client.\n if (raw.signer !== undefined && raw.signer !== kwilSigner) return staleIdle(store, blobUrl);\n\n return new idOSClientIdle(store, raw, enclaveProvider, idleBlobGateway(blobUrl));\n });\n}\n\nexport type idOSClient =\n | idOSClientConfiguration\n | idOSClientIdle\n | idOSClientWithUserSigner\n | idOSClientLoggedIn;\n\nexport class idOSClientConfiguration<Provider extends BaseProvider = IframeEnclave> {\n readonly state: \"configuration\";\n readonly chainId?: string;\n readonly nodeUrl: string;\n readonly blobGatewayUrl?: string;\n readonly enclaveOptions: Omit<Provider[\"options\"], \"mode\">;\n readonly store: Store;\n readonly enclaveProvider: BaseProvider;\n\n constructor(params: {\n chainId?: string;\n nodeUrl: string;\n /**\n * Optional blob gateway base URL. Defaults to `nodeUrl`.\n * In the browser this must share KGW's session-cookie Domain\n * (typically the same host), because reads use `credentials: \"include\"`.\n */\n blobGatewayUrl?: string;\n enclaveOptions: Omit<Provider[\"options\"], \"mode\">;\n enclaveProvider?: new (options: Omit<Provider[\"options\"], \"mode\">) => Provider;\n store?: Store;\n }) {\n this.state = \"configuration\";\n this.chainId = params.chainId;\n this.nodeUrl = params.nodeUrl;\n this.blobGatewayUrl = params.blobGatewayUrl;\n this.enclaveOptions = params.enclaveOptions;\n this.store = params.store ?? (isBrowserRuntime() ? new LocalStorageStore() : new MemoryStore());\n\n // TODO: This is a mess because of types...\n if (params.enclaveProvider) {\n this.enclaveProvider = new params.enclaveProvider({\n ...params.enclaveOptions,\n // Some of enclave providers require store to be passed in constructor\n store: this.store,\n });\n } else {\n // @ts-expect-error - In case of missing \"container\" in options, enclave will blow up\n this.enclaveProvider = new IframeEnclave(params.enclaveOptions);\n }\n }\n\n async createClient(): Promise<idOSClientIdle> {\n return idOSClientIdle.fromConfig(this);\n }\n}\n\nexport class idOSClientIdle {\n readonly state: \"idle\";\n readonly store: Store;\n readonly kwilClient: KwilActionClient;\n readonly enclaveProvider: BaseProvider;\n readonly blobGateway: BlobGateway;\n\n constructor(\n store: Store,\n kwilClient: KwilActionClient,\n enclaveProvider: BaseProvider,\n blobGateway: BlobGateway,\n ) {\n this.state = \"idle\";\n this.store = store;\n this.kwilClient = kwilClient;\n this.enclaveProvider = enclaveProvider;\n this.blobGateway = blobGateway;\n }\n\n static async fromConfig(params: idOSClientConfiguration<BaseProvider>): Promise<idOSClientIdle> {\n const createKwilClient = isBrowserRuntime() ? createWebKwilClient : createNodeKwilClient;\n const kwilClient = await createKwilClient({\n nodeUrl: params.nodeUrl,\n chainId: params.chainId,\n });\n\n await params.enclaveProvider.load();\n\n const blobGatewayUrl = params.blobGatewayUrl ?? params.nodeUrl;\n return new idOSClientIdle(\n params.store,\n kwilClient,\n params.enclaveProvider,\n idleBlobGateway(blobGatewayUrl),\n );\n }\n\n async addressHasProfile(address: string): Promise<boolean> {\n return hasProfile(this.kwilClient, { address }).then((res) => res.has_profile);\n }\n\n async withUserSigner(_signer: Wallet): Promise<idOSClientWithUserSigner> {\n let signer = _signer;\n const [kwilSigner, walletIdentifier, walletPublicKey, walletType] =\n await createClientKwilSigner(this.store, this.kwilClient, signer);\n\n if (walletType === \"NEAR\") {\n const originalSigner = signer;\n signer = {\n signMessage: async (message: string) => {\n const signature = await signNearMessage(\n originalSigner as Parameters<typeof signNearMessage>[0],\n message,\n );\n return { signedMessage: signature } as { signedMessage: string };\n },\n } as unknown as Wallet;\n }\n\n return exclusive(this.kwilClient, async () => {\n this.kwilClient.setSigner(kwilSigner);\n return new idOSClientWithUserSigner(\n this,\n signer,\n kwilSigner,\n walletIdentifier,\n walletPublicKey,\n walletType,\n blobGatewayForSigner(this, kwilSigner),\n );\n });\n }\n\n async logOut(): Promise<idOSClientIdle> {\n return this;\n }\n}\n\nexport class idOSClientWithUserSigner implements Omit<Properties<idOSClientIdle>, \"state\"> {\n readonly state: \"with-user-signer\";\n readonly store: Store;\n readonly #kwilClient: KwilActionClient;\n readonly #enclaveProvider: BaseProvider;\n readonly signer: Wallet;\n readonly kwilSigner: KwilSigner;\n readonly walletIdentifier: string;\n readonly walletPublicKey: string | undefined;\n readonly walletType: WalletType;\n readonly blobGateway: BlobGateway;\n\n constructor(\n idOSClientIdle: idOSClientIdle,\n signer: Wallet,\n kwilSigner: KwilSigner,\n walletIdentifier: string,\n walletPublicKey: string | undefined,\n walletType: WalletType,\n blobGateway: BlobGateway,\n ) {\n this.state = \"with-user-signer\";\n this.store = idOSClientIdle.store;\n this.#kwilClient = idOSClientIdle.kwilClient;\n this.#enclaveProvider = idOSClientIdle.enclaveProvider;\n this.signer = signer;\n this.kwilSigner = kwilSigner;\n this.walletIdentifier = walletIdentifier;\n this.walletPublicKey = walletPublicKey;\n this.walletType = walletType;\n this.blobGateway = blobGateway;\n // @ts-expect-error - TODO: Fix this\n this.#enclaveProvider.setSigner(this.signer);\n }\n\n get kwilClient(): KwilActionClient {\n return boundKwilClient(this.#kwilClient, this.kwilSigner);\n }\n\n get enclaveProvider(): BaseProvider {\n return boundEnclave(this.#enclaveProvider, this.#kwilClient, this.kwilSigner);\n }\n\n async logOut(): Promise<idOSClientIdle> {\n return finishLogOut(\n this.store,\n this.#kwilClient,\n this.kwilSigner,\n this.#enclaveProvider,\n this.blobGateway.url,\n );\n }\n\n async hasProfile(): Promise<boolean> {\n return hasProfile(this.kwilClient, { address: this.walletIdentifier }).then(\n (x) => x.has_profile,\n );\n }\n\n async createUserEncryptionProfile(\n userId: string,\n forceEncryptionPasswordStore?: EncryptionPasswordStore,\n ): Promise<PublicEncryptionProfile> {\n await exclusive(this.#kwilClient, async () => {\n assertSigner(this.#kwilClient, this.kwilSigner);\n await this.enclaveProvider.reconfigure({\n mode: \"new\",\n userId,\n walletAddress: this.walletIdentifier,\n walletPublicKey: this.walletPublicKey,\n walletType: this.walletType,\n encryptionPasswordStore: forceEncryptionPasswordStore,\n expectedUserEncryptionPublicKey: undefined,\n });\n assertSigner(this.#kwilClient, this.kwilSigner);\n });\n assertSigner(this.#kwilClient, this.kwilSigner);\n return this.enclaveProvider.ensureUserEncryptionProfile();\n }\n\n async logIn(): Promise<idOSClientLoggedIn> {\n if (!(await this.hasProfile())) throw new Error(\"User does not have a profile\");\n\n const kwilUser = await getUser(this.kwilClient);\n\n return exclusive(this.#kwilClient, async () => {\n assertSigner(this.#kwilClient, this.kwilSigner);\n await this.enclaveProvider.reconfigure({\n mode: \"existing\",\n userId: kwilUser.id,\n expectedUserEncryptionPublicKey: kwilUser.recipient_encryption_public_key,\n walletAddress: this.walletIdentifier,\n walletType: this.walletType,\n encryptionPasswordStore: kwilUser.encryption_password_store,\n walletPublicKey: this.walletPublicKey,\n });\n assertSigner(this.#kwilClient, this.kwilSigner);\n return new idOSClientLoggedIn(this, kwilUser);\n });\n }\n}\n\nexport class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSigner>, \"state\"> {\n readonly state: \"logged-in\";\n readonly store: Store;\n readonly #kwilClient: KwilActionClient;\n readonly #enclaveProvider: BaseProvider;\n readonly signer: Wallet;\n readonly kwilSigner: KwilSigner;\n readonly walletIdentifier: string;\n readonly walletPublicKey: string | undefined;\n readonly walletType: WalletType;\n readonly user: idOSUser;\n readonly blobGateway: BlobGateway;\n\n constructor(idOSClientWithUserSigner: idOSClientWithUserSigner, user: idOSUser) {\n this.state = \"logged-in\";\n this.store = idOSClientWithUserSigner.store;\n this.#kwilClient = sharedKwilClient(idOSClientWithUserSigner.kwilClient);\n this.#enclaveProvider = sharedEnclave(idOSClientWithUserSigner.enclaveProvider);\n this.signer = idOSClientWithUserSigner.signer;\n this.kwilSigner = idOSClientWithUserSigner.kwilSigner;\n this.walletIdentifier = idOSClientWithUserSigner.walletIdentifier;\n this.walletPublicKey = idOSClientWithUserSigner.walletPublicKey;\n this.walletType = idOSClientWithUserSigner.walletType;\n this.user = user;\n this.blobGateway = idOSClientWithUserSigner.blobGateway;\n }\n\n get kwilClient(): KwilActionClient {\n return boundKwilClient(this.#kwilClient, this.kwilSigner);\n }\n\n get enclaveProvider(): BaseProvider {\n return boundEnclave(this.#enclaveProvider, this.#kwilClient, this.kwilSigner);\n }\n\n async logOut(): Promise<idOSClientIdle> {\n return finishLogOut(\n this.store,\n this.#kwilClient,\n this.kwilSigner,\n this.#enclaveProvider,\n this.blobGateway.url,\n );\n }\n\n async requestDWGMessage(params: idOSDelegatedWriteGrant): Promise<string> {\n return dwgMessage(this.kwilClient, params).then((res) => res.message);\n }\n\n async createCredential(\n publicNotes: string,\n plaintextContent: Uint8Array<ArrayBufferLike>,\n // In case of credential creation on users behalf, this would be a issuer key\n issuerSigningSecretKey?: Uint8Array,\n ): Promise<Omit<idOSCredential, \"user_id\" | \"content\" | \"inserter_type\" | \"inserter_id\">> {\n const credentialId = crypto.randomUUID();\n const preliminaryCredential: PreliminaryIDOSCredential = {\n ...(await buildPreliminaryIDOSCredential({\n publicNotes,\n plaintextContent,\n recipientEncryptionPublicKey: base64Decode(this.user.recipient_encryption_public_key),\n issuerSigningSecretKey,\n contentUri: contentUriForWallet(this.walletType, this.kwilSigner, credentialId),\n })),\n id: credentialId,\n };\n requireAccessTokenForUkycContent(\n preliminaryCredential.contentUri,\n this.blobGateway.hasAccessToken,\n );\n\n const requestId = crypto.randomUUID();\n\n const payload: CreatePreliminaryCredentialInput = {\n request_id: requestId,\n credential_id: preliminaryCredential.id,\n issuer_auth_public_key: preliminaryCredential.issuerAuthPublicKey,\n encryptor_public_key: preliminaryCredential.encryptorPublicKey,\n content_uri: preliminaryCredential.contentUri,\n content_size: preliminaryCredential.contentSize,\n content_hash: hexEncodeSha256Hash(plaintextContent),\n public_notes: preliminaryCredential.publicNotes,\n public_notes_signature: preliminaryCredential.publicNotesSignature,\n broader_signature: preliminaryCredential.broaderSignature,\n };\n\n await createPreliminaryCredential(this.kwilClient, payload);\n\n await this.blobGateway.uploadCredentialBlobs({\n requestId,\n original: preliminaryCredential.encryptedContent,\n });\n\n return mapPreliminaryToIDOSCredential(preliminaryCredential);\n }\n\n async removeCredential(id: string): Promise<{ id: string }> {\n const credential = await this.getCredentialById(id);\n invariant(credential, `\"idOSCredential\" with id ${id} not found`);\n\n const contentUri = credential.content_uri ?? null;\n requireAccessTokenForUkycContent(contentUri, this.blobGateway.hasAccessToken);\n\n await removeCredential(this.kwilClient, { id });\n\n if (!contentUri) {\n return { id };\n }\n\n await this.blobGateway.deleteCredentialBlob({ credentialId: id });\n return { id };\n }\n\n async getCredentialById(id: string): Promise<idOSCredential | undefined> {\n return getCredentialOwned(this.kwilClient, { id }).then((res) => res[0]);\n }\n\n async shareCredential(\n credential: SharePreliminaryCredentialInput,\n ): Promise<SharePreliminaryCredentialInput> {\n await sharePreliminaryCredential(this.kwilClient, credential);\n return credential;\n }\n\n async getAllCredentials(): Promise<idOSCredentialListItem[]> {\n return getCredentials(this.kwilClient);\n }\n\n async getAccessGrantsOwned(): Promise<idOSGrant[]> {\n return getAccessGrantsOwned(this.kwilClient);\n }\n\n async getAttributes(): Promise<idOSUserAttribute[]> {\n return getAttributes(this.kwilClient);\n }\n\n async createAttribute(attribute: AddAttributeInput): Promise<AddAttributeInput> {\n await createAttribute(this.kwilClient, attribute);\n return attribute;\n }\n\n async getCredentialContentSha256Hash(id: string): Promise<string> {\n const credential = await this.getCredentialById(id);\n\n invariant(credential, `\"idOSCredential\" with id ${id} not found`);\n const plaintext = await this.#decryptCredentialContent(credential);\n\n return hexEncodeSha256Hash(plaintext);\n }\n\n async getCredentialContent(id: string): Promise<string> {\n const credential = await this.getCredentialById(id);\n\n invariant(credential, `\"idOSCredential\" with id ${id} not found`);\n const plaintext = await this.#decryptCredentialContent(credential);\n\n return utf8Decode(plaintext);\n }\n\n async getCredentialWithEncryptedContent(id: string): Promise<idOSCredential> {\n const credential = await this.getCredentialById(id);\n invariant(credential, `\"idOSCredential\" with id ${id} not found`);\n return this.#credentialWithInlineContent(credential);\n }\n\n async getCredentialSharedContent(id: string): Promise<string> {\n const credential = await this.getCredentialShared(id);\n\n invariant(credential, `Shared credential with id ${id} not found`);\n const plaintext = await this.#decryptCredentialContent(credential);\n\n return utf8Decode(plaintext);\n }\n\n async getGrants(\n params: Partial<GetAccessGrantsGrantedInput>,\n ): Promise<{ grants: idOSGrant[]; totalCount: number }> {\n return {\n grants: await getGrants(this.kwilClient, params),\n totalCount: await this.getGrantsCount(),\n };\n }\n\n async addWallets(params: AddWalletInput[]): Promise<AddWalletInput[]> {\n await addWallets(this.kwilClient, params);\n return params;\n }\n\n async getGrantsCount(): Promise<number> {\n return getAccessGrantsGrantedCount(this.kwilClient, {\n user_id: null,\n }).then((res) => res.count);\n }\n\n async getCredentialShared(id: string): Promise<idOSCredential | undefined> {\n return getCredentialShared(this.kwilClient, { id }).then((res) => res[0]);\n }\n\n async revokeAccessGrant(id: string): Promise<{ id: string }> {\n await revokeAccessGrant(this.kwilClient, { id });\n return { id };\n }\n\n async addWalletMessage(params: AddWalletMessageInput): Promise<string> {\n const result = await requestAddWalletMessage(this.kwilClient, params);\n return result.message;\n }\n\n async addWallet(params: AddWalletInput): Promise<AddWalletInput> {\n await addWallet(this.kwilClient, params);\n\n // we don't need to add the wallet to MPC if the user is not using MPC\n if (this.user.encryption_password_store !== \"mpc\") {\n console.log(\"MPC is not enabled or the user is not using MPC\");\n return params;\n }\n\n if (!params.wallet_type) {\n throw new Error(\"Wallet type is required for MPC users\");\n }\n\n const messageToSign = await this.enclaveProvider.addAddressMessageToSign(\n params.address,\n params.public_key ?? undefined,\n params.wallet_type,\n );\n\n const signature = await this.enclaveProvider.signTypedData(\n messageToSign.domain,\n messageToSign.types,\n messageToSign.value,\n );\n\n const result = await this.enclaveProvider.addAddressToMpcSecret(\n this.user.id,\n messageToSign.value,\n signature,\n );\n\n if (result !== \"success\") {\n console.error(`Failed to add wallet to MPC: ${result}`);\n }\n\n return params;\n }\n\n async getWallets(): Promise<GetWalletsOutput[]> {\n return getWallets(this.kwilClient);\n }\n\n async removeWallet(id: string): Promise<{ id: string }> {\n const wallets = await this.getWallets();\n const wallet = wallets.find((wallet) => wallet.id === id);\n if (!wallet) {\n throw new Error(`Wallet with id ${id} not found`);\n }\n\n await removeWallet(this.kwilClient, { id });\n\n // we don't need to add the wallet to MPC if the user is not using MPC\n if (this.user.encryption_password_store !== \"mpc\") {\n console.log(\"MPC is not enabled or the user is not using MPC\");\n return { id };\n }\n\n const messageToSign = await this.enclaveProvider.removeAddressMessageToSign(\n wallet.address,\n wallet.public_key ?? undefined,\n wallet.wallet_type,\n );\n const signature = await this.enclaveProvider.signTypedData(\n messageToSign.domain,\n messageToSign.types,\n messageToSign.value,\n );\n const result = await this.enclaveProvider.removeAddressFromMpcSecret(\n wallet.user_id,\n messageToSign.value,\n signature,\n );\n if (result !== \"success\") {\n console.error(`Failed to add wallet to MPC: ${result}`);\n }\n\n return { id };\n }\n\n async removeWallets(ids: string[]): Promise<string[]> {\n for (const id of ids) {\n await this.removeWallet(id);\n }\n\n return ids;\n }\n\n async filterCredentials(requirements: {\n acceptedIssuers: {\n authPublicKey: string;\n }[];\n publicNotesFieldFilters?: {\n pick: Parameters<typeof recordFilter>[1];\n omit: Parameters<typeof recordFilter>[2];\n };\n privateFieldFilters?: {\n pick: Parameters<typeof recordFilter>[1];\n omit: Parameters<typeof recordFilter>[2];\n };\n credentialLevelOrHigherFilter?: {\n userLevel: BaseLevel;\n requiredAddons: Addon[];\n };\n }): Promise<idOSCredentialListItem[]> {\n const credentials = await this.getAllCredentials();\n const originalCredentials = credentials.filter(\n (cred) => !cred.original_id && !!cred.public_notes,\n );\n\n // invariant(originalCredentials.length, \"No original credentials found\");\n let result = originalCredentials.filter((cred) => {\n return requirements.acceptedIssuers?.some(\n (issuer) => issuer.authPublicKey === cred.issuer_auth_public_key,\n );\n });\n\n const publicNotesFieldFilters = requirements.publicNotesFieldFilters;\n const credentialLevelOrHigherFilter = requirements.credentialLevelOrHigherFilter;\n const privateFieldFilters = requirements.privateFieldFilters;\n\n if (credentialLevelOrHigherFilter) {\n result = result.filter((credential) => {\n let publicNotes: Record<string, string>;\n\n try {\n publicNotes = JSON.parse(credential.public_notes);\n } catch (_) {\n throw new Error(`Credential ${credential.id} has non-JSON public notes.`);\n }\n\n return matchLevelOrHigher(\n credentialLevelOrHigherFilter.userLevel,\n credentialLevelOrHigherFilter.requiredAddons,\n publicNotes.level,\n );\n });\n }\n\n if (\n publicNotesFieldFilters &&\n (Object.keys(publicNotesFieldFilters.pick).length > 0 ||\n Object.keys(publicNotesFieldFilters.omit).length > 0)\n ) {\n result = result.filter((credential) => {\n let publicNotes: Record<string, string>;\n\n try {\n publicNotes = JSON.parse(credential.public_notes);\n } catch (_) {\n throw new Error(`Credential ${credential.id} has non-JSON public notes.`);\n }\n\n return recordFilter(\n publicNotes,\n publicNotesFieldFilters.pick,\n publicNotesFieldFilters.omit,\n );\n });\n }\n\n // Private field filtering requires decryption and the full idOS credential content\n // it's most \"expensive\", since it requires a roundtrip to the nodes and roundtrip to enclave.\n if (\n privateFieldFilters &&\n (Object.keys(privateFieldFilters.pick).length > 0 ||\n Object.keys(privateFieldFilters.omit).length > 0)\n ) {\n const fullCredentials = await Promise.all(\n result.map((credential) => this.getCredentialById(credential.id)),\n );\n\n // Check for undefined, it will be sign of some internal error\n invariant(\n fullCredentials.every((cred) => cred !== undefined),\n \"Some credentials could not be fetched in full form for private field filtering\",\n );\n\n const matches = await this.enclaveProvider.filterCredentials(\n await Promise.all(\n fullCredentials.map((credential) => this.#credentialWithInlineContent(credential)),\n ),\n privateFieldFilters,\n );\n\n result = result.filter((credential) =>\n matches.some((matchedCredential) => matchedCredential.id === credential.id),\n );\n }\n\n return result;\n }\n\n async requestAccessGrant(\n credentialId: string,\n {\n consumerEncryptionPublicKey,\n consumerAuthPublicKey,\n lockedUntil = 0,\n }: {\n consumerEncryptionPublicKey: string;\n consumerAuthPublicKey: string;\n lockedUntil?: number;\n },\n ): Promise<SharePreliminaryCredentialInput> {\n const credential = await this.getCredentialById(credentialId);\n\n invariant(credential, `\"idOSCredential\" with id ${credentialId} not found`);\n\n const plaintextContent = await this.#decryptCredentialContent(credential);\n const contentHash = hexEncodeSha256Hash(plaintextContent);\n\n await this.enclaveProvider.ensureUserEncryptionProfile();\n\n const { content, encryptorPublicKey } = await this.enclaveProvider.encrypt(\n plaintextContent,\n base64Decode(consumerEncryptionPublicKey),\n );\n\n // User issues the shared copy: sign content_uri with an ephemeral user-side key.\n // Copy issuer_auth_public_key need not match the original credential's issuer.\n const copyId = crypto.randomUUID();\n const ukycContentUri = contentUriForWallet(this.walletType, this.kwilSigner, copyId);\n requireAccessTokenForUkycContent(ukycContentUri, this.blobGateway.hasAccessToken);\n const copyReference = ukycContentUri\n ? { uri: ukycContentUri, size: content.byteLength }\n : await createBlobContentReference(content);\n const signedReference = buildEphemeralSignedCredentialContentReference(\"\", copyReference.uri);\n\n // Integrator-supplied. ed25519 @caller is lowercase hex; after exact grantee\n // matching, uppercase hex would store a grant the consumer cannot read. Other\n // identifier encodings (NEAR, XRPL, Stellar, MM) are case-sensitive, so leave them.\n const granteeWalletIdentifier = /^[0-9a-fA-F]{64}$/.test(consumerAuthPublicKey)\n ? consumerAuthPublicKey.toLowerCase()\n : consumerAuthPublicKey;\n\n const preliminaryCredential: SharePreliminaryCredentialInput = {\n ...signedReference,\n request_id: crypto.randomUUID(),\n copy_id: copyId,\n original_id: credential.id,\n content_uri: copyReference.uri,\n content_size: copyReference.size,\n encryptor_public_key: base64Encode(encryptorPublicKey),\n grantee_wallet_identifier: granteeWalletIdentifier,\n locked_until: lockedUntil,\n content_hash: contentHash,\n };\n\n await this.shareCredential(preliminaryCredential);\n await this.blobGateway.uploadCredentialBlobs({\n requestId: preliminaryCredential.request_id,\n copy: content,\n });\n\n return preliminaryCredential;\n }\n\n async #credentialWithInlineContent(credential: idOSCredential): Promise<idOSCredential> {\n if (credential.content) {\n return credential;\n }\n\n return {\n ...credential,\n content: base64Encode(await this.#getCredentialEncryptedContent(credential)),\n content_uri: null,\n content_size: null,\n };\n }\n\n async #decryptCredentialContent(credential: idOSCredential): Promise<Uint8Array> {\n await this.enclaveProvider.ensureUserEncryptionProfile();\n\n return this.enclaveProvider.decrypt(\n await this.#getCredentialEncryptedContent(credential),\n base64Decode(credential.encryptor_public_key),\n );\n }\n\n async #getCredentialEncryptedContent(credential: idOSCredential): Promise<Uint8Array> {\n return resolveCredentialEncryptedContent(credential, this.blobGateway);\n }\n}\n\nexport type {\n idOSDelegatedWriteGrant,\n DelegatedWriteGrantBaseParams,\n idOSCredential,\n idOSCredentialListItem,\n idOSGrant,\n idOSUser,\n idOSUserAttribute,\n idOSWallet,\n};\n\nexport { signNearMessage, toDelegatedWriteGrantBaseParams };\n\nexport function createIDOSClient(params: {\n nodeUrl: string;\n /**\n * Optional blob gateway base URL. Defaults to `nodeUrl`.\n * In the browser this must share KGW's session-cookie Domain\n * (typically the same host), because reads use `credentials: \"include\"`.\n */\n blobGatewayUrl?: string;\n enclaveOptions: Omit<IframeEnclave[\"options\"], \"mode\">;\n}): idOSClientConfiguration<IframeEnclave> {\n return new idOSClientConfiguration({\n nodeUrl: params.nodeUrl,\n blobGatewayUrl: params.blobGatewayUrl,\n enclaveOptions: params.enclaveOptions,\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["createAttribute","requestAddWalletMessage"],"sources":["../src/enclave/iframe-enclave.ts","../src/index.ts"],"sourcesContent":["import type { idOSCredentialRecord as idOSCredential } from \"@idos-network/credentials/types\";\nimport type {\n AddAddressMessageToSign,\n AddAddressSignatureMessage,\n RemoveAddressMessageToSign,\n RemoveAddressSignatureMessage,\n} from \"@idos-network/enclave/mpc\";\n\nimport {\n BaseProvider,\n type EnclaveOptions,\n type PublicEncryptionProfile,\n} from \"@idos-network/enclave\";\n\nimport type { BaseProviderMethodArgs, BaseProviderMethodReturn } from \"./helpers\";\n\nexport interface IframeEnclaveOptions extends EnclaveOptions {\n container: string;\n url?: string;\n throwOnUserCancelUnlock?: boolean;\n}\n\nexport class IframeEnclave extends BaseProvider<IframeEnclaveOptions> {\n private container: string;\n private iframe: HTMLIFrameElement;\n private hostUrl: URL;\n private bound = false;\n\n constructor(options: IframeEnclaveOptions) {\n super(options);\n\n if (!this.options.container) {\n throw new Error(\"container is required\");\n }\n\n this.container = this.options.container;\n this.hostUrl = new URL(this.options.url ?? \"https://enclave.idos.network\");\n this.iframe = document.createElement(\"iframe\");\n this.iframe.id = \"idos-enclave-iframe\";\n }\n\n /** @see parent method */\n async load(): Promise<void> {\n // First we have to create and load the iframe\n await this.createAndLoadIframe();\n\n // Load the enclave from the store (trigger load() method in the iframe)\n await this.requestToEnclave(\"load\");\n\n // Pass current options\n await this.reconfigure();\n\n // Bind the message listener to the iframe (in case iframe -> enclave comm)\n await this.bindMessageListener();\n }\n\n /**\n * Embedding pages cannot reset enclave storage. The iframe rejects `reset`\n * because it deletes every idOS-* key with no origin check.\n */\n async reset(): Promise<void> {\n throw new Error(\"Embedding pages cannot reset enclave storage\");\n }\n\n /** @override parent method to call iframe */\n async reconfigure(options: Omit<IframeEnclaveOptions, \"container\" | \"url\"> = {}): Promise<void> {\n super.reconfigure(options);\n await this.requestToEnclave(\"reconfigure\", this.options);\n }\n\n /** @override parent method to call iframe */\n async confirm(message: string): Promise<boolean> {\n this.showEnclave();\n\n try {\n return await this.requestToEnclave(\"confirm\", message);\n } catch (error) {\n console.error(error);\n return false;\n } finally {\n this.hideEnclave();\n }\n }\n\n /** @override parent method to call iframe */\n async filterCredentials(\n credentials: idOSCredential[],\n privateFieldFilters: { pick: Record<string, unknown[]>; omit: Record<string, unknown[]> },\n ): Promise<idOSCredential[]> {\n return await this.requestToEnclave(\"filterCredentials\", credentials, privateFieldFilters);\n }\n\n /** @override parent method to call iframe */\n async encrypt(\n message: Uint8Array,\n receiverPublicKey: Uint8Array,\n ): Promise<{ content: Uint8Array; encryptorPublicKey: Uint8Array }> {\n return this.requestToEnclave(\"encrypt\", message, receiverPublicKey);\n }\n\n /** @override parent method to call iframe */\n async decrypt(\n message: Uint8Array,\n senderPublicKey: Uint8Array,\n ): Promise<Uint8Array<ArrayBufferLike>> {\n return this.requestToEnclave(\"decrypt\", message, senderPublicKey);\n }\n\n /** @override parent method to call iframe */\n async backupUserEncryptionProfile(): Promise<void> {\n this.showEnclave();\n\n try {\n await this.requestToEnclave(\"backupUserEncryptionProfile\");\n } catch (error) {\n console.error(error);\n } finally {\n this.hideEnclave();\n }\n }\n\n /** @override parent method to call iframe */\n async ensureUserEncryptionProfile(): Promise<PublicEncryptionProfile> {\n this.showEnclave();\n\n try {\n return await this.requestToEnclave(\"ensureUserEncryptionProfile\");\n } finally {\n this.hideEnclave();\n }\n }\n\n async addAddressMessageToSign(\n address: string,\n publicKey: string | undefined,\n addressToAddType: string,\n ): Promise<AddAddressMessageToSign> {\n return this.requestToEnclave(\"addAddressMessageToSign\", address, publicKey, addressToAddType);\n }\n\n async removeAddressMessageToSign(\n address: string,\n publicKey: string | undefined,\n addressToRemoveType: string,\n ): Promise<RemoveAddressMessageToSign> {\n return this.requestToEnclave(\n \"removeAddressMessageToSign\",\n address,\n publicKey,\n addressToRemoveType,\n );\n }\n\n async addAddressToMpcSecret(\n userId: string,\n message: AddAddressSignatureMessage,\n signature: string,\n ): Promise<string> {\n return this.requestToEnclave(\"addAddressToMpcSecret\", userId, message, signature);\n }\n\n async removeAddressFromMpcSecret(\n userId: string,\n message: RemoveAddressSignatureMessage,\n signature: string,\n ): Promise<string> {\n return this.requestToEnclave(\"removeAddressFromMpcSecret\", userId, message, signature);\n }\n\n private async createAndLoadIframe(): Promise<void> {\n const container = document.querySelector(this.container);\n\n if (!container) {\n throw new Error(`Can't find container with selector ${this.container}`);\n }\n\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy#directives\n const permissionsPolicies = [\"publickey-credentials-get\", \"storage-access\"];\n\n // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox\n const liftedSandboxRestrictions = [\n \"forms\",\n \"modals\",\n \"popups\",\n \"popups-to-escape-sandbox\",\n \"same-origin\",\n \"scripts\",\n ].map((toLift) => `allow-${toLift}`);\n\n // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#referrerpolicy\n const referrerPolicy = \"origin\";\n\n const styles = {\n \"aspect-ratio\": \"4/1\",\n \"background-color\": \"transparent\",\n border: \"none\",\n display: \"block\",\n overflow: \"hidden\",\n width: \"100%\",\n };\n\n this.iframe.allow = permissionsPolicies.join(\"; \");\n this.iframe.referrerPolicy = referrerPolicy;\n this.iframe.sandbox.add(...liftedSandboxRestrictions);\n this.iframe.src = this.hostUrl.toString();\n for (const [k, v] of Object.entries(styles)) {\n this.iframe.style.setProperty(k, v);\n }\n\n let el: HTMLElement | null;\n // oxlint-disable-next-line no-cond-assign -- it's on purpose\n while ((el = document.getElementById(this.iframe.id))) {\n console.log(\"reinstalling idOS iframe...\");\n container.removeChild(el);\n }\n container.appendChild(this.iframe);\n\n return new Promise((resolve) =>\n this.iframe.addEventListener(\n \"load\",\n () => {\n resolve();\n },\n { once: true },\n ),\n );\n }\n\n private showEnclave(): void {\n // oxlint-disable-next-line typescript/no-non-null-assertion -- Make the explosion visible.\n this.iframe.parentElement!.classList.add(\"visible\");\n }\n\n private hideEnclave(): void {\n // oxlint-disable-next-line typescript/no-non-null-assertion -- Make the explosion visible.\n this.iframe.parentElement!.classList.remove(\"visible\");\n }\n\n private async requestToEnclave<TMethod extends keyof BaseProviderMethodArgs>(\n method: TMethod,\n ...args: BaseProviderMethodArgs[TMethod]\n ): Promise<BaseProviderMethodReturn[TMethod]> {\n return new Promise((resolve, reject) => {\n const { port1, port2 } = new MessageChannel();\n\n port1.onmessage = ({ data }) => {\n port1.close();\n // oxlint-disable-next-line no-unused-expressions\n data.error ? reject(data.error) : resolve(data.result);\n };\n\n // oxlint-disable-next-line typescript/no-non-null-assertion -- Make the explosion visible.\n this.iframe.contentWindow!.postMessage(\n {\n method,\n data: args,\n },\n this.hostUrl.origin,\n [port2],\n );\n });\n }\n\n private bindMessageListener(): void {\n if (!this.bound) window.addEventListener(\"message\", this.onMessage.bind(this));\n this.bound = true;\n }\n\n private async onMessage(message: MessageEvent): Promise<void> {\n // We can't be sure about the message and the content\n // so we have to validate it carefully.\n if (!message || !message.data || typeof message.data !== \"object\") return;\n\n if (message.data.type !== \"idOS:signTypedData\" || message.origin !== this.hostUrl.origin)\n return;\n\n const payload = message.data.payload;\n const signature = await this.signTypedData(payload.domain, payload.types, payload.value);\n await this.requestToEnclave(\"signTypedDataResponse\", signature);\n }\n}\n","import type {\n BaseProvider,\n EncryptionPasswordStore,\n PublicEncryptionProfile,\n} from \"@idos-network/enclave\";\n\nimport {\n buildEphemeralSignedCredentialContentReference,\n buildPreliminaryIDOSCredential,\n mapPreliminaryToIDOSCredential,\n matchClaims,\n matchLevelOrHigher,\n type PreliminaryIDOSCredential,\n recordFilter,\n type BaseLevel,\n type Addon,\n type Claim,\n type ClaimRequirements,\n type Claims,\n type ClaimSource,\n type ClaimSources,\n} from \"@idos-network/credentials/utils\";\nimport {\n createClientKwilSigner,\n createKgwAuthenticatedBlobGateway,\n createNodeKwilClient,\n createWebKwilClient,\n isMmTokenAuth,\n type KwilActionClient,\n mmTokenStorageId,\n signNearMessage,\n type Wallet,\n} from \"@idos-network/kwil-infra\";\nimport {\n type AddAttributeInput,\n type AddWalletInput,\n type AddWalletMessageInput,\n addWallet,\n addWalletMessage as requestAddWalletMessage,\n addWallets,\n addAttribute as createAttribute,\n createPreliminaryCredential,\n credentialBroaderMessage,\n type CreatePreliminaryCredentialInput,\n dwgMessage,\n type GetAccessGrantsGrantedInput,\n type GetWalletsOutput,\n getAccessGrantsGrantedCount,\n getAccessGrantsOwned,\n getAttributes,\n getCredentialOwned,\n getCredentialShared,\n getCredentials,\n getGrants,\n getUser,\n getWallets,\n hasProfile,\n type idOSCredential,\n type idOSCredentialListItem,\n type idOSDelegatedWriteGrant,\n type DelegatedWriteGrantBaseParams,\n toDelegatedWriteGrantBaseParams,\n type idOSGrant,\n type idOSUser,\n type idOSUserAttribute,\n type idOSWallet,\n removeCredential,\n removeWallet,\n revokeAccessGrant,\n type SharePreliminaryCredentialInput,\n sharePreliminaryCredential,\n type WalletType,\n} from \"@idos-network/kwil-infra/actions\";\nimport { NodeKwil, type KwilSigner } from \"@idos-network/kwil-js\";\nimport {\n BlobGateway,\n BlobGatewayUploadOutcomeUnknownError,\n createBlobContentReference,\n createUkycContentReference,\n requireAccessTokenForUkycContent,\n resolveCredentialEncryptedContent,\n type UploadCredentialBlobsParams,\n} from \"@idos-network/utils/blob-gateway\";\nimport {\n base64Decode,\n base64Encode,\n hexEncodeSha256Hash,\n utf8Decode,\n} from \"@idos-network/utils/codecs\";\nimport { LocalStorageStore, MemoryStore, type Store } from \"@idos-network/utils/store\";\nimport invariant from \"tiny-invariant\";\n\nimport { IframeEnclave } from \"./enclave/iframe-enclave\";\nexport { IframeEnclave };\n\ntype Properties<T> = {\n // oxlint-disable-next-line typescript/no-restricted-types -- All functions are to be removed.\n [K in keyof T as Exclude<T[K], Function> extends never ? never : K]: T[K];\n};\n\nfunction isBrowserRuntime(): boolean {\n return typeof window !== \"undefined\";\n}\n\nfunction usesNodeKwil(kwilClient: KwilActionClient): boolean {\n return kwilClient.client instanceof NodeKwil;\n}\n\nfunction idleBlobGateway(url: string): BlobGateway {\n if (!isBrowserRuntime()) {\n return new BlobGateway({ url });\n }\n\n return new BlobGateway({\n url,\n // Browser blob reads need the KGW HttpOnly session cookie. That only works if the\n // blob gateway is covered by the cookie's Domain (typically same host as nodeUrl/KGW).\n fetchFn: (input, init) => fetch(input, { ...init, credentials: \"include\" }),\n });\n}\n\nfunction blobGatewayForSigner(idle: idOSClientIdle, kwilSigner: KwilSigner): BlobGateway {\n if (usesNodeKwil(idle.kwilClient)) {\n return createKgwAuthenticatedBlobGateway({\n url: idle.blobGateway.url,\n kwilClient: idle.kwilClient,\n signer: kwilSigner,\n });\n }\n\n return isMmTokenAuth(kwilSigner)\n ? idle.blobGateway.withAccessToken(kwilSigner.accessToken)\n : idle.blobGateway;\n}\n\nfunction ukycStorageIdForWallet(\n walletType: WalletType,\n kwilSigner: KwilSigner,\n): string | undefined {\n if (walletType !== \"MM\") {\n return undefined;\n }\n return mmTokenStorageId(kwilSigner);\n}\n\n// Deadline for reading a blob back after an unknown upload outcome. A slower read leaves the\n// outcome unknown, which callers already have to handle, instead of hanging the call.\nconst READ_BACK_TIMEOUT_MS = 60_000;\n\nfunction bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n return a.byteLength === b.byteLength && a.every((byte, index) => byte === b[index]);\n}\n\nconst STALE_CLIENT =\n \"This idOS client is stale: another signer was set or it was logged out. Use the client returned by the latest `withUserSigner()`.\";\n\n// Wrappers from one idle client share its Kwil client and enclave. `rawOf` unwraps the\n// guard below; `turns` keeps signer replacement and enclave reconfiguration from interleaving.\nconst rawOf = new WeakMap<KwilActionClient, KwilActionClient>();\nconst boundOf = new WeakMap<KwilActionClient, WeakMap<KwilSigner, KwilActionClient>>();\nconst rawEnclaveOf = new WeakMap<BaseProvider, BaseProvider>();\nconst boundEnclaveOf = new WeakMap<BaseProvider, WeakMap<KwilSigner, BaseProvider>>();\nconst turns = new WeakMap<KwilActionClient, Promise<void>>();\nconst resetPending = new WeakSet<KwilActionClient>();\n\nfunction sharedKwilClient(kwilClient: KwilActionClient): KwilActionClient {\n return rawOf.get(kwilClient) ?? kwilClient;\n}\n\nfunction assertSigner(kwilClient: KwilActionClient, kwilSigner: KwilSigner): void {\n if (kwilClient.signer !== kwilSigner) throw new Error(STALE_CLIENT);\n}\n\n// shortcut: guards call/execute/waitForTx/setSigner only; wrap any new KwilActionClient method here.\nfunction boundKwilClient(kwilClient: KwilActionClient, kwilSigner: KwilSigner): KwilActionClient {\n const raw = sharedKwilClient(kwilClient);\n const cached = kwilSigner ? boundOf.get(raw)?.get(kwilSigner) : undefined;\n if (cached) return cached;\n\n const guard = (): void => assertSigner(raw, kwilSigner);\n const bound = {\n get signer() {\n guard();\n return raw.signer;\n },\n get client() {\n guard();\n return raw.client;\n },\n call: async (...args: Parameters<KwilActionClient[\"call\"]>) => {\n guard();\n return raw.call(...args);\n },\n execute: async (...args: Parameters<KwilActionClient[\"execute\"]>) => {\n guard();\n return raw.execute(...args);\n },\n waitForTx: async (txHash: string) => {\n guard();\n return raw.waitForTx(txHash);\n },\n setSigner: (signer: KwilSigner | undefined) => {\n guard();\n raw.setSigner(signer);\n },\n } as KwilActionClient;\n\n rawOf.set(bound, raw);\n if (kwilSigner) {\n const bySigner = boundOf.get(raw) ?? new WeakMap<KwilSigner, KwilActionClient>();\n bySigner.set(kwilSigner, bound);\n boundOf.set(raw, bySigner);\n }\n return bound;\n}\n\nfunction sharedEnclave(enclave: BaseProvider): BaseProvider {\n return (enclave && rawEnclaveOf.get(enclave)) || enclave;\n}\n\nfunction boundEnclave(\n enclave: BaseProvider,\n kwilClient: KwilActionClient,\n kwilSigner: KwilSigner,\n): BaseProvider {\n const raw = sharedEnclave(enclave);\n const cached = kwilSigner ? boundEnclaveOf.get(raw)?.get(kwilSigner) : undefined;\n if (cached) return cached;\n\n const bound = new Proxy(raw, {\n get(target, prop) {\n if (prop === \"then\" || typeof prop === \"symbol\") return undefined;\n const value = Reflect.get(target, prop, target);\n if (typeof value !== \"function\") {\n assertSigner(kwilClient, kwilSigner);\n return value;\n }\n return (...args: unknown[]) => {\n assertSigner(kwilClient, kwilSigner);\n return value.apply(target, args);\n };\n },\n }) as BaseProvider;\n\n rawEnclaveOf.set(bound, raw);\n if (kwilSigner) {\n const bySigner = boundEnclaveOf.get(raw) ?? new WeakMap<KwilSigner, BaseProvider>();\n bySigner.set(kwilSigner, bound);\n boundEnclaveOf.set(raw, bySigner);\n }\n return bound;\n}\n\nfunction exclusive<T>(kwilClient: KwilActionClient, run: () => Promise<T>): Promise<T> {\n const raw = sharedKwilClient(kwilClient);\n const previous = turns.get(raw) ?? Promise.resolve();\n const result = previous.then(run, run);\n turns.set(\n raw,\n result.then(\n () => undefined,\n () => undefined,\n ),\n );\n return result;\n}\n\n// `setSigner` is synchronous on the real clients. A rejected promise here is not awaited\n// by `withUserSigner` or the enclave constructor, and Node can terminate on it.\nfunction detachedSurface<T extends object>(): T {\n return new Proxy({} as T, {\n get(_target, prop) {\n if (prop === \"signer\") return undefined;\n if (prop === \"then\" || typeof prop === \"symbol\") return undefined;\n if (prop === \"client\") throw new Error(STALE_CLIENT);\n if (prop === \"setSigner\") {\n return () => {\n throw new Error(STALE_CLIENT);\n };\n }\n return async () => {\n throw new Error(STALE_CLIENT);\n };\n },\n });\n}\n\nfunction staleIdle(store: Store, blobUrl: string): idOSClientIdle {\n return new idOSClientIdle(\n store,\n detachedSurface<KwilActionClient>(),\n detachedSurface<BaseProvider>(),\n idleBlobGateway(blobUrl),\n );\n}\n\n// A replaced signer keeps the session. The signer that actually logged out must finish\n// `reset` on a later attempt; success is only returned once that reset completes.\nfunction finishLogOut(\n store: Store,\n kwilClient: KwilActionClient,\n kwilSigner: KwilSigner,\n enclaveProvider: BaseProvider,\n blobUrl: string,\n): Promise<idOSClientIdle> {\n const raw = sharedKwilClient(kwilClient);\n return exclusive(raw, async () => {\n const current = raw.signer;\n if (current !== undefined && current !== kwilSigner) return staleIdle(store, blobUrl);\n\n if (current === kwilSigner) {\n raw.setSigner(undefined);\n resetPending.add(raw);\n }\n\n if (resetPending.has(raw)) {\n await enclaveProvider.reset();\n resetPending.delete(raw);\n }\n\n // A signer installed while `reset` was in progress must not ride back on this idle client.\n if (raw.signer !== undefined && raw.signer !== kwilSigner) return staleIdle(store, blobUrl);\n\n return new idOSClientIdle(store, raw, enclaveProvider, idleBlobGateway(blobUrl));\n });\n}\n\nexport type idOSClient =\n | idOSClientConfiguration\n | idOSClientIdle\n | idOSClientWithUserSigner\n | idOSClientLoggedIn;\n\nexport class idOSClientConfiguration<Provider extends BaseProvider = IframeEnclave> {\n readonly state: \"configuration\";\n readonly chainId?: string;\n readonly nodeUrl: string;\n readonly blobGatewayUrl?: string;\n readonly enclaveOptions: Omit<Provider[\"options\"], \"mode\">;\n readonly store: Store;\n readonly enclaveProvider: BaseProvider;\n\n constructor(params: {\n chainId?: string;\n nodeUrl: string;\n /**\n * Optional blob gateway base URL. Defaults to `nodeUrl`.\n * In the browser this must share KGW's session-cookie Domain\n * (typically the same host), because reads use `credentials: \"include\"`.\n */\n blobGatewayUrl?: string;\n enclaveOptions: Omit<Provider[\"options\"], \"mode\">;\n enclaveProvider?: new (options: Omit<Provider[\"options\"], \"mode\">) => Provider;\n store?: Store;\n }) {\n this.state = \"configuration\";\n this.chainId = params.chainId;\n this.nodeUrl = params.nodeUrl;\n this.blobGatewayUrl = params.blobGatewayUrl;\n this.enclaveOptions = params.enclaveOptions;\n this.store = params.store ?? (isBrowserRuntime() ? new LocalStorageStore() : new MemoryStore());\n\n // TODO: This is a mess because of types...\n if (params.enclaveProvider) {\n this.enclaveProvider = new params.enclaveProvider({\n ...params.enclaveOptions,\n // Some of enclave providers require store to be passed in constructor\n store: this.store,\n });\n } else {\n // @ts-expect-error - In case of missing \"container\" in options, enclave will blow up\n this.enclaveProvider = new IframeEnclave(params.enclaveOptions);\n }\n }\n\n async createClient(): Promise<idOSClientIdle> {\n return idOSClientIdle.fromConfig(this);\n }\n}\n\nexport class idOSClientIdle {\n readonly state: \"idle\";\n readonly store: Store;\n readonly kwilClient: KwilActionClient;\n readonly enclaveProvider: BaseProvider;\n readonly blobGateway: BlobGateway;\n\n constructor(\n store: Store,\n kwilClient: KwilActionClient,\n enclaveProvider: BaseProvider,\n blobGateway: BlobGateway,\n ) {\n this.state = \"idle\";\n this.store = store;\n this.kwilClient = kwilClient;\n this.enclaveProvider = enclaveProvider;\n this.blobGateway = blobGateway;\n }\n\n static async fromConfig(params: idOSClientConfiguration<BaseProvider>): Promise<idOSClientIdle> {\n const createKwilClient = isBrowserRuntime() ? createWebKwilClient : createNodeKwilClient;\n const kwilClient = await createKwilClient({\n nodeUrl: params.nodeUrl,\n chainId: params.chainId,\n });\n\n await params.enclaveProvider.load();\n\n const blobGatewayUrl = params.blobGatewayUrl ?? params.nodeUrl;\n return new idOSClientIdle(\n params.store,\n kwilClient,\n params.enclaveProvider,\n idleBlobGateway(blobGatewayUrl),\n );\n }\n\n async addressHasProfile(address: string): Promise<boolean> {\n return hasProfile(this.kwilClient, { address }).then((res) => {\n if (!res) throw new Error(\"has_profile returned no rows\");\n return res.has_profile;\n });\n }\n\n async withUserSigner(_signer: Wallet): Promise<idOSClientWithUserSigner> {\n let signer = _signer;\n const [kwilSigner, walletIdentifier, walletPublicKey, walletType] =\n await createClientKwilSigner(this.store, this.kwilClient, signer);\n\n if (walletType === \"NEAR\") {\n const originalSigner = signer;\n signer = {\n signMessage: async (message: string) => {\n const signature = await signNearMessage(\n originalSigner as Parameters<typeof signNearMessage>[0],\n message,\n );\n return { signedMessage: signature } as { signedMessage: string };\n },\n } as unknown as Wallet;\n }\n\n return exclusive(this.kwilClient, async () => {\n this.kwilClient.setSigner(kwilSigner);\n return new idOSClientWithUserSigner(\n this,\n signer,\n kwilSigner,\n walletIdentifier,\n walletPublicKey,\n walletType,\n blobGatewayForSigner(this, kwilSigner),\n );\n });\n }\n\n async logOut(): Promise<idOSClientIdle> {\n return this;\n }\n}\n\nexport class idOSClientWithUserSigner implements Omit<Properties<idOSClientIdle>, \"state\"> {\n readonly state: \"with-user-signer\";\n readonly store: Store;\n readonly #kwilClient: KwilActionClient;\n readonly #enclaveProvider: BaseProvider;\n readonly signer: Wallet;\n readonly kwilSigner: KwilSigner;\n readonly walletIdentifier: string;\n readonly walletPublicKey: string | undefined;\n readonly walletType: WalletType;\n readonly blobGateway: BlobGateway;\n\n constructor(\n idOSClientIdle: idOSClientIdle,\n signer: Wallet,\n kwilSigner: KwilSigner,\n walletIdentifier: string,\n walletPublicKey: string | undefined,\n walletType: WalletType,\n blobGateway: BlobGateway,\n ) {\n this.state = \"with-user-signer\";\n this.store = idOSClientIdle.store;\n this.#kwilClient = idOSClientIdle.kwilClient;\n this.#enclaveProvider = idOSClientIdle.enclaveProvider;\n this.signer = signer;\n this.kwilSigner = kwilSigner;\n this.walletIdentifier = walletIdentifier;\n this.walletPublicKey = walletPublicKey;\n this.walletType = walletType;\n this.blobGateway = blobGateway;\n // @ts-expect-error - TODO: Fix this\n this.#enclaveProvider.setSigner(this.signer);\n }\n\n get kwilClient(): KwilActionClient {\n return boundKwilClient(this.#kwilClient, this.kwilSigner);\n }\n\n get enclaveProvider(): BaseProvider {\n return boundEnclave(this.#enclaveProvider, this.#kwilClient, this.kwilSigner);\n }\n\n async logOut(): Promise<idOSClientIdle> {\n return finishLogOut(\n this.store,\n this.#kwilClient,\n this.kwilSigner,\n this.#enclaveProvider,\n this.blobGateway.url,\n );\n }\n\n async hasProfile(): Promise<boolean> {\n // NEAR profiles are keyed by the ed25519 public key. walletIdentifier is the account id.\n let address = this.walletIdentifier;\n if (this.walletType === \"NEAR\") {\n if (!this.walletPublicKey) throw new Error(\"NEAR wallet public key is required\");\n address = this.walletPublicKey;\n }\n return hasProfile(this.kwilClient, { address }).then((res) => {\n if (!res) throw new Error(\"has_profile returned no rows\");\n return res.has_profile;\n });\n }\n\n async createUserEncryptionProfile(\n userId: string,\n forceEncryptionPasswordStore?: EncryptionPasswordStore,\n ): Promise<PublicEncryptionProfile> {\n await exclusive(this.#kwilClient, async () => {\n assertSigner(this.#kwilClient, this.kwilSigner);\n await this.enclaveProvider.reconfigure({\n mode: \"new\",\n userId,\n walletAddress: this.walletIdentifier,\n walletPublicKey: this.walletPublicKey,\n walletType: this.walletType,\n encryptionPasswordStore: forceEncryptionPasswordStore,\n expectedUserEncryptionPublicKey: undefined,\n });\n assertSigner(this.#kwilClient, this.kwilSigner);\n });\n assertSigner(this.#kwilClient, this.kwilSigner);\n return this.enclaveProvider.ensureUserEncryptionProfile();\n }\n\n async logIn(): Promise<idOSClientLoggedIn> {\n if (!(await this.hasProfile())) throw new Error(\"User does not have a profile\");\n\n const kwilUser = await getUser(this.kwilClient);\n\n return exclusive(this.#kwilClient, async () => {\n assertSigner(this.#kwilClient, this.kwilSigner);\n await this.enclaveProvider.reconfigure({\n mode: \"existing\",\n userId: kwilUser.id,\n expectedUserEncryptionPublicKey: kwilUser.recipient_encryption_public_key,\n walletAddress: this.walletIdentifier,\n walletType: this.walletType,\n encryptionPasswordStore: kwilUser.encryption_password_store,\n walletPublicKey: this.walletPublicKey,\n });\n assertSigner(this.#kwilClient, this.kwilSigner);\n return new idOSClientLoggedIn(this, kwilUser);\n });\n }\n}\n\nfunction credentialRecipientWallet(client: {\n walletType: string;\n walletIdentifier: string;\n walletPublicKey?: string;\n}): string {\n // NEAR @caller is the ed25519 public key. walletIdentifier is the account id.\n if (client.walletType === \"NEAR\") {\n if (!client.walletPublicKey) throw new Error(\"NEAR wallet public key is required\");\n return client.walletPublicKey;\n }\n return client.walletIdentifier;\n}\n\nexport class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSigner>, \"state\"> {\n readonly state: \"logged-in\";\n readonly store: Store;\n readonly #kwilClient: KwilActionClient;\n readonly #enclaveProvider: BaseProvider;\n readonly signer: Wallet;\n readonly kwilSigner: KwilSigner;\n readonly walletIdentifier: string;\n readonly walletPublicKey: string | undefined;\n readonly walletType: WalletType;\n readonly user: idOSUser;\n readonly blobGateway: BlobGateway;\n\n constructor(idOSClientWithUserSigner: idOSClientWithUserSigner, user: idOSUser) {\n this.state = \"logged-in\";\n this.store = idOSClientWithUserSigner.store;\n this.#kwilClient = sharedKwilClient(idOSClientWithUserSigner.kwilClient);\n this.#enclaveProvider = sharedEnclave(idOSClientWithUserSigner.enclaveProvider);\n this.signer = idOSClientWithUserSigner.signer;\n this.kwilSigner = idOSClientWithUserSigner.kwilSigner;\n this.walletIdentifier = idOSClientWithUserSigner.walletIdentifier;\n this.walletPublicKey = idOSClientWithUserSigner.walletPublicKey;\n this.walletType = idOSClientWithUserSigner.walletType;\n this.user = user;\n this.blobGateway = idOSClientWithUserSigner.blobGateway;\n }\n\n get kwilClient(): KwilActionClient {\n return boundKwilClient(this.#kwilClient, this.kwilSigner);\n }\n\n get enclaveProvider(): BaseProvider {\n return boundEnclave(this.#enclaveProvider, this.#kwilClient, this.kwilSigner);\n }\n\n async logOut(): Promise<idOSClientIdle> {\n return finishLogOut(\n this.store,\n this.#kwilClient,\n this.kwilSigner,\n this.#enclaveProvider,\n this.blobGateway.url,\n );\n }\n\n async requestDWGMessage(params: idOSDelegatedWriteGrant): Promise<string> {\n return dwgMessage(this.kwilClient, params).then((res) => {\n if (!res) throw new Error(\"dwg_message returned no rows\");\n return res.message;\n });\n }\n\n async createCredential(\n publicNotes: string,\n plaintextContent: Uint8Array<ArrayBufferLike>,\n // In case of credential creation on users behalf, this would be a issuer key\n issuerSigningSecretKey?: Uint8Array,\n ): Promise<Omit<idOSCredential, \"user_id\" | \"content\" | \"inserter_type\" | \"inserter_id\">> {\n const credentialId = crypto.randomUUID();\n const preliminaryCredential: PreliminaryIDOSCredential = {\n ...(await buildPreliminaryIDOSCredential({\n publicNotes,\n plaintextContent,\n recipientEncryptionPublicKey: base64Decode(this.user.recipient_encryption_public_key),\n broaderMessageFor: (publicNotesSignature, contentUri) =>\n credentialBroaderMessage(this.kwilClient, {\n public_notes_signature: publicNotesSignature,\n content_uri: contentUri,\n recipient_wallet: credentialRecipientWallet(this),\n }).then((row) => row.message),\n issuerSigningSecretKey,\n ukycStorageId: ukycStorageIdForWallet(this.walletType, this.kwilSigner),\n })),\n id: credentialId,\n };\n requireAccessTokenForUkycContent(\n preliminaryCredential.contentUri,\n this.blobGateway.hasAccessToken,\n );\n\n const requestId = crypto.randomUUID();\n\n const payload: CreatePreliminaryCredentialInput = {\n request_id: requestId,\n credential_id: preliminaryCredential.id,\n issuer_auth_public_key: preliminaryCredential.issuerAuthPublicKey,\n encryptor_public_key: preliminaryCredential.encryptorPublicKey,\n content_uri: preliminaryCredential.contentUri,\n content_size: preliminaryCredential.contentSize,\n content_hash: hexEncodeSha256Hash(plaintextContent),\n public_notes: preliminaryCredential.publicNotes,\n public_notes_signature: preliminaryCredential.publicNotesSignature,\n broader_signature: preliminaryCredential.broaderSignature,\n };\n\n await createPreliminaryCredential(this.kwilClient, payload);\n\n await this.#uploadOwnedCredentialBlobs({\n requestId,\n credentialIds: [preliminaryCredential.id],\n original: preliminaryCredential.encryptedContent,\n });\n\n return mapPreliminaryToIDOSCredential(preliminaryCredential);\n }\n\n /**\n * A lost upload response can hide a finalized credential. The user owns it, so look it up\n * by id and read its blob back: the record alone doesn't prove the gateway stored our bytes\n * (a 2xx with a CID mismatch also lands here). Rethrow the unknown outcome unless both check\n * out, including when the credential isn't visible yet, a read fails, or the read takes\n * longer than READ_BACK_TIMEOUT_MS.\n */\n async #uploadOwnedCredentialBlobs(\n params: UploadCredentialBlobsParams & { credentialIds: [string] },\n ): Promise<void> {\n try {\n await this.blobGateway.uploadCredentialBlobs(params);\n } catch (error) {\n if (!(error instanceof BlobGatewayUploadOutcomeUnknownError)) throw error;\n\n const created = await this.getCredentialById(params.credentialIds[0]).catch(() => undefined);\n if (!created?.content_uri) throw error;\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), READ_BACK_TIMEOUT_MS);\n const stored = await this.blobGateway\n .fetchBlob({\n credentialId: created.id,\n contentUri: created.content_uri,\n expectedSize: created.content_size,\n signal: controller.signal,\n })\n .catch(() => undefined)\n .finally(() => clearTimeout(timer));\n const uploaded = params.original ?? params.copy;\n if (!stored || !bytesEqual(stored, uploaded)) throw error;\n }\n }\n\n async removeCredential(id: string): Promise<{ id: string }> {\n const credential = await this.getCredentialById(id);\n invariant(credential, `\"idOSCredential\" with id ${id} not found`);\n\n const contentUri = credential.content_uri ?? null;\n requireAccessTokenForUkycContent(contentUri, this.blobGateway.hasAccessToken);\n\n await removeCredential(this.kwilClient, { id });\n\n if (!contentUri) {\n return { id };\n }\n\n await this.blobGateway.deleteCredentialBlob({ credentialId: id });\n return { id };\n }\n\n async getCredentialById(id: string): Promise<idOSCredential | undefined> {\n return getCredentialOwned(this.kwilClient, { id }).then((res) => res[0]);\n }\n\n async shareCredential(\n credential: SharePreliminaryCredentialInput,\n ): Promise<SharePreliminaryCredentialInput> {\n await sharePreliminaryCredential(this.kwilClient, credential);\n return credential;\n }\n\n async getAllCredentials(): Promise<idOSCredentialListItem[]> {\n return getCredentials(this.kwilClient);\n }\n\n async getAccessGrantsOwned(): Promise<idOSGrant[]> {\n return getAccessGrantsOwned(this.kwilClient);\n }\n\n async getAttributes(): Promise<idOSUserAttribute[]> {\n return getAttributes(this.kwilClient);\n }\n\n async createAttribute(attribute: AddAttributeInput): Promise<AddAttributeInput> {\n await createAttribute(this.kwilClient, attribute);\n return attribute;\n }\n\n async getCredentialContentSha256Hash(id: string): Promise<string> {\n const credential = await this.getCredentialById(id);\n\n invariant(credential, `\"idOSCredential\" with id ${id} not found`);\n const plaintext = await this.#decryptCredentialContent(credential);\n\n return hexEncodeSha256Hash(plaintext);\n }\n\n async getCredentialContent(id: string): Promise<string> {\n const credential = await this.getCredentialById(id);\n\n invariant(credential, `\"idOSCredential\" with id ${id} not found`);\n const plaintext = await this.#decryptCredentialContent(credential);\n\n return utf8Decode(plaintext);\n }\n\n async getCredentialWithEncryptedContent(id: string): Promise<idOSCredential> {\n const credential = await this.getCredentialById(id);\n invariant(credential, `\"idOSCredential\" with id ${id} not found`);\n return this.#credentialWithInlineContent(credential);\n }\n\n async getCredentialSharedContent(id: string): Promise<string> {\n const credential = await this.getCredentialShared(id);\n\n invariant(credential, `Shared credential with id ${id} not found`);\n const plaintext = await this.#decryptCredentialContent(credential);\n\n return utf8Decode(plaintext);\n }\n\n async getGrants(\n params: Partial<GetAccessGrantsGrantedInput>,\n ): Promise<{ grants: idOSGrant[]; totalCount: number }> {\n return {\n grants: await getGrants(this.kwilClient, params),\n totalCount: await this.getGrantsCount(),\n };\n }\n\n async addWallets(params: AddWalletInput[]): Promise<AddWalletInput[]> {\n await addWallets(this.kwilClient, params);\n return params;\n }\n\n async getGrantsCount(): Promise<number> {\n return getAccessGrantsGrantedCount(this.kwilClient, {\n user_id: null,\n }).then((res) => {\n if (!res) throw new Error(\"get_access_grants_granted_count returned no rows\");\n return res.count;\n });\n }\n\n async getCredentialShared(id: string): Promise<idOSCredential | undefined> {\n return getCredentialShared(this.kwilClient, { id }).then((res) => res[0]);\n }\n\n async revokeAccessGrant(id: string): Promise<{ id: string }> {\n await revokeAccessGrant(this.kwilClient, { id });\n return { id };\n }\n\n async addWalletMessage(params: AddWalletMessageInput): Promise<string> {\n const result = await requestAddWalletMessage(this.kwilClient, params);\n return result.message;\n }\n\n async addWallet(params: AddWalletInput): Promise<AddWalletInput> {\n await addWallet(this.kwilClient, params);\n\n // we don't need to add the wallet to MPC if the user is not using MPC\n if (this.user.encryption_password_store !== \"mpc\") {\n console.log(\"MPC is not enabled or the user is not using MPC\");\n return params;\n }\n\n if (!params.wallet_type) {\n throw new Error(\"Wallet type is required for MPC users\");\n }\n\n const messageToSign = await this.enclaveProvider.addAddressMessageToSign(\n params.address,\n params.public_key ?? undefined,\n params.wallet_type,\n );\n\n const signature = await this.enclaveProvider.signTypedData(\n messageToSign.domain,\n messageToSign.types,\n messageToSign.value,\n );\n\n const result = await this.enclaveProvider.addAddressToMpcSecret(\n this.user.id,\n messageToSign.value,\n signature,\n );\n\n if (result !== \"success\") {\n console.error(`Failed to add wallet to MPC: ${result}`);\n }\n\n return params;\n }\n\n async getWallets(): Promise<GetWalletsOutput[]> {\n return getWallets(this.kwilClient);\n }\n\n async removeWallet(id: string): Promise<{ id: string }> {\n const wallets = await this.getWallets();\n const wallet = wallets.find((wallet) => wallet.id === id);\n if (!wallet) {\n throw new Error(`Wallet with id ${id} not found`);\n }\n\n await removeWallet(this.kwilClient, { id });\n\n // we don't need to add the wallet to MPC if the user is not using MPC\n if (this.user.encryption_password_store !== \"mpc\") {\n console.log(\"MPC is not enabled or the user is not using MPC\");\n return { id };\n }\n\n const messageToSign = await this.enclaveProvider.removeAddressMessageToSign(\n wallet.address,\n wallet.public_key ?? undefined,\n wallet.wallet_type,\n );\n const signature = await this.enclaveProvider.signTypedData(\n messageToSign.domain,\n messageToSign.types,\n messageToSign.value,\n );\n const result = await this.enclaveProvider.removeAddressFromMpcSecret(\n wallet.user_id,\n messageToSign.value,\n signature,\n );\n if (result !== \"success\") {\n console.error(`Failed to add wallet to MPC: ${result}`);\n }\n\n return { id };\n }\n\n async removeWallets(ids: string[]): Promise<string[]> {\n for (const id of ids) {\n await this.removeWallet(id);\n }\n\n return ids;\n }\n\n async filterCredentials(requirements: {\n acceptedIssuers: {\n authPublicKey: string;\n }[];\n publicNotesFieldFilters?: {\n pick: Parameters<typeof recordFilter>[1];\n omit: Parameters<typeof recordFilter>[2];\n };\n privateFieldFilters?: {\n pick: Parameters<typeof recordFilter>[1];\n omit: Parameters<typeof recordFilter>[2];\n };\n /** @deprecated The level leaves out self-attested data. Use `claimsFilter` instead. */\n credentialLevelOrHigherFilter?: {\n userLevel: BaseLevel;\n requiredAddons: Addon[];\n };\n /** Accepted sources per claim, e.g. `{ email: [\"VERIFIED\", \"MANUAL\"] }`. See `matchClaims`. */\n claimsFilter?: ClaimRequirements;\n }): Promise<idOSCredentialListItem[]> {\n const credentials = await this.getAllCredentials();\n const originalCredentials = credentials.filter(\n (cred) => !cred.original_id && !!cred.public_notes,\n );\n\n // invariant(originalCredentials.length, \"No original credentials found\");\n let result = originalCredentials.filter((cred) => {\n return requirements.acceptedIssuers?.some(\n (issuer) => issuer.authPublicKey === cred.issuer_auth_public_key,\n );\n });\n\n const publicNotesFieldFilters = requirements.publicNotesFieldFilters;\n const credentialLevelOrHigherFilter = requirements.credentialLevelOrHigherFilter;\n const privateFieldFilters = requirements.privateFieldFilters;\n const claimsFilter = requirements.claimsFilter;\n\n if (claimsFilter) {\n result = result.filter((credential) => {\n let publicNotes: Parameters<typeof matchClaims>[1];\n\n try {\n publicNotes = JSON.parse(credential.public_notes);\n } catch (_) {\n throw new Error(`Credential ${credential.id} has non-JSON public notes.`);\n }\n\n return matchClaims(claimsFilter, publicNotes);\n });\n }\n\n if (credentialLevelOrHigherFilter) {\n result = result.filter((credential) => {\n let publicNotes: Record<string, string>;\n\n try {\n publicNotes = JSON.parse(credential.public_notes);\n } catch (_) {\n throw new Error(`Credential ${credential.id} has non-JSON public notes.`);\n }\n\n return matchLevelOrHigher(\n credentialLevelOrHigherFilter.userLevel,\n credentialLevelOrHigherFilter.requiredAddons,\n publicNotes.level,\n );\n });\n }\n\n if (\n publicNotesFieldFilters &&\n (Object.keys(publicNotesFieldFilters.pick).length > 0 ||\n Object.keys(publicNotesFieldFilters.omit).length > 0)\n ) {\n result = result.filter((credential) => {\n let publicNotes: Record<string, string>;\n\n try {\n publicNotes = JSON.parse(credential.public_notes);\n } catch (_) {\n throw new Error(`Credential ${credential.id} has non-JSON public notes.`);\n }\n\n return recordFilter(\n publicNotes,\n publicNotesFieldFilters.pick,\n publicNotesFieldFilters.omit,\n );\n });\n }\n\n // Private field filtering requires decryption and the full idOS credential content\n // it's most \"expensive\", since it requires a roundtrip to the nodes and roundtrip to enclave.\n if (\n privateFieldFilters &&\n (Object.keys(privateFieldFilters.pick).length > 0 ||\n Object.keys(privateFieldFilters.omit).length > 0)\n ) {\n const fullCredentials = await Promise.all(\n result.map((credential) => this.getCredentialById(credential.id)),\n );\n\n // Check for undefined, it will be sign of some internal error\n invariant(\n fullCredentials.every((cred) => cred !== undefined),\n \"Some credentials could not be fetched in full form for private field filtering\",\n );\n\n const matches = await this.enclaveProvider.filterCredentials(\n await Promise.all(\n fullCredentials.map((credential) => this.#credentialWithInlineContent(credential)),\n ),\n privateFieldFilters,\n );\n\n result = result.filter((credential) =>\n matches.some((matchedCredential) => matchedCredential.id === credential.id),\n );\n }\n\n return result;\n }\n\n async requestAccessGrant(\n credentialId: string,\n {\n consumerEncryptionPublicKey,\n consumerAuthPublicKey,\n lockedUntil = 0,\n }: {\n consumerEncryptionPublicKey: string;\n consumerAuthPublicKey: string;\n lockedUntil?: number;\n },\n ): Promise<SharePreliminaryCredentialInput> {\n const credential = await this.getCredentialById(credentialId);\n\n invariant(credential, `\"idOSCredential\" with id ${credentialId} not found`);\n\n const plaintextContent = await this.#decryptCredentialContent(credential);\n const contentHash = hexEncodeSha256Hash(plaintextContent);\n\n await this.enclaveProvider.ensureUserEncryptionProfile();\n\n const { content, encryptorPublicKey } = await this.enclaveProvider.encrypt(\n plaintextContent,\n base64Decode(consumerEncryptionPublicKey),\n );\n\n // User issues the shared copy: sign content_uri with an ephemeral user-side key.\n // Copy issuer_auth_public_key need not match the original credential's issuer.\n const copyId = crypto.randomUUID();\n const ukycStorageId = ukycStorageIdForWallet(this.walletType, this.kwilSigner);\n const copyReference = ukycStorageId\n ? createUkycContentReference(ukycStorageId, content)\n : await createBlobContentReference(content);\n requireAccessTokenForUkycContent(copyReference.uri, this.blobGateway.hasAccessToken);\n const signedReference = await buildEphemeralSignedCredentialContentReference(\n \"\",\n copyReference.uri,\n (publicNotesSignature, contentUri) =>\n credentialBroaderMessage(this.kwilClient, {\n public_notes_signature: publicNotesSignature,\n content_uri: contentUri,\n recipient_wallet: credentialRecipientWallet(this),\n }).then((row) => row.message),\n );\n\n // Integrator-supplied. ed25519 @caller is lowercase hex; after exact grantee\n // matching, uppercase hex would store a grant the consumer cannot read. Other\n // identifier encodings (NEAR, XRPL, Stellar, MM) are case-sensitive, so leave them.\n const granteeWalletIdentifier = /^[0-9a-fA-F]{64}$/.test(consumerAuthPublicKey)\n ? consumerAuthPublicKey.toLowerCase()\n : consumerAuthPublicKey;\n\n const preliminaryCredential: SharePreliminaryCredentialInput = {\n ...signedReference,\n request_id: crypto.randomUUID(),\n copy_id: copyId,\n original_id: credential.id,\n content_uri: copyReference.uri,\n content_size: copyReference.size,\n encryptor_public_key: base64Encode(encryptorPublicKey),\n grantee_wallet_identifier: granteeWalletIdentifier,\n locked_until: lockedUntil,\n content_hash: contentHash,\n };\n\n await this.shareCredential(preliminaryCredential);\n await this.#uploadOwnedCredentialBlobs({\n requestId: preliminaryCredential.request_id,\n credentialIds: [copyId],\n copy: content,\n });\n\n return preliminaryCredential;\n }\n\n async #credentialWithInlineContent(credential: idOSCredential): Promise<idOSCredential> {\n if (credential.content) {\n return credential;\n }\n\n return {\n ...credential,\n content: base64Encode(await this.#getCredentialEncryptedContent(credential)),\n content_uri: null,\n content_size: null,\n };\n }\n\n async #decryptCredentialContent(credential: idOSCredential): Promise<Uint8Array> {\n await this.enclaveProvider.ensureUserEncryptionProfile();\n\n return this.enclaveProvider.decrypt(\n await this.#getCredentialEncryptedContent(credential),\n base64Decode(credential.encryptor_public_key),\n );\n }\n\n async #getCredentialEncryptedContent(credential: idOSCredential): Promise<Uint8Array> {\n return resolveCredentialEncryptedContent(credential, this.blobGateway);\n }\n}\n\nexport type {\n Claim,\n ClaimRequirements,\n Claims,\n ClaimSource,\n ClaimSources,\n idOSDelegatedWriteGrant,\n DelegatedWriteGrantBaseParams,\n idOSCredential,\n idOSCredentialListItem,\n idOSGrant,\n idOSUser,\n idOSUserAttribute,\n idOSWallet,\n};\n\nexport { signNearMessage, toDelegatedWriteGrantBaseParams };\n\nexport function createIDOSClient(params: {\n nodeUrl: string;\n /**\n * Optional blob gateway base URL. Defaults to `nodeUrl`.\n * In the browser this must share KGW's session-cookie Domain\n * (typically the same host), because reads use `credentials: \"include\"`.\n */\n blobGatewayUrl?: string;\n enclaveOptions: Omit<IframeEnclave[\"options\"], \"mode\">;\n}): idOSClientConfiguration<IframeEnclave> {\n return new idOSClientConfiguration({\n nodeUrl: params.nodeUrl,\n blobGatewayUrl: params.blobGatewayUrl,\n enclaveOptions: params.enclaveOptions,\n });\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@idos-network/client",
3
- "version": "3.0.0",
3
+ "version": "4.0.0",
4
4
  "description": "idOS Client JavaScript SDK for browser environments",
5
5
  "homepage": "https://idos.network",
6
6
  "license": "MIT",
@@ -28,11 +28,11 @@
28
28
  "access": "public"
29
29
  },
30
30
  "dependencies": {
31
- "@idos-network/credentials": "3.0.0",
32
- "@idos-network/enclave": "3.0.0",
33
- "@idos-network/kwil-infra": "3.0.0",
31
+ "@idos-network/credentials": "4.0.0",
32
+ "@idos-network/enclave": "3.0.2",
33
+ "@idos-network/kwil-infra": "4.0.0",
34
34
  "@idos-network/kwil-js": "0.2.2",
35
- "@idos-network/utils": "3.0.0",
35
+ "@idos-network/utils": "3.1.0",
36
36
  "tiny-invariant": "^1.3.3"
37
37
  },
38
38
  "devDependencies": {
package/src/index.test.ts CHANGED
@@ -5,7 +5,12 @@ import type { BaseProvider } from "@idos-network/enclave";
5
5
  import { createMmTokenAuth, KwilActionClient } from "@idos-network/kwil-infra";
6
6
  import { NodeKwil } from "@idos-network/kwil-js";
7
7
  import { BlobGateway, createBlobContentReference } from "@idos-network/utils/blob-gateway";
8
- import { base64Encode, base64UrlEncode, utf8Encode } from "@idos-network/utils/codecs";
8
+ import {
9
+ base64Encode,
10
+ base64UrlEncode,
11
+ hexEncodeSha256Hash,
12
+ utf8Encode,
13
+ } from "@idos-network/utils/codecs";
9
14
  import { MemoryStore } from "@idos-network/utils/store";
10
15
  import { afterEach, describe, expect, it, vi } from "vitest";
11
16
 
@@ -13,7 +18,7 @@ import {
13
18
  idOSClientConfiguration,
14
19
  idOSClientIdle,
15
20
  idOSClientLoggedIn,
16
- type idOSClientWithUserSigner,
21
+ idOSClientWithUserSigner,
17
22
  toDelegatedWriteGrantBaseParams,
18
23
  } from "./index.js";
19
24
 
@@ -303,6 +308,70 @@ describe("signer switching on a shared idle client", () => {
303
308
  });
304
309
  });
305
310
 
311
+ describe("hasProfile", () => {
312
+ const nearPublicKey = "ed25519:9esz1ouR3vwBwjnUjjcFB8ETfQb6cnBPtXt8v6QPM2Nf";
313
+
314
+ function clientFor(wallet: {
315
+ walletIdentifier: string;
316
+ walletPublicKey: string | undefined;
317
+ walletType: "NEAR" | "EVM";
318
+ }) {
319
+ const idle = idleClient();
320
+ const kwilSigner = {} as never;
321
+ idle.kwilClient.setSigner(kwilSigner);
322
+ return {
323
+ client: new idOSClientWithUserSigner(
324
+ idle,
325
+ {} as never,
326
+ kwilSigner,
327
+ wallet.walletIdentifier,
328
+ wallet.walletPublicKey,
329
+ wallet.walletType,
330
+ idle.blobGateway,
331
+ ),
332
+ call: idle.kwilClient.call,
333
+ };
334
+ }
335
+
336
+ it("looks up a NEAR profile by public key and an EVM profile by wallet identifier", async () => {
337
+ const near = clientFor({
338
+ walletIdentifier: "alice.near",
339
+ walletPublicKey: nearPublicKey,
340
+ walletType: "NEAR",
341
+ });
342
+
343
+ await expect(near.client.hasProfile()).resolves.toBe(true);
344
+ expect(near.call).toHaveBeenCalledWith(
345
+ { name: "has_profile", inputs: { address: nearPublicKey } },
346
+ undefined,
347
+ );
348
+
349
+ const evmIdentifier = "0x1234567890123456789012345678901234567890";
350
+ const evm = clientFor({
351
+ walletIdentifier: evmIdentifier,
352
+ walletPublicKey: undefined,
353
+ walletType: "EVM",
354
+ });
355
+
356
+ await expect(evm.client.hasProfile()).resolves.toBe(true);
357
+ expect(evm.call).toHaveBeenCalledWith(
358
+ { name: "has_profile", inputs: { address: evmIdentifier } },
359
+ undefined,
360
+ );
361
+ });
362
+
363
+ it("throws when a NEAR signer has no public key", async () => {
364
+ const near = clientFor({
365
+ walletIdentifier: "alice.near",
366
+ walletPublicKey: undefined,
367
+ walletType: "NEAR",
368
+ });
369
+
370
+ await expect(near.client.hasProfile()).rejects.toThrow("NEAR wallet public key is required");
371
+ expect(near.call).not.toHaveBeenCalled();
372
+ });
373
+ });
374
+
306
375
  describe("Node client defaults", () => {
307
376
  it("defaults to MemoryStore outside the browser", () => {
308
377
  class FakeEnclave {
@@ -414,6 +483,7 @@ async function createCredentialForWallet(walletType: "MM" | "EVM"): Promise<{
414
483
  const kwilSigner = walletType === "MM" ? createMmTokenAuth(mmToken) : {};
415
484
  const kwilClient = {
416
485
  signer: kwilSigner,
486
+ call: async () => [{ message: "credential-message" }],
417
487
  execute: async ({ inputs }: { inputs: Record<string, unknown> }) => {
418
488
  preliminaryInput = inputs;
419
489
  },
@@ -463,7 +533,9 @@ describe("credential blob storage", () => {
463
533
  it("creates MM credentials with ukyc:// and the encrypted byte size", async () => {
464
534
  const { credential, preliminaryInput, uploadedBytes } = await createCredentialForWallet("MM");
465
535
 
466
- expect(credential.content_uri).toMatch(/^ukyc:\/\/storage-abc\/blobs\//);
536
+ expect(credential.content_uri).toBe(
537
+ `ukyc://storage-abc/blobs/${hexEncodeSha256Hash(uploadedBytes ?? new Uint8Array())}`,
538
+ );
467
539
  expect(preliminaryInput?.content_uri).toBe(credential.content_uri);
468
540
  expect(preliminaryInput?.content_size).toBe(
469
541
  credentialPlaintext.byteLength + NACL_BOX_ENCRYPTION_OVERHEAD_BYTES,
@@ -482,6 +554,144 @@ describe("credential blob storage", () => {
482
554
  expect(uploadedBytes?.byteLength).toBe(preliminaryInput?.content_size);
483
555
  });
484
556
 
557
+ describe("when the upload outcome is unknown", () => {
558
+ type StoredRecord = { content_uri: string; content_size: number; blob: Uint8Array };
559
+
560
+ afterEach(() => {
561
+ vi.useRealTimers();
562
+ });
563
+
564
+ // The upload POST loses its response; blob GETs serve whatever the record says is stored.
565
+ function clientWithLostUpload(
566
+ lookup: (id: string, uploaded: Uint8Array) => Promise<StoredRecord | undefined>,
567
+ onRead?: (signal: AbortSignal | undefined) => Promise<Response>,
568
+ ): idOSClientLoggedIn {
569
+ let uploaded = new Uint8Array();
570
+ let stored: StoredRecord | undefined;
571
+ const kwilSigner = {};
572
+ const kwilClient = {
573
+ signer: kwilSigner,
574
+ execute: async () => undefined,
575
+ call: async ({ name, inputs }: { name: string; inputs: { id: string } }) => {
576
+ // Other view calls made while building the credential (e.g. a message to sign).
577
+ if (name !== "get_credential_owned") return [{ message: "credential-message" }];
578
+ stored = await lookup(inputs.id, uploaded);
579
+ return stored ? [{ id: inputs.id, ...stored }] : [];
580
+ },
581
+ } as unknown as KwilActionClient;
582
+ const blobGateway = new BlobGateway({
583
+ url: "https://blob.example",
584
+ uploadRetries: 0,
585
+ fetchFn: async (_input, init) => {
586
+ if (init?.method === "POST") {
587
+ const original = (init.body as FormData).get("original") as Blob;
588
+ uploaded = new Uint8Array(await original.arrayBuffer());
589
+ throw new TypeError("fetch failed");
590
+ }
591
+ if (!stored) throw new Error("unexpected blob read");
592
+ if (onRead) return onRead(init?.signal ?? undefined);
593
+ return new Response(stored.blob.slice());
594
+ },
595
+ });
596
+ const withSigner = {
597
+ store: new MemoryStore(),
598
+ kwilClient,
599
+ enclaveProvider: {},
600
+ signer: {},
601
+ kwilSigner,
602
+ walletIdentifier: "wallet",
603
+ walletPublicKey: undefined,
604
+ walletType: "EVM",
605
+ blobGateway,
606
+ } as unknown as idOSClientWithUserSigner;
607
+ return new idOSClientLoggedIn(withSigner, {
608
+ id: crypto.randomUUID(),
609
+ recipient_encryption_public_key: base64Encode(new Uint8Array(32).fill(7)),
610
+ encryption_password_store: "user",
611
+ });
612
+ }
613
+
614
+ it("returns the credential when it exists and its blob matches the upload", async () => {
615
+ const lookedUp: string[] = [];
616
+ const client = clientWithLostUpload(async (id, uploaded) => {
617
+ lookedUp.push(id);
618
+ const { uri } = await createBlobContentReference(uploaded);
619
+ return { content_uri: uri, content_size: uploaded.byteLength, blob: uploaded };
620
+ });
621
+
622
+ const credential = await client.createCredential("public notes", credentialPlaintext);
623
+
624
+ expect(lookedUp).toEqual([credential.id]);
625
+ });
626
+
627
+ it("rethrows when the stored blob differs from the upload", async () => {
628
+ const client = clientWithLostUpload(async (_id, uploaded) => {
629
+ const tampered = uploaded.slice();
630
+ tampered[0] ^= 1;
631
+ // A non-ipfs URI skips the CID check, so this exercises the byte comparison.
632
+ return {
633
+ content_uri: "ukyc://storage-abc/blobs/credential",
634
+ content_size: tampered.byteLength,
635
+ blob: tampered,
636
+ };
637
+ });
638
+
639
+ await expect(
640
+ client.createCredential("public notes", credentialPlaintext),
641
+ ).rejects.toMatchObject({ name: "BlobGatewayUploadOutcomeUnknownError" });
642
+ });
643
+
644
+ it("gives up on a stalled read-back after the deadline", async () => {
645
+ vi.useFakeTimers({ toFake: ["setTimeout", "clearTimeout"] });
646
+ let readStarted!: () => void;
647
+ const started = new Promise<void>((resolve) => {
648
+ readStarted = resolve;
649
+ });
650
+ const client = clientWithLostUpload(
651
+ async (_id, uploaded) => {
652
+ const { uri } = await createBlobContentReference(uploaded);
653
+ return { content_uri: uri, content_size: uploaded.byteLength, blob: uploaded };
654
+ },
655
+ (signal) => {
656
+ readStarted();
657
+ // Never answers; only the abort signal can end it.
658
+ return new Promise((_resolve, reject) => {
659
+ signal?.addEventListener("abort", () => reject(signal.reason));
660
+ });
661
+ },
662
+ );
663
+
664
+ const creation = client.createCredential("public notes", credentialPlaintext);
665
+ const outcome = expect(creation).rejects.toMatchObject({
666
+ name: "BlobGatewayUploadOutcomeUnknownError",
667
+ });
668
+ await started;
669
+ await vi.advanceTimersByTimeAsync(60_000);
670
+ await outcome;
671
+ });
672
+
673
+ it("rethrows with the credential id when the credential isn't there", async () => {
674
+ const client = clientWithLostUpload(async () => undefined);
675
+
676
+ await expect(
677
+ client.createCredential("public notes", credentialPlaintext),
678
+ ).rejects.toMatchObject({
679
+ name: "BlobGatewayUploadOutcomeUnknownError",
680
+ credentialIds: [expect.any(String)],
681
+ });
682
+ });
683
+
684
+ it("rethrows the unknown outcome when the lookup itself fails", async () => {
685
+ const client = clientWithLostUpload(async () => {
686
+ throw new Error("node unavailable");
687
+ });
688
+
689
+ await expect(
690
+ client.createCredential("public notes", credentialPlaintext),
691
+ ).rejects.toMatchObject({ name: "BlobGatewayUploadOutcomeUnknownError" });
692
+ });
693
+ });
694
+
485
695
  it("returns the dwg message string and maps params via toDelegatedWriteGrantBaseParams", async () => {
486
696
  const callAction = vi.fn(async () => [{ message: "mock-dwg-message" }]);
487
697
  const kwilClient = {
package/src/index.ts CHANGED
@@ -8,11 +8,17 @@ import {
8
8
  buildEphemeralSignedCredentialContentReference,
9
9
  buildPreliminaryIDOSCredential,
10
10
  mapPreliminaryToIDOSCredential,
11
+ matchClaims,
11
12
  matchLevelOrHigher,
12
13
  type PreliminaryIDOSCredential,
13
14
  recordFilter,
14
15
  type BaseLevel,
15
16
  type Addon,
17
+ type Claim,
18
+ type ClaimRequirements,
19
+ type Claims,
20
+ type ClaimSource,
21
+ type ClaimSources,
16
22
  } from "@idos-network/credentials/utils";
17
23
  import {
18
24
  createClientKwilSigner,
@@ -21,7 +27,7 @@ import {
21
27
  createWebKwilClient,
22
28
  isMmTokenAuth,
23
29
  type KwilActionClient,
24
- mmTokenCredentialContentUri,
30
+ mmTokenStorageId,
25
31
  signNearMessage,
26
32
  type Wallet,
27
33
  } from "@idos-network/kwil-infra";
@@ -34,6 +40,7 @@ import {
34
40
  addWallets,
35
41
  addAttribute as createAttribute,
36
42
  createPreliminaryCredential,
43
+ credentialBroaderMessage,
37
44
  type CreatePreliminaryCredentialInput,
38
45
  dwgMessage,
39
46
  type GetAccessGrantsGrantedInput,
@@ -67,9 +74,12 @@ import {
67
74
  import { NodeKwil, type KwilSigner } from "@idos-network/kwil-js";
68
75
  import {
69
76
  BlobGateway,
77
+ BlobGatewayUploadOutcomeUnknownError,
70
78
  createBlobContentReference,
79
+ createUkycContentReference,
71
80
  requireAccessTokenForUkycContent,
72
81
  resolveCredentialEncryptedContent,
82
+ type UploadCredentialBlobsParams,
73
83
  } from "@idos-network/utils/blob-gateway";
74
84
  import {
75
85
  base64Decode,
@@ -123,15 +133,22 @@ function blobGatewayForSigner(idle: idOSClientIdle, kwilSigner: KwilSigner): Blo
123
133
  : idle.blobGateway;
124
134
  }
125
135
 
126
- function contentUriForWallet(
136
+ function ukycStorageIdForWallet(
127
137
  walletType: WalletType,
128
138
  kwilSigner: KwilSigner,
129
- credentialId: string,
130
139
  ): string | undefined {
131
140
  if (walletType !== "MM") {
132
141
  return undefined;
133
142
  }
134
- return mmTokenCredentialContentUri(kwilSigner, credentialId);
143
+ return mmTokenStorageId(kwilSigner);
144
+ }
145
+
146
+ // Deadline for reading a blob back after an unknown upload outcome. A slower read leaves the
147
+ // outcome unknown, which callers already have to handle, instead of hanging the call.
148
+ const READ_BACK_TIMEOUT_MS = 60_000;
149
+
150
+ function bytesEqual(a: Uint8Array, b: Uint8Array): boolean {
151
+ return a.byteLength === b.byteLength && a.every((byte, index) => byte === b[index]);
135
152
  }
136
153
 
137
154
  const STALE_CLIENT =
@@ -400,7 +417,10 @@ export class idOSClientIdle {
400
417
  }
401
418
 
402
419
  async addressHasProfile(address: string): Promise<boolean> {
403
- return hasProfile(this.kwilClient, { address }).then((res) => res.has_profile);
420
+ return hasProfile(this.kwilClient, { address }).then((res) => {
421
+ if (!res) throw new Error("has_profile returned no rows");
422
+ return res.has_profile;
423
+ });
404
424
  }
405
425
 
406
426
  async withUserSigner(_signer: Wallet): Promise<idOSClientWithUserSigner> {
@@ -494,9 +514,16 @@ export class idOSClientWithUserSigner implements Omit<Properties<idOSClientIdle>
494
514
  }
495
515
 
496
516
  async hasProfile(): Promise<boolean> {
497
- return hasProfile(this.kwilClient, { address: this.walletIdentifier }).then(
498
- (x) => x.has_profile,
499
- );
517
+ // NEAR profiles are keyed by the ed25519 public key. walletIdentifier is the account id.
518
+ let address = this.walletIdentifier;
519
+ if (this.walletType === "NEAR") {
520
+ if (!this.walletPublicKey) throw new Error("NEAR wallet public key is required");
521
+ address = this.walletPublicKey;
522
+ }
523
+ return hasProfile(this.kwilClient, { address }).then((res) => {
524
+ if (!res) throw new Error("has_profile returned no rows");
525
+ return res.has_profile;
526
+ });
500
527
  }
501
528
 
502
529
  async createUserEncryptionProfile(
@@ -542,6 +569,19 @@ export class idOSClientWithUserSigner implements Omit<Properties<idOSClientIdle>
542
569
  }
543
570
  }
544
571
 
572
+ function credentialRecipientWallet(client: {
573
+ walletType: string;
574
+ walletIdentifier: string;
575
+ walletPublicKey?: string;
576
+ }): string {
577
+ // NEAR @caller is the ed25519 public key. walletIdentifier is the account id.
578
+ if (client.walletType === "NEAR") {
579
+ if (!client.walletPublicKey) throw new Error("NEAR wallet public key is required");
580
+ return client.walletPublicKey;
581
+ }
582
+ return client.walletIdentifier;
583
+ }
584
+
545
585
  export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSigner>, "state"> {
546
586
  readonly state: "logged-in";
547
587
  readonly store: Store;
@@ -588,7 +628,10 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
588
628
  }
589
629
 
590
630
  async requestDWGMessage(params: idOSDelegatedWriteGrant): Promise<string> {
591
- return dwgMessage(this.kwilClient, params).then((res) => res.message);
631
+ return dwgMessage(this.kwilClient, params).then((res) => {
632
+ if (!res) throw new Error("dwg_message returned no rows");
633
+ return res.message;
634
+ });
592
635
  }
593
636
 
594
637
  async createCredential(
@@ -603,8 +646,14 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
603
646
  publicNotes,
604
647
  plaintextContent,
605
648
  recipientEncryptionPublicKey: base64Decode(this.user.recipient_encryption_public_key),
649
+ broaderMessageFor: (publicNotesSignature, contentUri) =>
650
+ credentialBroaderMessage(this.kwilClient, {
651
+ public_notes_signature: publicNotesSignature,
652
+ content_uri: contentUri,
653
+ recipient_wallet: credentialRecipientWallet(this),
654
+ }).then((row) => row.message),
606
655
  issuerSigningSecretKey,
607
- contentUri: contentUriForWallet(this.walletType, this.kwilSigner, credentialId),
656
+ ukycStorageId: ukycStorageIdForWallet(this.walletType, this.kwilSigner),
608
657
  })),
609
658
  id: credentialId,
610
659
  };
@@ -630,14 +679,49 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
630
679
 
631
680
  await createPreliminaryCredential(this.kwilClient, payload);
632
681
 
633
- await this.blobGateway.uploadCredentialBlobs({
682
+ await this.#uploadOwnedCredentialBlobs({
634
683
  requestId,
684
+ credentialIds: [preliminaryCredential.id],
635
685
  original: preliminaryCredential.encryptedContent,
636
686
  });
637
687
 
638
688
  return mapPreliminaryToIDOSCredential(preliminaryCredential);
639
689
  }
640
690
 
691
+ /**
692
+ * A lost upload response can hide a finalized credential. The user owns it, so look it up
693
+ * by id and read its blob back: the record alone doesn't prove the gateway stored our bytes
694
+ * (a 2xx with a CID mismatch also lands here). Rethrow the unknown outcome unless both check
695
+ * out, including when the credential isn't visible yet, a read fails, or the read takes
696
+ * longer than READ_BACK_TIMEOUT_MS.
697
+ */
698
+ async #uploadOwnedCredentialBlobs(
699
+ params: UploadCredentialBlobsParams & { credentialIds: [string] },
700
+ ): Promise<void> {
701
+ try {
702
+ await this.blobGateway.uploadCredentialBlobs(params);
703
+ } catch (error) {
704
+ if (!(error instanceof BlobGatewayUploadOutcomeUnknownError)) throw error;
705
+
706
+ const created = await this.getCredentialById(params.credentialIds[0]).catch(() => undefined);
707
+ if (!created?.content_uri) throw error;
708
+
709
+ const controller = new AbortController();
710
+ const timer = setTimeout(() => controller.abort(), READ_BACK_TIMEOUT_MS);
711
+ const stored = await this.blobGateway
712
+ .fetchBlob({
713
+ credentialId: created.id,
714
+ contentUri: created.content_uri,
715
+ expectedSize: created.content_size,
716
+ signal: controller.signal,
717
+ })
718
+ .catch(() => undefined)
719
+ .finally(() => clearTimeout(timer));
720
+ const uploaded = params.original ?? params.copy;
721
+ if (!stored || !bytesEqual(stored, uploaded)) throw error;
722
+ }
723
+ }
724
+
641
725
  async removeCredential(id: string): Promise<{ id: string }> {
642
726
  const credential = await this.getCredentialById(id);
643
727
  invariant(credential, `"idOSCredential" with id ${id} not found`);
@@ -733,7 +817,10 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
733
817
  async getGrantsCount(): Promise<number> {
734
818
  return getAccessGrantsGrantedCount(this.kwilClient, {
735
819
  user_id: null,
736
- }).then((res) => res.count);
820
+ }).then((res) => {
821
+ if (!res) throw new Error("get_access_grants_granted_count returned no rows");
822
+ return res.count;
823
+ });
737
824
  }
738
825
 
739
826
  async getCredentialShared(id: string): Promise<idOSCredential | undefined> {
@@ -849,10 +936,13 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
849
936
  pick: Parameters<typeof recordFilter>[1];
850
937
  omit: Parameters<typeof recordFilter>[2];
851
938
  };
939
+ /** @deprecated The level leaves out self-attested data. Use `claimsFilter` instead. */
852
940
  credentialLevelOrHigherFilter?: {
853
941
  userLevel: BaseLevel;
854
942
  requiredAddons: Addon[];
855
943
  };
944
+ /** Accepted sources per claim, e.g. `{ email: ["VERIFIED", "MANUAL"] }`. See `matchClaims`. */
945
+ claimsFilter?: ClaimRequirements;
856
946
  }): Promise<idOSCredentialListItem[]> {
857
947
  const credentials = await this.getAllCredentials();
858
948
  const originalCredentials = credentials.filter(
@@ -869,6 +959,21 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
869
959
  const publicNotesFieldFilters = requirements.publicNotesFieldFilters;
870
960
  const credentialLevelOrHigherFilter = requirements.credentialLevelOrHigherFilter;
871
961
  const privateFieldFilters = requirements.privateFieldFilters;
962
+ const claimsFilter = requirements.claimsFilter;
963
+
964
+ if (claimsFilter) {
965
+ result = result.filter((credential) => {
966
+ let publicNotes: Parameters<typeof matchClaims>[1];
967
+
968
+ try {
969
+ publicNotes = JSON.parse(credential.public_notes);
970
+ } catch (_) {
971
+ throw new Error(`Credential ${credential.id} has non-JSON public notes.`);
972
+ }
973
+
974
+ return matchClaims(claimsFilter, publicNotes);
975
+ });
976
+ }
872
977
 
873
978
  if (credentialLevelOrHigherFilter) {
874
979
  result = result.filter((credential) => {
@@ -971,12 +1076,21 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
971
1076
  // User issues the shared copy: sign content_uri with an ephemeral user-side key.
972
1077
  // Copy issuer_auth_public_key need not match the original credential's issuer.
973
1078
  const copyId = crypto.randomUUID();
974
- const ukycContentUri = contentUriForWallet(this.walletType, this.kwilSigner, copyId);
975
- requireAccessTokenForUkycContent(ukycContentUri, this.blobGateway.hasAccessToken);
976
- const copyReference = ukycContentUri
977
- ? { uri: ukycContentUri, size: content.byteLength }
1079
+ const ukycStorageId = ukycStorageIdForWallet(this.walletType, this.kwilSigner);
1080
+ const copyReference = ukycStorageId
1081
+ ? createUkycContentReference(ukycStorageId, content)
978
1082
  : await createBlobContentReference(content);
979
- const signedReference = buildEphemeralSignedCredentialContentReference("", copyReference.uri);
1083
+ requireAccessTokenForUkycContent(copyReference.uri, this.blobGateway.hasAccessToken);
1084
+ const signedReference = await buildEphemeralSignedCredentialContentReference(
1085
+ "",
1086
+ copyReference.uri,
1087
+ (publicNotesSignature, contentUri) =>
1088
+ credentialBroaderMessage(this.kwilClient, {
1089
+ public_notes_signature: publicNotesSignature,
1090
+ content_uri: contentUri,
1091
+ recipient_wallet: credentialRecipientWallet(this),
1092
+ }).then((row) => row.message),
1093
+ );
980
1094
 
981
1095
  // Integrator-supplied. ed25519 @caller is lowercase hex; after exact grantee
982
1096
  // matching, uppercase hex would store a grant the consumer cannot read. Other
@@ -999,8 +1113,9 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
999
1113
  };
1000
1114
 
1001
1115
  await this.shareCredential(preliminaryCredential);
1002
- await this.blobGateway.uploadCredentialBlobs({
1116
+ await this.#uploadOwnedCredentialBlobs({
1003
1117
  requestId: preliminaryCredential.request_id,
1118
+ credentialIds: [copyId],
1004
1119
  copy: content,
1005
1120
  });
1006
1121
 
@@ -1035,6 +1150,11 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
1035
1150
  }
1036
1151
 
1037
1152
  export type {
1153
+ Claim,
1154
+ ClaimRequirements,
1155
+ Claims,
1156
+ ClaimSource,
1157
+ ClaimSources,
1038
1158
  idOSDelegatedWriteGrant,
1039
1159
  DelegatedWriteGrantBaseParams,
1040
1160
  idOSCredential,