github.com/decred/politeia@v1.4.0/politeiawww/cmd/politeiaverify/comments.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 "strconv" 12 "strings" 13 14 cmv1 "github.com/decred/politeia/politeiawww/api/comments/v1" 15 "github.com/decred/politeia/politeiawww/client" 16 ) 17 18 // commentsBundle represents the comments bundle that is available for download 19 // in politeiagui. 20 type commentsBundle struct { 21 Comments []cmv1.Comment `json:"comments"` 22 ServerPublicKey string `json:"serverpublickey"` 23 } 24 25 // verifyCommentsBundle takes the filepath of a comments bundle and verifies 26 // the contents of the file. This includes verifying the signature and receipt 27 // of each comment in the bundle. If the comment has been deleted, the original 28 // comment signature will not exist but the deletion signature and receipt are 29 // verified instead. 30 func verifyCommentsBundle(fp string) error { 31 // Decode comments bundle 32 b, err := os.ReadFile(fp) 33 if err != nil { 34 return err 35 } 36 var cb commentsBundle 37 err = json.Unmarshal(b, &cb) 38 if err != nil { 39 return fmt.Errorf("could not unmarshal comments bundle: %v", err) 40 } 41 if len(cb.Comments) == 0 { 42 fmt.Printf("No comments found\n") 43 return nil 44 } 45 46 // Verify comment signatures and receipts 47 var ( 48 comments int 49 dels int 50 ) 51 for _, v := range cb.Comments { 52 err := client.CommentVerify(v, cb.ServerPublicKey) 53 if err != nil { 54 return err 55 } 56 if v.Deleted { 57 dels++ 58 continue 59 } 60 comments++ 61 } 62 63 fmt.Printf("Record token : %v\n", cb.Comments[0].Token) 64 fmt.Printf("Comments : %v\n", comments) 65 fmt.Printf("Deleted comments: %v\n", dels) 66 fmt.Printf("All signatures and receipts verified!\n") 67 68 return nil 69 } 70 71 // verifyCommentTimestamps takes the filepath of a comment timestamps file and 72 // verifies the validity of all timestamps included in the comments v1 73 // TimestampsReply. 74 func verifyCommentTimestamps(fp string) error { 75 // Decode timestamps reply 76 b, err := os.ReadFile(fp) 77 if err != nil { 78 return err 79 } 80 var tr cmv1.TimestampsReply 81 err = json.Unmarshal(b, &tr) 82 if err != nil { 83 return err 84 } 85 if len(tr.Comments) == 0 { 86 return fmt.Errorf("no comments found") 87 } 88 89 fmt.Printf("Total comments: %v\n", len(tr.Comments)) 90 91 // Verify timestamps 92 notTimestamped, err := client.CommentTimestampsVerify(tr) 93 if err != nil { 94 return err 95 } 96 97 // Print the IDs of the comments that have not been timestamped yet 98 if len(notTimestamped) > 0 { 99 // Write all comment IDs to a string 100 builder := strings.Builder{} 101 for i, cid := range notTimestamped { 102 s := strconv.FormatUint(uint64(cid), 10) 103 if i == len(notTimestamped)-1 { 104 // This is the last comment ID. Don't include a comma. 105 builder.WriteString(s) 106 break 107 } 108 builder.WriteString(fmt.Sprintf("%v, ", s)) 109 } 110 111 // Print results 112 fmt.Printf("Comments not yet timestamped: %v\n", builder.String()) 113 } 114 115 fmt.Printf("All timestamps verified!\n") 116 117 return nil 118 119 }