Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add debug command to sign DID document command #57

Merged
merged 4 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 142 additions & 7 deletions cmd/swisstronikd/cmd/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,24 @@ import (
"crypto/rand"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"os"
"strings"

"encoding/hex"
didutil "swisstronik/testutil/did"
"swisstronik/x/did/types"
didcli "swisstronik/x/did/client/cli"
didtypes "swisstronik/x/did/types"

"github.com/cometbft/cometbft/libs/bytes"
"github.com/cosmos/cosmos-sdk/client"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
"github.com/ethereum/go-ethereum/common"
"github.com/google/uuid"
"github.com/spf13/cobra"
"github.com/cometbft/cometbft/libs/bytes"
)

type DIDDocument struct {
Expand Down Expand Up @@ -55,6 +57,11 @@ type Service struct {
ServiceEndpoint []string `json:"serviceEndpoint"`
}

type KeyPair struct {
PrivateKeyBase64 string `json:"private_key_base_64"`
PublicKeyBase64 string `json:"public_key_base_64"`
}

// Cmd creates a CLI main command
func DebugCmd() *cobra.Command {
cmd := &cobra.Command{
Expand All @@ -68,6 +75,7 @@ func DebugCmd() *cobra.Command {
cmd.AddCommand(ExtractPubkeyCmd())
cmd.AddCommand(ConvertAddressCmd())
cmd.AddCommand(SampleDIDResource())
cmd.AddCommand(SignDIDDocument())

return cmd
}
Expand Down Expand Up @@ -180,6 +188,133 @@ func SampleDIDDocument() *cobra.Command {
return cmd
}

func ReadKeyPairFromFile(file string) (KeyPair, error) {
bytes, err := os.ReadFile(file)
if err != nil {
return KeyPair{}, err
}

keyPair := KeyPair{}
err = json.Unmarshal(bytes, &keyPair)
if err != nil {
return KeyPair{}, err
}

return keyPair, nil
}

func SignDIDDocument() *cobra.Command {
cmd := &cobra.Command{
Use: "sign-did-document [did.json] [key.json]",
Short: "Generates signed DID document ready to be stored in DID registry",
Long: "Generates signed self-controlled DID document from the payload and key information provided, which is ready to be stored in DID registry.",
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) != 2 {
return errors.New("invalid input parameters")
}

signInputs := make([]didcli.SignInput, 0)

// Decode did.json to have payload
payloadJSON, err := didcli.ReadPayloadFromFile(args[0])
if err != nil {
// Decode did.json to have payload & sign inputs
payloadJSON, signInputs, err = didcli.ReadPayloadWithSignInputsFromFile(args[0])
}

if err != nil {
return errors.New("invalid payload")
}

// Decode key.json to have private and public key pair
keyPairFromFile, err := ReadKeyPairFromFile(args[1])
if err != nil {
return err
}

// Decode base64 based private key string to have byte[]
privateKeyBytesFromFile, err := base64.StdEncoding.DecodeString(keyPairFromFile.PrivateKeyBase64)
if err != nil {
return err
}

// Encode ed25519 based private key
privateKeyFromFile := ed25519.PrivateKey(privateKeyBytesFromFile)
// Encode ed25519 based public key
publicKeyFromFile := privateKeyFromFile.Public().(ed25519.PublicKey)
// Multibase public key
publicKeyMultibaseFromFile := didutil.GenerateEd25519VerificationKey2020VerificationMaterial(publicKeyFromFile)

// Unmarshal spec-compliant payload
var specPayload didcli.DIDDocument
err = json.Unmarshal([]byte(payloadJSON), &specPayload)
if err != nil {
return err
}

if len(specPayload.VerificationMethod) < 1 {
return errors.New("publicKeyMultibase is not specified")
}

validKey := false
keyId := ""
for _, v := range specPayload.VerificationMethod {
// Check if public key is addressed in verfication method
_, ok := v["publicKeyMultibase"]
if !ok {
continue
}

_, ok = v["id"]
if !ok {
continue
}

// Get multibase public key address
publicKeyMultibase := v["publicKeyMultibase"].(string)

// if there is matching verification method,
if publicKeyMultibase == publicKeyMultibaseFromFile {
keyId = v["id"].(string)
validKey = true
break
}
}

// if there is no matching verification method
if !validKey {
return errors.New("invalid key information")
}

// Construct sign inputs
if len(signInputs) < 1 {
signInputs = append(signInputs, didcli.SignInput{
VerificationMethodID: keyId,
PrivKey: privateKeyFromFile,
})
}

// Construct payload with sign inputs
result := didcli.PayloadWithSignInputs{
Payload: payloadJSON,
SignInputs: signInputs,
}

// Encode the structured result
encodedResult, err := json.Marshal(result)
if err != nil {
return err
}

// Print output.
_, err = fmt.Fprintln(cmd.OutOrStdout(), string(encodedResult))
return err
},
}

return cmd
}

func SampleDIDResource() *cobra.Command {
cmd := &cobra.Command{
Use: "sample-did-resource [existing-did] [base64-encoded-ed25519-private-key]",
Expand Down Expand Up @@ -210,7 +345,7 @@ func SampleDIDResource() *cobra.Command {
if !didtypes.IsValidDID(did, didtypes.DIDMethod) {
return fmt.Errorf("provided DID is invalid")
}

// Derive collection id from provided DID
_, collectionId, err := didtypes.TrySplitDID(did)
if err != nil {
Expand All @@ -220,12 +355,12 @@ func SampleDIDResource() *cobra.Command {
resource := didtypes.MsgCreateResourcePayload{
CollectionId: collectionId,
Id: uuid.NewString(),
Name: "sample-resource",
Version: "sample-version",
Name: "sample-resource",
Version: "sample-version",
ResourceType: "SampleResourceType",
AlsoKnownAs: []*types.AlternativeUri{
AlsoKnownAs: []*didtypes.AlternativeUri{
{
Uri: "http://example.com/example-did",
Uri: "http://example.com/example-did",
Description: "http-uri",
},
},
Expand Down
31 changes: 25 additions & 6 deletions x/did/client/cli/tx.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package cli

import (
"fmt"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"crypto/ed25519"
"encoding/json"
"fmt"
"os"


"github.com/cosmos/cosmos-sdk/client"
"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"

"swisstronik/x/did/types"
)

Expand Down Expand Up @@ -61,6 +62,10 @@ type Service struct {
ServiceEndpoint []string `json:"serviceEndpoint"`
}

type Payload struct {
Payload json.RawMessage
}

type PayloadWithSignInputs struct {
Payload json.RawMessage
SignInputs []SignInput
Expand Down Expand Up @@ -119,6 +124,21 @@ func AccAddrByKeyRef(keyring keyring.Keyring, keyRef string) (sdk.AccAddress, er
return sdk.AccAddressFromBech32(keyRef)
}

func ReadPayloadFromFile(filePath string) (json.RawMessage, error) {
bytes, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}

payload := &Payload{}
err = json.Unmarshal(bytes, payload)
if err != nil {
return nil, err
}

return payload.Payload, nil
}

func ReadPayloadWithSignInputsFromFile(filePath string) (json.RawMessage, []SignInput, error) {
bytes, err := os.ReadFile(filePath)
if err != nil {
Expand Down Expand Up @@ -202,4 +222,3 @@ func GetFromSpecCompliantPayload(specPayload DIDDocument) ([]*types.Verification

return verificationMethod, service, nil
}