artwook / ledger

Permissioned Ledger
MIT License
0 stars 0 forks source link

Register on Chain Account should be able to define multi-sig account #8

Closed AlexChien closed 7 years ago

AlexChien commented 7 years ago

In order to have multi-sig enabled account, register account command in cli_wallet should be able to accept parameters to allow multiple public key / account when invoked by web faucet service.

AlexChien commented 7 years ago

We need a better security model for user account control with possible 2Factor authentication. https://github.com/artwook/ledger/wiki/Wallet%202-Factor%20Authentication%20Protocol

For example, we have user account alice and a control account sfactor.

A typical user alice onchain account setup will be like this:

alice:

active permission: alice's pubkey (w:1), alice.sfactor(w:1) owner permission: alice's pubkey (w:1), alice.sfactor(w:1)

With this setup, we are able to achieve these:

  1. When user forgets wallet password and loses access, alice.sfactor is able to reset ailce owner key
  2. When user needs to do onchain operation, alice signs her operation and requests alice.sfactor's permission. While sfactor provider is able to give user options to determine when to
    • reject user operation if suspicious
    • conditionally auto sign (eg, amount less than 100, auto sign, amount over 100, needs alternative verification)
    • needs alternative authentication before sign (eg, SMS verification code, Google Authenticor)

To accomplish this, we need an enhanced register_account wallet api, current signature is as below:

>>> gethelp register_account
gethelp register_account

usage: register_account ACCOUNT_NAME OWNER_PUBLIC_KEY ACTIVE_PUBLIC_KEY REGISTRAR REFERRER REFERRER_PERCENT BROADCAST

The enahnced register_account2 should be able to accept something like below:

usage: register_account2 ACCOUNT_NAME OWNER_AUTHORITIES ACTIVE_AUTHORITIES REGISTRAR REFERRER REFERRER_PERCENT BROADCAST

OWNER_AUTHORITIES [Array]: structure like this [THREADHOLD,["PUBKEY_OR_ACCOUNT1",WEIGHT1], ["PUBKEY_OR_ACCOUNT2",WEIGHT]]
ACTIVE_AUTHORITIES [Array]: structure like this [THREADHOLD,["PUBKEY_OR_ACCOUNT1",WEIGHT1], ["PUBKEY_OR_ACCOUNT2",WEIGHT]]

when provide parameters as below, register_account2 is same as register_account:

regiser_account2 ACCOUNT_NAME [1, ["OWNER_PUBLIC_KEY", 1]], [1, ["ACTIVE_PUBLIC_KEY", 1]] REGISTRAR REFERRER REFERRER_PERCENT BROADCAST
AlexChien commented 7 years ago

api name update: register_escorted_account

Account Setup

2 Factor Active Permission:

thresdhold: 2
alice publickey: 1
alice.sfactor: 1

Owner Permission:

threshold: 2
alice public key: 1
alice.sfactor: 1
sfactor: 1

alice.sfactor and sfactor must stay in different wallet and different server, so that hacker must hack all of service provider's server to get access to both sfactor accounts.

hackfisher commented 7 years ago

Maybe use another name for the api name: register_escorted_account

AlexChien commented 7 years ago

I am giving this issue a high priority because registration / faucet will rely on this.

hackfisher commented 7 years ago

This is how authority are formatted in JSON: thinking maybe we need some more simplified format?

new >>> get_account init1
get_account init1
{
  "id": "1.2.7",
  "membership_expiration_date": "1969-12-31T23:59:59",
  "registrar": "1.2.7",
  "referrer": "1.2.7",
  "lifetime_referrer": "1.2.7",
  "network_fee_percentage": 2000,
  "lifetime_referrer_fee_percentage": 8000,
  "referrer_rewards_percentage": 0,
  "name": "init1",
  "owner": {
    "weight_threshold": 1,
    "account_auths": [],
    "key_auths": [[
        "AWK8dmH7xa4NBEcPcmuD9nnH3h84CXb29MrKBwbaWTS9nFFsmTvvs",
        1
      ]
    ],
    "address_auths": []
  },
  "active": {
    "weight_threshold": 1,
    "account_auths": [],
    "key_auths": [[
        "AWK8dmH7xa4NBEcPcmuD9nnH3h84CXb29MrKBwbaWTS9nFFsmTvvs",
        1
      ]
    ],
    "address_auths": []
  },
  "options": {
    "memo_key": "AWK8dmH7xa4NBEcPcmuD9nnH3h84CXb29MrKBwbaWTS9nFFsmTvvs",
    "voting_account": "1.2.5",
    "num_witness": 0,
    "num_committee": 0,
    "votes": [],
    "extensions": []
  },
  "statistics": "2.6.7",
  "whitelisting_accounts": [],
  "blacklisting_accounts": [],
  "whitelisted_accounts": [],
  "blacklisted_accounts": [],
  "owner_special_authority": [
    0,{}
  ],
  "active_special_authority": [
    0,{}
  ],
  "top_n_control_flags": 0
}
AlexChien commented 7 years ago

Update api signature:

usage: register_escorted_account ACCOUNT_NAME OWNER_AUTHORITIES ACTIVE_AUTHORITIES MEMO_PUBKEY REGISTRAR REFERRER REFERRER_PERCENT BROADCAST

OWNER_AUTHORITIES [JSON Object]: structure like this { "weight_threshold": 1, "account_auths": [["1.2.37",1]], "key_auths": [["AWK8dmH7xa4NBEcPcmuD9nnH3h84CXb29MrKBwbaWTS9nFFsmTvvs",1]], "address_auths": []}
ACTIVE_AUTHORITIES [JSON Object]: structure like this { "weight_threshold": 1, "account_auths": [["1.2.37",1]], "key_auths": [["AWK8dmH7xa4NBEcPcmuD9nnH3h84CXb29MrKBwbaWTS9nFFsmTvvs",1]], "address_auths": []}

NOTE: account_auths only accept account_id not account name.

hackfisher commented 7 years ago

When register_escorted_account, we need to specify a memo_key from active, Is it ok that we always use the first key from active, Or add a new parameter?

auto active_keys = active.get_keys();
FC_ASSERT( active_keys.size() > 0 );
account_create_op.options.memo_key = active_keys[0];
hackfisher commented 7 years ago

Testing Result:

unlocked >>>
register_escorted_account "escortaccount" {"weight_threshold":1,"account_auths":[["1.2.15",1]],"key_auths":[["AWK5RbVQsduKxk4bUjzxfDPRiPjHAtw8UCjHvZzJ6cw346ABNwACY",1]],"address_auths":[]} {"weight_threshold":1,"account_auths":[["1.2.15",1]],"key_auths":[["AWK5RbVQsduKxk4bUjzxfDPRiPjHAtw8UCjHvZzJ6cw346ABNwACY",1]],"address_auths":[]} "AWK5RbVQsduKxk4bUjzxfDPRiPjHAtw8UCjHvZzJ6cw346ABNwACY" "1.2.15" "1.2.15" 50 true
unlocked >>> register_escorted_account "escortaccount" {"weight_threshold":1,"account_auths":[["1.2.15",1]],"key_auths":[["AWK5RbVQsduKxk4bUjzxfDPRiPjHAtw8UCjHvZzJ6cw346ABNwACY",1]],"address_auths":[]} {"weight_threshold":1,"account_auths":[["1.2.15",1]],"key_auths":[["AWK5RbVQsduKxk4bUjzxfDPRiPjHAtw8UCjHvZzJ6cw346ABNwACY",1]],"address_auths":[]} "AWK5RbVQsduKxk4bUjzxfDPRiPjHAtw8UCjHvZzJ6cw346ABNwACY" "1.2.15" "1.2.15" 50 true
{
  "ref_block_num": 61487,
  "ref_block_prefix": 4167862900,
  "expiration": "2016-12-23T12:10:05",
  "operations": [[
      5,{
        "fee": {
          "amount": 200015429,
          "asset_id": "1.3.0"
        },
        "registrar": "1.2.15",
        "referrer": "1.2.15",
        "referrer_percent": 5000,
        "name": "escortaccount",
        "owner": {
          "weight_threshold": 1,
          "account_auths": [[
              "1.2.15",
              1
            ]
          ],
          "key_auths": [[
              "AWK5RbVQsduKxk4bUjzxfDPRiPjHAtw8UCjHvZzJ6cw346ABNwACY",
              1
            ]
          ],
          "address_auths": []
        },
        "active": {
          "weight_threshold": 1,
          "account_auths": [[
              "1.2.15",
              1
            ]
          ],
          "key_auths": [[
              "AWK5RbVQsduKxk4bUjzxfDPRiPjHAtw8UCjHvZzJ6cw346ABNwACY",
              1
            ]
          ],
          "address_auths": []
        },
        "options": {
          "memo_key": "AWK5RbVQsduKxk4bUjzxfDPRiPjHAtw8UCjHvZzJ6cw346ABNwACY",
          "voting_account": "1.2.5",
          "num_witness": 0,
          "num_committee": 0,
          "votes": [],
          "extensions": []
        },
        "extensions": {}
      }
    ]
  ],
  "extensions": [],
  "signatures": [
    "1f69971e870f1b6c1ada6e98c6b6c5b595a9717d721f20171b989824cccac936731747c02c3762ac40c36048df2ad6222d188f4c8e1457a6365bacf476558dcac0"
  ]
}

unlocked >>>
get_account escortaccount
unlocked >>> get_account escortaccount
{
  "id": "1.2.17",
  "membership_expiration_date": "1970-01-01T00:00:00",
  "registrar": "1.2.15",
  "referrer": "1.2.15",
  "lifetime_referrer": "1.2.15",
  "network_fee_percentage": 2000,
  "lifetime_referrer_fee_percentage": 3000,
  "referrer_rewards_percentage": 5000,
  "name": "escortaccount",
  "owner": {
    "weight_threshold": 1,
    "account_auths": [[
        "1.2.15",
        1
      ]
    ],
    "key_auths": [[
        "AWK5RbVQsduKxk4bUjzxfDPRiPjHAtw8UCjHvZzJ6cw346ABNwACY",
        1
      ]
    ],
    "address_auths": []
  },
  "active": {
    "weight_threshold": 1,
    "account_auths": [[
        "1.2.15",
        1
      ]
    ],
    "key_auths": [[
        "AWK5RbVQsduKxk4bUjzxfDPRiPjHAtw8UCjHvZzJ6cw346ABNwACY",
        1
      ]
    ],
    "address_auths": []
  },
  "options": {
    "memo_key": "AWK5RbVQsduKxk4bUjzxfDPRiPjHAtw8UCjHvZzJ6cw346ABNwACY",
    "voting_account": "1.2.5",
    "num_witness": 0,
    "num_committee": 0,
    "votes": [],
    "extensions": []
  },
  "statistics": "2.6.17",
  "whitelisting_accounts": [],
  "blacklisting_accounts": [],
  "whitelisted_accounts": [],
  "blacklisted_accounts": [],
  "owner_special_authority": [
    0,{}
  ],
  "active_special_authority": [
    0,{}
  ],
  "top_n_control_flags": 0
}

unlocked >>>