@idos-network/client 3.1.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/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/index.test.ts +148 -2
- package/src/index.ts +103 -16
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/enclave/iframe-enclave.ts","../src/index.ts"],"mappings":";;;;;;;;;;UAgBiB,6BAA6B;EAC5C;EACA;EACA;;qBAGW,sBAAsB,aAAa;UACtC;UACA;UACA;UACA;EAER,YAAY,SAAS;;EAcrB,QAAc;;;;;EAkBd,SAAe;;EAKf,YAAkB,UAAS,KAAK,6CAAkD;;EAMlF,QAAc,kBAAkB;;EAchC,kBACE,aAAa,wBACb;IAAuB,MAAM;IAA2B,MAAM;MAC7D,QAAQ;;EAKX,QACE,SAAS,YACT,mBAAmB,aAClB;IAAU,SAAS;IAAY,oBAAoB;;;EAKtD,QACE,SAAS,YACT,iBAAiB,aAChB,QAAQ,WAAW;;EAKtB,+BAAqC;;EAarC,+BAAqC,QAAQ;EAU7C,wBACE,iBACA,+BACA,2BACC,QAAQ;EAIX,2BACE,iBACA,+BACA,8BACC,QAAQ;EASX,sBACE,gBACA,SAAS,4BACT,oBACC;EAIH,2BACE,gBACA,SAAS,+BACT,oBACC;UAIW;UA2DN;UAKA;UAKM;UAyBN;UAKM;;;;
|
|
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,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,mmTokenCredentialContentUri 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 te,dwgMessage as g,getAccessGrantsGrantedCount as _,getAccessGrantsOwned as ne,getAttributes as re,getCredentialOwned as ie,getCredentialShared as ae,getCredentials as oe,getGrants as v,getUser as se,getWallets as ce,hasProfile as y,removeCredential as b,removeWallet as le,revokeAccessGrant as x,sharePreliminaryCredential as ue,toDelegatedWriteGrantBaseParams as de}from"@idos-network/kwil-infra/actions";import{NodeKwil as fe}from"@idos-network/kwil-js";import{BlobGateway as S,createBlobContentReference as pe,requireAccessTokenForUkycContent as C,resolveCredentialEncryptedContent as me}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 he,MemoryStore as ge}from"@idos-network/utils/store";import O from"tiny-invariant";import{BaseProvider as _e}from"@idos-network/enclave";var k=class extends _e{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 fe}function M(e){return A()?new S({url:e,fetchFn:(e,t)=>fetch(e,{...t,credentials:`include`})}):new S({url:e})}function N(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 P(e,t,n){if(e===`MM`)return d(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 ve(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)?ve(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??(A()?new he:new ge),this.enclaveProvider=e.enclaveProvider?new e.enclaveProvider({...e.enclaveOptions,store:this.store}):new k(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(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=>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 q(this.kwilClient,async()=>(this.kwilClient.setSigner(n),new Q(this,t,n,r,i,a,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(){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=>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 g(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 te(this.kwilClient,c),await this.blobGateway.uploadCredentialBlobs({requestId:s,original:o.encryptedContent}),n(o)}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 ie(this.kwilClient,{id:e}).then(e=>e[0])}async shareCredential(e){return await ue(this.kwilClient,e),e}async getAllCredentials(){return oe(this.kwilClient)}async getAccessGrantsOwned(){return ne(this.kwilClient)}async getAttributes(){return re(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.#r(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.#r(t);return D(n)}async getCredentialWithEncryptedContent(e){let t=await this.getCredentialById(e);return O(t,`"idOSCredential" with id ${e} not found`),this.#n(t)}async getCredentialSharedContent(e){let t=await this.getCredentialShared(e);O(t,`Shared credential with id ${e} not found`);let n=await this.#r(t);return D(n)}async getGrants(e){return{grants:await v(this.kwilClient,e),totalCount:await this.getGrantsCount()}}async addWallets(e){return await ee(this.kwilClient,e),e}async getGrantsCount(){return _(this.kwilClient,{user_id:null}).then(e=>e.count)}async getCredentialShared(e){return ae(this.kwilClient,{id:e}).then(e=>e[0])}async revokeAccessGrant(e){return await x(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 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 le(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.#n(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.#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 pe(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 me(e,this.blobGateway)}};function ye(e){return new X({nodeUrl:e.nodeUrl,blobGatewayUrl:e.blobGatewayUrl,enclaveOptions:e.enclaveOptions})}export{k as IframeEnclave,ye as createIDOSClient,X as idOSClientConfiguration,Z as idOSClientIdle,$ as idOSClientLoggedIn,Q as idOSClientWithUserSigner,f as signNearMessage,de 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 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 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 // 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((x) => x.has_profile);\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 /** @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 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 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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"}
|
|
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
|
+
"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": "
|
|
32
|
-
"@idos-network/enclave": "3.0.
|
|
33
|
-
"@idos-network/kwil-infra": "
|
|
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
|
|
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 {
|
|
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
|
|
|
@@ -478,6 +483,7 @@ async function createCredentialForWallet(walletType: "MM" | "EVM"): Promise<{
|
|
|
478
483
|
const kwilSigner = walletType === "MM" ? createMmTokenAuth(mmToken) : {};
|
|
479
484
|
const kwilClient = {
|
|
480
485
|
signer: kwilSigner,
|
|
486
|
+
call: async () => [{ message: "credential-message" }],
|
|
481
487
|
execute: async ({ inputs }: { inputs: Record<string, unknown> }) => {
|
|
482
488
|
preliminaryInput = inputs;
|
|
483
489
|
},
|
|
@@ -527,7 +533,9 @@ describe("credential blob storage", () => {
|
|
|
527
533
|
it("creates MM credentials with ukyc:// and the encrypted byte size", async () => {
|
|
528
534
|
const { credential, preliminaryInput, uploadedBytes } = await createCredentialForWallet("MM");
|
|
529
535
|
|
|
530
|
-
expect(credential.content_uri).
|
|
536
|
+
expect(credential.content_uri).toBe(
|
|
537
|
+
`ukyc://storage-abc/blobs/${hexEncodeSha256Hash(uploadedBytes ?? new Uint8Array())}`,
|
|
538
|
+
);
|
|
531
539
|
expect(preliminaryInput?.content_uri).toBe(credential.content_uri);
|
|
532
540
|
expect(preliminaryInput?.content_size).toBe(
|
|
533
541
|
credentialPlaintext.byteLength + NACL_BOX_ENCRYPTION_OVERHEAD_BYTES,
|
|
@@ -546,6 +554,144 @@ describe("credential blob storage", () => {
|
|
|
546
554
|
expect(uploadedBytes?.byteLength).toBe(preliminaryInput?.content_size);
|
|
547
555
|
});
|
|
548
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
|
+
|
|
549
695
|
it("returns the dwg message string and maps params via toDelegatedWriteGrantBaseParams", async () => {
|
|
550
696
|
const callAction = vi.fn(async () => [{ message: "mock-dwg-message" }]);
|
|
551
697
|
const kwilClient = {
|
package/src/index.ts
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
createWebKwilClient,
|
|
28
28
|
isMmTokenAuth,
|
|
29
29
|
type KwilActionClient,
|
|
30
|
-
|
|
30
|
+
mmTokenStorageId,
|
|
31
31
|
signNearMessage,
|
|
32
32
|
type Wallet,
|
|
33
33
|
} from "@idos-network/kwil-infra";
|
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
addWallets,
|
|
41
41
|
addAttribute as createAttribute,
|
|
42
42
|
createPreliminaryCredential,
|
|
43
|
+
credentialBroaderMessage,
|
|
43
44
|
type CreatePreliminaryCredentialInput,
|
|
44
45
|
dwgMessage,
|
|
45
46
|
type GetAccessGrantsGrantedInput,
|
|
@@ -73,9 +74,12 @@ import {
|
|
|
73
74
|
import { NodeKwil, type KwilSigner } from "@idos-network/kwil-js";
|
|
74
75
|
import {
|
|
75
76
|
BlobGateway,
|
|
77
|
+
BlobGatewayUploadOutcomeUnknownError,
|
|
76
78
|
createBlobContentReference,
|
|
79
|
+
createUkycContentReference,
|
|
77
80
|
requireAccessTokenForUkycContent,
|
|
78
81
|
resolveCredentialEncryptedContent,
|
|
82
|
+
type UploadCredentialBlobsParams,
|
|
79
83
|
} from "@idos-network/utils/blob-gateway";
|
|
80
84
|
import {
|
|
81
85
|
base64Decode,
|
|
@@ -129,15 +133,22 @@ function blobGatewayForSigner(idle: idOSClientIdle, kwilSigner: KwilSigner): Blo
|
|
|
129
133
|
: idle.blobGateway;
|
|
130
134
|
}
|
|
131
135
|
|
|
132
|
-
function
|
|
136
|
+
function ukycStorageIdForWallet(
|
|
133
137
|
walletType: WalletType,
|
|
134
138
|
kwilSigner: KwilSigner,
|
|
135
|
-
credentialId: string,
|
|
136
139
|
): string | undefined {
|
|
137
140
|
if (walletType !== "MM") {
|
|
138
141
|
return undefined;
|
|
139
142
|
}
|
|
140
|
-
return
|
|
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]);
|
|
141
152
|
}
|
|
142
153
|
|
|
143
154
|
const STALE_CLIENT =
|
|
@@ -406,7 +417,10 @@ export class idOSClientIdle {
|
|
|
406
417
|
}
|
|
407
418
|
|
|
408
419
|
async addressHasProfile(address: string): Promise<boolean> {
|
|
409
|
-
return hasProfile(this.kwilClient, { address }).then((res) =>
|
|
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
|
+
});
|
|
410
424
|
}
|
|
411
425
|
|
|
412
426
|
async withUserSigner(_signer: Wallet): Promise<idOSClientWithUserSigner> {
|
|
@@ -506,7 +520,10 @@ export class idOSClientWithUserSigner implements Omit<Properties<idOSClientIdle>
|
|
|
506
520
|
if (!this.walletPublicKey) throw new Error("NEAR wallet public key is required");
|
|
507
521
|
address = this.walletPublicKey;
|
|
508
522
|
}
|
|
509
|
-
return hasProfile(this.kwilClient, { address }).then((
|
|
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
|
+
});
|
|
510
527
|
}
|
|
511
528
|
|
|
512
529
|
async createUserEncryptionProfile(
|
|
@@ -552,6 +569,19 @@ export class idOSClientWithUserSigner implements Omit<Properties<idOSClientIdle>
|
|
|
552
569
|
}
|
|
553
570
|
}
|
|
554
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
|
+
|
|
555
585
|
export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSigner>, "state"> {
|
|
556
586
|
readonly state: "logged-in";
|
|
557
587
|
readonly store: Store;
|
|
@@ -598,7 +628,10 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
|
|
|
598
628
|
}
|
|
599
629
|
|
|
600
630
|
async requestDWGMessage(params: idOSDelegatedWriteGrant): Promise<string> {
|
|
601
|
-
return dwgMessage(this.kwilClient, params).then((res) =>
|
|
631
|
+
return dwgMessage(this.kwilClient, params).then((res) => {
|
|
632
|
+
if (!res) throw new Error("dwg_message returned no rows");
|
|
633
|
+
return res.message;
|
|
634
|
+
});
|
|
602
635
|
}
|
|
603
636
|
|
|
604
637
|
async createCredential(
|
|
@@ -613,8 +646,14 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
|
|
|
613
646
|
publicNotes,
|
|
614
647
|
plaintextContent,
|
|
615
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),
|
|
616
655
|
issuerSigningSecretKey,
|
|
617
|
-
|
|
656
|
+
ukycStorageId: ukycStorageIdForWallet(this.walletType, this.kwilSigner),
|
|
618
657
|
})),
|
|
619
658
|
id: credentialId,
|
|
620
659
|
};
|
|
@@ -640,14 +679,49 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
|
|
|
640
679
|
|
|
641
680
|
await createPreliminaryCredential(this.kwilClient, payload);
|
|
642
681
|
|
|
643
|
-
await this
|
|
682
|
+
await this.#uploadOwnedCredentialBlobs({
|
|
644
683
|
requestId,
|
|
684
|
+
credentialIds: [preliminaryCredential.id],
|
|
645
685
|
original: preliminaryCredential.encryptedContent,
|
|
646
686
|
});
|
|
647
687
|
|
|
648
688
|
return mapPreliminaryToIDOSCredential(preliminaryCredential);
|
|
649
689
|
}
|
|
650
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
|
+
|
|
651
725
|
async removeCredential(id: string): Promise<{ id: string }> {
|
|
652
726
|
const credential = await this.getCredentialById(id);
|
|
653
727
|
invariant(credential, `"idOSCredential" with id ${id} not found`);
|
|
@@ -743,7 +817,10 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
|
|
|
743
817
|
async getGrantsCount(): Promise<number> {
|
|
744
818
|
return getAccessGrantsGrantedCount(this.kwilClient, {
|
|
745
819
|
user_id: null,
|
|
746
|
-
}).then((res) =>
|
|
820
|
+
}).then((res) => {
|
|
821
|
+
if (!res) throw new Error("get_access_grants_granted_count returned no rows");
|
|
822
|
+
return res.count;
|
|
823
|
+
});
|
|
747
824
|
}
|
|
748
825
|
|
|
749
826
|
async getCredentialShared(id: string): Promise<idOSCredential | undefined> {
|
|
@@ -999,12 +1076,21 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
|
|
|
999
1076
|
// User issues the shared copy: sign content_uri with an ephemeral user-side key.
|
|
1000
1077
|
// Copy issuer_auth_public_key need not match the original credential's issuer.
|
|
1001
1078
|
const copyId = crypto.randomUUID();
|
|
1002
|
-
const
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
? { uri: ukycContentUri, size: content.byteLength }
|
|
1079
|
+
const ukycStorageId = ukycStorageIdForWallet(this.walletType, this.kwilSigner);
|
|
1080
|
+
const copyReference = ukycStorageId
|
|
1081
|
+
? createUkycContentReference(ukycStorageId, content)
|
|
1006
1082
|
: await createBlobContentReference(content);
|
|
1007
|
-
|
|
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
|
+
);
|
|
1008
1094
|
|
|
1009
1095
|
// Integrator-supplied. ed25519 @caller is lowercase hex; after exact grantee
|
|
1010
1096
|
// matching, uppercase hex would store a grant the consumer cannot read. Other
|
|
@@ -1027,8 +1113,9 @@ export class idOSClientLoggedIn implements Omit<Properties<idOSClientWithUserSig
|
|
|
1027
1113
|
};
|
|
1028
1114
|
|
|
1029
1115
|
await this.shareCredential(preliminaryCredential);
|
|
1030
|
-
await this
|
|
1116
|
+
await this.#uploadOwnedCredentialBlobs({
|
|
1031
1117
|
requestId: preliminaryCredential.request_id,
|
|
1118
|
+
credentialIds: [copyId],
|
|
1032
1119
|
copy: content,
|
|
1033
1120
|
});
|
|
1034
1121
|
|