github.com/decred/politeia@v1.4.0/politeiawww/cmd/politeiaverify/record.go (about) 1 // Copyright (c) 2020-2021 The Decred developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "encoding/json" 9 "fmt" 10 "os" 11 12 "github.com/decred/politeia/politeiad/backend" 13 rcv1 "github.com/decred/politeia/politeiawww/api/records/v1" 14 "github.com/decred/politeia/politeiawww/client" 15 ) 16 17 // recordBundle represents the record bundle that is available for download 18 // in politeiagui. 19 type recordBundle struct { 20 Record rcv1.Record `json:"record"` 21 ServerPublicKey string `json:"serverpublickey"` 22 } 23 24 // verifyRecordBundle takes the file path of a record bundle file and verifies 25 // that the record bundle has been accepted by politeia and that all user 26 // signatures are correct. 27 func verifyRecordBundle(fp string) error { 28 // Decode record bundle 29 b, err := os.ReadFile(fp) 30 if err != nil { 31 return err 32 } 33 var rb recordBundle 34 err = json.Unmarshal(b, &rb) 35 if err != nil { 36 return fmt.Errorf("could not unmarshal record bundle: %v", err) 37 } 38 39 // Verify censorship record 40 fmt.Printf("Server public key: %v\n", rb.ServerPublicKey) 41 fmt.Printf("Censorship record\n") 42 fmt.Printf(" Token : %v\n", rb.Record.CensorshipRecord.Token) 43 fmt.Printf(" Merkle root: %v\n", rb.Record.CensorshipRecord.Merkle) 44 fmt.Printf(" Signature : %v\n", rb.Record.CensorshipRecord.Signature) 45 46 err = client.RecordVerify(rb.Record, rb.ServerPublicKey) 47 if err != nil { 48 return fmt.Errorf("could not verify record: %v", err) 49 } 50 51 fmt.Printf("Censorship record verified!\n") 52 fmt.Printf("\n") 53 54 // Verify user metadata 55 um, err := client.UserMetadataDecode(rb.Record.Metadata) 56 if err != nil { 57 return err 58 } 59 60 fmt.Printf("Author metadata\n") 61 fmt.Printf(" ID : %v\n", um.UserID) 62 fmt.Printf(" Public key: %v\n", um.PublicKey) 63 fmt.Printf(" Signature : %v\n", um.Signature) 64 65 err = client.UserMetadataVerify(*um, rb.Record.CensorshipRecord.Merkle) 66 if err != nil { 67 return err 68 } 69 70 fmt.Printf("Author signature verified!\n") 71 fmt.Printf("\n") 72 73 // Verify status change signatures 74 schanges, err := client.StatusChangesDecode(rb.Record.Metadata) 75 if err != nil { 76 return err 77 } 78 if len(schanges) == 0 { 79 // No status changes have occurred. We're done. 80 return nil 81 } 82 83 for _, v := range schanges { 84 fmt.Printf("Status change: %v\n", rcv1.RecordStatuses[v.Status]) 85 if v.Reason != "" { 86 fmt.Printf(" Reason : %v\n", v.Reason) 87 } 88 fmt.Printf(" Public key : %v\n", v.PublicKey) 89 fmt.Printf(" Signature : %v\n", v.Signature) 90 } 91 92 err = client.StatusChangesVerify(schanges) 93 if err != nil { 94 return err 95 } 96 97 fmt.Printf("Status change signatures verified!\n") 98 99 return nil 100 } 101 102 // verifyRecordTimestamps takes the filepath of record timestamps and verifies 103 // the validity of all timestamps included in the records v1 TimestampsReply. 104 func verifyRecordTimestamps(fp string) error { 105 // Decode timestamps reply 106 b, err := os.ReadFile(fp) 107 if err != nil { 108 return err 109 } 110 var tr rcv1.TimestampsReply 111 err = json.Unmarshal(b, &tr) 112 if err != nil { 113 return fmt.Errorf("could not unmarshal record timestamps: %v", err) 114 } 115 if tr.RecordMetadata.TxID == "" { 116 return fmt.Errorf("data not anchored yet") 117 } 118 119 // Pull the token out of the record metadata 120 var rm backend.RecordMetadata 121 err = json.Unmarshal([]byte(tr.RecordMetadata.Data), &rm) 122 if err != nil { 123 return fmt.Errorf("could not unmarshal record metadata: %v", err) 124 } 125 126 fmt.Printf("Token : %v\n", rm.Token) 127 fmt.Printf("Merkle root: %v\n", tr.RecordMetadata.MerkleRoot) 128 fmt.Printf("DCR tx : %v\n", tr.RecordMetadata.TxID) 129 fmt.Printf("Record contents\n") 130 fmt.Printf(" Metadata\n") 131 for mdID, streams := range tr.Metadata { 132 for streamID := range streams { 133 fmt.Printf(" %v %v\n", mdID, streamID) 134 } 135 } 136 fmt.Printf(" Files\n") 137 for fn := range tr.Files { 138 fmt.Printf(" %v\n", fn) 139 } 140 141 // Verify timestamps 142 err = client.RecordTimestampsVerify(tr) 143 if err != nil { 144 return err 145 } 146 147 fmt.Printf("Record timestamps verified!\n") 148 fmt.Printf("The merkle root can be found in the OP_RETURN of the DCR tx.\n") 149 150 return nil 151 }