1"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[2231],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>p});var i=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function s(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function r(e,t){if(null==e)return{};var n,i,o=function(e,t){if(null==e)return{};var n,i,o={},a=Object.keys(e);for(i=0;i<a.length;i++)n=a[i],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i<a.length;i++)n=a[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=i.createContext({}),d=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},c=function(e){var t=d(e.components);return i.createElement(l.Provider,{value:t},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},m=i.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,c=r(e,["components","mdxType","originalType","parentName"]),u=d(n),m=o,p=u["".concat(l,".").concat(m)]||u[m]||h[m]||a;return n?i.createElement(p,s(s({ref:t},c),{},{components:n})):i.createElement(p,s({ref:t},c))}));function p(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,s=new Array(a);s[0]=m;var r={};for(var l in t)hasOwnProperty.call(t,l)&&(r[l]=t[l]);r.originalType=e,r[u]="string"==typeof e?e:o,s[1]=r;for(var d=2;d<a;d++)s[d]=n[d];return i.createElement.apply(null,s)}return i.createElement.apply(null,n)}m.displayName="MDXCreateElement"},1512:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>l,default:()=>p,frontMatter:()=>r,metadata:()=>d,toc:()=>u});var i=n(7462),o=n(3366),a=(n(7294),n(3905)),s=["components"],r={title:"DID"},l=void 0,d={unversionedId:"sdk/did/js/guide/did",id:"sdk/did/js/guide/did",title:"DID",description:"Access the DID Document",source:"@site/../docs/7.sdk/did/js/guide/did.md",sourceDirName:"7.sdk/did/js/guide",slug:"/sdk/did/js/guide/did",permalink:"/sdk/did/js/guide/did",draft:!1,editUrl:"https://github.com/elastos/Elastos.Wiki/edit/master/website/../docs/7.sdk/did/js/guide/did.md",tags:[],version:"current",lastUpdatedBy:"racollette",lastUpdatedAt:1677260880,formattedLastUpdatedAt:"Feb 24, 2023",frontMatter:{title:"DID"},sidebar:"sdkSidebar",previous:{title:"RootIdentity",permalink:"/sdk/did/js/guide/root-identity"},next:{title:"JSON Web Token",permalink:"/sdk/did/js/guide/json"}},c={},u=[{value:"Access the DID Document",id:"access-the-did-document",level:2},{value:"Usage",id:"usage",level:4},{value:"Create DID",id:"create-did",level:2},{value:"Example",id:"example",level:4},{value:"Usage",id:"usage-1",level:4},{value:"Create DIDDocument",id:"create-diddocument",level:2},{value:"Example",id:"example-1",level:4},{value:"Usage",id:"usage-2",level:4},{value:"Create Customized DID",id:"create-customized-did",level:2},{value:"Example",id:"example-2",level:4},{value:"Usage",id:"usage-3",level:4},{value:"Create Multi-signed Customized DID",id:"create-multi-signed-customized-did",level:2},{value:"Example",id:"example-3",level:4},{value:"Usage",id:"usage-4",level:4},{value:"Sign and Verify Data by DID Document",id:"sign-and-verify-data-by-did-document",level:2},{value:"Usage",id:"usage-5",level:4},{value:"Verify the Integrity of DIDDocument",id:"verify-the-integrity-of-diddocument",level:2},{value:"Usage",id:"usage-6",level:4},{value:"Publish DID",id:"publish-did",level:2},{value:"Example",id:"example-4",level:4},{value:"Usage",id:"usage-7",level:4},{value:"Transfer Ownership of the Customized DID",id:"transfer-ownership-of-the-customized-did",level:2},{value:"Example",id:"example-5",level:4},{value:"Usage",id:"usage-8",level:4},{value:"Deactivate DID",id:"deactivate-did",level:2},{value:"Example",id:"example-6",level:4},{value:"Usage",id:"usage-9",level:4},{value:"Resolve DIDs",id:"resolve-dids",level:2},{value:"Chain Resolve",id:"chain-resolve",level:3},{value:"Local Resolve",id:"local-resolve",level:3},{value:"Example",id:"example-7",level:5},{value:"Usage",id:"usage-10",level:5}],h={toc:u},m="wrapper";function p(e){var t=e.components,n=(0,o.Z)(e,s);return(0,a.kt)(m,(0,i.Z)({},h,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h2",{id:"access-the-did-document"},"Access the DID Document"),(0,a.kt)("p",null,"The DID document provides the method to get the number and individuals of internal objects, i.e. Subject, Controller, Multisig, Public Key, Authentication Key, Authorization Key, Verifiable Credential, and Service. It's relatively simple to understand and use these APIs, and users can refer to the API document directly."),(0,a.kt)("p",null,"This section mentions the method provided by the DID document to acquire DID Metadata and Default Key."),(0,a.kt)("h4",{id:"usage"},"Usage"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public getDefaultPublicKeyId(): DIDURL\uff1b\n")),(0,a.kt)("p",null,"This method is the main key to get DID document."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public getMetadata(): DIDMetadata\uff1b\n")),(0,a.kt)("p",null,"This method gets DIDMetadata, which contains the information that the DID cannot put into DID document."),(0,a.kt)("h2",{id:"create-did"}
1,"Create DID"),(0,a.kt)("p",null,"DID provides three methods to create DID objects based on DID strings. The DID string is roughly divided into three parts: schema, method, and methodSpecificId, which are separated by \u201c:\u201d, for example:"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"did:elastos:icJ4z2DULrHEzYSvjKNJpKyhqFDxvYV7pN")),(0,a.kt)("h4",{id:"example"},"Example"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},'let did1 = new DID("did:elastos:icJ4z2DULrHEzYSvjKNJpKyhqFDxvYV7pN");\nlet did2 = new DID("elastos", "abc");\nlet did3 = DID.createFrom("did:elastos:littlefish", 0, 22);\nlet did4 = DID.From("did:elastos:icJ4z2DULrHEzYSvjKNJpKyhqFDxvYV7pN");\nlet did5 = DID.From(did2);\n')),(0,a.kt)("h4",{id:"usage-1"},"Usage"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public constructor(\n methodOrDID: string,\n methodSpecificId: string | null = null,\n start?: number, limit?: number\n)\uff1b\n")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public static createFrom(\n methodOrDID: string,\n start: number,\n limit: number\n): DID\uff1b\n")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public static from(\n did: DID | string | null\n): DID | null\uff1b\n")),(0,a.kt)("h2",{id:"create-diddocument"},"Create DIDDocument"),(0,a.kt)("p",null,"DID documents are divided into ordinary and customized DIDs, and everything explained here is applicable to ordinary ones. The customized DID document will be described in detail in the following sections."),(0,a.kt)("p",null,"Generate the DID document by newDid. This DID document is the most basic, containing only the default key. Users can modify the content of DID document via DID document Builder, and can terminate the modification by the seal method to get a new DID document."),(0,a.kt)("p",null,"The DID document contains five elements: public key, authentication key, authorization key, verifiable credential, and service. The document can be correspondingly modified by adding or removing methods. Please refer to API doc for specific methods."),(0,a.kt)("h4",{id:"example-1"},"Example"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},'let rootPath = "root/store";\nlet store = await DIDStore.open(rootPath);\nlet storePass = "pwd";\n... ... ... ...\nlet rootidentity = await store.loadRootIdentity();\n//create did\nlet doc = await rootidentity.newDid(storePass);\n//edit builder\nlet db = DIDDocument.Builder.newFromDocument(doc).edit();\n\n//add authentication key\nlet id = DIDURL.from("#test1", db.getSubject());\nlet key = HDKey.deriveWithPath(HDKey.DERIVE_PATH_PREFIX + 5);\ndb.addAuthenticationKey(id, doc.getSubject(), key.getPublicKeyBase58());//\n//to add/delete other elem\n... ... ... ...\n//seal DID Document\nlet doc = await db.seal(storePass);\ndoc.publish(storePass);\n... ... ... ...\nstore.close();\n')),(0,a.kt)("h4",{id:"usage-2"},"Usage"),(0,a.kt)("p",null,"The newDid method has been introduced in the chapter of RootIdentity, so it's unnecessary to go into details here."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public static newFromDocument(\n doc: DIDDocument,\n controller?: DIDDocument\n): Builder;\n")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public edit(\n controller?: DIDDocument\n): Builder;\n")),(0,a.kt)("p",null,"newFromDocument is used together with the edit method, as shown in the example."),(0,a.kt)("p",null,"NewFromDocument copies the original DID document to prevent subsequent modification from affecting the original DID document, and edit checks whether the document signed by DID document subject meets the requirements."),(0,a.kt)("p",null,"Controller parameter is modified for the customized DID document, which will be explained in detail in the following sections. For ordinary DID document, there is no need to provide parameters."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public async seal(\n storepass: string\n): Promise<DIDDocument>;\n")),(0,a.kt)("p",null,"The seal method encapsulates and gets a new DID document. Storepass is the password of the DID Store, which is used to sign the main content of the modified DID document via the private key of the master key."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},'public createAndAddPublicKey(\n id: DIDURL | string,\n pk: string,\n controller?: DID | string,\n type = "ECDSAsecp256r1"\n): Builder;\n')),(0,a.kt)("p",null,"If this method adds the public key that already exists (with id or pk being the same), an error is returned."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public removePublicKey(\n id: DIDURL | string,\n force = false\n): Builder\uff1b\n")),(0,a.kt)("p",null,"It should be noted that the default key cannot be removed; when you want to remove the authentication or authorization key, decide whether to remove it according to the force parameter. If force is true and removal is supported, an error is returned."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public addExistingAuthenticationKey(\n id: DIDURL | string\n): Builder\uff1b\n")),(0,a.kt)("p",null,"The method is to add the public key that already exists but meets the authentication key as the authentication key. If it doesn't exist or its type does not meet the requirements, errors are returned."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public addAuthenticationKey(\n id: DIDURL | string,\n pk: string\n): Builder\uff1b\n")),(0,a.kt)("p",null,"This method is to add the new authentication key. If it already exists, an error is returned."),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Pk is the base58 string of the public key.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public removeAuthenticationKey(\n id: DIDURL | string\n): Builder\uff1b\n")),(0,a.kt)("p",null,"This method removes the authentication key that already exists. If no authentication key exists, an error is returned."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public addExistingAuthorizationKey(\n id: DIDURL | string\n): Builder\uff1b\n")),(0,a.kt)("p",null,"This method adds the public key that already exists as the authorization key. The following conditions should be met:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"The public key already exists."),(0,a.kt)("li",{parentName:"ol"},"It's neither an authentication key nor an authorization key."),(0,a.kt)("li",{parentName:"ol"},"The controller is not a DID document subject. If these conditions are not met, an error is returned.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public addAuthorizationKey(\n id: DIDURL | string,\n controller: DID | string,\n pk: string\n): Builder\uff1b\n")),(0,a.kt)("p",null,"This method adds a new authorization key. If it already exists, an error is returned."),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Pk is the base58 string of the public key; the controller refers to the owner of the key.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public async authorizeDid(\n id: DIDURL,\n controller: DID,\n key: DIDURL\n): Promise<Builder>\uff1b\n")),(0,a.kt)("p",null,"This method is to add the specified key to be an Authorization key - this
1specified key is the key of specified controller. Authentication is the mechanism by which the controller(s) of a DID can cryptographically prove that they are associated with that DID. A DID Document must include an authentication key."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public removeAuthorizationKey(\n inputId: DIDURL | string\n): Builder\uff1b\n")),(0,a.kt)("p",null,"This method removes the specified authorization key. If this key does not exist or it is not an authorization key, an error is returned."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public addCredential(\n vc: VerifiableCredential\n): Builder\uff1b\n")),(0,a.kt)("p",null,"This method adds the verifiable credential provided by users. If the ID of this credential already exists in the DID document, an error is returned."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public async createAndAddCredential(\n storepass: string,\n id: DIDURL | string,\n subject: JSONObject | string = null, // Subject refers to the theme of the credential, that is, the primary content of the json credential\n types: string[] = null,\n expirationDate: Date = null // expirationDate is the validity period, which cannot be greater than that of the document of the DID.\n): Promise<Builder>\uff1b\n")),(0,a.kt)("p",null,"This method is used to directly add the self-proclaimed credential, without having to creating the credential and then adding it to the DID document."),(0,a.kt)("p",null,"Types refer to the types of credentials. The SDK supports the following five types:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"SelfProclaimedCredential"),(0,a.kt)("li",{parentName:"ul"},"EmailCredential"),(0,a.kt)("li",{parentName:"ul"},"ProfileCredential"),(0,a.kt)("li",{parentName:"ul"},"SocialCredential"),(0,a.kt)("li",{parentName:"ul"},"WalletCredential")),(0,a.kt)("p",null,"Users can choose the type according to their needs, or add customized types using corresponding methods."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public removeCredential(\n id: DIDURL | string\n): Builder\uff1b\n")),(0,a.kt)("p",null,"This method removes the specified credential. If it does not exist, an error is returned."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public addService(\n id: DIDURL | string,\n type: string,\n endpoint: string, // the address of the service point\n properties?: JSONObject // the content customized by users\n): Builder\uff1b\n")),(0,a.kt)("p",null,"This method adds the service. If the specified ID already exists, an error is returned."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public removeService(\n id: DIDURL | string\n): Builder\uff1b\n")),(0,a.kt)("p",null,"This method removes specified service. If no specified service exists, an error is returned."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public setExpires(\n expires: Date\n): Builder\uff1b\n")),(0,a.kt)("p",null,"The validity period of DID Document is five years after its creation by default. If the validity period is customized by users, it's set using this method cannot exceed five years, otherwise an error will be returned."),(0,a.kt)("h2",{id:"create-customized-did"},"Create Customized DID"),(0,a.kt)("p",null,"DIDSDK supports customized DID, which means that the corresponding DID document is needed. There is a cryptographically verifiable key between the subject and the default key in ordinary DID document. When the DID document finally uses this default key to sign the document body, there is a closed-loop verification process to avoid malicious means such as tampering."),(0,a.kt)("p",null,"However, the customized DID identifier is only an arbitrary string provided by the user, and it's impossible to generate a key cryptographically associated with the DID identifier. If a random key is added and used to sign the principal data in the DID document, then the key can be replaced by the content modified by others at any time, which cannot guarantee that the DID document will not be tampered with maliciously. To solve this problem, the controller and Multisig are introduced. The controller is the actual holder of the customized DID document, and Multisig refers to the multi-signature rule for multiple controllers."),(0,a.kt)("p",null,"According to the number of controllers, the creation of customized DID involves two cases, namely single-signed and multi-signed. This section provides two single-signed examples."),(0,a.kt)("h4",{id:"example-2"},"Example"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},'let rootPath = "root/store";\nlet store = await DIDStore.open(rootPath);\nlet storePass = "pwd";\n... ... ... ...\nlet rootidentity = store.loadRootidentity();\nlet controller = await identity.newDid(storePass);\nawait controller.publish(storePass);\n... ... ... ...\nresolved = await controller.getSubject().resolve();\n\n// Create customized DID\nlet did = new DID("did:elastos:helloworld");\n//new Customized DID\nlet doc = await controller.newCustomized(did, 1, storePass, false);\nawait doc.publish(storePass);\n... ... ... ...\nlet resolved = await did.resolve();\n... ... ... ...\nstore.close();\n')),(0,a.kt)("h4",{id:"usage-3"},"Usage"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"}
1,"public newCustomized(\n inputDID: DID | string, // the customized DID identifier\n storepass: string,\n force?: boolean // if true, the document is overwritten; if false, the document is not overwritten\n): Promise<DIDDocument>\uff1b\n")),(0,a.kt)("p",null,"This method is the most classic method to generate single-signed customized DID document. See the above example for details.\ninputDID denotes"),(0,a.kt)("p",null,"The newCustomizedDidWithController method in the example is more often used in multi-signed cases, so the detailed introduction is presented in the next section."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public isCustomizedDid(): boolean\uff1b\n")),(0,a.kt)("p",null,"This method can be used to check if the DID document is a customized one."),(0,a.kt)("h2",{id:"create-multi-signed-customized-did"},"Create Multi-signed Customized DID"),(0,a.kt)("p",null,"This section mainly introduces the method of generating and modifying the multi-signed customized DID document, which isn't available in the ordinary document."),(0,a.kt)("p",null,"The multi-signature (m:n) rule requires n>1. M represents the number of signers, that is, the number of signatures in the proof of document. If the number of signatures is less than m, it means that the document at this time is not really a valid multi-signed document, and the remaining controllers who haven\u2019t signed need to sign the documents."),(0,a.kt)("h4",{id:"example-3"},"Example"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},'let rootPath = "root/store";\nlet store = await DIDStore.open(rootPath);\nlet storePass = "pwd";\n... ... ... ...\nlet rootidentity = store.loadRootidentity();\n//get the first controller\nlet controller1 = await identity.newDid(storePass);\nawait controller1.publish(storePass);\n//get the second controller\nlet controller2 = await identity.newDid(storePass);\nawait controller2.publish(storePass);\n//get the third controller\nlet controller3 = await identity.newDid(storePass);\nawait controller3.publish(storePass);\n... ... ... ...\nlet did = new DID("did:elastos:byeworld");\n//new multi-signed Customized DID\n//customized document has three controller and multisig is 2:3, so document must be signed by two controllers. controller2 is the first signer.\nlet doc = await controller2.newCustomizedDidWithController(did, [controller1.getSubject(), controller2.getSubject(), controller3.getSubject()], 2, storePass);\n//check signer is enough\nif (!doc.isQualified())\n //the second signer, and finished multi-signure.\n await controller1.signWithDocument(doc, storePass);\n\n//check the doc\nif (doc.isQualified()) {\n console.log("create multi-signed customized document successfully." );\n} else {\n console.log("create multi-signed customized document failed." );\n}\n... ... ... ...\n//modify the document:remove controller1,mutisig 2:2\nlet db = DIDDocument.Builder.newFromDocument(doc).edit(controller2);\ndb.removeController(controller1.getSubject());\n//do other things\n... ... ... ...\nlet doc = db.seal();\nawait controller3.signWithDocument(doc, storePass);\nif (doc.isValid()) {\n console.log("create multi-signed customized document successfully." );\n} else {\n console.log("create multi-signed customized document failed." );\n}\n\ndoc.setEffectiveController(controller3.getSubject());\nawait doc.publish(storePass);\n... ... ... ...\nstore.close();\n')),(0,a.kt)("h4",{id:"usage-4"},"Usage"),(0,a.kt)("p",null,"The methods of adding and removing elements in the ordinary DID document are also applicable to the customized DID document, and what is described here is the unique content of customized DID document."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public async newCustomizedDidWithController(\n inputDID: DID | string,\n inputControllers: Array<DID | string>,\n multisig: number,\n storepass: string,\n force?: boolean\n): Promise<DIDDocument>\uff1b\n")),(0,a.kt)("p",null,"This method generates the initial multi-signed document. At this time, only one controller signs the primary data in the obtained document, and whether the number of signatures accords with the multi-signature rule is verified by the isQualified method."),
1(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public isQualified(): boolean;\n")),(0,a.kt)("p",null,"This method tells whether the number of signatures in the current customized document lives up to the multi-signature rule. If false is returned, the controller who hasn\u2019t signed will continue to complete the signature work to improve the document."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public async addController(\n controller: DID | string\n): Promise<Builder>\uff1b\n")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public removeController(\n controller: DID | string\n): Builder;\n")),(0,a.kt)("p",null,"The above two methods are apparently exclusive to the customized DID document. If adding and removing controllers is used for the ordinary DID document, an error is returned."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public setMultiSignature(\n m: number\n): Builder;\n")),(0,a.kt)("p",null,"This method resets the over-signature rule."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public setEffectiveController(controller: DID)\uff1avoid;\n")),(0,a.kt)("p",null,"Before signing the multi-signed customized DID document, the effective controller should set to specify which controller\u2019s master key is used for signing."),(0,a.kt)("h2",{id:"sign-and-verify-data-by-did-document"},"Sign and Verify Data by DID Document"),(0,a.kt)("p",null,"The DID document can sign the data on behalf of DID, so the DID document offers methods for signing and verifying data."),(0,a.kt)("h4",{id:"usage-5"},"Usage"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public signWithId(\n id: DIDURL | string | null,\n storepass: string,\n ...data: Buffer[]\n): Promise<string>\uff1b\n")),(0,a.kt)("p",null,"This method signs the data with the private key of the specified key, and then return signature."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public signWithStorePass(\n storepass: string,\n ...data: Buffer[]\n): Promise<string>\uff1b\n")),(0,a.kt)("p",null,"This method uses the default key of the DID document to sign the data, and then return the signature. If the DID document is a multi-signed customized DID document, an error is returned."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public async signWithTicket(\n ticket: TransferTicket,\n storepass: string\n): Promise<TransferTicket>\uff1b\n")),(0,a.kt)("p",null,"This method applies to the multi-signing of TransferTicket. According to the multi-signature rule of the customized DID document, this method is used for the second and later controller DID document signature. See \u201cTransfer DID\u201d for specific examples."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public async signWithDocument(\n doc: DIDDocument,\n storepass: string\n): Promise<DIDDocument>\uff1b\n")),(0,a.kt)("p",null,"The method is used for the multi-signing of the customized DID Document. According to the multi-signature rule of the customized DID document, it is used for the second and later controller DID document signature. See \u201cCreate multi-signed customized DID\u201d for specific examples."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public verify(\n id: DIDURL | string | null, // the ID of the key\n signature: string, // the string of the results containing a signature\n ...data: Buffer[] // the original signed data\n): boolean;\n")),(0,a.kt)("p",null,"This method verifies the signature. If the key, signature, and data don't match, the verification fails, which mainly prevents data from being tampered with."),(0,a.kt)("h2",{id:"verify-the-integrity-of-diddocument"},"Verify the Integrity of DIDDocument"),(0,a.kt)("p",null,"For security and the unity of documents on the chain, it's necessary to verify the usability of the DID document by checking whether the DID document itself is valid, expired, or invalid."),(0,a.kt)("h4",{id:"usage-6"},"Usage"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public isGenuine(\n listener: VerificationEventListener = null\n): boolean\uff1b\n")),(0,a.kt)("p",null,"The DID document provides a method to check whether the document is complete, each element of meets the requirements, whether can be verified and signed, or it's been tampered with. For instance, whether the number of signatures of the customized DID document meets the multi-signature rule is important to understand."),(0,a.kt)("p",null,"The listener obtains the error information set in the verification process and locates the points of failure of specific deep calls."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public isExpired(): boolean\uff1b\n")),(0,a.kt)("p",null,"The DID document offers a method for checking if it expires."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public isDeactivated(): boolean\uff1b\n")),(0,a.kt)("p",null,"The DID document also provides a method of checking if it's invalid. Invalidity is not equivalent to expiration. In the case of invalidity, the invalid document should be operated by the DID itself or the client. Whether the document expires is determined by whether it is beyond its validity period, and the document that expires can be reset and restored."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public isValid(\n listener: VerificationEventListener = null\n): boolean \uff1b\n")),(0,a.kt)("p",null,"The DID document offers a method of comprehensively verifying whether it's valid, which includes the above three rules."),(0,a.kt)("h2",{id:"publish-did"},"Publish DID"),(0,a.kt)("p",null,"The publishing of DID is divided into valid and deactivated publishing. Deactivated publishing is to inform that the DID on the chain has failed and cannot be used again (this part will be introduced in the following section); valid publishing means updating the effective DID information to the chain (relevant instructions will be introduced in this section)."),(0,a.kt)("p",null,"The DID Document stands for the publishing of DID, which provides Publish DID as a method of updating DID to the chain. This method is suitable for effectively updating ordinary DID and customized DID without changing the subject\u2019s information (Controller and Multisig) to the chain."),(0,a.kt)("p",null,"To prevent the published content from being maliciously tampered with, DID signs the published content with its own authentication key, and the receiver verifies the signature of the content based on the provided information to confirm the reliability of the published content."),(0,a.kt)("h4",{id:"example-4"},"Example"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},'let rootPath = "root/store";\nlet store = await DIDStore.open(rootPath);\nlet storePass = "pwd";\n... ... ... ...\nlet rootidentity = store.loadRootidentity();\nlet controller = await identity.newDid(storePass);\n//publish controller\nawait controller.publish(storePass);\n// Create customized DID\nlet did = new DID("did:elastos:helloworld");\n//new Customized DID\nlet doc = await controller.newCustomized(did, 1, storePass, false);\n//publish DID\nawait doc.publish(storePass);\n... ... ... ...\nlet db = DIDDocument.Builder.newFromDocument(doc).edit();\n//add authentication key\nlet id = DIDURL.from("#test1", db.getSubject());\nlet key = HDKey.deriveWithPath(HDKey.DERIVE_PATH_PREFIX + 5);\ndb.addAuthenticationKey(id, doc.getSubject(), key.getPublicKeyBase58()
1);\n//seal DID Document\nlet doc = await db.seal(storePass);\ndoc.publish(storePass);\n... ... ... ...\nstore.close();\n')),(0,a.kt)("h4",{id:"usage-7"},"Usage"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"export interface DIDTransactionAdapter {\n createIdTransaction(payload: string, memo: string);\n}\n\npublic async publish(\n storepass: string,\n inputSignKey: DIDURL | string = null,\n force = false,\n adapter: DIDTransactionAdapter = null\n): Promise<void>\uff1b\n")),(0,a.kt)("p",null,"InputSignKey is the authentication key designated to sign the content updated to the chain. Here, it should be noted that the publishing of ordinary DID only requires a random authentication key. However, the sign key of customized DID can only be its own authentication key or the default key of the controller. When the inputSignKey is null, the default key of the DID document is used for signing the published content, and the ordinary DID document must have the default key. However, for customized DIDs, only the customized DID with single signature has the default key, while the multi-signed customized DID does not have one. Therefore, if the multi-signed customized DID uses the default value null, an error will be reported. Please be sure to assign the specified sign key."),(0,a.kt)("p",null,"Force indicates whether it's possible to force the publishing of data to the chain when the DID document expires or the local DID document is not modified and updated based on the latest version on the chain. Generally, it's recommended that the local DID Document be modified based on the latest version on the chain, so as to smoothly publish the document. Under special circumstances, by setting force to be true, the publishing can also be forced. If force is true, the documents that have expired can also be updated."),(0,a.kt)("p",null,"The adapter provides an interface for publishing the data to the chain. Users can implement it on their own or use the default interface provided by Publish DID."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"Whether by modifying the controller or multisig, the customized DID document cannot publish the data to the chain by means of Publish DID.")),(0,a.kt)("h2",{id:"transfer-ownership-of-the-customized-did"},"Transfer Ownership of the Customized DID"),(0,a.kt)("p",null,"As mentioned in the previous section, Publish DID is used for effectively updating ordinary DID and customized DID without changing the subject\u2019s information (Controller and Multisig) to the chain. This section introduces how to update the DID document to the chain after modifying the information of the controller."),(0,a.kt)("p",null,"The DID document offers the TransferDID method to complete the transaction of modifying the controller\u2019s information. This transaction should be accomplished using the master key of the original controller of the DID based on the modified document and the transfer ticket."),(0,a.kt)("h4",{id:"example-5"},"Example"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},'let rootPath = "root/store";\nlet store = await DIDStore.open(rootPath);\nlet storePass = "pwd";\n... ... ... ...\nlet identity = store.loadRootidentity();\n// Create normal DID first\nlet controller = await identity.newDid(storePass);\nawait controller.publish(storePass);\n// Create customized DID\nlet did = new DID("did:elastos:helloworld");\nlet doc = await controller.newCustomized(did, 1, storePass);\nawait doc.publish(storePass);\n// create new controller\nlet newController = await identity.newDid(storePass);\nawait newController.publish(storePass);\n// create the transfer ticket from one old Controller\nlet ticket = await controller.createTransferTicket(newController.getSubject(), storePass, doc.getSubject());\n// create new document for customized DID\ndoc = await newController.newCustomized(did, 1, storePass, true);\n// transfer DID\nawait doc.publishWithTicket(ticket, newController.getDefaultPublicKeyId(), storePass);\n... ... ... ...\nstore.close();\n')),(0,a.kt)("h4",{id:"usage-8"},"Usage"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"}
1,"public async createTransferTicket(\n to: DID,\n storepass: string,\n from?: DID\n): Promise<TransferTicket>;\n")),(0,a.kt)("p",null,"The DID document provides the method of generating the transfer ticket. CreateTransferTicket was initiated by one of the controllers of the DID document before it's modified, and the transfer ticket is also signed and encapsulated by the initiator."),(0,a.kt)("p",null,"To is the recipient of the transfer ticket, who must be one of the controllers and signers of the modified DID document - otherwise, the transfer DID fails."),(0,a.kt)("p",null,"From is the owner of the transfer ticket - that is, the customized DID."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public async publishWithTicket(\n ticket: TransferTicket,\n inputSignKey: DIDURL | string | null,\n storepass: string,\n adapter: DIDTransactionAdapter = null\n): void\uff1b\n")),(0,a.kt)("p",null,"inputSignKey is the authentication key of the modified document or the master key of the controller. The other parameters are the same as those of Publish DID."),(0,a.kt)("h2",{id:"deactivate-did"},"Deactivate DID"),(0,a.kt)("p",null,"Both Publish and Transfer DID update valid data to the chain, while Deactivate DID means stopping the use of the DID."),(0,a.kt)("p",null,"The DID can be deactivated by itself or the client. The ordinary DID can be deactivated by the authentication key and the authorization key. The customized DID can be deactivated by the authentication key and the controller\u2019s default key."),(0,a.kt)("p",null,"The DID that has not been published to the chain cannot be deactivated."),(0,a.kt)("h4",{id:"example-6"},"Example"),(0,a.kt)("p",null,"Deactivate self use authentication key:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},'let rootPath = "root/store";\nlet store = await DIDStore.open(rootPath);\nlet storePass = "pwd";\n... ... ... ...\nlet rootidentity = store.loadRootidentity();\nlet doc = await identity.newDid(storePass);\n//publish controller\nawait doc.publish(storePass);\n.. ... ... ...\nlet resolved = await doc.getSubject().resolve();\nif (resolved)\n await doc.deactivate(null, storePass, null);\nif (doc.isDeactivated())\n console.log("deactivate did successfully.");\nelse\n console.log("deactivate did failed.");\n... ... ... ...\nstore.close();\n')),(0,a.kt)("p",null,"Deactivate target DID by the authorizor's DID\uff1a"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},'let rootPath = "root/store";\nlet store = await DIDStore.open(rootPath);\nlet storePass = "pwd";\n... ... ... ...\nlet rootidentity = store.loadRootidentity();\nlet doc = await identity.newDid(storePass);\nlet db = DIDDocument.Builder.newFromDocument(doc).edit();\n\nlet id = DIDURL.from("#key-2", doc.getSubject());\nlet key = HDKey.deriveWithPath(HDKey.DERIVE_PATH_PREFIX + 5);\ndb.addAuthenticationKey(id, key.getPublicKeyBase58());\nstore.storePrivateKey(id, key.serialize(), storePass);\ndoc = await db.seal(storePass);\nawait store.storeDid(doc);\nawait doc.publish(storePass);\nlet resolved = await doc.getSubject().resolve();\n... ... ... ...\nlet target = await identity.newDid(storePass);\ndb = DIDDocument.Builder.newFromDocument(target).edit();\ndb.addAuthorizationKey("#recovery", doc.getSubject().toString(), key.getPublicKeyBase58());\ntarget = await db.seal(storePass);\nawait store.storeDid(target);\nawait target.publish(TestConfig.storePass);\nresolved = await target.getSubject().resolve();\nif (resolved)\n console.log();\n\nawait doc.deactivateTargetDID(target.getSubject(), null, storePass, null);\ntarget = await target.getSubject().resolve();\nif (target.isDeactivated())\n console.log("deactivate did successfully.");\nelse\n console.log("deactivate did failed.");\n... ... ... ...\nstore.close();\n')),(0,a.kt)("h4",{id:"usage-9"},"Usage"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public async deactivate(\n signKey: DIDURL = null, // the authentication key designated to sign the deactivated transaction. If signKey is null, the default key will be used\n storepass: string,\n adapter: DIDTransactionAdapter = null\n): void\uff1b\n")),(0,a.kt)("p",null,"This method is initiated by the deactivated DID itself. The DID deactivates does this using its own authentication key."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public async deactivateTargetDID(\n target: DID, // the DID to be deactivated\n signKey: DIDURL = null,\n storepass: string,\n adapter: DIDTransactionAdapter = null\n): void\uff1b\n")),(0,a.kt)("p",null,"This method is a deactivation operation initiated by the client."),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"signKey parameter: The deactivation of ordinary DID is initiated by the authorizer DID document, which provides the authorizer authentication key. This key must exist as authorization key in the DID document of the target. The customized DID is initiated by the controller DID document, with the controller default key as the sign key.")),(0,a.kt)("h2",{id:"resolve-dids"},"Resolve DIDs"),(0,a.kt)("p",null,"The DID provides a method of acquiring the DID document or the historical DID document, and verifying the validity of the DID document."),(0,a.kt)("p",null,"Resolve has two ways to obtain the DID document. The first is chain resolve, which returns the DID document that exists on the chain;
1 the second way is local resolve. Under certain special circumstances, some DID documents only need to exist rather than to be published to the chain, but in the follow-up work, the resolve function is required to access the DID Document. At this time, local resolve can be used. The DID document that needs to be returned is provided by the user - this method is mainly used for verification."),(0,a.kt)("p",null,"Only through chain resolve can the historical transactions of DID be obtained."),(0,a.kt)("p",null,"To enhance flexibility, the DID document obtained through resolve needs to be saved to the DID store and updated locally by users themselves."),(0,a.kt)("h3",{id:"chain-resolve"},"Chain Resolve"),(0,a.kt)("p",null,"Before using the chain resolve method, make sure that DIDBackend has been initialized and the chain address of resolve has been provided; otherwise resolve will fail."),(0,a.kt)("p",null,"There are three states of DID on the chain:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"not found (which means that the DID is not published to the chain)"),(0,a.kt)("li",{parentName:"ol"},"valid"),(0,a.kt)("li",{parentName:"ol"},"deactivated.")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Example")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},'let rpcEndpoint = "testnet";\nlet contractAddress = "0xF654c3cBBB60D7F4ac7cDA325d51E62f47ACD436";\n... ... ... ...\nlet adapter = new Web3Adapter(rpcEndpoint, contractAddress, null, null);\nDIDBackend.initialize(adapter);\n... ... ... ...\nlet rootPath = "root/store";\nlet store = await DIDStore.open(rootPath);\n\nlet did = new DID("did:elastos:iXcRhYB38gMt1phi5JXJMjeXL2TL8cg58y");\nif (did) {\n //resolve did\n let doc = did.resolve(true);\n if (doc)\n console.log("resolve did {} successfully.", did);\n else\n cosole.log("resolve did {} failed.", did);\n ... ... ...\n //resolve did history\n let bio = did.resolveBiography();\n if (bio) {\n console.log("resolve did biography: count={}", bio.getTransactionCount());\n ... ... ... ...\n } else {\n console.log("resolve did biography failed.");\n }\n}\n... ... ... ...\nstore.close();\n')),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Usage")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public async resolve(\n force = false\n): Promise<DIDDocument>;\n")),(0,a.kt)("p",null,"Resolve gets the latest DID document on the chain, or the last document published to the chain. If the document exists on the chain and the network normally works, the DID document is verified as valid, and the DIDDocument object is returned; otherwise, null is returned, and the reason of failure can be obtained by exception."),(0,a.kt)("p",null,"Force indicates whether it's necessary to get the DID document from the chain. The SDK has a cache freshness for the resolved results, which is 10 minutes by default. If force is false and the cache is within its validity period, resolve returns the caching results; if force is false but the cache is in effect, or if force is true, the DID document data will be obtained directly from the chain."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"public resolveBiography(): Promise<DIDBiography>;\n")),(0,a.kt)("p",null,"This method can obtain the historical information of DID. If it fails, null is returned; if it succeeds, DIDBiography object is returned. DIDBiography contains DID status and the content of each transaction. See \u201cAPI document\u201d for details."),(0,a.kt)("h3",{id:"local-resolve"},"Local Resolve"),(0,a.kt)("h5",{id:"example-7"},"Example"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},'let rpcEndpoint = "testnet";\nlet contractAddress = "0xF654c3cBBB60D7F4ac7cDA325d51E62f47ACD436";\n... ... ... ...\nlet adapter = new Web3Adapter(rpcEndpoint, contractAddress, null, null);\nDIDBackend.initialize(adapter);\n... ... ... ...\nlet rootPath = "root/store";\nlet store = await DIDStore.open(rootPath);\n\nlet did = new DID("did:elastos:iXcRhYB38gMt1phi5JXJMjeXL2TL8cg58y");\n//set resolve handle\nDIDBackend.getInstance().setResolveHandle(new class implements LocalResolveHandle {\n public resolve(d: DID): DIDDocument {\n return store.loadDid(d);\n }\n});\n\nif (did) {\n // resolve doc is from line 13\n let doc = did.resolve(true);\n if (doc)\n console.log("resolve did {} successfully.", did);\n else\n cosole.log("resolve did {} failed.", did);\n}\n... ... ... ...\n//if you don\'t use local chain\nDIDBackend.getInstance().setResolveHandle(null);\n... ... ... ...\nstore.close();\n')),(0,a.kt)("h5",{id:"usage-10"},"Usage"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-ts"},"export interface LocalResolveHandle {\n resolve(did: DID): DIDDocument;\n}
1\npublic setResolveHandle(handle: LocalResolveHandle);\n")),(0,a.kt)("p",null,"Handle is null, which means that the DID document is obtained from the chain without using local resolve. When you need to use local resolve, implement LocalResolveHandle."))}p.isMDXComponent=!0}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.