clef: documentation generator + docs (#19020)
* clef: implement documentation generation + remove unused struct * clef: formatting + spelling * clef: updates to doc
This commit is contained in:
committed by
GitHub
parent
3fd6db2bf6
commit
e9f70c9064
165
cmd/clef/main.go
165
cmd/clef/main.go
@@ -36,12 +36,15 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/console"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
@@ -171,10 +174,16 @@ Clef that the file is 'safe' to execute.`,
|
||||
signerSecretFlag,
|
||||
},
|
||||
Description: `
|
||||
The setpw command stores a password for a given address (keyfile). If you enter a blank passphrase, it will
|
||||
The setpw command stores a password for a given address (keyfile). If you enter a blank passphrase, it will
|
||||
remove any stored credential for that address (keyfile)
|
||||
`,
|
||||
}
|
||||
`}
|
||||
gendocCommand = cli.Command{
|
||||
Action: GenDoc,
|
||||
Name: "gendoc",
|
||||
Usage: "Generate documentation about json-rpc format",
|
||||
Description: `
|
||||
The gendoc generates example structures of the json-rpc communication types.
|
||||
`}
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -203,7 +212,7 @@ func init() {
|
||||
advancedMode,
|
||||
}
|
||||
app.Action = signer
|
||||
app.Commands = []cli.Command{initCommand, attestCommand, setCredentialCommand}
|
||||
app.Commands = []cli.Command{initCommand, attestCommand, setCredentialCommand, gendocCommand}
|
||||
|
||||
}
|
||||
func main() {
|
||||
@@ -743,6 +752,154 @@ func decryptSeed(keyjson []byte, auth string) ([]byte, error) {
|
||||
return seed, err
|
||||
}
|
||||
|
||||
// GenDoc outputs examples of all structures used in json-rpc communication
|
||||
func GenDoc(ctx *cli.Context) {
|
||||
|
||||
var (
|
||||
a = common.HexToAddress("0xdeadbeef000000000000000000000000deadbeef")
|
||||
b = common.HexToAddress("0x1111111122222222222233333333334444444444")
|
||||
meta = core.Metadata{
|
||||
Scheme: "http",
|
||||
Local: "localhost:8545",
|
||||
Origin: "www.malicious.ru",
|
||||
Remote: "localhost:9999",
|
||||
UserAgent: "Firefox 3.2",
|
||||
}
|
||||
output []string
|
||||
add = func(name, desc string, v interface{}) {
|
||||
if data, err := json.MarshalIndent(v, "", " "); err == nil {
|
||||
output = append(output, fmt.Sprintf("### %s\n\n%s\n\nExample:\n```json\n%s\n```", name, desc, data))
|
||||
} else {
|
||||
log.Error("Error generating output", err)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
{ // Sign plain text request
|
||||
desc := "SignDataRequest contains information about a pending request to sign some data. " +
|
||||
"The data to be signed can be of various types, defined by content-type. Clef has done most " +
|
||||
"of the work in canonicalizing and making sense of the data, and it's up to the UI to present" +
|
||||
"the user with the contents of the `message`"
|
||||
sighash, msg := accounts.TextAndHash([]byte("hello world"))
|
||||
message := []*core.NameValueType{{"message", msg, accounts.MimetypeTextPlain}}
|
||||
|
||||
add("SignDataRequest", desc, &core.SignDataRequest{
|
||||
Address: common.NewMixedcaseAddress(a),
|
||||
Meta: meta,
|
||||
ContentType: accounts.MimetypeTextPlain,
|
||||
Rawdata: []byte(msg),
|
||||
Message: message,
|
||||
Hash: sighash})
|
||||
}
|
||||
{ // Sign plain text response
|
||||
add("SignDataResponse - approve", "Response to SignDataRequest",
|
||||
&core.SignDataResponse{Password: "apassword", Approved: true})
|
||||
add("SignDataResponse - deny", "Response to SignDataRequest",
|
||||
&core.SignDataResponse{})
|
||||
}
|
||||
{ // Sign transaction request
|
||||
desc := "SignTxRequest contains information about a pending request to sign a transaction. " +
|
||||
"Aside from the transaction itself, there is also a `call_info`-struct. That struct contains " +
|
||||
"messages of various types, that the user should be informed of." +
|
||||
"\n\n" +
|
||||
"As in any request, it's important to consider that the `meta` info also contains untrusted data." +
|
||||
"\n\n" +
|
||||
"The `transaction` (on input into clef) can have either `data` or `input` -- if both are set, " +
|
||||
"they must be identical, otherwise an error is generated. " +
|
||||
"However, Clef will always use `data` when passing this struct on (if Clef does otherwise, please file a ticket)"
|
||||
|
||||
data := hexutil.Bytes([]byte{0x01, 0x02, 0x03, 0x04})
|
||||
add("SignTxRequest", desc, &core.SignTxRequest{
|
||||
Meta: meta,
|
||||
Callinfo: []core.ValidationInfo{
|
||||
{"Warning", "Something looks odd, show this message as a warning"},
|
||||
{"Info", "User should see this aswell"},
|
||||
},
|
||||
Transaction: core.SendTxArgs{
|
||||
Data: &data,
|
||||
Nonce: 0x1,
|
||||
Value: hexutil.Big(*big.NewInt(6)),
|
||||
From: common.NewMixedcaseAddress(a),
|
||||
To: nil,
|
||||
GasPrice: hexutil.Big(*big.NewInt(5)),
|
||||
Gas: 1000,
|
||||
Input: nil,
|
||||
}})
|
||||
}
|
||||
{ // Sign tx response
|
||||
data := hexutil.Bytes([]byte{0x04, 0x03, 0x02, 0x01})
|
||||
add("SignDataResponse - approve", "Response to SignDataRequest. This response needs to contain the `transaction`"+
|
||||
", because the UI is free to make modifications to the transaction.",
|
||||
&core.SignTxResponse{Password: "apassword", Approved: true,
|
||||
Transaction: core.SendTxArgs{
|
||||
Data: &data,
|
||||
Nonce: 0x4,
|
||||
Value: hexutil.Big(*big.NewInt(6)),
|
||||
From: common.NewMixedcaseAddress(a),
|
||||
To: nil,
|
||||
GasPrice: hexutil.Big(*big.NewInt(5)),
|
||||
Gas: 1000,
|
||||
Input: nil,
|
||||
}})
|
||||
add("SignDataResponse - deny", "Response to SignDataRequest. When denying a request, there's no need to "+
|
||||
"provide the transaction in return",
|
||||
&core.SignDataResponse{})
|
||||
}
|
||||
{ // WHen a signed tx is ready to go out
|
||||
desc := "SignTransactionResult is used in the call `clef` -> `OnApprovedTx(result)`" +
|
||||
"\n\n" +
|
||||
"This occurs _after_ successful completion of the entire signing procedure, but right before the signed " +
|
||||
"transaction is passed to the external caller. This method (and data) can be used by the UI to signal " +
|
||||
"to the user that the transaction was signed, but it is primarily useful for ruleset implementations." +
|
||||
"\n\n" +
|
||||
"A ruleset that implements a rate limitation needs to know what transactions are sent out to the external " +
|
||||
"interface. By hooking into this methods, the ruleset can maintain track of that count." +
|
||||
"\n\n" +
|
||||
"**OBS:** Note that if an attacker can restore your `clef` data to a previous point in time" +
|
||||
" (e.g through a backup), the attacker can reset such windows, even if he/she is unable to decrypt the content. " +
|
||||
"\n\n" +
|
||||
"The `OnApproved` method cannot be responded to, it's purely informative"
|
||||
|
||||
rlpdata := common.FromHex("0xf85d640101948a8eafb1cf62bfbeb1741769dae1a9dd47996192018026a0716bd90515acb1e68e5ac5867aa11a1e65399c3349d479f5fb698554ebc6f293a04e8a4ebfff434e971e0ef12c5bf3a881b06fd04fc3f8b8a7291fb67a26a1d4ed")
|
||||
var tx types.Transaction
|
||||
rlp.DecodeBytes(rlpdata, &tx)
|
||||
add("OnApproved - SignTransactionResult", desc, ðapi.SignTransactionResult{Raw: rlpdata, Tx: &tx})
|
||||
|
||||
}
|
||||
{ // User input
|
||||
add("UserInputRequest", "Sent when clef needs the user to provide data. If 'password' is true, the input field should be treated accordingly (echo-free)",
|
||||
&core.UserInputRequest{IsPassword: true, Title: "The title here", Prompt: "The question to ask the user"})
|
||||
add("UserInputResponse", "Response to SignDataRequest",
|
||||
&core.UserInputResponse{Text: "The textual response from user"})
|
||||
}
|
||||
{ // List request
|
||||
add("ListRequest", "Sent when a request has been made to list addresses. The UI is provided with the "+
|
||||
"full `account`s, including local directory names. Note: this information is not passed back to the external caller, "+
|
||||
"who only sees the `address`es. ",
|
||||
&core.ListRequest{
|
||||
Meta: meta,
|
||||
Accounts: []accounts.Account{
|
||||
{a, accounts.URL{Scheme: "keystore", Path: "/path/to/keyfile/a"}},
|
||||
{b, accounts.URL{Scheme: "keystore", Path: "/path/to/keyfile/b"}}},
|
||||
})
|
||||
|
||||
add("UserInputResponse", "Response to list request. The response contains a list of all addresses to show to the caller. "+
|
||||
"Note: the UI is free to respond with any address the caller, regardless of whether it exists or not",
|
||||
&core.ListResponse{
|
||||
Accounts: []accounts.Account{
|
||||
{common.HexToAddress("0xcowbeef000000cowbeef00000000000000000c0w"), accounts.URL{Path: ".. ignored .."}},
|
||||
{common.HexToAddress("0xffffffffffffffffffffffffffffffffffffffff"), accounts.URL{}},
|
||||
}})
|
||||
}
|
||||
|
||||
fmt.Println(`## UI Client interface
|
||||
|
||||
These data types are defined in the channel between clef and the UI`)
|
||||
for _, elem := range output {
|
||||
fmt.Println(elem)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
//Create Account
|
||||
|
||||
|
Reference in New Issue
Block a user