diff --git a/agent/storage/mongo.go b/agent/storage/mongo.go index 42c4004..671d800 100644 --- a/agent/storage/mongo.go +++ b/agent/storage/mongo.go @@ -58,7 +58,7 @@ func (ir *identifierRecord) decode() (*did.Identifier, *did.ProofLD, error) { return id, proof, nil } -func (ir *identifierRecord) load(id *did.Identifier, proof *did.ProofLD) { +func (ir *identifierRecord) encode(id *did.Identifier, proof *did.ProofLD) { data, _ := json.Marshal(id.Document(true)) pp, _ := json.Marshal(proof) ir.Method = id.Method() @@ -97,10 +97,7 @@ func (ms *MongoStore) Close() error { // Exists returns true if the provided DID instance is already available // in the store. func (ms *MongoStore) Exists(id *did.Identifier) bool { - filter := orm.Filter() - filter["method"] = id.Method() - filter["subject"] = id.Subject() - n, _ := ms.did.Count(filter) + n, _ := ms.did.Count(filter(id)) return n > 0 } @@ -121,28 +118,28 @@ func (ms *MongoStore) Get(req *protov1.QueryRequest) (*did.Identifier, *did.Proo // Save will create or update an entry for the provided DID instance. func (ms *MongoStore) Save(id *did.Identifier, proof *did.ProofLD) error { - // Filter - filter := orm.Filter() - filter["method"] = id.Method() - filter["subject"] = id.Subject() - // Record rec := new(identifierRecord) - rec.load(id, proof) + rec.encode(id, proof) // Run upsert operation - return ms.did.Update(filter, rec, true) + return ms.did.Update(filter(id), rec, true) } // Delete any existing record for the provided DID instance. func (ms *MongoStore) Delete(id *did.Identifier) error { - filter := orm.Filter() - filter["method"] = id.Method() - filter["subject"] = id.Subject() - return ms.did.Delete(filter) + return ms.did.Delete(filter(id)) } // Description returns a brief summary for the storage instance. func (ms *MongoStore) Description() string { return "MongoDB data store" } + +// Helper method to produce a selector from a DID instance. +func filter(id *did.Identifier) map[string]interface{} { + filter := orm.Filter() + filter["method"] = id.Method() + filter["subject"] = id.Subject() + return filter +} diff --git a/client/cli/cmd/sign.go b/client/cli/cmd/proof.go similarity index 50% rename from client/cli/cmd/sign.go rename to client/cli/cmd/proof.go index d5d809b..17b6d05 100644 --- a/client/cli/cmd/sign.go +++ b/client/cli/cmd/proof.go @@ -11,50 +11,58 @@ import ( "go.bryk.io/x/cli" ) -var signCmd = &cobra.Command{ - Use: "sign", - Short: "Produce a linked digital signature", - Example: "didctl sign [DID reference name] --input \"contents to sign\"", - RunE: runSignCmd, +var proofCmd = &cobra.Command{ + Use: "proof", + Short: "Produce a linked digital proof document", + Example: "didctl proof [DID reference name] --input \"contents to sign\"", + Aliases: []string{"sign"}, + RunE: runProofCmd, } func init() { params := []cli.Param{ { Name: "input", - Usage: "contents to sign, if longer than 32 bytes a SHA3-256 will be generated", - FlagKey: "sign.input", + Usage: "contents to sign", + FlagKey: "proof.input", ByDefault: "", Short: "i", }, { Name: "key", - Usage: "key to use to produce the signature", - FlagKey: "sign.key", + Usage: "key to use to produce the proof", + FlagKey: "proof.key", ByDefault: "master", Short: "k", }, { Name: "domain", - Usage: "domain value to use when producing LD signatures", - FlagKey: "sign.domain", + Usage: "domain value to use", + FlagKey: "proof.domain", ByDefault: didDomainValue, Short: "d", }, + { + Name: "purpose", + Usage: "specific intent for the proof", + FlagKey: "proof.purpose", + ByDefault: "authentication", + Short: "p", + }, } - if err := cli.SetupCommandParams(signCmd, params); err != nil { + if err := cli.SetupCommandParams(proofCmd, params); err != nil { panic(err) } - rootCmd.AddCommand(signCmd) + rootCmd.AddCommand(proofCmd) } -func runSignCmd(_ *cobra.Command, args []string) error { +func runProofCmd(_ *cobra.Command, args []string) error { if len(args) != 1 { return errors.New("you must specify a DID reference name") } // Get input, CLI takes precedence, from standard input otherwise - input := []byte(viper.GetString("sign.input")) + input := []byte(viper.GetString("proof.input")) if len(input) == 0 { input, _ = cli.ReadPipedInput(maxPipeInputSize) } @@ -76,19 +84,21 @@ func runSignCmd(_ *cobra.Command, args []string) error { } // Get key - key := id.Key(viper.GetString("sign.key")) + key := id.Key(viper.GetString("proof.key")) if key == nil { - return fmt.Errorf("selected key is not available on the DID: %s", viper.GetString("sign.key")) + return fmt.Errorf("selected key is not available on the DID: %s", viper.GetString("proof.key")) } - // Sign - sld, err := key.ProduceSignatureLD(input, viper.GetString("sign.domain")) + // Produce proof + purpose := viper.GetString("proof.purpose") + domain := viper.GetString("proof.domain") + pld, err := key.ProduceProof(input, purpose, domain) if err != nil { - return fmt.Errorf("failed to produce signature: %s", err) + return fmt.Errorf("failed to produce proof: %s", err) } - js, err := json.MarshalIndent(sld, "", " ") + js, err := json.MarshalIndent(pld, "", " ") if err != nil { - return fmt.Errorf("failed to produce signature: %s", err) + return fmt.Errorf("failed to produce proof: %s", err) } fmt.Printf("%s\n", js) return nil diff --git a/client/cli/cmd/verify.go b/client/cli/cmd/verify.go index 86b363d..34f130f 100644 --- a/client/cli/cmd/verify.go +++ b/client/cli/cmd/verify.go @@ -14,8 +14,8 @@ import ( var verifyCmd = &cobra.Command{ Use: "verify", - Short: "Check the validity of a SignatureLD document", - Example: "didctl verify [signature file] --input \"contents to verify\"", + Short: "Check the validity of a ProofLD document", + Example: "didctl verify [proof file] --input \"contents to verify\"", RunE: runVerifyCmd, } @@ -49,24 +49,25 @@ func runVerifyCmd(_ *cobra.Command, args []string) error { return errors.New("no input passed in to verify") } - // Load signature file - log.Info("verifying LD signature") + // Load proof file + log.Info("verifying proof document") log.Debug("load signature file") entry, err := ioutil.ReadFile(args[0]) if err != nil { return fmt.Errorf("failed to read the signature file: %s", err) } log.Debug("decoding contents") - sig := &did.SignatureLD{} - if err = json.Unmarshal(entry, sig); err != nil { + proof := &did.ProofLD{} + if err = json.Unmarshal(entry, proof); err != nil { return fmt.Errorf("invalid signature file: %s", err) } - // Validate signature creator - log.Debug("validating signature creator") - id, err := did.Parse(sig.Creator) + // Validate verification method + log.Debug("validating proof verification method") + vm := proof.VerificationMethod + id, err := did.Parse(vm) if err != nil { - return fmt.Errorf("invalid signature creator: %s", err) + return fmt.Errorf("invalid proof verification method: %s", err) } // Retrieve subject @@ -74,25 +75,36 @@ func runVerifyCmd(_ *cobra.Command, args []string) error { if err != nil { return err } - doc := &did.Document{} - if err := json.Unmarshal(jsDoc, doc); err != nil { - return err + + // Decode result obtained from resolve + doc := new(did.Document) + result := map[string]json.RawMessage{} + if err := json.Unmarshal([]byte(jsDoc), &result); err != nil { + return fmt.Errorf("invalid DID document received: %s", jsDoc) + } + if _, ok := result["document"]; !ok { + return fmt.Errorf("invalid DID document received: %s", jsDoc) } + if err := json.Unmarshal(result["document"], doc); err != nil { + return fmt.Errorf("invalid DID document received: %s", jsDoc) + } + + // Restore peer DID instance peer, err := did.FromDocument(doc) if err != nil { return err } // Get creator's key - ck := peer.Key(sig.Creator) + ck := peer.Key(vm) if ck == nil { - return fmt.Errorf("creator key is not available on the DID Document: %s", sig.Creator) + return fmt.Errorf("verification method is not available on the DID document: %s", vm) } // Verify signature - if !ck.VerifySignatureLD(input, sig) { - return errors.New("signature is invalid") + if !ck.VerifyProof(input, proof) { + return errors.New("proof is invalid") } - log.Info("signature is valid") + log.Info("proof is valid") return nil }