orbitdb-archive / orbit-db-identity-provider

Default identity provider for OrbitDB
MIT License
31 stars 17 forks source link

importing identity #54

Open sirpy opened 4 years ago

sirpy commented 4 years ago

I can't use orbitdb local keystore for stoarge so I serialize the identity to JSON and save it on another storage How can I import the saved identity back to orbitdb every time my server starts?

sirpy commented 4 years ago

any one?

bluelovers commented 4 years ago

i want to know too

sirpy commented 4 years ago

can anyone from the mainters comment on this? pointer on how to implement?

shamb0t commented 4 years ago

@sirpy @bluelovers the keystore is required to be able to use the identity as that is where the signing keys are stored, so they will need to be stored in some persistent storage somewhere. The identity JSON does not contain key information and cannot be used to sign entries. To import and recreate the identity on start you should specify the keystore location and recreate the identity using createIdentity with some id (which you specify) as follows:

const Keystore = require('orbit-db-keystore')
const Identities = require('orbit-db-identity-provider')

const keystore = new Keystore('PATH_TO_KEYSTORE_IN_STORAGE')
const identity = await Identities.createIdentity({ keystore: keystore, id: 'myId' }) 
// should always return same identity if you use the same keystore and id

Are you able to recreate the identity this way?

sirpy commented 4 years ago

@shamb0t Yes I understand how it basically works, but as explained, I can't use localstorage and I want to save it in some other remote storage, so the question is how can this be done if at all

sirpy commented 4 years ago

@shamb0t we would like to use an external source or to import an identity to the keystore

choetech160 commented 3 years ago

Anyone got an answer on this? I have a packaged App which can't be used when moved on other devices because the identities aren't matching, thus cannot write to the database. I understand that one identity cannot be at multiple places at the same time, but would like to build the app somewhere and then distribute it, with the specific ID to someone else. I don't understand how the IDs/keys are generated and everyone say "it's random" but I feel it uses some specific UID from the hardware because I get the same ID/keys across build when on the same machine.

LucaPanofsky commented 2 years ago

@sirpy I think that you could try to follow this example

https://github.com/libp2p/js-libp2p/blob/master/examples/webrtc-direct/listener.js

In particular, you have to find a way to store in Heroku either your peer id or a secret which enables you to to recreate in a deterministic way your id every time the server process starts. In this way your Ipfs node will always have the same peer id which means that you are also going to obtain the same orbit id.

I tried to do something similar here https://github.com/LucaPanofsky/ipfs-wss-heroku-node (although the code needs improvement).

In addition I think that there is another option available. You can try to implement your custom identity provider: https://github.com/orbitdb/orbit-db-identity-provider For instance, if you look at the Ethereum identity provider https://github.com/orbitdb/orbit-db-identity-provider/blob/main/src/ethereum-identity-provider.js

const { Wallet, verifyMessage } = require('@ethersproject/wallet')

...

async getId (options = {}) {
    if (!this.wallet) {
      this.wallet = await this._createWallet(options)
    }
    return this.wallet.getAddress()
  }

...

it seems possible to write a custom identity provider which fetches identity data from wherever you desire.

mateuszjarzewski commented 2 years ago

I did something like this and it works perfectly, it is a browser version, might need a little tweaking to work on node

var my_store_provider = {

  status: 'open',

  open: function(){

    //if ( window.console ){
      // console.log('open arguments:')
      // console.log(arguments)
    //}
  },
  put: function(){

    //if ( window.console ){
      // console.log('put arguments:')
      // console.log(arguments)
    //}
  },
  get: function(){

    //if ( window.console ){
      // console.log('get arguments:')
      // console.log(arguments)
    //}

    if ( 'myId' === arguments[0] ){

      return "{\"publicKey\":\"04c27a8828aec4d3352c30d7c8f8d5743c9317646e70f0ffb7c017d36aac28dae946606952edeca823828e3a6939637d277da53b6eaf510142b184aa2ffa6e4375\",\"privateKey\":\"7905676d074489f7ee1997f86c8f1f3cbd258f318eae76b7a9ac5b4104c15f71\"}";
    }

    if ( '03c27a8828aec4d3352c30d7c8f8d5743c9317646e70f0ffb7c017d36aac28dae9' === arguments[0] ){

      return "{\"publicKey\":\"0454b2e47526ede9d8a06e048b216609f969f50d456b6beeaa558f6a91cd83b3cb93044a6d10a25922095e77644b680a49e24afe9808cdfe7d813f56c6be20a4d0\",\"privateKey\":\"0f72d1451ca9cf9a267f1f26d242edc769c601daf5d16bc85b53c087bfa6ee6e\"}";
    }
  }
}

var keystore = new OrbitDB.Keystore(my_store_provider)
OrbitDB.Identities.createIdentity({ keystore: keystore, id: 'myId' }).then(function(e){

})
mateuszjarzewski commented 2 years ago

Better still I think this code will create so called "deterministic key" that will always be the same, so no point migrating nothing when you can create key from password each time user logs in. Same idea behind this: https://keybase.io/warp/

// cdn.jsdelivr.net/npm/node-forge@1.3.0/dist/forge.min.js
// unpkg.com/ipfs@0.55.4/dist/index.min.js
// unpkg.com/orbit-db@0.26.1/dist/orbitdb.js

var password = 'mystrongpassword';
var md = forge.md.sha256.create();
md.update(password);
var seed = md.digest().data
var ed25519 = forge.pki.ed25519;
var keypair = ed25519.generateKeyPair({seed: seed});

class MyIdentityProvider extends OrbitDB.Identities.IdentityProvider {
  static get type () { return 'MyIdentityType' } // return type
  async getId () {

    return Buffer.from(keypair.publicKey).toString('hex')
   } // return identifier of external id (eg. a public key)
    async signIdentity (data) {

    var signature = ed25519.sign({
      message: data,
      // also accepts `binary` if you want to pass a binary string
      encoding: 'utf8',
      // node.js Buffer, Uint8Array, forge ByteBuffer, binary string
      privateKey: keypair.privateKey
    });

    signature = forge.util.bytesToHex(signature)

    return signature

   } //return a signature of data (signature of the OrbtiDB public key)
  static async verifyIdentity (identity) {

    // verify a signature on a UTF-8 message
    return ed25519.verify({
      message: identity.publicKey + identity.signatures.id,
      encoding: 'utf8',
      signature: forge.util.hexToBytes(identity.signatures.publicKey),
      publicKey: forge.util.hexToBytes(identity.id)
    })
    // `verified` is true/false

  } //return true if identity.sigantures are valid
}

OrbitDB.Identities.addIdentityProvider(MyIdentityProvider)

OrbitDB.Identities.createIdentity({ type: `MyIdentityType`, id: 'myId' }).then(function(e){

})