Skip to content
This repository was archived by the owner on Dec 12, 2022. It is now read-only.

Code Examples

Derk Norton edited this page Aug 16, 2021 · 11 revisions

Importing the Modules

The following code shows a typical set of imports for using the Bali Digital Notary™ and how to initialize the notary and repository APIs.

const debug = 1;  // debug level: 0..3
const bali = require('bali-component-framework').api(debug);
const account = bali.tag();  // new account
const directory = 'config/';  // for testing purposes only
const notary = require('bali-digital-notary').test(account, directory, debug);
const Repository = require('bali-document-repository');
const storage = Repository.local(notary, directory, debug);
const repository = Repository.repository(notary, storage, debug);

The debug level can be set to one of the following values:

  • 0 - no logging to console.log or console.error will occur
  • 1 - exceptions will be logged to console.error
  • 2 - additional validation of arguments passed into the API will occur
  • 3 - detailed information will be logged to console.log

Note that the above example uses a test version of the digital notary and document repository. The actual statements required depends on whether the code resides in a client application or if it is part of a service that implements the document repository.

Client Application

When implementing a client application that uses the remote document repository service use the following declarations:

const uri = 'https://bali-nebula.net/repository';  // the URI for the remote document repository
const hsm = require('bali-hsm-proxy').proxy(directory, debug);  // hardware security module proxy
const notary = require('bali-digital-notary').notary(hsm, account, directory, debug);
const repository = require('bali-document-repository').client(notary, uri, debug);

Service Implementation

When implementing a remote document repository service use something like the following declarations:

const configuration = {
    names: 'bali-nebula-names-us-east-1',
    documents: 'bali-nebula-documents-us-east-1',
    contracts: 'bali-nebula-contracts-us-east-1',
    messages: 'bali-nebula-messages-us-east-1'
};
const notary = require('bali-digital-notary').service(debug);
const repository = require('bali-document-repository').service(notary, configuration, debug);

Note, the AWS buckets listed in this configuration are private. Anyone implementing their own document repository service must setup their own AWS environment.

Initializing the Digital Notary and Publishing the Public Certificate

Once the proper imports are done, the digital notary needs to be initialized with a new private notary key and its associated notarized public certificate must be published to the Bali Nebula™. The private notary key will be used to notarize documents. The public certificate is published so that it may be made available to anyone who wants to use it to verify the authenticity of any document notarized using the private notary key.

var certificate = await notary.generateKey();
certificate = await notary.notarizeDocument(certificate);
await notary.activateKey(certificate);
await storage.writeContract(certificate);

For more details on how the digital notary works and how to use it, see the bali-digital-notary project.

Creating a New Document

Now we are ready to create and save our own documents to the document repository. We start by creating a document using the attributes provided in a template.

First, we create a new instance of a document using a JavaScript object containing the attributes that define the profile.

var document = bali.instance('/acme/types/Profile/v1', {
    $name: 'Jane Doe',
    $email: bali.resource('mailto:jane.doe@acme.org')
});
console.log('document: ' + document);
console.log();

The resulting document containing the profile information looks something like this:

document: [
    $name: "Jane Doe"
    $email: <mailto:jane.doe@acme.org>
](
    $type: /acme/types/Profile/v1
    $tag: #7HNW7NLGAR2M6KZKH3655KKHW1VZBVWM
    $version: v1
    $permissions: /bali/permissions/public/v1
    $previous: none
)

All documents including this profile are parameterized by standard attributes that are required by the document repository. These include the $type of the document, the unique $tag and $version string that identify the document, a named reference to the $permissions that define who is allowed to access the document, and finally, a document citation to the $previous version of the document if one exists (in this case it doesn't since this is the first version).

Saving the Document to the Repository

Once the document has been created we can save it to the document repository.

var citation = await repository.saveDocument(document);
console.log('citation: ' + citation);
console.log();

A document citation is returned citing the new document in the document repository. It can be used later on to retrieve the document from the repository.

citation: [
    $protocol: v2
    $tag: #7HNW7NLGAR2M6KZKH3655KKHW1VZBVWM
    $version: v1
    $digest: '
        1G3DLD7XZAMZ7S68Z21SXSSF0K9Q238LCZ3W67TM0KL36H7BH8J63P7P1M7B
        BSMJDCL7FY0P65FDFD92MKQC4DH49G46J5ZD92C3DMH
    '
]($type: /bali/notary/Citation/v1)

Each document citation contains attributes describing the version of the security $protocol used to create the citation, the unique $tag and $version string for the cited document, and a digital $digest (or fingerprint) of the cited document that can be used to verify that the document has not been modified or corrupted since it was created. If even a single character in the cited document is changed, the digital digest in the document citation will be completely different.

Retrieving and Updating the Document

Once a draft document has been saved in the repository it is simple to retrieve it again and make updates to it.

document = await repository.retrieveDocument(citation);
document.setAttribute('$age', 29);
console.log('updated document: ' + document);
console.log();

The updated document now looks like this.

updated document: [
    $name: "Jane Doe"
    $email: <mailto:jane.doe@acme.org>
    $age: 29
](
    $type: /acme/types/Profile/v1
    $tag: #7HNW7NLGAR2M6KZKH3655KKHW1VZBVWM
    $version: v1
    $permissions: /bali/permissions/public/v1
    $previous: none
)

Signing a Contract

Once we have the document the way we want it, we can digitally notarize it and save it to the document repository as a signed contract which cannot be modified or deleted at a later time.

const name = '/acme/profiles/jane/v1';
await repository.signContract(name, document);

The notarized contract now resides in the document repository and is associated with the specified name.

It can be retrieved from the repository as follows:

document = await repository.retrieveDocument(name);
console.log('document: ' + document);
console.log();

The named document has not changed.

named document: [
    $name: "Jane Doe"
    $email: <mailto:jane.doe@acme.org>
    $age: 29
](
    $type: /acme/types/Profile/v1
    $tag: #7HNW7NLGAR2M6KZKH3655KKHW1VZBVWM
    $version: v1
    $permissions: /bali/permissions/public/v1
    $previous: none
)

Checking Out a new Version of a Signed Contract

We can checkout a new version of the signed contract if we want to make changes to it since the current version has been digitally notarized and cannot be changed. We will make the next version of the contract v1.1.

const level = 2;  // version level to increment
document = await repository.checkoutContract(name, level);
document.setAttribute('$age', 30);
console.log('next version: ' + document);
console.log();

The next version of the document looks like this:

next version: [
    $name: "Jane Doe"
    $email: <mailto:jane.doe@acme.org>
    $age: 30
](
    $type: /acme/types/Profile/v1
    $tag: #7HNW7NLGAR2M6KZKH3655KKHW1VZBVWM
    $version: v1.1
    $permissions: /bali/permissions/public/v1
    $previous: [
        $protocol: v2
        $tag: #7HNW7NLGAR2M6KZKH3655KKHW1VZBVWM
        $version: v1
        $digest: '
            88WKVZPP5M1WGJSB40BPVK94GDTDBQWJNF3ZRX98JF94YSZ1ZT9QS70YTTCC
            LC2R8J7H13HV8WXD21WK01RBNQA30JJTPCTMWZQC56H
        '
    ]($type: /bali/notary/Citation/v1)
)

Notice that in addition to the $age attribute and the $version string parameter being different, the $previous version citation now refers to the original document as well.

We can then digitally notarize the new version of the contract in the same way that we signed the original version.

name = '/acme/profiles/jane/v1.1';
await repository.signContract(name, document);

Notice that we have incremented the version number in the name as well. The new version of the signed contract has been saved in the document repository.

Retrieving the Entire Notarized Contract

Remember that the named document is actually stored within the notarized contract. The entire contract itself can be retrieved from the repository as follows:

const contract = await repository.retrieveContract(name);
console.log('contract: ' + contract);
console.log();

The notarized contract looks like this:

notarized contract: [
    $protocol: v2
    $timestamp: <2020-06-04T00:23:41.953>
    $account: #1H87ZSZQ6MY9TX1JQBD0MHGN76SNR8HS
    $document: [
        $name: "Jane Doe"
        $email: <mailto:jane.doe@acme.org>
        $age: 30
    ](
        $type: /acme/types/Profile/v1
        $tag: #7HNW7NLGAR2M6KZKH3655KKHW1VZBVWM
        $version: v1.1
        $permissions: /bali/permissions/public/v1
        $previous: [
            $protocol: v2
            $tag: #7HNW7NLGAR2M6KZKH3655KKHW1VZBVWM
            $version: v1
            $digest: '
                88WKVZPP5M1WGJSB40BPVK94GDTDBQWJNF3ZRX98JF94YSZ1ZT9QS70YTTCC
                LC2R8J7H13HV8WXD21WK01RBNQA30JJTPCTMWZQC56H
            '
        ]($type: /bali/notary/Citation/v1)
    )
    $certificate: [
        $protocol: v2
        $tag: #BMW5GZD7DBF12S3MT5V25VWRV1NJVASA
        $version: v1
        $digest: '
            C8A72T8TMANV2NDCSKB3LVN59N7880PQ45AG59BS56NAK46D6CVXWT407M24
            17J44SS6CAKF47VMTDVYFB5NHK4SMVXY3G5HNQL1MC8
        '
    ]($type: /bali/notary/Citation/v1)
    $signature: '
        QXPNB41J5HQL34AQTQXW6RXHH9GZVN1DJ0G5C0CKMATQCLXCWZYHCFWRBHXX
        C4L9K19PCCPRRYRRG1HYWRPJPW7JG6RTYQARA1AHK1R
    '
]($type: /bali/notary/Contract/v1)

Notice that the document containing the profile information has been embedded within a contract that contains additional information about the $account that owns the document, and a digital $signature that can be used to verify the authenticity of the document using the cited public $certificate.