Skip to content

Commit

Permalink
comments: Update signature and settings.
Browse files Browse the repository at this point in the history
This diff adds `ExtraData` & `ExtraDataHint` fields to the `Signature`
field in both `New` & `Edit` comments plugin commands.

Also, this updates the `Signature` validation and adds a new
comments plugin setting `allowExtraData` with a new validation to ensure
no extra data is provided while the setting is switched off.
  • Loading branch information
amass01 committed Aug 17, 2021
1 parent b909d7c commit 5bc5b00
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 20 deletions.
29 changes: 27 additions & 2 deletions politeiad/backendv2/tstorebe/plugins/comments/cmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,9 +441,16 @@ func (p *commentsPlugin) cmdNew(token []byte, payload string) (string, error) {
return "", err
}

// Ensure no extra data provided if not allowed
err = p.verifyExtraData(n.ExtraData, n.ExtraDataHint)
if err != nil {
return "", err
}

// Verify signature
msg := strconv.FormatUint(uint64(n.State), 10) + n.Token +
strconv.FormatUint(uint64(n.ParentID), 10) + n.Comment
strconv.FormatUint(uint64(n.ParentID), 10) + n.Comment +
n.ExtraData + n.ExtraDataHint
err = util.VerifySignature(n.Signature, n.PublicKey, msg)
if err != nil {
return "", convertSignatureError(err)
Expand Down Expand Up @@ -560,9 +567,16 @@ func (p *commentsPlugin) cmdEdit(token []byte, payload string) (string, error) {
return "", err
}

// Ensure no extra data provided if not allowed
err = p.verifyExtraData(e.ExtraData, e.ExtraDataHint)
if err != nil {
return "", err
}

// Verify signature
msg := strconv.FormatUint(uint64(e.State), 10) + e.Token +
strconv.FormatUint(uint64(e.ParentID), 10) + e.Comment
strconv.FormatUint(uint64(e.ParentID), 10) + e.Comment +
e.ExtraData + e.ExtraDataHint
err = util.VerifySignature(e.Signature, e.PublicKey, msg)
if err != nil {
return "", convertSignatureError(err)
Expand Down Expand Up @@ -687,6 +701,17 @@ func (p *commentsPlugin) cmdEdit(token []byte, payload string) (string, error) {
return string(reply), nil
}

// verifyExtraData ensures no extra data provided if it's not allowed.
func (p *commentsPlugin) verifyExtraData(extraData, extraDataHint string) error {
if !p.allowExtraData && (extraData != "" || extraDataHint != "") {
return backend.PluginError{
PluginID: comments.PluginID,
ErrorCode: uint32(comments.ErrorCodeExtraDataNotAllowed),
}
}
return nil
}

// cmdDel deletes a comment.
func (p *commentsPlugin) cmdDel(token []byte, payload string) (string, error) {
// Decode payload
Expand Down
18 changes: 14 additions & 4 deletions politeiad/backendv2/tstorebe/plugins/comments/comments.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
package comments

import (
"fmt"
"os"
"path/filepath"
"strconv"
Expand All @@ -15,6 +14,7 @@ import (
backend "github.com/decred/politeia/politeiad/backendv2"
"github.com/decred/politeia/politeiad/backendv2/tstorebe/plugins"
"github.com/decred/politeia/politeiad/plugins/comments"
"github.com/pkg/errors"
)

var (
Expand Down Expand Up @@ -42,6 +42,7 @@ type commentsPlugin struct {
// Plugin settings
commentLengthMax uint32
voteChangesMax uint32
allowExtraData bool
}

// Setup performs any plugin setup that is required.
Expand Down Expand Up @@ -137,6 +138,7 @@ func New(tstore plugins.TstoreClient, settings []backend.PluginSetting, dataDir
var (
commentLengthMax = comments.SettingCommentLengthMax
voteChangesMax = comments.SettingVoteChangesMax
allowExtraData = comments.SettingAllowExtraData
)

// Override defaults with any passed in settings
Expand All @@ -145,19 +147,26 @@ func New(tstore plugins.TstoreClient, settings []backend.PluginSetting, dataDir
case comments.SettingKeyCommentLengthMax:
u, err := strconv.ParseUint(v.Value, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid plugin setting %v '%v': %v",
return nil, errors.Errorf("invalid plugin setting %v '%v': %v",
v.Key, v.Value, err)
}
commentLengthMax = uint32(u)
case comments.SettingKeyVoteChangesMax:
u, err := strconv.ParseUint(v.Value, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid plugin setting %v '%v': %v",
return nil, errors.Errorf("invalid plugin setting %v '%v': %v",
v.Key, v.Value, err)
}
voteChangesMax = uint32(u)
case comments.SettingKeyAllowExtraData:
b, err := strconv.ParseBool(v.Value)
if err != nil {
return nil, errors.Errorf("invalid plugin setting %v '%v': %v",
v.Key, v.Value, err)
}
allowExtraData = b
default:
return nil, fmt.Errorf("invalid comments plugin setting '%v'", v.Key)
return nil, errors.Errorf("invalid comments plugin setting '%v'", v.Key)
}
}

Expand All @@ -167,5 +176,6 @@ func New(tstore plugins.TstoreClient, settings []backend.PluginSetting, dataDir
dataDir: dataDir,
commentLengthMax: commentLengthMax,
voteChangesMax: voteChangesMax,
allowExtraData: allowExtraData,
}, nil
}
87 changes: 78 additions & 9 deletions politeiad/plugins/comments/comments.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ const (
// SettingKeyVoteChangesMax is the plugin setting key for the
// SettingVoteChangesMax plugin setting.
SettingKeyVoteChangesMax = "votechangesmax"

// SettingKeyAllowExtraData is the plugin setting key for the
// SettingAllowExtraData plugin setting.
SettingKeyAllowExtraData = "allowextradata"
)

// Plugin setting default values. These can be overridden by providing a plugin
Expand All @@ -47,6 +51,10 @@ const (
// user can change their vote on a comment. This prevents a
// malicious user from being able to spam comment votes.
SettingVoteChangesMax uint32 = 5

// SettingAllowExtraData is the default value of the bool flag which
// determines whether posting extra data along with the comment is allowed.
SettingAllowExtraData = false
)

// ErrorCodeT represents a error that was caused by the user.
Expand Down Expand Up @@ -99,8 +107,12 @@ const (
// does not match the record state.
ErrorCodeRecordStateInvalid ErrorCodeT = 11

// ErrorCodeExtraDataNotAllowed is returned when comment extra data
// is found while comment plugin setting does not allow it.
ErrorCodeExtraDataNotAllowed = 12

// ErrorCodeLast unit test only.
ErrorCodeLast ErrorCodeT = 12
ErrorCodeLast ErrorCodeT = 13
)

var (
Expand All @@ -118,6 +130,7 @@ var (
ErrorCodeVoteInvalid: "vote invalid",
ErrorCodeVoteChangesMaxExceeded: "vote changes max exceeded",
ErrorCodeRecordStateInvalid: "record state invalid",
ErrorCodeExtraDataNotAllowed: "comment extra data not allowed",
}
)

Expand Down Expand Up @@ -151,7 +164,15 @@ const (
// the deleted comment. Everything else from the original comment is
// permanently deleted.
//
// Signature is the client signature of State+Token+ParentID+Comment.
// PublicKey is the user's public key that is used to verify the signature.
//
// Signature is the user signature of the:
// State + Token + ParentID + Comment + ExtraData + ExtraDataHint
//
// Receipt is the server signature of the user signature.
//
// The PublicKey, Signature, and Receipt are all hex encoded and use the
// ed25519 signature scheme.
type Comment struct {
UserID string `json:"userid"` // Unique user ID
State RecordStateT `json:"state"` // Record state
Expand All @@ -178,7 +199,15 @@ type Comment struct {
// CommentAdd is the structure that is saved to disk when a comment is created
// or edited.
//
// Signature is the client signature of State+Token+ParentID+Comment.
// PublicKey is the user's public key that is used to verify the signature.
//
// Signature is the user signature of the:
// State + Token + ParentID + Comment + ExtraData + ExtraDataHint
//
// Receipt is the server signature of the user signature.
//
// The PublicKey, Signature, and Receipt are all hex encoded and use the
// ed25519 signature scheme.
type CommentAdd struct {
// Data generated by client
UserID string `json:"userid"` // Unique user ID
Expand Down Expand Up @@ -206,7 +235,13 @@ type CommentAdd struct {
// additional fields to properly display the deleted comment in the comment
// hierarchy.
//
// Signature is the client signature of the State+Token+CommentID+Reason
// PublicKey is the user's public key that is used to verify the signature.
//
// Signature is the user signature of the:
// State + Token + CommentID + Reason
//
// The PublicKey and Signature are hex encoded and use the
// ed25519 signature scheme.
type CommentDel struct {
// Data generated by client
Token string `json:"token"` // Record token
Expand Down Expand Up @@ -240,7 +275,13 @@ const (
// CommentVote is the structure that is saved to disk when a comment is voted
// on.
//
// Signature is the client signature of the State+Token+CommentID+Vote.
// PublicKey is the user's public key that is used to verify the signature.
//
// Signature is the user signature of the:
// State + Token + CommentID + Vote
//
// The PublicKey and Signature are hex encoded and use the
// ed25519 signature scheme.
type CommentVote struct {
// Data generated by client
UserID string `json:"userid"` // Unique user ID
Expand All @@ -261,7 +302,15 @@ type CommentVote struct {
// The parent ID is used to reply to an existing comment. A parent ID of 0
// indicates that the comment is a base level comment and not a reply commment.
//
// Signature is the client signature of State+Token+ParentID+Comment.
// PublicKey is the user's public key that is used to verify the signature.
//
// Signature is the user signature of the:
// State + Token + ParentID + Comment + ExtraData + ExtraDataHint
//
// Receipt is the server signature of the user signature.
//
// The PublicKey, Signature, and Receipt are all hex encoded and use the
// ed25519 signature scheme.
type New struct {
UserID string `json:"userid"` // Unique user ID
State RecordStateT `json:"state"` // Record state
Expand All @@ -283,7 +332,15 @@ type NewReply struct {

// Edit edits an existing comment.
//
// Signature is the client signature of State+Token+ParentID+Comment.
// PublicKey is the user's public key that is used to verify the signature.
//
// Signature is the user signature of the:
// State + Token + ParentID + Comment + ExtraData + ExtraDataHint
//
// Receipt is the server signature of the user signature.
//
// The PublicKey, Signature, and Receipt are all hex encoded and use the
// ed25519 signature scheme.
type Edit struct {
UserID string `json:"userid"` // Unique user ID
State RecordStateT `json:"state"` // Record state
Expand All @@ -306,7 +363,13 @@ type EditReply struct {

// Del permanently deletes all versions of the provided comment.
//
// Signature is the client signature of the State+Token+CommentID+Reason
// PublicKey is the user's public key that is used to verify the signature.
//
// Signature is the user signature of the:
// State + Token + CommentID + Reason
//
// The PublicKey and Signature are hex encoded and use the
// ed25519 signature scheme.
type Del struct {
State RecordStateT `json:"state"` // Record state
Token string `json:"token"` // Record token
Expand All @@ -329,7 +392,13 @@ type DelReply struct {
// original upvote. The public key cannot be relied on to remain the same for
// each user so a user ID must be included.
//
// Signature is the client signature of the State+Token+CommentID+Vote.
// PublicKey is the user's public key that is used to verify the signature.
//
// Signature is the user signature of the:
// State + Token + CommentID + Vote
//
// The PublicKey and Signature are hex encoded and use the
// ed25519 signature scheme.
type Vote struct {
UserID string `json:"userid"` // Unique user ID
State RecordStateT `json:"state"` // Record state
Expand Down
42 changes: 37 additions & 5 deletions politeiawww/api/comments/v1/v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,15 @@ const (
// information for the deleted comment. Everything else from the original
// comment is permanently deleted.
//
// Signature is the client signature of State+Token+ParentID+Comment.
// PublicKey is the user's public key that is used to verify the signature.
//
// Signature is the user signature of the:
// State + Token + ParentID + Comment + ExtraData + ExtraDataHint
//
// Receipt is the server signature of the user signature.
//
// The PublicKey, Signature, and Receipt are all hex encoded and use the
// ed25519 signature scheme.
type Comment struct {
UserID string `json:"userid"` // Unique user ID
Username string `json:"username"` // Username
Expand All @@ -167,7 +175,13 @@ type Comment struct {

// CommentVote represents a comment vote (upvote/downvote).
//
// Signature is the client signature of the State+Token+CommentID+Vote.
// PublicKey is the user's public key that is used to verify the signature.
//
// Signature is the user signature of the:
// State + Token + CommentID + Vote
//
// The PublicKey and Signature are hex encoded and use the
// ed25519 signature scheme.
type CommentVote struct {
UserID string `json:"userid"` // Unique user ID
Username string `json:"username"` // Username
Expand All @@ -186,7 +200,13 @@ type CommentVote struct {
// The parent ID is used to reply to an existing comment. A parent ID of 0
// indicates that the comment is a base level comment and not a reply commment.
//
// Signature is the client signature of State+Token+ParentID+Comment.
// PublicKey is the user's public key that is used to verify the signature.
//
// Signature is the user signature of the:
// State + Token + ParentID + Comment + ExtraData + ExtraDataHint
//
// The PublicKey and Signature are hex encoded and use the
// ed25519 signature scheme.
type New struct {
State RecordStateT `json:"state"`
Token string `json:"token"`
Expand Down Expand Up @@ -227,7 +247,13 @@ const (
// upvoted, the resulting vote score is 0 due to the second upvote removing the
// original upvote.
//
// Signature is the client signature of the State+Token+CommentID+Vote.
// PublicKey is the user's public key that is used to verify the signature.
//
// Signature is the user signature of the:
// State + Token + CommentID + Vote
//
// The PublicKey and Signature are hex encoded and use the
// ed25519 signature scheme.
type Vote struct {
State RecordStateT `json:"state"`
Token string `json:"token"`
Expand All @@ -248,7 +274,13 @@ type VoteReply struct {
// Del permanently deletes the provided comment. Only admins can delete
// comments. A reason must be given for the deletion.
//
// Signature is the client signature of the State+Token+CommentID+Reason
// PublicKey is the user's public key that is used to verify the signature.
//
// Signature is the user signature of the:
// State + Token + CommentID + Reason
//
// The PublicKey and Signature are hex encoded and use the
// ed25519 signature scheme.
type Del struct {
State RecordStateT `json:"state"`
Token string `json:"token"`
Expand Down

0 comments on commit 5bc5b00

Please sign in to comment.