Skip to content

Commit

Permalink
feat: wallet command controllers for issue, prove, verify, derive
Browse files Browse the repository at this point in the history
- Part of hyperledger-archives#2770

Signed-off-by: sudesh.shetty <sudesh.shetty@securekey.com>
  • Loading branch information
sudeshrshetty committed May 3, 2021
1 parent 1609f80 commit b914977
Show file tree
Hide file tree
Showing 3 changed files with 860 additions and 66 deletions.
202 changes: 202 additions & 0 deletions pkg/controller/command/vcwallet/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package vcwallet

import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
Expand Down Expand Up @@ -58,6 +59,18 @@ const (

// QueryWalletErrorCode for errors while querying credentials contents from wallet.
QueryWalletErrorCode

// IssueFromWalletErrorCode for errors while issuing a credential from wallet.
IssueFromWalletErrorCode

// ProveFromWalletErrorCode for errors while producing a presentation from wallet.
ProveFromWalletErrorCode

// VerifyFromWalletErrorCode for errors while verifying a presentation or credential from wallet.
VerifyFromWalletErrorCode

// DeriveFromWalletErrorCode for errors while deriving a credential from wallet.
DeriveFromWalletErrorCode
)

// All command operations.
Expand All @@ -74,13 +87,19 @@ const (
GetMethod = "Get"
GetAllMethod = "GetAll"
QueryMethod = "Query"
IssueMethod = "Issue"
ProveMethod = "Prove"
VerifyMethod = "Verify"
DeriveMethod = "Derive"
)

// miscellaneous constants for the vc wallet command controller.
const (
// log constants.
logSuccess = "success"
logUserIDKey = "userID"

emptyRawLength = 4
)

// provider contains dependencies for the verifiable credential wallet command controller
Expand Down Expand Up @@ -114,6 +133,10 @@ func (o *Command) GetHandlers() []command.Handler {
cmdutil.NewCommandHandler(CommandName, GetMethod, o.Get),
cmdutil.NewCommandHandler(CommandName, GetAllMethod, o.GetAll),
cmdutil.NewCommandHandler(CommandName, QueryMethod, o.Query),
cmdutil.NewCommandHandler(CommandName, IssueMethod, o.Issue),
cmdutil.NewCommandHandler(CommandName, ProveMethod, o.Prove),
cmdutil.NewCommandHandler(CommandName, VerifyMethod, o.Verify),
cmdutil.NewCommandHandler(CommandName, DeriveMethod, o.Derive),
}
}

Expand Down Expand Up @@ -400,6 +423,146 @@ func (o *Command) Query(rw io.Writer, req io.Reader) command.Error {
return nil
}

// Issue adds proof to a Verifiable Credential from wallet.
func (o *Command) Issue(rw io.Writer, req io.Reader) command.Error {
request := &IssueRequest{}

err := json.NewDecoder(req).Decode(&request)
if err != nil {
logutil.LogInfo(logger, CommandName, IssueMethod, err.Error())

return command.NewValidationError(InvalidRequestErrorCode, err)
}

vcWallet, err := wallet.New(request.UserID, o.ctx)
if err != nil {
logutil.LogInfo(logger, CommandName, IssueMethod, err.Error())

return command.NewExecuteError(IssueFromWalletErrorCode, err)
}

credential, err := vcWallet.Issue(request.Auth, request.Credential, request.ProofOptions)
if err != nil {
logutil.LogInfo(logger, CommandName, IssueMethod, err.Error())

return command.NewExecuteError(IssueFromWalletErrorCode, err)
}

command.WriteNillableResponse(rw, &IssueResponse{Credential: credential}, logger)

logutil.LogDebug(logger, CommandName, IssueMethod, logSuccess,
logutil.CreateKeyValueString(logUserIDKey, request.UserID))

return nil
}

// Prove produces a Verifiable Presentation from wallet.
func (o *Command) Prove(rw io.Writer, req io.Reader) command.Error {
request := &ProveRequest{}

err := json.NewDecoder(req).Decode(&request)
if err != nil {
logutil.LogInfo(logger, CommandName, ProveMethod, err.Error())

return command.NewValidationError(InvalidRequestErrorCode, err)
}

vcWallet, err := wallet.New(request.UserID, o.ctx)
if err != nil {
logutil.LogInfo(logger, CommandName, ProveMethod, err.Error())

return command.NewExecuteError(ProveFromWalletErrorCode, err)
}

vp, err := vcWallet.Prove(request.Auth, request.ProofOptions, prepareProveOptions(request)...)
if err != nil {
logutil.LogInfo(logger, CommandName, ProveMethod, err.Error())

return command.NewExecuteError(ProveFromWalletErrorCode, err)
}

command.WriteNillableResponse(rw, &ProveResponse{Presentation: vp}, logger)

logutil.LogDebug(logger, CommandName, ProveMethod, logSuccess,
logutil.CreateKeyValueString(logUserIDKey, request.UserID))

return nil
}

// Verify verifies credential/presentation from wallet.
func (o *Command) Verify(rw io.Writer, req io.Reader) command.Error {
request := &VerifyRequest{}

err := json.NewDecoder(req).Decode(&request)
if err != nil {
logutil.LogInfo(logger, CommandName, VerifyMethod, err.Error())

return command.NewValidationError(InvalidRequestErrorCode, err)
}

vcWallet, err := wallet.New(request.UserID, o.ctx)
if err != nil {
logutil.LogInfo(logger, CommandName, VerifyMethod, err.Error())

return command.NewExecuteError(VerifyFromWalletErrorCode, err)
}

option, err := prepareVerifyOption(request)
if err != nil {
logutil.LogInfo(logger, CommandName, VerifyMethod, err.Error())

return command.NewValidationError(InvalidRequestErrorCode, err)
}

verified, err := vcWallet.Verify(request.Auth, option)

response := &VerifyResponse{Verified: verified}

if err != nil {
response.Error = err.Error()
}

command.WriteNillableResponse(rw, response, logger)

logutil.LogDebug(logger, CommandName, VerifyMethod, logSuccess,
logutil.CreateKeyValueString(logUserIDKey, request.UserID))

return nil
}

// Derive derives a credential from wallet.
func (o *Command) Derive(rw io.Writer, req io.Reader) command.Error {
request := &DeriveRequest{}

err := json.NewDecoder(req).Decode(&request)
if err != nil {
logutil.LogInfo(logger, CommandName, DeriveMethod, err.Error())

return command.NewValidationError(InvalidRequestErrorCode, err)
}

vcWallet, err := wallet.New(request.UserID, o.ctx)
if err != nil {
logutil.LogInfo(logger, CommandName, DeriveMethod, err.Error())

return command.NewExecuteError(DeriveFromWalletErrorCode, err)
}

derived, err := vcWallet.Derive(request.Auth, prepareDeriveOption(request), request.DeriveOptions)
if err != nil {
logutil.LogInfo(logger, CommandName, DeriveMethod, err.Error())

return command.NewExecuteError(DeriveFromWalletErrorCode, err)
}

command.WriteNillableResponse(rw, &DeriveResponse{Credential: derived}, logger)

logutil.LogDebug(logger, CommandName, DeriveMethod, logSuccess,
logutil.CreateKeyValueString(logUserIDKey, request.UserID))

return nil
}

// prepareProfileOptions prepares options for creating wallet profile.
func prepareProfileOptions(rqst *CreateOrUpdateProfileRequest) []wallet.ProfileOptions {
var options []wallet.ProfileOptions
Expand Down Expand Up @@ -450,3 +613,42 @@ func prepareUnlockOptions(rqst *UnlockWalletRquest) []wallet.UnlockOptions {
// TODO web kms sign header function for zcap support #2433
return options
}

func prepareProveOptions(rqst *ProveRequest) []wallet.ProveOptions {
var options []wallet.ProveOptions

if len(rqst.StoredCredentials) > 0 {
options = append(options, wallet.WithStoredCredentialsToPresent(rqst.StoredCredentials...))
}

if len(rqst.RawCredentials) > 0 {
options = append(options, wallet.WithRawCredentialsToPresent(rqst.RawCredentials...))
}

// TODO option to pass raw presentation #2433
return options
}

func prepareVerifyOption(rqst *VerifyRequest) (wallet.VerificationOption, error) {
if len(rqst.StoredCredentialID) > 0 {
return wallet.WithStoredCredentialToVerify(rqst.StoredCredentialID), nil
}

if len(rqst.RawCredential) > emptyRawLength {
return wallet.WithRawCredentialToVerify(rqst.RawCredential), nil
}

if len(rqst.Presentation) > emptyRawLength {
return wallet.WithRawPresentationToVerify(rqst.Presentation), nil
}

return nil, errors.New("invalid option")
}

func prepareDeriveOption(rqst *DeriveRequest) wallet.CredentialToDerive {
if len(rqst.StoredCredentialID) > 0 {
return wallet.FromStoredCredential(rqst.StoredCredentialID)
}

return wallet.FromRawCredential(rqst.RawCredential)
}
Loading

0 comments on commit b914977

Please sign in to comment.