# IDENTITY SDK

> This package facilitate the interaction with Identities stored in the BlockChain.

## Specifications

### Functionality

- Deploy identities
- List and Manage keys on an Identity
- List and manage Claims on an Identity.
- Issue claims for an Identity.
- Fetch claim data using their URI.
- Request access to claim private data using their URI.
- Use access grants to access private data of claims.

---

## Usage

### Installation

**Install with `npm install @investorid/identity-sdk`**

Then require with:

```javascript
const IdentitySDK = require('@investorid/identity-sdk');
```


### Tutorials

- [Tutorial Homepage](./docs/tutorials/README.md)
  - [Implement a Claim Issuer service](./docs/tutorials/implement%20a%20claim%20issuer.md);
  - [Access Identity information](./docs/tutorials/access%20identity%20information.md);
  - [Connect with Identity 🚧]()

### BlockChain Provider

To interact with the BlockChain, you will need to instantiate a Provider.

The SDK is using [Ethers](https://github.com/ethers-io/ethers.js) to connect with Ethereum network.
Thus, any provider supported by Ethers can be used with the SDK.
This means any standard web3 provider should by supported.

Connect to a default provider:

```javascript
// You can use any standard network name
//  - "homestead"
//  - "rinkeby"
//  - "ropsten"
//  - "kovan"

IdentitySDK.Config.setProvider('ropsten');
const ropstenProvider = IdentitySDK.Config.getProvider(); 
IdentitySDK.Config.setProvider('homestead');
const mainProvider = IdentitySDK.Config.getProvider();
```

Connect to JSON RPC:

```javascript
// When using the JSON-RPC API, the network will be automatically detected


// Default: http://localhost:8545
let httpProvider = new IdentitySDK.Providers.JsonRpcProvider();
IdentitySDK.Config.setProvider(httpProvider);
```

Connect to any Web3 Provider:

```javascript
// When using a Web3 provider, the network will be automatically detected

// e.g. HTTP provider
let currentProvider = new web3.providers.HttpProvider('http://localhost:8545');

let web3Provider = new IdentitySDK.Providers.Web3Provider(currentProvider);
IdentitySDK.Config.setProvider(web3Provider);
```

Connect to metamask:

```javascript
// The network will be automatically detected; if the network is
// changed in MetaMask, it causes a page refresh.

let provider = new IdentitySDK.Providers.Web3Provider(web3.currentProvider);
IdentitySDK.Config.setProvider(web3Provider);
```

> Please refer to the [Ethers Providers Documentation](https://docs.ethers.io/ethers.js/html/api-providers.html) for more information.

### Configuration

#### Providers
By default, unsecured providers are not allowed. The SDK will refuse to fetch data on these endpoints.
A claim that has an uri which is not an HTTPS endpoint won't be retrieved.

Allow unsecured endpoints with:
```
const IdentitySDK = require('@investorid/identity-sdk');
IdentitySDK.Config.config({ allowUnsecuredProviders: true });
``` 

### SignerModule

Many interaction with identities, and especially claims, require to sign a challenge message.
Functions requiring these signatures expect a SignerModule as argument.

A SignerModule must expose a .getPublicKey() and a .signMessage(message: string) functions.

This is, for instance, a valid SignerModule:

```javascript
const jsrasign = require('jsrasign');

const signer = new SignerModule({
    getPublicKey: async () => ({
        key: "-----BEGIN CERTIFICATE----- my_super_public_key -----END CERTIFICATE-----",
        type: "X.509",
        signingMethod: "SHA-256",
    }),
    signMessage: async (message) => {
        const signer = new jsrsasign.Signature({ alg: 'SHA256withRSA' });
        signer.init("-----BEGIN CERTIFICATE----- my_super_PRIVATE_no_really_super_secret_PRIVATE_key -----END CERTIFICATE-----");
        signer.updateString(message);
        return signer.sign();
    },
});
```

As a convenient method, a SignerModule can be created from an ethers Wallet:

```javascript
const wallet = new IdentitySDK.Providers.Wallet('PRIVATE_KEY', provider);
const signer = new IdentitySDK.SignerModule(wallet);
```

It can be used in functions such as `Claim.requestAccess()`:

```javascript
claim.requestAccess(IdentitySDK.utils.enums.AccessGrantType.PERSISTENT, signer);
```

### Examples

Find examples in the [Example folder](./examples).

#### Load a contract

```javascript
const IdentitySDK = require('@investorid/identity-sdk');

const provider = new IdentitySDK.Providers.JsonRpcProvider();

(async () => {
  const identity = new IdentitySDK.Identity(); // Create the Identity Object

  console.log(identity.instantiateAtAddress('0xadD92F8Ef0729E969c5a98Ea5740c9b644B362e3', provider)); // Get the instance of the Identity

  console.log(await identity.instance.getClaimIdsByType(1)); // Call directly a function from the Contract.
})();
```

#### Get claims of an Identity

```javascript
const IdentitySDK = require('@investorid/identity-sdk');

const provider = new IdentitySDK.Providers.JsonRpcProvider();

(async () => {
  const identity = new IdentitySDK.Identity('0xadD92F8Ef0729E969c5a98Ea5740c9b644B362e3', provider);

  const claims = await identity.getClaimsByType(1);

  console.log(claims);
})();
```

#### Get keys of an Identity

```javascript
const IdentitySDK = require('@investorid/identity-sdk');

const provider = new IdentitySDK.Providers.JsonRpcProvider();

(async () => {
  const identity = new IdentitySDK.Identity('0xadD92F8Ef0729E969c5a98Ea5740c9b644B362e3', provider);

  const keys = await identity.getKeysByPurpose(IdentitySDK.utils.enums.KeyPurpose.CLAIM);
  
  console.log(keys);
  
  console.log(await identity.getKeyPurpose(keys[0].key));
})();
```

#### Deploy an identity

```javascript
const IdentitySDK = require('@investorid/identity-sdk');

const provider = new IdentitySDK.Providers.JsonRpcProvider();

const CLAIM_ISSUER_PRIVATE_KEY = 'issuer_private_key';
const claimIssuerWallet = new IdentitySDK.Providers.Wallet(CLAIM_ISSUER_PRIVATE_KEY, provider);

const DEPLOY_PRIVATE_KEY = 'deploy_private_key';
const deployWallet = new IdentitySDK.Providers.Wallet(DEPLOY_PRIVATE_KEY, provider);

(async () => {
  // Deploy a new Identity
  const identity = await IdentitySDK.Identity.deployNew(deployWallet);

  await identity.addKey(IdentitySDK.utils.crypto.keccak256(claimIssuerWallet.address), IdentitySDK.utils.enums.KeyPurpose.CLAIM, IdentitySDK.utils.enums.KeyType.ECDSA);
  
  identity.useProvider(claimIssuerWallet);

  await identity.addClaim(IdentitySDK.utils.enums.ClaimType.KYC, IdentitySDK.utils.enums.ClaimScheme.SOME, claimIssuerWallet.address, "a signature", "what a lot of data", "http://localhost:8080/claims/666");
})();

```

---

#### Get details of a claim
```javascript
const IdentitySDK = require('@investorid/identity-sdk');

const provider = new IdentitySDK.Providers.JsonRpcProvider();

(async () => {
    IdentitySDK.config({ allowUnsecuredProviders: true });

    const identity = new IdentitySDK.Identity('0xadD92F8Ef0729E969c5a98Ea5740c9b644B362e3', provider);

    const claims = await identity.getClaimsByType(IdentitySDK.utils.enums.ClaimType.KYC);

    const claim = new IdentitySDK.Claim(claims[0]);

    await claim.populate();

    console.log(claim);
    
    /*
    Claim {
      data: '0x65773261724950755a302f626e5a744e327961676676376139462f6a3672744a4e3761666a52414c6871493d',
      id: '0x3c6532cc1f4d1a44de8f58d4bde617bef8e744168bf92d783a0e1b66e7c6a44a',
      issuer: '0x8c78fF753c63ea0e8CA1FcA9997A132bC3e6a8F1',
      scheme: 1,
      type: 1,
      uri: 'http://localhost:8080/claims/b701e350-2a08-11e9-ac7e-517ddf10b60e',
      issuanceDate: 2019-02-06T12:14:12.996Z,
      emissionDate: 2019-02-06T12:15:02.039Z,
      status: 'PENDING',
      publicData: { result: 'clear' } }
     */
})();
```

## Development

**Don't forget to `npm install` first.**

**Build with `npm run build`.**

This will build package into the `dist/` folder from the TypeScript sources.
This will also build the TypeDoc website into `docs/type_doc`.

**Lint with `npm run lint`**
