Skip to content

Latest commit

 

History

History
1196 lines (978 loc) · 36.2 KB

File metadata and controls

1196 lines (978 loc) · 36.2 KB

Table of Contents

About Keychain

Putting private keys directly into websites is not safe or secure, even ones run by reputable community members. Yet this is currently how nearly every Steem-based site or service currently works. On top of that, most Steem users likely use their master password which is even worse.

The Vessel desktop wallet software is a secure alternative, but it is too difficult to use for the majority of Steem users and does not easily interact with websites - which is Steem's primary use case.

On Ethereum, you never have to enter your private key into a website to use a dApp. You can just use a browser extension like Metamask, which dApp websites can interface with to securely store your keys and broadcast transactions to the blockchain.

Steem Keychain aims to bring the security and ease-of-use of Metamask to the Steem blockchain platform.

Installation

You can download and install the latest published version of the extension for the following browsers:

  • Google Chrome (or Opera/Brave): on Chrome Store
    • Export your keys from Steem keychain (in settings)
    • Download this repository as zip
    • Unzip the downloaded folder
    • Right click on any existing extension > Manage my extensions.
    • Activate developer mode.
    • Click "Load Unpacked" and select the unzipped folder.
    • Import your keys (use the same master password)
  • Firefox: on Firefox Addon Store

Features

The Steem Keychain extension includes the following features:

  • Store an unlimited number of Steem account keys, encrypted with AES
  • View balances, transaction history, voting power, and resource credits
  • Send STEEM and SBD transfers, manage witness votes, and update SP delegation right from the extension
  • Manage your Steem Engine tokens
  • Power up or down
  • Securely interact with Steem-based websites that have integrated with Steem Keychain
  • Manage transaction confirmation preferences by account and by website
  • Locks automatically on browser shutdown or manually using the lock button

Website Integration

Websites can currently request the Steem Keychain extension to perform the following functions / broadcast operations:

  • Send a handshake to make sure the extension is installed
  • Decrypt a message encrypted by a Steem account private key (commonly used for "logging in")
  • Post a comment (top level or reply)
  • Broadcast a vote
  • Broadcast a custom JSON operation
  • Send a transfer
  • Send Steem Engine tokens
  • Send Delegations
  • Power up/down
  • Vote for witnesses
  • Create/Remove/Vote for proposals
  • Create claimed accounts
  • Sign Tx

Usage

Example

An example of a web page that interacts with the extension is included in the "example" folder in the repo. You can test it by running a local HTTP server and going to http://localhost:1337/main.html in your browser.

cd example python -m http.server 1337 //or any other method to run a static server

NOTE: On localhost, it will run on port 1337.

Using Keychain for logins

To login, you can encode a message from your backend and verify that the user can decode it using the requestVerifyKey method. See an example in this project by @howo (@steempress witness):

Frontend

Backend

Alternatively, you can use requestSignTx and verify the signature on your backend.

@hiveio/keychain

This npm module makes it easy to add Keychain support within the browser. It also includes helpful functions to check whether Keychain was used before. It was developed by @therealwolf (witness).

Operations

The Steem Keychain extension will inject a "steem_keychain" JavaScript into all web pages opened in the browser while the extension is running. You can therefore check if the current user has the extension installed using the following code:

steem_keychain

Use the steem_keychain methods listed below to issue requests to the Steem blockchain.

requestHandshake

This function is called to verify Keychain installation on a user's device

Parameters
  • callback function Confirms Keychain installation (has no parameters)

requestEncodeMessage

This function is called to verify that the user has a certain authority over an account, by requesting to decode a message

Parameters
  • username String Steem account to perform the request
  • receiver String Account that will decode the string
  • message String Message to be encrypted
  • key String Type of key. Can be 'Posting','Active' or 'Memo'
  • callback requestCallback Function that handles Keychain's response to the request
Examples
const keychain = window.steem_keychain;
const message = username + Date.now();
keychain.requestEncodeMessage(
  username,
  myUsername,
  message,
  'Memo',
  (response) => {
    if (response.success) {
      const encodedMessage = response.result;
      // Send message to a server where you can use your private key to decode it
    }
  },
);

requestEncodeWithKeys

This function is called to allow encoding a message with multiple receivers. This is used in the case of multisig

Parameters
  • username String Steem account to perform the request
  • publicKeys Array<String> Key that can decode the string
  • message String Message to be encrypted
  • key String Type of key. Can be 'Posting','Active' or 'Memo'
  • callback requestCallback Function that handles Keychain's response to the request
Examples
const keychain = window.steem_keychain;
const message = username + Date.now();
keychain.requestEncodeMessage(
  username,
  [pubKey1, pubKey2],
  message,
  'Memo',
  (response) => {
    if (response.success) {
      const encodedMessages = response.result;
      // Send message to a server where you can use your private key to decode it
    }
  },
);

requestVerifyKey

This function is called to verify that the user has a certain authority over an account, by requesting to decode a message

Parameters
  • account String Steem account to perform the request
  • message String Message to be decoded by the account
  • key String Type of key. Can be 'Posting','Active' or 'Memo'
  • callback requestCallback Function that handles Keychain's response to the request
Examples
const keychain = window.steem_keychain;
keychain.requestVerifyKey('faisalamin', encodedMessage, 'Posting', (response) => {
  if (response.success === true) {
    const decodedMessage = response.result;
  }
});

requestSignBuffer

Requests a message to be signed with proper authority

Parameters
  • account String Steem account to perform the request. If null, user can choose the account from a dropdown (optional, default null)
  • message String Message to be signed by the account
  • key String Type of key. Can be 'Posting','Active' or 'Memo'
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
  • title String Override "Sign message" title (optional, default null)

requestAddAccountAuthority

Requests to add account authority over another account. For more information about multisig, please read https://steempro.com/utopian-io/@stoodkev/how-to-set-up-and-use-multisignature-accounts-on-steem-blockchain

Parameters
  • account String Steem account to perform the request
  • authorizedUsername String Authorized account
  • role String Type of authority. Can be 'Posting','Active' or 'Memo'
  • weight number Weight of the authority
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
// Gives @faisalamin active authority with weight 2 to `account`
const keychain = window.steem_keychain;
keychain.requestAddAccountAuthority(
  account,
  'faisalamin',
  'Active',
  2,
  (response) => {
    console.log(response);
  },
);

requestRemoveAccountAuthority

Requests to remove an account authority over another account. For more information about multisig, please read https://steempro.com/utopian-io/@stoodkev/how-to-set-up-and-use-multisignature-accounts-on-steem-blockchain

Parameters
  • account String Steem account to perform the request
  • authorizedUsername String Account to lose authority
  • role String Type of authority. Can be 'Posting','Active' or 'Memo'
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
// Removes @faisalamin's active authority from `account`
const keychain = window.steem_keychain;
keychain.requestRemoveAccountAuthority(
  account,
  'faisalamin',
  'Active',
  (response) => {
    console.log(response);
  },
);

requestAddKeyAuthority

Requests to add a new key authority to an account. For more information about multisig, please read https://steempro.com/utopian-io/@stoodkev/how-to-set-up-and-use-multisignature-accounts-on-steem-blockchain

Parameters
  • account String Steem account to perform the request
  • authorizedKey String New public key to be associated with the account
  • role String Type of authority. Can be 'Posting','Active' or 'Memo'
  • weight number Weight of the key authority
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
const keychain = window.steem_keychain;
keychain.requestAddKeyAuthority(username, publicKey, 'Memo', 1, (response) => {
  console.log(response);
});

requestRemoveKeyAuthority

Requests to remove a key to an account. For more information about multisig, please read https://steempro.com/utopian-io/@stoodkev/how-to-set-up-and-use-multisignature-accounts-on-steem-blockchain

Parameters
  • account String Steem account to perform the request
  • authorizedKey String Key to be removed (public key).
  • role String Type of authority. Can be 'Posting','Active' or 'Memo'.
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
const keychain = window.steem_keychain;
keychain.requestRemoveKeyAuthority(username, publicKey, 'Memo', (response) => {
  console.log(response);
});

requestBroadcast

Generic broadcast request

Parameters
  • account String Steem account to perform the request
  • operations Array Array of operations to be broadcasted
  • key String Type of key. Can be 'Posting','Active' or 'Memo'
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
const keychain = window.steem_keychain;
keychain.requestBroadcast(
  'npfedwards',
  [
    [
      'account_witness_vote',
      {
        account: 'npfedwards',
        witness: 'faisalamin',
        approve: true,
      },
    ],
  ],
  'Active',
  (response) => {
    console.log(response);
  },
);

requestSignTx

Requests to sign a transaction with a given authority

Parameters
  • account String Steem account to perform the request
  • tx Object Unsigned transaction
  • key String Type of key. Can be 'Posting','Active' or 'Memo'
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
// This example would be done much easier with requestBroadcast
import dsteem from '@steempro/dsteem';

const client = new dsteem.Client(['https://api.steemit.com', 'https://api.justyy.co', 'https://api.steemitdev.com']);
const keychain = window.steem_keychain;

const props = await client.database.getDynamicGlobalProperties();
const headBlockNumber = props.head_block_number;
const headBlockId = props.head_block_id;
const expireTime = 600000;

const op = {
  ref_block_num: headBlockNumber & 0xffff,
  ref_block_prefix: Buffer.from(headBlockId, 'hex').readUInt32LE(4),
  expiration: new Date(Date.now() + expireTime).toISOString(),
  operations: [...] // Add operations here
};
keychain.requestSignTx(username, op, 'Posting', async (response) => {
  if (!response.error) {
    console.log(response.result);
    await client.database.verifyAuthority(response.result);
    await client.broadcast.send(response.result);
  }
});

requestSignedCall

Requests a signed call

Parameters
  • account String Steem account to perform the request
  • method String Method of the call
  • params String Parameters of the call
  • key String Type of key. Can be 'Posting','Active' or 'Memo'
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)

Meta

  • deprecated: This is deprecated.

requestPost

Requests to broadcast a blog post/comment

Parameters
Examples
const keychain = window.steem_keychain;
keychain.requestPost(
  'faisalamin',
  'Hello World!',
  '## This is a blog post \
\
And this is some text',
  'Blog',
  null,
  { format: 'markdown', description: 'A blog post', tags: ['Blog'] },
  'hello-world',
  {
    author: 'faisalamin',
    permlink: 'hi',
    max_accepted_payout: '100000.000 SBD',
    percent_steem_dollars: 10000,
    allow_votes: true,
    allow_curation_rewards: true,
    extensions: [
      [
        0,
        {
          beneficiaries: [
            { account: 'yabapmatt', weight: 1000 },
            { account: 'steemplus-pay', weight: 500 },
          ],
        },
      ],
    ],
  },
  (response) => {
    console.log(response);
  },
);

requestVote

Requests a vote

Parameters
  • account String Steem account to perform the request
  • permlink String Permlink of the blog post
  • author String Author of the blog post
  • weight Number Weight of the vote, comprised between -10,000 (-100%) and 10,000 (100%)
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
// Upvote with 50% weight
const keychain = window.steem_keychain;
keychain.requestVote(
  'npfedwards',
  'hello-world',
  'faisalamin',
  5000,
  (response) => {
    console.log(response);
  },
);

requestCustomJson

Requests a custom JSON broadcast

Parameters
  • account String Steem account to perform the request. If null, user can choose the account from a dropdown (optional, default null)
  • id String Type of custom_json to be broadcasted
  • key String Type of key. Can be 'Posting','Active' or 'Memo'
  • json String Stringified custom json
  • display_msg String Message to display to explain to the user what this broadcast is about
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
const keychain = window.steem_keychain;
keychain.requestCustomJson(
  null,
  'sm_market_rent',
  'Active',
  JSON.stringify({
    items: ['9292cd44ccaef8b73a607949cc787f1679ede10b-93'],
    currency: 'DEC',
    days: 1,
  }),
  'Rent 1 card on Splinterlands',
  (response) => {
    console.log(response);
  },
);

requestTransfer

Requests a transfer

Parameters
  • account String Steem account to perform the request
  • to String Steem account to receive the transfer
  • amount String Amount to be transfered. Requires 3 decimals.
  • memo String The memo will be automatically encrypted if starting by '#' and the memo key is available on Keychain. It will also overrule the account to be enforced, regardless of the 'enforce' parameter
  • currency String 'STEEM' or 'SBD'
  • callback requestCallback Function that handles Keychain's response to the request
  • enforce boolean If set to true, user cannot chose to make the transfer from another account (optional, default false)
  • rpc String Override user's RPC settings (optional, default null)
Examples
const keychain = window.steem_keychain;
keychain.requestTransfer(
  username,
  toUsername,
  amount.toFixed(3),
  '',
  'STEEM',
  (response) => {
    console.log(response);
  },
  true,
);

requestSendToken

Requests a token transfer

Parameters
  • account String Steem account to perform the request
  • to String Steem account to receive the transfer
  • amount String Amount to be transferred. Requires 3 decimals.
  • memo String Memo attached to the transfer
  • currency String Token to be sent
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
if (window.steem_keychain) {
  const keychain = window.steem_keychain;
  keychain.requestSendToken(
    username,
    toUsername,
    amount.toFixed(3),
    memo,
    'DEC',
    (response) => {
      console.log(response);
    },
  );
} else {
  alert('You do not have steem keychain installed');
}

requestDelegation

Requests a delegation broadcast

Parameters
  • username String Steem account to perform the request. If null, user can choose the account from a dropdown (optional, default null)
  • delegatee String Account to receive the delegation
  • amount String Amount to be transfered. Requires 3 decimals for SP, 6 for VESTS.
  • unit String SP or VESTS
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
if (window.steem_keychain) {
  const keychain = window.steem_keychain;
  keychain.requestDelegation(null, 'faisalamin', '1.000', 'SP', (response) => {
    console.log(response);
  });
} else {
  alert('You do not have steem keychain installed');
}

requestWitnessVote

Requests a witness vote broadcast

Parameters
  • username String Steem account to perform the request. If null, user can choose the account from a dropdown (optional, default null)
  • witness String Account to receive the witness vote
  • vote boolean Set to true to vote for the witness, false to unvote
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
// Unvote our witness vote for @faisalamin
if (window.steem_keychain) {
  const keychain = window.steem_keychain;
  keychain.requestWitnessVote(null, 'faisalamin', false, (response) => {
    console.log(response);
  });
} else {
  alert('You do not have steem keychain installed');
}

requestProxy

Select an account as proxy

Parameters
  • username String Steem account to perform the request. If null, user can choose the account from a dropdown (optional, default null)
  • proxy String Account to become the proxy. Empty string ('') to remove a proxy
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
// Let @faisalamin use our voting power in governance votes
if (window.steem_keychain) {
  const keychain = window.steem_keychain;
  keychain.requestProxy(null, 'faisalamin', (response) => {
    console.log(response);
  });
} else {
  alert('You do not have steem keychain installed');
}
// Remove voting proxy
if (window.steem_keychain) {
  const keychain = window.steem_keychain;
  keychain.requestProxy(null, '', (response) => {
    console.log(response);
  });
} else {
  alert('You do not have steem keychain installed');
}

requestPowerUp

Request a power up

Parameters
  • username String Steem account to perform the request
  • recipient String Account to receive the power up
  • steem String Amount of STEEM to be powered up
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
// Power up 5 SP
if (window.steem_keychain) {
  const keychain = window.steem_keychain;
  keychain.requestPowerUp(username, username, '5.000', (response) => {
    console.log(response);
  });
} else {
  alert('You do not have steem keychain installed');
}

requestPowerDown

Request a power down

Parameters
  • username String Steem account to perform the request
  • steem_power String Amount of STEEM to be powered down
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
// Power down 5 SP
if (window.steem_keychain) {
  const keychain = window.steem_keychain;
  keychain.requestPowerDown(username, '5.000', (response) => {
    console.log(response);
  });
} else {
  alert('You do not have steem keychain installed');
}

requestCreateClaimedAccount

Request the creation of an account using claimed tokens

Parameters
  • username String Steem account to perform the request
  • new_account String New account to be created
  • owner object owner authority object
  • active object active authority object
  • posting object posting authority object
  • memo String public memo key
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)

requestCreateProposal

Request the creation of a DHF proposal

Parameters
  • username String Steem account to perform the request
  • receiver String Account receiving the funding if the proposal is voted
  • subject String Title of the DAO
  • permlink String Permlink to the proposal description
  • daily_pay String Daily amount to be received by receiver
  • start String Starting date
  • end String Ending date
  • extensions String Stringified Array of extensions
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
if (window.steem_keychain) {
  const keychain = window.steem_keychain;
  keychain.requestCreateProposal(
    'keychain',
    'keychain',
    'Steem Keychain development',
    'steem-keychain-proposal-dhf-ran717',
    '10.000',
    '2022-03-22',
    '2023-03-21',
    JSON.stringify([]),
    (response) => {
      console.log(response);
    },
  );
} else {
  alert('You do not have steem keychain installed');
}

requestRemoveProposal

Request the removal of a DHF proposal

Parameters
  • username String Steem account to perform the request
  • proposal_ids String Stringified Array of ids of the proposals to be removed
  • extensions String Stringified Array of extensions
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
if (window.steem_keychain) {
  const keychain = window.steem_keychain;
  keychain.requestRemoveProposal(
    username,
    JSON.stringify([216]),
    JSON.stringify([]),
    (response) => {
      console.log(response);
    },
  );
} else {
  alert('You do not have steem keychain installed');
}

requestUpdateProposalVote

Vote/Unvote a DHF proposal

Parameters
  • username String Steem account to perform the request
  • proposal_ids String Stringified Array of Ids of the proposals to be voted
  • approve boolean Set to true to support the proposal, false to remove a vote
  • extensions String Stringified Array of extensions
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
// Approve a proposal
if (window.steem_keychain) {
  const keychain = window.steem_keychain;
  keychain.requestUpdateProposalVote(
    username,
    JSON.stringify([216]),
    true,
    JSON.stringify([]),
    (response) => {
      console.log(response);
    },
  );
} else {
  alert('You do not have steem keychain installed');
}
// Unapprove a proposal
if (window.steem_keychain) {
  const keychain = window.steem_keychain;
  keychain.requestUpdateProposalVote(
    username,
    JSON.stringify([216]),
    false,
    JSON.stringify([]),
    (response) => {
      console.log(response);
    },
  );
} else {
  alert('You do not have steem keychain installed');
}

requestAddAccount

Add a new account to Keychain

Parameters
  • username String username of the account to be added
  • keys Object private keys of the account : {active:'...',posting:'...',memo:'...'}. At least one must be specified. Alternatively, authorized accounts can be specified with @${username}.
  • callback requestCallback Function that handles Keychain's response to the request
Examples
if (window.steem_keychain) {
  const postingKey = '...';
  const keychain = window.steem_keychain;
  keychain.requestConversion(
    username,
    {
      posting: postingKey,
    },
    (response) => {
      console.log(response);
    },
  );
} else {
  alert('You do not have steem keychain installed');
}

requestConversion

Request currency conversion

Parameters
  • username String Steem account to perform the request
  • amount String amount to be converted.
  • collaterized Boolean true to convert STEEM to SBD. false to convert SBD to STEEM.
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
// Convert 5 STEEM to SBD
if (window.steem_keychain) {
  const keychain = window.steem_keychain;
  keychain.requestConversion(username, '5.000', true, (response) => {
    console.log(response);
  });
} else {
  alert('You do not have steem keychain installed');
}

requestRecurrentTransfer

Request recurrent transfer

Parameters
  • username String Steem account to perform the request (optional, default null)
  • to String Steem account receiving the transfers.
  • amount String amount to be sent on each execution.
  • currency String STEEM or SBD on mainnet.
  • memo String transfer memo
  • recurrence Number How often will the payment be triggered (in hours) - minimum 24.
  • executions Number The times the recurrent payment will be executed - minimum 2.
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
// Let's send @faisalamin 5 STEEM a day
if (window.steem_keychain) {
  const keychain = window.steem_keychain;
  keychain.requestConversion(
    null,
    'faisalamin',
    '5.000',
    'STEEM',
    memo,
    24,
    7,
    (response) => {
      console.log(response);
    },
  );
} else {
  alert('You do not have steem keychain installed');
}

requestSwap

Request swap

Parameters
  • username String Steem account to perform the request (optional, default null)
  • startToken String Incoming token
  • endToken String Outgoing token
  • amount number Amount of tokens to be swapped
  • slippage number Max slippage
  • steps Object Steps returned by KeychainSDK.swaps.getEstimation(), of type IStep[]
  • callback requestCallback Function that handles Keychain's response to the request
  • rpc String Override user's RPC settings (optional, default null)
Examples
// Let's swap 5 STEEM to DEC
// Estimated steps can be obtained via KeychainSDK.swaps.getEstimation()

if (window.steem_keychain) {
  const keychain = window.steem_keychain;
  keychain.requestSwap(
    'keychain',
    'STEEM',
    'DEC',
    5,
    1,
    estimatedSteps,
    (response) => {
      console.log(response);
    },
  );
} else {
  alert('You do not have steem keychain installed');
}

requestCallback

Type: Function

Parameters

  • response Object Keychain's response to the request