github.com/decred/politeia@v1.4.0/politeiawww/api/www/v1/v1.go (about)

     1  // Copyright (c) 2017-2020 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 v1
     6  
     7  import (
     8  	"fmt"
     9  
    10  	"github.com/decred/politeia/politeiad/backend/gitbe/decredplugin"
    11  )
    12  
    13  type ErrorStatusT int
    14  type PropStateT int
    15  type PropStatusT int
    16  type PropVoteStatusT int
    17  type UserManageActionT int
    18  type EmailNotificationT int
    19  type VoteT int
    20  type TOTPMethodT int
    21  
    22  const (
    23  	PoliteiaWWWAPIVersion = 1 // API version this backend understands
    24  
    25  	CsrfToken = "X-CSRF-Token"    // CSRF token for replies
    26  	Forward   = "X-Forwarded-For" // Proxy header
    27  
    28  	RouteVersion                  = "/version"
    29  	RoutePolicy                   = "/policy"
    30  	RouteSecret                   = "/secret"
    31  	RouteLogin                    = "/login"
    32  	RouteLogout                   = "/logout"
    33  	RouteUserMe                   = "/user/me"
    34  	RouteNewUser                  = "/user/new"
    35  	RouteResendVerification       = "/user/new/resend"
    36  	RouteVerifyNewUser            = "/user/verify"
    37  	RouteEditUser                 = "/user/edit"
    38  	RouteUpdateUserKey            = "/user/key"
    39  	RouteVerifyUpdateUserKey      = "/user/key/verify"
    40  	RouteChangeUsername           = "/user/username/change"
    41  	RouteChangePassword           = "/user/password/change"
    42  	RouteResetPassword            = "/user/password/reset"
    43  	RouteVerifyResetPassword      = "/user/password/reset/verify"
    44  	RouteUserRegistrationPayment  = "/user/payments/registration"
    45  	RouteUserProposalPaywall      = "/user/payments/paywall"
    46  	RouteUserProposalPaywallTx    = "/user/payments/paywalltx"
    47  	RouteUserProposalCredits      = "/user/payments/credits"
    48  	RouteUserPaymentsRescan       = "/user/payments/rescan"
    49  	RouteManageUser               = "/user/manage"
    50  	RouteSetTOTP                  = "/user/totp"
    51  	RouteVerifyTOTP               = "/user/verifytotp"
    52  	RouteUserDetails              = "/user/{userid:[0-9a-zA-Z-]{36}}"
    53  	RouteUsers                    = "/users"
    54  	RouteUnauthenticatedWebSocket = "/ws"
    55  	RouteAuthenticatedWebSocket   = "/aws"
    56  
    57  	// The following routes have been DEPRECATED.
    58  	RouteTokenInventory   = "/proposals/tokeninventory"
    59  	RouteProposalDetails  = "/proposals/{token:[A-Fa-f0-9]{7,64}}"
    60  	RouteAllVetted        = "/proposals/vetted"
    61  	RouteBatchProposals   = "/proposals/batch"
    62  	RouteVoteStatus       = "/proposals/{token:[A-Fa-f0-9]{7,64}}/votestatus"
    63  	RouteAllVoteStatus    = "/proposals/votestatus"
    64  	RouteBatchVoteSummary = "/proposals/batchvotesummary"
    65  	RouteActiveVote       = "/proposals/activevote"
    66  	RouteCastVotes        = "/proposals/castvotes"
    67  	RouteVoteResults      = "/proposals/{token:[A-Fa-f0-9]{7,64}}/votes"
    68  
    69  	// The following routes are NO LONGER SUPPORTED.
    70  	RouteNewProposal       = "/proposals/new"
    71  	RouteEditProposal      = "/proposals/edit"
    72  	RouteAuthorizeVote     = "/proposals/authorizevote"
    73  	RouteStartVote         = "/proposals/startvote"
    74  	RouteSetProposalStatus = "/proposals/{token:[A-Fa-f0-9]{7,64}}/status"
    75  	RouteCommentsGet       = "/proposals/{token:[A-Fa-f0-9]{7,64}}/comments"
    76  	RouteNewComment        = "/comments/new"
    77  	RouteLikeComment       = "/comments/like"
    78  	RouteCensorComment     = "/comments/censor"
    79  	RouteUserCommentsLikes = "/user/proposals/{token:[A-z0-9]{64}}/commentslikes"
    80  	RouteUserProposals     = "/user/proposals"
    81  
    82  	// VerificationTokenSize is the size of verification token in bytes
    83  	VerificationTokenSize = 32
    84  
    85  	// TokenPrefixLength is the length of the token prefix that can
    86  	// be used in RouteProposalDetails. This should match what is defined
    87  	// in politeiad, and once a Policy route is created in politeiad,
    88  	// this should be removed.
    89  	TokenPrefixLength = 7
    90  
    91  	// VerificationExpiryHours is the number of hours before the
    92  	// verification token expires
    93  	VerificationExpiryHours = 24
    94  
    95  	// PolicyIdexFilename is the file name of the proposal markdown
    96  	// file. Every proposal is required to have a index file. The index
    97  	// file should contain the proposal content.
    98  	PolicyIndexFilename = "index.md"
    99  
   100  	// PolicyMaxImages is the maximum number of images accepted
   101  	// when creating a new proposal
   102  	PolicyMaxImages = 5
   103  
   104  	// PolicyMaxImageSize is the maximum image file size (in bytes)
   105  	// accepted when creating a new proposal
   106  	PolicyMaxImageSize = 512 * 1024
   107  
   108  	// PolicyMaxMDs is the maximum number of markdown files accepted
   109  	// when creating a new proposal.
   110  	PolicyMaxMDs = 1
   111  
   112  	// PolicyMaxMDSize is the maximum markdown file size (in bytes)
   113  	// accepted when creating a new proposal
   114  	PolicyMaxMDSize = 512 * 1024
   115  
   116  	// PolicyMinPasswordLength is the minimum number of characters
   117  	// accepted for user passwords
   118  	PolicyMinPasswordLength = 8
   119  
   120  	// PolicyMaxUsernameLength is the max length of a username
   121  	PolicyMaxUsernameLength = 30
   122  
   123  	// PolicyMinUsernameLength is the min length of a username
   124  	PolicyMinUsernameLength = 3
   125  
   126  	// PolicyMaxProposalNameLength is the max length of a proposal name
   127  	PolicyMaxProposalNameLength = 80
   128  
   129  	// PolicyMinProposalNameLength is the min length of a proposal name
   130  	PolicyMinProposalNameLength = 8
   131  
   132  	// PolicyMaxCommentLength is the maximum number of characters
   133  	// accepted for comments
   134  	PolicyMaxCommentLength = 8000
   135  
   136  	// ProposalListPageSize is the maximum number of proposals returned
   137  	// for the routes that return lists of proposals
   138  	ProposalListPageSize = 20
   139  
   140  	// UserListPageSize is the maximum number of users returned
   141  	// for the routes that return lists of users
   142  	UserListPageSize = 20
   143  
   144  	// Error status codes
   145  	ErrorStatusInvalid                     ErrorStatusT = 0
   146  	ErrorStatusInvalidPassword             ErrorStatusT = 1
   147  	ErrorStatusMalformedEmail              ErrorStatusT = 2
   148  	ErrorStatusVerificationTokenInvalid    ErrorStatusT = 3
   149  	ErrorStatusVerificationTokenExpired    ErrorStatusT = 4
   150  	ErrorStatusProposalMissingFiles        ErrorStatusT = 5
   151  	ErrorStatusProposalNotFound            ErrorStatusT = 6
   152  	ErrorStatusProposalDuplicateFilenames  ErrorStatusT = 7
   153  	ErrorStatusProposalInvalidTitle        ErrorStatusT = 8
   154  	ErrorStatusMaxMDsExceededPolicy        ErrorStatusT = 9
   155  	ErrorStatusMaxImagesExceededPolicy     ErrorStatusT = 10
   156  	ErrorStatusMaxMDSizeExceededPolicy     ErrorStatusT = 11
   157  	ErrorStatusMaxImageSizeExceededPolicy  ErrorStatusT = 12
   158  	ErrorStatusMalformedPassword           ErrorStatusT = 13
   159  	ErrorStatusCommentNotFound             ErrorStatusT = 14
   160  	ErrorStatusInvalidFilename             ErrorStatusT = 15
   161  	ErrorStatusInvalidFileDigest           ErrorStatusT = 16
   162  	ErrorStatusInvalidBase64               ErrorStatusT = 17
   163  	ErrorStatusInvalidMIMEType             ErrorStatusT = 18
   164  	ErrorStatusUnsupportedMIMEType         ErrorStatusT = 19
   165  	ErrorStatusInvalidPropStatusTransition ErrorStatusT = 20
   166  	ErrorStatusInvalidPublicKey            ErrorStatusT = 21
   167  	ErrorStatusNoPublicKey                 ErrorStatusT = 22
   168  	ErrorStatusInvalidSignature            ErrorStatusT = 23
   169  	ErrorStatusInvalidInput                ErrorStatusT = 24
   170  	ErrorStatusInvalidSigningKey           ErrorStatusT = 25
   171  	ErrorStatusCommentLengthExceededPolicy ErrorStatusT = 26
   172  	ErrorStatusUserNotFound                ErrorStatusT = 27
   173  	ErrorStatusWrongStatus                 ErrorStatusT = 28
   174  	ErrorStatusNotLoggedIn                 ErrorStatusT = 29
   175  	ErrorStatusUserNotPaid                 ErrorStatusT = 30
   176  	ErrorStatusReviewerAdminEqualsAuthor   ErrorStatusT = 31
   177  	ErrorStatusMalformedUsername           ErrorStatusT = 32
   178  	ErrorStatusDuplicateUsername           ErrorStatusT = 33
   179  	ErrorStatusVerificationTokenUnexpired  ErrorStatusT = 34
   180  	ErrorStatusCannotVerifyPayment         ErrorStatusT = 35
   181  	ErrorStatusDuplicatePublicKey          ErrorStatusT = 36
   182  	ErrorStatusInvalidPropVoteStatus       ErrorStatusT = 37
   183  	ErrorStatusUserLocked                  ErrorStatusT = 38
   184  	ErrorStatusNoProposalCredits           ErrorStatusT = 39
   185  	ErrorStatusInvalidUserManageAction     ErrorStatusT = 40
   186  	ErrorStatusUserActionNotAllowed        ErrorStatusT = 41
   187  	ErrorStatusWrongVoteStatus             ErrorStatusT = 42
   188  	ErrorStatusUnused1                     ErrorStatusT = 43 // XXX
   189  	ErrorStatusCannotVoteOnPropComment     ErrorStatusT = 44
   190  	ErrorStatusChangeMessageCannotBeBlank  ErrorStatusT = 45
   191  	ErrorStatusCensorReasonCannotBeBlank   ErrorStatusT = 46
   192  	ErrorStatusCannotCensorComment         ErrorStatusT = 47
   193  	ErrorStatusUserNotAuthor               ErrorStatusT = 48
   194  	ErrorStatusVoteNotAuthorized           ErrorStatusT = 49
   195  	ErrorStatusVoteAlreadyAuthorized       ErrorStatusT = 50
   196  	ErrorStatusInvalidAuthVoteAction       ErrorStatusT = 51
   197  	ErrorStatusUserDeactivated             ErrorStatusT = 52
   198  	ErrorStatusInvalidPropVoteBits         ErrorStatusT = 53
   199  	ErrorStatusInvalidPropVoteParams       ErrorStatusT = 54
   200  	ErrorStatusEmailNotVerified            ErrorStatusT = 55
   201  	ErrorStatusInvalidUUID                 ErrorStatusT = 56
   202  	ErrorStatusInvalidLikeCommentAction    ErrorStatusT = 57
   203  	ErrorStatusInvalidCensorshipToken      ErrorStatusT = 58
   204  	ErrorStatusEmailAlreadyVerified        ErrorStatusT = 59
   205  	ErrorStatusNoProposalChanges           ErrorStatusT = 60
   206  	ErrorStatusMaxProposalsExceededPolicy  ErrorStatusT = 61
   207  	ErrorStatusDuplicateComment            ErrorStatusT = 62
   208  	ErrorStatusInvalidLogin                ErrorStatusT = 63
   209  	ErrorStatusCommentIsCensored           ErrorStatusT = 64
   210  	ErrorStatusInvalidProposalVersion      ErrorStatusT = 65
   211  	ErrorStatusMetadataInvalid             ErrorStatusT = 66
   212  	ErrorStatusMetadataMissing             ErrorStatusT = 67
   213  	ErrorStatusMetadataDigestInvalid       ErrorStatusT = 68
   214  	ErrorStatusInvalidVoteType             ErrorStatusT = 69
   215  	ErrorStatusInvalidVoteOptions          ErrorStatusT = 70
   216  	ErrorStatusLinkByDeadlineNotMet        ErrorStatusT = 71
   217  	ErrorStatusNoLinkedProposals           ErrorStatusT = 72
   218  	ErrorStatusInvalidLinkTo               ErrorStatusT = 73
   219  	ErrorStatusInvalidLinkBy               ErrorStatusT = 74
   220  	ErrorStatusInvalidRunoffVote           ErrorStatusT = 75
   221  	ErrorStatusWrongProposalType           ErrorStatusT = 76
   222  	ErrorStatusTOTPFailedValidation        ErrorStatusT = 77
   223  	ErrorStatusTOTPInvalidType             ErrorStatusT = 78
   224  	ErrorStatusRequiresTOTPCode            ErrorStatusT = 79
   225  	ErrorStatusTOTPWaitForNewCode          ErrorStatusT = 80
   226  	ErrorStatusLast                        ErrorStatusT = 81
   227  
   228  	// Proposal state codes
   229  	//
   230  	// PropStateUnvetted includes proposals with a status of:
   231  	//   * PropStatusNotReviewed
   232  	//   * PropStatusUnreviewedChanges
   233  	//   * PropStatusCensored
   234  	// PropStateVetted includes proposals with a status of:
   235  	//   * PropStatusPublic
   236  	//   * PropStatusAbandoned
   237  	//
   238  	// Proposal states correspond to the unvetted and vetted politeiad
   239  	// repositories.
   240  	PropStateInvalid  PropStateT = 0 // Invalid state
   241  	PropStateUnvetted PropStateT = 1 // Unvetted proposal
   242  	PropStateVetted   PropStateT = 2 // Vetted proposal
   243  
   244  	// Proposal status codes (set and get)
   245  	PropStatusInvalid           PropStatusT = 0 // Invalid status
   246  	PropStatusNotFound          PropStatusT = 1 // Proposal not found
   247  	PropStatusNotReviewed       PropStatusT = 2 // Proposal has not been reviewed
   248  	PropStatusCensored          PropStatusT = 3 // Proposal has been censored
   249  	PropStatusPublic            PropStatusT = 4 // Proposal is publicly visible
   250  	PropStatusUnreviewedChanges PropStatusT = 5 // Proposal is not public and has unreviewed changes
   251  	PropStatusAbandoned         PropStatusT = 6 // Proposal has been declared abandoned by an admin
   252  	PropStatusLast              PropStatusT = 7 // Unit test only
   253  
   254  	// Proposal vote status codes
   255  	PropVoteStatusInvalid       PropVoteStatusT = 0 // Invalid vote status
   256  	PropVoteStatusNotAuthorized PropVoteStatusT = 1 // Vote has not been authorized by author
   257  	PropVoteStatusAuthorized    PropVoteStatusT = 2 // Vote has been authorized by author
   258  	PropVoteStatusStarted       PropVoteStatusT = 3 // Proposal vote has been started
   259  	PropVoteStatusFinished      PropVoteStatusT = 4 // Proposal vote has been finished
   260  	PropVoteStatusDoesntExist   PropVoteStatusT = 5 // Proposal doesn't exist
   261  	PropVoteLast                PropVoteStatusT = 6 // Unit test only
   262  
   263  	// Vote types
   264  	//
   265  	// VoteTypeStandard is used to indicate a simple approve or reject
   266  	// proposal vote where the winner is the voting option that has met
   267  	// the specified pass and quorum requirements.
   268  	//
   269  	// VoteTypeRunoff specifies a runoff vote that multiple proposals compete in.
   270  	// All proposals are voted on like normal, but there can only be one winner
   271  	// in a runoff vote. The winner is the proposal that meets the quorum
   272  	// requirement, meets the pass requirement, and that has the most net yes
   273  	// votes. The winning proposal is considered approved and all other proposals
   274  	// are considered rejected. If no proposals meet the quorum and pass
   275  	// requirements then all proposals are considered rejected.
   276  	// Note: in a runoff vote it is possible for a proposal to meet the quorum
   277  	// and pass requirements but still be rejected if it does not have the most
   278  	// net yes votes.
   279  	VoteTypeInvalid  VoteT = 0
   280  	VoteTypeStandard VoteT = 1
   281  	VoteTypeRunoff   VoteT = 2
   282  
   283  	// User manage actions
   284  	UserManageInvalid                         UserManageActionT = 0 // Invalid action type
   285  	UserManageExpireNewUserVerification       UserManageActionT = 1
   286  	UserManageExpireUpdateKeyVerification     UserManageActionT = 2
   287  	UserManageExpireResetPasswordVerification UserManageActionT = 3
   288  	UserManageClearUserPaywall                UserManageActionT = 4
   289  	UserManageUnlock                          UserManageActionT = 5
   290  	UserManageDeactivate                      UserManageActionT = 6
   291  	UserManageReactivate                      UserManageActionT = 7
   292  	UserManageLast                            UserManageActionT = 8
   293  
   294  	// Email notification types
   295  	NotificationEmailMyProposalStatusChange      EmailNotificationT = 1 << 0
   296  	NotificationEmailMyProposalVoteStarted       EmailNotificationT = 1 << 1
   297  	NotificationEmailRegularProposalVetted       EmailNotificationT = 1 << 2
   298  	NotificationEmailRegularProposalEdited       EmailNotificationT = 1 << 3
   299  	NotificationEmailRegularProposalVoteStarted  EmailNotificationT = 1 << 4
   300  	NotificationEmailAdminProposalNew            EmailNotificationT = 1 << 5
   301  	NotificationEmailAdminProposalVoteAuthorized EmailNotificationT = 1 << 6
   302  	NotificationEmailCommentOnMyProposal         EmailNotificationT = 1 << 7
   303  	NotificationEmailCommentOnMyComment          EmailNotificationT = 1 << 8
   304  
   305  	// Time-base one time password types
   306  	TOTPTypeInvalid TOTPMethodT = 0 // Invalid TOTP type
   307  	TOTPTypeBasic   TOTPMethodT = 1
   308  )
   309  
   310  var (
   311  	// PolicyProposalNameSupportedChars is the regular expression of a valid
   312  	// proposal name
   313  	PolicyProposalNameSupportedChars = []string{
   314  		"A-z", "0-9", "&", ".", ",", ":", ";", "-", " ", "@", "+", "#", "/",
   315  		"(", ")", "!", "?", "\"", "'"}
   316  
   317  	// PolicyUsernameSupportedChars is the regular expression of a valid
   318  	// username
   319  	PolicyUsernameSupportedChars = []string{
   320  		"a-z", "0-9", ".", ",", ":", ";", "-", "@", "+", "(", ")", "_"}
   321  
   322  	// PoliteiaWWWAPIRoute is the prefix to the API route
   323  	PoliteiaWWWAPIRoute = fmt.Sprintf("/v%v", PoliteiaWWWAPIVersion)
   324  
   325  	// CookieSession is the cookie name that indicates that a user is
   326  	// logged in.
   327  	CookieSession = "session"
   328  
   329  	// ErrorStatus converts error status codes to human readable text.
   330  	ErrorStatus = map[ErrorStatusT]string{
   331  		ErrorStatusInvalid:                     "invalid error status",
   332  		ErrorStatusInvalidPassword:             "invalid password",
   333  		ErrorStatusMalformedEmail:              "malformed email",
   334  		ErrorStatusVerificationTokenInvalid:    "invalid verification token",
   335  		ErrorStatusVerificationTokenExpired:    "expired verification token",
   336  		ErrorStatusProposalMissingFiles:        "missing proposal files",
   337  		ErrorStatusProposalNotFound:            "proposal not found",
   338  		ErrorStatusProposalDuplicateFilenames:  "duplicate proposal files",
   339  		ErrorStatusProposalInvalidTitle:        "invalid proposal title",
   340  		ErrorStatusMaxMDsExceededPolicy:        "maximum markdown files exceeded",
   341  		ErrorStatusMaxImagesExceededPolicy:     "maximum image files exceeded",
   342  		ErrorStatusMaxMDSizeExceededPolicy:     "maximum markdown file size exceeded",
   343  		ErrorStatusMaxImageSizeExceededPolicy:  "maximum image file size exceeded",
   344  		ErrorStatusMalformedPassword:           "malformed password",
   345  		ErrorStatusCommentNotFound:             "comment not found",
   346  		ErrorStatusInvalidFilename:             "invalid filename",
   347  		ErrorStatusInvalidFileDigest:           "invalid file digest",
   348  		ErrorStatusInvalidBase64:               "invalid base64 file content",
   349  		ErrorStatusInvalidMIMEType:             "invalid MIME type detected for file",
   350  		ErrorStatusUnsupportedMIMEType:         "unsupported MIME type for file",
   351  		ErrorStatusInvalidPropStatusTransition: "invalid proposal status",
   352  		ErrorStatusInvalidPublicKey:            "invalid public key",
   353  		ErrorStatusNoPublicKey:                 "no active public key",
   354  		ErrorStatusInvalidSignature:            "invalid signature",
   355  		ErrorStatusInvalidInput:                "invalid input",
   356  		ErrorStatusInvalidSigningKey:           "invalid signing key",
   357  		ErrorStatusCommentLengthExceededPolicy: "maximum comment length exceeded",
   358  		ErrorStatusUserNotFound:                "user not found",
   359  		ErrorStatusWrongStatus:                 "wrong proposal status",
   360  		ErrorStatusNotLoggedIn:                 "user not logged in",
   361  		ErrorStatusUserNotPaid:                 "user hasn't paid paywall",
   362  		ErrorStatusReviewerAdminEqualsAuthor:   "user cannot change the status of his own proposal",
   363  		ErrorStatusMalformedUsername:           "malformed username",
   364  		ErrorStatusDuplicateUsername:           "duplicate username",
   365  		ErrorStatusVerificationTokenUnexpired:  "verification token not yet expired",
   366  		ErrorStatusCannotVerifyPayment:         "cannot verify payment at this time",
   367  		ErrorStatusDuplicatePublicKey:          "public key already taken by another user",
   368  		ErrorStatusInvalidPropVoteStatus:       "invalid proposal vote status",
   369  		ErrorStatusUserLocked:                  "user locked due to too many login attempts",
   370  		ErrorStatusNoProposalCredits:           "no proposal credits",
   371  		ErrorStatusInvalidUserManageAction:     "invalid user edit action",
   372  		ErrorStatusUserActionNotAllowed:        "user action is not allowed",
   373  		ErrorStatusWrongVoteStatus:             "wrong proposal vote status",
   374  		ErrorStatusUnused1:                     "UNUSED STATUS 1",
   375  		ErrorStatusCannotVoteOnPropComment:     "cannot vote on proposal comment",
   376  		ErrorStatusChangeMessageCannotBeBlank:  "status change message cannot be blank",
   377  		ErrorStatusCensorReasonCannotBeBlank:   "censor comment reason cannot be blank",
   378  		ErrorStatusCannotCensorComment:         "cannot censor comment",
   379  		ErrorStatusUserNotAuthor:               "user is not the proposal author",
   380  		ErrorStatusVoteNotAuthorized:           "vote has not been authorized",
   381  		ErrorStatusVoteAlreadyAuthorized:       "vote has already been authorized",
   382  		ErrorStatusInvalidAuthVoteAction:       "invalid authorize vote action",
   383  		ErrorStatusUserDeactivated:             "user account is deactivated",
   384  		ErrorStatusInvalidPropVoteBits:         "invalid proposal vote option bits",
   385  		ErrorStatusInvalidPropVoteParams:       "invalid proposal vote parameters",
   386  		ErrorStatusEmailNotVerified:            "email address is not verified",
   387  		ErrorStatusInvalidUUID:                 "invalid user UUID",
   388  		ErrorStatusInvalidLikeCommentAction:    "invalid like comment action",
   389  		ErrorStatusInvalidCensorshipToken:      "invalid proposal censorship token",
   390  		ErrorStatusEmailAlreadyVerified:        "email address is already verified",
   391  		ErrorStatusNoProposalChanges:           "no changes found in proposal",
   392  		ErrorStatusMaxProposalsExceededPolicy:  "max proposals exceeded",
   393  		ErrorStatusDuplicateComment:            "duplicate comment",
   394  		ErrorStatusInvalidLogin:                "invalid login credentials",
   395  		ErrorStatusCommentIsCensored:           "comment is censored",
   396  		ErrorStatusInvalidProposalVersion:      "invalid proposal version",
   397  		ErrorStatusMetadataInvalid:             "invalid metadata",
   398  		ErrorStatusMetadataMissing:             "missing metadata",
   399  		ErrorStatusMetadataDigestInvalid:       "metadata digest invalid",
   400  		ErrorStatusInvalidVoteType:             "invalid vote type",
   401  		ErrorStatusInvalidVoteOptions:          "invalid vote options",
   402  		ErrorStatusLinkByDeadlineNotMet:        "linkby deadline note met yet",
   403  		ErrorStatusNoLinkedProposals:           "no linked proposals",
   404  		ErrorStatusInvalidLinkTo:               "invalid proposal linkto",
   405  		ErrorStatusInvalidLinkBy:               "invalid proposal linkby",
   406  		ErrorStatusInvalidRunoffVote:           "invalid runoff vote",
   407  		ErrorStatusWrongProposalType:           "wrong proposal type",
   408  		ErrorStatusTOTPFailedValidation:        "the provided passcode does not match the saved secret key",
   409  		ErrorStatusTOTPInvalidType:             "invalid totp type",
   410  		ErrorStatusRequiresTOTPCode:            "login requires totp code",
   411  		ErrorStatusTOTPWaitForNewCode:          "must wait until next totp code window",
   412  	}
   413  
   414  	// PropStatus converts propsal status codes to human readable text
   415  	PropStatus = map[PropStatusT]string{
   416  		PropStatusInvalid:           "invalid proposal status",
   417  		PropStatusNotFound:          "not found",
   418  		PropStatusNotReviewed:       "unreviewed",
   419  		PropStatusCensored:          "censored",
   420  		PropStatusPublic:            "public",
   421  		PropStatusUnreviewedChanges: "unreviewed changes",
   422  		PropStatusAbandoned:         "abandoned",
   423  	}
   424  
   425  	// PropVoteStatus converts votes status codes to human readable text
   426  	PropVoteStatus = map[PropVoteStatusT]string{
   427  		PropVoteStatusInvalid:       "invalid vote status",
   428  		PropVoteStatusNotAuthorized: "voting has not been authorized by author",
   429  		PropVoteStatusAuthorized:    "voting has been authorized by author",
   430  		PropVoteStatusStarted:       "voting active",
   431  		PropVoteStatusFinished:      "voting finished",
   432  		PropVoteStatusDoesntExist:   "proposal does not exist",
   433  	}
   434  
   435  	// UserManageAction converts user edit actions to human readable text
   436  	UserManageAction = map[UserManageActionT]string{
   437  		UserManageInvalid:                         "invalid action",
   438  		UserManageExpireNewUserVerification:       "expire new user verification",
   439  		UserManageExpireUpdateKeyVerification:     "expire update key verification",
   440  		UserManageExpireResetPasswordVerification: "expire reset password verification",
   441  		UserManageClearUserPaywall:                "clear user paywall",
   442  		UserManageUnlock:                          "unlock user",
   443  		UserManageDeactivate:                      "deactivate user",
   444  		UserManageReactivate:                      "reactivate user",
   445  	}
   446  )
   447  
   448  // File describes an individual file that is part of the proposal.  The
   449  // directory structure must be flattened.  The server side SHALL verify MIME
   450  // and Digest.
   451  type File struct {
   452  	// Meta-data
   453  	Name   string `json:"name"`   // Suggested filename
   454  	MIME   string `json:"mime"`   // Mime type
   455  	Digest string `json:"digest"` // Digest of unencoded payload
   456  
   457  	// Data
   458  	Payload string `json:"payload"` // File content, base64 encoded
   459  }
   460  
   461  const (
   462  	// Metadata hints
   463  	HintProposalMetadata = "proposalmetadata"
   464  )
   465  
   466  // ProposalMetadata contains metadata that is specified by the user on proposal
   467  // submission. It is attached to a proposal submission as a Metadata object.
   468  //
   469  // LinkBy must allow for a minimum of one week after the proposal vote ends for
   470  // RFP submissions to be submitted. The LinkBy field is validated on both
   471  // proposal submission and before the proposal vote is started to ensure that
   472  // the RFP submissions have sufficient time to be submitted.
   473  type ProposalMetadata struct {
   474  	Name   string `json:"name"`             // Proposal name
   475  	LinkTo string `json:"linkto,omitempty"` // Token of proposal to link to
   476  	LinkBy int64  `json:"linkby,omitempty"` // UNIX timestamp of RFP deadline
   477  }
   478  
   479  // Metadata describes user specified metadata.
   480  //
   481  // Payload is the base64 encoding of the JSON encoded metadata. Its required
   482  // to be base64 encoded because it's stored in politeiad as a file and the
   483  // politeiad file payload must be base64.
   484  type Metadata struct {
   485  	Digest  string `json:"digest"`  // SHA256 digest of JSON encoded payload
   486  	Hint    string `json:"hint"`    // Hint that describes the payload
   487  	Payload string `json:"payload"` // Base64 encoded metadata content
   488  }
   489  
   490  // CensorshipRecord contains the proof that a proposal was accepted for review.
   491  // The proof is verifiable on the client side.
   492  //
   493  // The Merkle field contains the ordered merkle root of all files and metadata
   494  // in the proposal.  The Token field contains a random censorship token that is
   495  // signed by the server private key.  The token can be used on the client to
   496  // verify the authenticity of the CensorshipRecord.
   497  type CensorshipRecord struct {
   498  	Token     string `json:"token"`     // Censorship token
   499  	Merkle    string `json:"merkle"`    // Merkle root of proposal
   500  	Signature string `json:"signature"` // Server side signature of []byte(Merkle+Token)
   501  }
   502  
   503  // VoteSummary contains a summary of the vote information for a specific
   504  // proposal. It is a light weight version of the VoteResultsReply that is used
   505  // when the full ticket snapshot or the full cast vote data is not needed.
   506  type VoteSummary struct {
   507  	Status           PropVoteStatusT    `json:"status"`                     // Vote status
   508  	Approved         bool               `json:"approved"`                   // Was the vote approved
   509  	Type             VoteT              `json:"type,omitempty"`             // Vote type
   510  	EligibleTickets  uint32             `json:"eligibletickets,omitempty"`  // Number of eligible tickets
   511  	Duration         uint32             `json:"duration,omitempty"`         // Duration of vote
   512  	EndHeight        uint64             `json:"endheight,omitempty"`        // Vote end height
   513  	QuorumPercentage uint32             `json:"quorumpercentage,omitempty"` // Percent of eligible votes required for quorum
   514  	PassPercentage   uint32             `json:"passpercentage,omitempty"`   // Percent of total votes required to pass
   515  	Results          []VoteOptionResult `json:"results,omitempty"`          // Vote results
   516  }
   517  
   518  // ProposalRecord is an entire proposal and it's content.
   519  //
   520  // Signature is a signature of the proposal merkle root where the merkle root
   521  // contains all Files and Metadata of the proposal.
   522  type ProposalRecord struct {
   523  	Name                string      `json:"name"`                          // Suggested short proposal name
   524  	State               PropStateT  `json:"state"`                         // Current state of proposal
   525  	Status              PropStatusT `json:"status"`                        // Current status of proposal
   526  	Timestamp           int64       `json:"timestamp"`                     // Last update of proposal
   527  	UserId              string      `json:"userid"`                        // ID of user who submitted proposal
   528  	Username            string      `json:"username"`                      // Username of user who submitted proposal
   529  	PublicKey           string      `json:"publickey"`                     // Key used for signature.
   530  	Signature           string      `json:"signature"`                     // Signature of merkle root
   531  	NumComments         uint        `json:"numcomments"`                   // Number of comments on the proposal
   532  	Version             string      `json:"version"`                       // Record version
   533  	StatusChangeMessage string      `json:"statuschangemessage,omitempty"` // Message associated to the status change
   534  	PublishedAt         int64       `json:"publishedat,omitempty"`         // UNIX timestamp of when proposal was published
   535  	CensoredAt          int64       `json:"censoredat,omitempty"`          // UNIX timestamp of when proposal was censored
   536  	AbandonedAt         int64       `json:"abandonedat,omitempty"`         // UNIX timestamp of when proposal was abandoned
   537  	LinkTo              string      `json:"linkto,omitempty"`              // Token of linked parent proposal
   538  	LinkBy              int64       `json:"linkby,omitempty"`              // UNIX timestamp of RFP deadline
   539  	LinkedFrom          []string    `json:"linkedfrom,omitempty"`          // Tokens of public props that have linked to this this prop
   540  
   541  	Files            []File           `json:"files"`
   542  	Metadata         []Metadata       `json:"metadata"`
   543  	CensorshipRecord CensorshipRecord `json:"censorshiprecord"`
   544  }
   545  
   546  // ProposalCredit contains the details of a proposal credit that has been
   547  // purchased by the user.
   548  type ProposalCredit struct {
   549  	PaywallID     uint64 `json:"paywallid"`     // paywall that created this credit
   550  	Price         uint64 `json:"price"`         // Price credit was purchased at in atoms
   551  	DatePurchased int64  `json:"datepurchased"` // Unix timestamp of the purchase date
   552  	TxID          string `json:"txid"`          // Decred tx that purchased this credit
   553  }
   554  
   555  // UserError represents an error that is caused by something that the user
   556  // did (malformed input, bad timing, etc).
   557  type UserError struct {
   558  	ErrorCode    ErrorStatusT
   559  	ErrorContext []string
   560  }
   561  
   562  // Error satisfies the error interface.
   563  func (e UserError) Error() string {
   564  	return fmt.Sprintf("user error code: %v", e.ErrorCode)
   565  }
   566  
   567  // ErrorReply are replies that the server returns when it encounters an
   568  // unrecoverable problem while executing a command. The HTTP status code will
   569  // be 500 and the ErrorCode field will contain a UNIX timestamp that the user
   570  // can provide to the server admin to track down the error details in the logs.
   571  type ErrorReply struct {
   572  	ErrorCode    int64    `json:"errorcode,omitempty"`
   573  	ErrorContext []string `json:"errorcontext,omitempty"`
   574  }
   575  
   576  // Error satisfies the error interface.
   577  func (e ErrorReply) Error() string {
   578  	return fmt.Sprintf("server error: %v", e.ErrorCode)
   579  }
   580  
   581  // Version command is used to determine the lowest API version that this
   582  // backend supports and additionally it provides the route to said API.  This
   583  // call is required in order to establish CSRF for the session.  The client
   584  // should verify compatibility with the server version.
   585  type Version struct{}
   586  
   587  // VersionReply returns information that indicates the lowest version that
   588  // this backend supports and additionally the route to the API and the public
   589  // signing key of the server.
   590  type VersionReply struct {
   591  	Version           uint   `json:"version"`           // Lowest supported WWW API version
   592  	Route             string `json:"route"`             // Prefix to API calls
   593  	BuildVersion      string `json:"buildversion"`      // Build version from hosted pi module
   594  	PubKey            string `json:"pubkey"`            // Server public key
   595  	TestNet           bool   `json:"testnet"`           // Network indicator
   596  	Mode              string `json:"mode"`              // current politeiawww mode running (piwww or cmswww)
   597  	ActiveUserSession bool   `json:"activeusersession"` // indicates if there is an active user session
   598  }
   599  
   600  // NewUser is used to request that a new user be created within the db.
   601  // If successful, the user will require verification before being able to login.
   602  type NewUser struct {
   603  	Email     string `json:"email"`
   604  	Password  string `json:"password"`
   605  	PublicKey string `json:"publickey"`
   606  	Username  string `json:"username"`
   607  }
   608  
   609  // NewUserReply is used to reply to the NewUser command with an error
   610  // if the command is unsuccessful.
   611  type NewUserReply struct {
   612  	VerificationToken string `json:"verificationtoken"` // Server verification token
   613  }
   614  
   615  // VerifyNewUser is used to perform verification for the user created through
   616  // the NewUser command using the token provided in NewUserReply.
   617  type VerifyNewUser struct {
   618  	Email             string `schema:"email"`             // User email address
   619  	VerificationToken string `schema:"verificationtoken"` // Server provided verification token
   620  	Signature         string `schema:"signature"`         // Verification token signature
   621  }
   622  
   623  // VerifyNewUserReply
   624  type VerifyNewUserReply struct{}
   625  
   626  // ResendVerification is used to resent a new user verification email.
   627  type ResendVerification struct {
   628  	Email     string `json:"email"`
   629  	PublicKey string `json:"publickey"`
   630  }
   631  
   632  // ResendVerificationReply is used to reply to the ResendVerification command.
   633  type ResendVerificationReply struct {
   634  	VerificationToken string `json:"verificationtoken"` // Server verification token
   635  }
   636  
   637  // UpdateUserKey is used to request a new active key.
   638  type UpdateUserKey struct {
   639  	PublicKey string `json:"publickey"`
   640  }
   641  
   642  // UpdateUserKeyReply replies to the UpdateUserKey command.
   643  type UpdateUserKeyReply struct {
   644  	VerificationToken string `json:"verificationtoken"` // Server verification token
   645  }
   646  
   647  // VerifyUpdateUserKey is used to request a new active key.
   648  type VerifyUpdateUserKey struct {
   649  	VerificationToken string `json:"verificationtoken"` // Server provided verification token
   650  	Signature         string `json:"signature"`         // Verification token signature
   651  }
   652  
   653  // VerifyUpdateUserKeyReply replies to the VerifyUpdateUserKey command.
   654  type VerifyUpdateUserKeyReply struct{}
   655  
   656  // ChangeUsername is used to perform a username change while the user
   657  // is logged in.
   658  type ChangeUsername struct {
   659  	Password    string `json:"password"`
   660  	NewUsername string `json:"newusername"`
   661  }
   662  
   663  // ChangeUsernameReply is used to perform a username change while the user
   664  // is logged in.
   665  type ChangeUsernameReply struct{}
   666  
   667  // ChangePassword is used to perform a password change while the user
   668  // is logged in.
   669  type ChangePassword struct {
   670  	CurrentPassword string `json:"currentpassword"`
   671  	NewPassword     string `json:"newpassword"`
   672  }
   673  
   674  // ChangePasswordReply is used to perform a password change while the user
   675  // is logged in.
   676  type ChangePasswordReply struct{}
   677  
   678  // ResetPassword is used to perform a password change when the user is not
   679  // logged in. If the username and email address match the user record in the
   680  // database then a reset password verification token will be email to the user.
   681  type ResetPassword struct {
   682  	Username string `json:"username"`
   683  	Email    string `json:"email"`
   684  }
   685  
   686  // ResetPasswordReply is used to reply to the ResetPassword command. The
   687  // verification token will only be present if the email server has been
   688  // disabled.
   689  type ResetPasswordReply struct {
   690  	VerificationToken string `json:"verificationtoken"`
   691  }
   692  
   693  // VerifyResetPassword is used to verify the verification token sent to a user
   694  // in the ResestPassword command and will update the user's password with the
   695  // provided NewPassword if everything matches.
   696  type VerifyResetPassword struct {
   697  	Username          string `json:"username"`
   698  	VerificationToken string `json:"verificationtoken"`
   699  	NewPassword       string `json:"newpassword"`
   700  }
   701  
   702  // VerifyResetPasswordReply is used to reply to the VerifyResetPassword
   703  // command.
   704  type VerifyResetPasswordReply struct{}
   705  
   706  // UserProposals is used to request a list of proposals that the
   707  // user has submitted. This command optionally takes either a Before
   708  // or After parameter, which specify a proposal's censorship token.
   709  // If After is specified, the "page" returned starts after the proposal
   710  // whose censorship token is provided. If Before is specified, the "page"
   711  // returned starts before the proposal whose censorship token is provided.
   712  //
   713  // This request is NO LONGER SUPPORTED.
   714  type UserProposals struct {
   715  	UserId string `schema:"userid"`
   716  	Before string `schema:"before"`
   717  	After  string `schema:"after"`
   718  }
   719  
   720  // UserProposalsReply replies to the UserProposals command with
   721  // a list of proposals that the user has submitted and the total
   722  // amount of proposals
   723  //
   724  // This request is NO LONGER SUPPORTED.
   725  type UserProposalsReply struct {
   726  	Proposals      []ProposalRecord `json:"proposals"`      // user proposals
   727  	NumOfProposals int              `json:"numofproposals"` // number of proposals submitted by the user
   728  }
   729  
   730  // Users is used to request a list of users given a filter.
   731  type Users struct {
   732  	Username  string `json:"username"`  // String which should match or partially match a username
   733  	Email     string `json:"email"`     // String which should match or partially match an email
   734  	PublicKey string `json:"publickey"` // Active or inactive user pubkey
   735  
   736  }
   737  
   738  // UsersReply is a reply to the Users command, replying with a list of users.
   739  type UsersReply struct {
   740  	TotalUsers   uint64         `json:"totalusers,omitempty"` // Total number of all users in the database
   741  	TotalMatches uint64         `json:"totalmatches"`         // Total number of users that match the filters
   742  	Users        []AbridgedUser `json:"users"`                // List of users that match the filters
   743  }
   744  
   745  // AbridgedUser is a shortened version of User that's used for the admin list.
   746  type AbridgedUser struct {
   747  	ID       string `json:"id"`
   748  	Email    string `json:"email,omitempty"`
   749  	Username string `json:"username"`
   750  }
   751  
   752  // Login attempts to login the user.  Note that by necessity the password
   753  // travels in the clear.
   754  type Login struct {
   755  	Email    string `json:"email"`
   756  	Password string `json:"password"`
   757  	Code     string `json:"code,omitempty"` // TOTP code based on user's TOTP secret (if verified)
   758  }
   759  
   760  // LoginReply is used to reply to the Login command.
   761  type LoginReply struct {
   762  	IsAdmin            bool   `json:"isadmin"`            // Set if user is an admin
   763  	UserID             string `json:"userid"`             // User id
   764  	Email              string `json:"email"`              // User email
   765  	Username           string `json:"username"`           // Username
   766  	PublicKey          string `json:"publickey"`          // Active public key
   767  	PaywallAddress     string `json:"paywalladdress"`     // Registration paywall address
   768  	PaywallAmount      uint64 `json:"paywallamount"`      // Registration paywall amount in atoms
   769  	PaywallTxNotBefore int64  `json:"paywalltxnotbefore"` // Minimum timestamp for paywall tx
   770  	PaywallTxID        string `json:"paywalltxid"`        // Paywall payment tx ID
   771  	ProposalCredits    uint64 `json:"proposalcredits"`    // Number of the proposal credits the user has available to spend
   772  	LastLoginTime      int64  `json:"lastlogintime"`      // Unix timestamp of last login date
   773  	SessionMaxAge      int64  `json:"sessionmaxage"`      // Unix timestamp of session max age
   774  	TOTPVerified       bool   `json:"totpverified"`       // Whether current totp secret has been verified with
   775  }
   776  
   777  // Logout attempts to log the user out.
   778  type Logout struct{}
   779  
   780  // LogoutReply indicates whether the Logout command was success or not.
   781  type LogoutReply struct{}
   782  
   783  // Me asks the server to return pertinent user information.
   784  //
   785  // Note that MeReply is not present because LoginReply is reused
   786  // for this endpoint.
   787  type Me struct{}
   788  
   789  // UserRegistrationPayment is used to request the server to check for the
   790  // provided transaction on the Decred blockchain and verify that it
   791  // satisfies the requirements for a user to pay his registration fee.
   792  type UserRegistrationPayment struct{}
   793  
   794  // UserRegistrationPaymentReply is used to reply to the UserRegistrationPayment
   795  // command.
   796  type UserRegistrationPaymentReply struct {
   797  	HasPaid            bool   `json:"haspaid"`
   798  	PaywallAddress     string `json:"paywalladdress"`     // Registration paywall address
   799  	PaywallAmount      uint64 `json:"paywallamount"`      // Registration paywall amount in atoms
   800  	PaywallTxNotBefore int64  `json:"paywalltxnotbefore"` // Minimum timestamp for paywall tx
   801  }
   802  
   803  // UserProposalPaywall is used to request proposal paywall details from the
   804  // server that the user needs in order to purchase paywall credits.
   805  type UserProposalPaywall struct{}
   806  
   807  // UserProposalPaywallReply is used to reply to the UserProposalPaywall
   808  // command.
   809  type UserProposalPaywallReply struct {
   810  	CreditPrice        uint64 `json:"creditprice"`        // Cost per proposal credit in atoms
   811  	PaywallAddress     string `json:"paywalladdress"`     // Proposal paywall address
   812  	PaywallTxNotBefore int64  `json:"paywalltxnotbefore"` // Minimum timestamp for paywall tx
   813  }
   814  
   815  // UserProposalPaywallTx is used to request payment details for a pending
   816  // proposal paywall payment.
   817  type UserProposalPaywallTx struct{}
   818  
   819  // UserProposalPaywallTxReply is used to reply to the ProposalPaywallPayment
   820  // command.
   821  type UserProposalPaywallTxReply struct {
   822  	TxID          string `json:"txid"`          // Transaction ID
   823  	TxAmount      uint64 `json:"amount"`        // Transaction amount in atoms
   824  	Confirmations uint64 `json:"confirmations"` // Number of block confirmations
   825  }
   826  
   827  // UserProposalCredits is used to request a list of all the user's unspent
   828  // proposal credits and a list of all of the user's spent proposal credits.
   829  // A spent credit means that the credit was used to submit a proposal.  Spent
   830  // credits have a proposal censorship token associated with them to signify
   831  // that they have been spent.
   832  type UserProposalCredits struct{}
   833  
   834  // UserProposalCreditsReply is used to reply to the UserProposalCredits command.
   835  // It contains unspent credits that the user purchased but did not yet use, and
   836  // the credits the user already spent to submit proposals.
   837  type UserProposalCreditsReply struct {
   838  	UnspentCredits []ProposalCredit `json:"unspentcredits"`
   839  	SpentCredits   []ProposalCredit `json:"spentcredits"`
   840  }
   841  
   842  // UserPaymentsRescan allows an admin to rescan a user's paywall address to
   843  // check for any payments that may have been missed by paywall polling. Any
   844  // proposal credits that are created as a result of the rescan are returned in
   845  // the UserPaymentsRescanReply. This call isn't RESTful, but a PUT request is
   846  // used since it's idempotent.
   847  type UserPaymentsRescan struct {
   848  	UserID string `json:"userid"` // ID of user to rescan
   849  }
   850  
   851  // UserPaymentsRescanReply is used to reply to the UserPaymentsRescan command.
   852  // Returns the credits that were created by the rescan.
   853  type UserPaymentsRescanReply struct {
   854  	NewCredits []ProposalCredit `json:"newcredits"`
   855  }
   856  
   857  // NewProposal attempts to submit a new proposal.
   858  //
   859  // Metadata is required to include a ProposalMetadata for all proposal
   860  // submissions.
   861  //
   862  // Signature is the signature of the proposal merkle root. The merkle root
   863  // contains the ordered files and metadata digests. The file digests are first
   864  // in the ordering.
   865  //
   866  // This request is NO LONGER SUPPORTED.
   867  type NewProposal struct {
   868  	Files     []File     `json:"files"`     // Proposal files
   869  	Metadata  []Metadata `json:"metadata"`  // User specified metadata
   870  	PublicKey string     `json:"publickey"` // Key used for signature.
   871  	Signature string     `json:"signature"` // Signature of merkle root
   872  }
   873  
   874  // NewProposalReply is used to reply to the NewProposal command
   875  //
   876  // This request is NO LONGER SUPPORTED.
   877  type NewProposalReply struct {
   878  	CensorshipRecord CensorshipRecord `json:"censorshiprecord"`
   879  }
   880  
   881  // ProposalsDetails is used to retrieve a proposal by it's token
   882  // and by the proposal version (optional). If the version isn't specified
   883  // the latest proposal version will be returned by default. Returns only
   884  // vetted proposals.
   885  //
   886  // This request has been DEPRECATED.
   887  type ProposalsDetails struct {
   888  	Token   string `json:"token"`             // Censorship token
   889  	Version string `json:"version,omitempty"` // Proposal version
   890  }
   891  
   892  // ProposalDetailsReply is used to reply to a proposal details command.
   893  //
   894  // This request has been DEPRECATED.
   895  type ProposalDetailsReply struct {
   896  	Proposal ProposalRecord `json:"proposal"`
   897  }
   898  
   899  // BatchProposals is used to request the proposal details for each of the
   900  // provided censorship tokens. The returned proposals do not include the
   901  // proposal files. Returns only vetted proposals.
   902  //
   903  // This request has been DEPRECATED.
   904  type BatchProposals struct {
   905  	Tokens []string `json:"tokens"` // Censorship tokens
   906  }
   907  
   908  // BatchProposalsReply is used to reply to a BatchProposals command.
   909  //
   910  // This request has been DEPRECATED.
   911  type BatchProposalsReply struct {
   912  	Proposals []ProposalRecord `json:"proposals"`
   913  }
   914  
   915  // BatchVoteSummary is used to request the VoteSummary for the each of the
   916  // provided censorship tokens.
   917  //
   918  // This request has been DEPRECATED.
   919  type BatchVoteSummary struct {
   920  	Tokens []string `json:"tokens"` // Censorship tokens
   921  }
   922  
   923  // BatchVoteSummaryReply is used to reply to a BatchVoteSummary command.
   924  //
   925  // This request has been DEPRECATED.
   926  type BatchVoteSummaryReply struct {
   927  	BestBlock uint64                 `json:"bestblock"` // Current block height
   928  	Summaries map[string]VoteSummary `json:"summaries"` // [token]VoteSummary
   929  }
   930  
   931  // SetProposalStatus is used to change the status of a proposal. Only admins
   932  // have the ability to change a proposal's status. Some status changes, such
   933  // as censoring a proposal, require the StatusChangeMessage to be populated
   934  // with the reason for the status change.
   935  //
   936  // This request is NO LONGER SUPPORTED.
   937  type SetProposalStatus struct {
   938  	Token               string      `json:"token"`                         // Proposal token
   939  	ProposalStatus      PropStatusT `json:"proposalstatus"`                // New status
   940  	StatusChangeMessage string      `json:"statuschangemessage,omitempty"` // Message associated to the status change
   941  	Signature           string      `json:"signature"`                     // Signature of Token+string(ProposalStatus)+StatusChangeMessage
   942  	PublicKey           string      `json:"publickey"`                     // Signature pubkey
   943  }
   944  
   945  // SetProposalStatusReply is used to reply to a SetProposalStatus command.
   946  //
   947  // This request is NO LONGER SUPPORTED.
   948  type SetProposalStatusReply struct {
   949  	Proposal ProposalRecord `json:"proposal"`
   950  }
   951  
   952  // GetAllVetted retrieves vetted proposals; the maximum number returned is
   953  // dictated by ProposalListPageSize.
   954  //
   955  // This command optionally takes either a Before or After parameter, which
   956  // specify a proposal's censorship token. If After is specified, the "page"
   957  // returned starts after the provided censorship token, when sorted in reverse
   958  // chronological order. A simplified example is shown below.
   959  //
   960  // input: [5,4,3,2,1]
   961  // after=3
   962  // output: [2,1]
   963  //
   964  // If Before is specified, the "page" returned starts before the provided
   965  // proposal censorship token, when sorted in reverse chronological order.
   966  //
   967  // This request is DEPRECATED. The Before and After arguments are NO LONGER
   968  // SUPPORTED. This route will only return a single page of vetted tokens. The
   969  // records API InventoryOrdered command should be used instead.
   970  type GetAllVetted struct {
   971  	Before string `schema:"before"`
   972  	After  string `schema:"after"`
   973  }
   974  
   975  // GetAllVettedReply is used to reply with a list of vetted proposals.
   976  //
   977  // This request is DEPRECATED.
   978  type GetAllVettedReply struct {
   979  	Proposals []ProposalRecord `json:"proposals"`
   980  }
   981  
   982  // Policy returns a struct with various maxima.  The client shall observe the
   983  // maxima.
   984  type Policy struct{}
   985  
   986  // PolicyReply is used to reply to the policy command. It returns
   987  // the file upload restrictions set for Politeia.
   988  type PolicyReply struct {
   989  	MinPasswordLength          uint     `json:"minpasswordlength"`
   990  	MinUsernameLength          uint     `json:"minusernamelength"`
   991  	MaxUsernameLength          uint     `json:"maxusernamelength"`
   992  	UsernameSupportedChars     []string `json:"usernamesupportedchars"`
   993  	ProposalListPageSize       uint     `json:"proposallistpagesize"`
   994  	UserListPageSize           uint     `json:"userlistpagesize"`
   995  	MaxImages                  uint     `json:"maximages"`
   996  	MaxImageSize               uint     `json:"maximagesize"`
   997  	MaxMDs                     uint     `json:"maxmds"`
   998  	MaxMDSize                  uint     `json:"maxmdsize"`
   999  	ValidMIMETypes             []string `json:"validmimetypes"`
  1000  	MinProposalNameLength      uint     `json:"minproposalnamelength"`
  1001  	MaxProposalNameLength      uint     `json:"maxproposalnamelength"`
  1002  	PaywallEnabled             bool     `json:"paywallenabled"`
  1003  	ProposalNameSupportedChars []string `json:"proposalnamesupportedchars"`
  1004  	MaxCommentLength           uint     `json:"maxcommentlength"`
  1005  	BackendPublicKey           string   `json:"backendpublickey"`
  1006  	TokenPrefixLength          int      `json:"tokenprefixlength"`
  1007  	BuildInformation           []string `json:"buildinformation"`
  1008  	IndexFilename              string   `json:"indexfilename"`
  1009  	MinLinkByPeriod            int64    `json:"minlinkbyperiod"`
  1010  	MaxLinkByPeriod            int64    `json:"maxlinkbyperiod"`
  1011  	MinVoteDuration            uint32   `json:"minvoteduration"`
  1012  	MaxVoteDuration            uint32   `json:"maxvoteduration"`
  1013  	PaywallConfirmations       uint64   `json:"paywallconfirmations"`
  1014  }
  1015  
  1016  // VoteOption describes a single vote option.
  1017  type VoteOption struct {
  1018  	Id          string `json:"id"`          // Single unique word identifying vote (e.g. yes)
  1019  	Description string `json:"description"` // Longer description of the vote.
  1020  	Bits        uint64 `json:"bits"`        // Bits used for this option
  1021  }
  1022  
  1023  // Vote represents the vote options for vote that is identified by its token.
  1024  type Vote struct {
  1025  	Token            string       `json:"token"`            // Token that identifies vote
  1026  	Mask             uint64       `json:"mask"`             // Valid votebits
  1027  	Duration         uint32       `json:"duration"`         // Duration in blocks
  1028  	QuorumPercentage uint32       `json:"quorumpercentage"` // Percent of eligible votes required for quorum
  1029  	PassPercentage   uint32       `json:"passpercentage"`   // Percent of total votes required to pass
  1030  	Options          []VoteOption `json:"options"`          // Vote options
  1031  }
  1032  
  1033  // ActiveVote obtains all proposals that have active votes.
  1034  //
  1035  // This request is NO LONGER SUPPORTED.
  1036  type ActiveVote struct{}
  1037  
  1038  // ProposalVoteTuple is the proposal, vote and vote details.
  1039  type ProposalVoteTuple struct {
  1040  	Proposal       ProposalRecord `json:"proposal"`       // Proposal
  1041  	StartVote      StartVote      `json:"startvote"`      // Vote bits and mask
  1042  	StartVoteReply StartVoteReply `json:"startvotereply"` // Eligible tickets and other details
  1043  }
  1044  
  1045  // ActiveVoteReply returns all proposals that have active votes.
  1046  //
  1047  // This request is DEPRECATED.
  1048  type ActiveVoteReply struct {
  1049  	Votes []ProposalVoteTuple `json:"votes"` // Active votes
  1050  }
  1051  
  1052  // plugin commands
  1053  
  1054  // AuthorizeVote is used to indicate that a proposal has been finalized and
  1055  // is ready to be voted on.  The signature and public key are from the
  1056  // proposal author.  The author can revoke a previously sent vote authorization
  1057  // by setting the Action field to revoke.
  1058  //
  1059  // This request is NO LONGER SUPPORTED.
  1060  type AuthorizeVote struct {
  1061  	Action    string `json:"action"`    // Authorize or revoke
  1062  	Token     string `json:"token"`     // Proposal token
  1063  	Signature string `json:"signature"` // Signature of token+version+action
  1064  	PublicKey string `json:"publickey"` // Key used for signature
  1065  }
  1066  
  1067  // AuthorizeVoteReply returns a receipt if the action was successfully
  1068  // executed.
  1069  //
  1070  // This request is NO LONGER SUPPORTED.
  1071  type AuthorizeVoteReply struct {
  1072  	Action  string `json:"action"`  // Authorize or revoke
  1073  	Receipt string `json:"receipt"` // Server signature of client signature
  1074  }
  1075  
  1076  // StartVote starts the voting process for a proposal.
  1077  //
  1078  // This request is NO LONGER SUPPORTED.
  1079  type StartVote struct {
  1080  	PublicKey string `json:"publickey"` // Key used for signature.
  1081  	Vote      Vote   `json:"vote"`      // Vote
  1082  	Signature string `json:"signature"` // Signature of Votehash
  1083  }
  1084  
  1085  // StartVoteReply returns the eligible ticket pool.
  1086  //
  1087  // This request is NO LONGER SUPPORTED.
  1088  type StartVoteReply struct {
  1089  	StartBlockHeight string   `json:"startblockheight"` // Block height
  1090  	StartBlockHash   string   `json:"startblockhash"`   // Block hash
  1091  	EndHeight        string   `json:"endheight"`        // Height of vote end
  1092  	EligibleTickets  []string `json:"eligibletickets"`  // Valid voting tickets
  1093  }
  1094  
  1095  // CastVote is a signed vote.
  1096  type CastVote struct {
  1097  	Token     string `json:"token"`     // Proposal ID
  1098  	Ticket    string `json:"ticket"`    // Ticket ID
  1099  	VoteBit   string `json:"votebit"`   // Vote bit that was selected, this is encode in hex
  1100  	Signature string `json:"signature"` // Signature of Token+Ticket+VoteBit
  1101  }
  1102  
  1103  // CastVoteReply is the answer to the CastVote command. The Error and
  1104  // ErrorStatus fields will only be populated if something went wrong while
  1105  // attempting to cast the vote.
  1106  type CastVoteReply struct {
  1107  	ClientSignature string                    `json:"clientsignature"`       // Signature that was sent in
  1108  	Signature       string                    `json:"signature"`             // Signature of the ClientSignature
  1109  	Error           string                    `json:"error"`                 // Error status message
  1110  	ErrorStatus     decredplugin.ErrorStatusT `json:"errorstatus,omitempty"` // Error status code
  1111  }
  1112  
  1113  // Ballot is a batch of votes that are sent to the server.
  1114  //
  1115  // This request has been DEPRECATED.
  1116  type Ballot struct {
  1117  	Votes []CastVote `json:"votes"`
  1118  }
  1119  
  1120  // BallotReply is a reply to a batched list of votes.
  1121  //
  1122  // This request has been DEPRECATED.
  1123  type BallotReply struct {
  1124  	Receipts []CastVoteReply `json:"receipts"`
  1125  }
  1126  
  1127  // VoteResults retrieves a single proposal vote results from the server. If the
  1128  // voting period has not yet started for the given proposal a reply is returned
  1129  // with all fields set to their zero value.
  1130  //
  1131  // This request has been DEPRECATED.
  1132  type VoteResults struct{}
  1133  
  1134  // VoteResultsReply returns the original proposal vote and the associated cast
  1135  // votes.
  1136  //
  1137  // This request has been DEPRECATED.
  1138  type VoteResultsReply struct {
  1139  	StartVote      StartVote      `json:"startvote"`      // Original vote
  1140  	CastVotes      []CastVote     `json:"castvotes"`      // Vote results
  1141  	StartVoteReply StartVoteReply `json:"startvotereply"` // Eligible tickets and other details
  1142  }
  1143  
  1144  // Comment is the structure that describes the full server side content.  It
  1145  // includes server side meta-data as well.
  1146  type Comment struct {
  1147  	// Data generated by client
  1148  	Token     string `json:"token"`     // Censorship token
  1149  	ParentID  string `json:"parentid"`  // Parent comment ID
  1150  	Comment   string `json:"comment"`   // Comment
  1151  	Signature string `json:"signature"` // Client Signature of Token+ParentID+Comment
  1152  	PublicKey string `json:"publickey"` // Pubkey used for Signature
  1153  
  1154  	// Metadata generated by decred plugin
  1155  	CommentID   string `json:"commentid"`           // Comment ID
  1156  	Receipt     string `json:"receipt"`             // Server signature of the client Signature
  1157  	Timestamp   int64  `json:"timestamp"`           // Received UNIX timestamp
  1158  	ResultVotes int64  `json:"resultvotes"`         // Vote score
  1159  	Upvotes     uint64 `json:"upvotes,omitempty"`   // Pro votes
  1160  	Downvotes   uint64 `json:"downvotes,omitempty"` // Contra votes
  1161  	Censored    bool   `json:"censored"`            // Has this comment been censored
  1162  
  1163  	// Metadata generated by www
  1164  	UserID   string `json:"userid"`   // User id
  1165  	Username string `json:"username"` // Username
  1166  }
  1167  
  1168  // NewComment sends a comment from a user to a specific proposal.  Note that
  1169  // the user is implied by the session.  A parent ID of 0 indicates that the
  1170  // comment does not have a parent.  A non-zero parent ID indicates that the
  1171  // comment is a reply to an existing comment.
  1172  //
  1173  // This request is NO LONGER SUPPORTED.
  1174  type NewComment struct {
  1175  	Token     string `json:"token"`     // Censorship token
  1176  	ParentID  string `json:"parentid"`  // Parent comment ID
  1177  	Comment   string `json:"comment"`   // Comment
  1178  	Signature string `json:"signature"` // Client Signature of Token+ParentID+Comment
  1179  	PublicKey string `json:"publickey"` // Pubkey used for Signature
  1180  }
  1181  
  1182  // NewCommentReply returns the site generated Comment ID or an error if
  1183  // something went wrong.
  1184  //
  1185  // This request is NO LONGER SUPPORTED.
  1186  type NewCommentReply struct {
  1187  	Comment Comment `json:"comment"` // Comment + receipt
  1188  }
  1189  
  1190  // GetComments retrieve all comments for a given proposal.
  1191  //
  1192  // This request is NO LONGER SUPPORTED.
  1193  type GetComments struct {
  1194  	Token string `json:"token"` // Censorship token
  1195  }
  1196  
  1197  // GetCommentsReply returns the provided number of comments.
  1198  //
  1199  // This request is NO LONGER SUPPORTED.
  1200  type GetCommentsReply struct {
  1201  	Comments   []Comment `json:"comments"`             // Comments
  1202  	AccessTime int64     `json:"accesstime,omitempty"` // User Access Time
  1203  }
  1204  
  1205  const (
  1206  	// VoteActionDown used when user votes down a comment
  1207  	VoteActionDown = "-1"
  1208  	// VoteActionUp used when user votes up a comment
  1209  	VoteActionUp = "1"
  1210  )
  1211  
  1212  // LikeComment allows a user to up or down vote a comment.
  1213  //
  1214  // This request is NO LONGER SUPPORTED.
  1215  type LikeComment struct {
  1216  	Token     string `json:"token"`     // Censorship token
  1217  	CommentID string `json:"commentid"` // Comment ID
  1218  	Action    string `json:"action"`    // VoteActionUp or VoteActionDown above
  1219  	Signature string `json:"signature"` // Client Signature of Token+CommentID+Action
  1220  	PublicKey string `json:"publickey"` // Pubkey used for Signature
  1221  }
  1222  
  1223  // LikeCommentReply returns the current up/down vote result.
  1224  //
  1225  // This request is NO LONGER SUPPORTED.
  1226  type LikeCommentReply struct {
  1227  	// XXX we probably need a sequence numkber or something here and some sort of rate limit
  1228  	Total     uint64 `json:"total"`               // Total number of up and down votes
  1229  	Result    int64  `json:"result"`              // Current tally of likes, can be negative
  1230  	Upvotes   uint64 `json:"upvotes,omitempty"`   // Current tally of pro votes
  1231  	Downvotes uint64 `json:"downvotes,omitempty"` // Current tally of contra votes
  1232  	Receipt   string `json:"receipt"`             // Server signature of client signature
  1233  	Error     string `json:"error,omitempty"`     // Error if something went wrong during liking a comment
  1234  }
  1235  
  1236  // CensorComment allows an admin to censor a comment. The signature and
  1237  // public key are from the admin that censored this comment.
  1238  //
  1239  // This request is NO LONGER SUPPORTED.
  1240  type CensorComment struct {
  1241  	Token     string `json:"token"`     // Proposal censorship token
  1242  	CommentID string `json:"commentid"` // Comment ID
  1243  	Reason    string `json:"reason"`    // Reason the comment was censored
  1244  	Signature string `json:"signature"` // Client signature of Token+CommentID+Reason
  1245  	PublicKey string `json:"publickey"` // Pubkey used for signature
  1246  }
  1247  
  1248  // CensorCommentReply returns a receipt if the comment was successfully
  1249  // censored.
  1250  //
  1251  // This request is NO LONGER SUPPORTED.
  1252  type CensorCommentReply struct {
  1253  	Receipt string `json:"receipt"` // Server signature of client signature
  1254  }
  1255  
  1256  // CommentLike describes the voting action an user has given
  1257  // to a comment (e.g: up or down vote)
  1258  type CommentLike struct {
  1259  	Action    string `json:"action"`    // VoteActionUp or VoteActionDown above
  1260  	CommentID string `json:"commentid"` // Comment ID
  1261  	Token     string `json:"token"`     // Censorship token
  1262  }
  1263  
  1264  // UserCommentsLikes is a command to fetch all user vote actions
  1265  // on the comments of a given proposal
  1266  //
  1267  // This request is NO LONGER SUPPORTED.
  1268  type UserCommentsLikes struct{}
  1269  
  1270  // UserCommentsLikesReply is a reply with all user vote actions
  1271  // for the comments of a given proposal
  1272  //
  1273  // This request is NO LONGER SUPPORTED.
  1274  type UserCommentsLikesReply struct {
  1275  	CommentsLikes []CommentLike `json:"commentslikes"`
  1276  }
  1277  
  1278  // VoteOptionResult is a structure that describes a VotingOption along with the
  1279  // number of votes it has received
  1280  type VoteOptionResult struct {
  1281  	Option        VoteOption `json:"option"`        // Vote Option
  1282  	VotesReceived uint64     `json:"votesreceived"` // Number of votes received by the option
  1283  }
  1284  
  1285  // VoteStatus is a command to fetch the the current vote status for a single
  1286  // public proposal
  1287  //
  1288  // This request is DEPRECATED.
  1289  type VoteStatus struct{}
  1290  
  1291  // VoteStatusReply describes the vote status for a given proposal
  1292  //
  1293  // This request is DEPRECATED.
  1294  type VoteStatusReply struct {
  1295  	Token              string             `json:"token"`              // Censorship token
  1296  	Status             PropVoteStatusT    `json:"status"`             // Vote status (finished, started, etc)
  1297  	TotalVotes         uint64             `json:"totalvotes"`         // Proposal's total number of votes
  1298  	OptionsResult      []VoteOptionResult `json:"optionsresult"`      // VoteOptionResult for each option
  1299  	EndHeight          string             `json:"endheight"`          // Vote end height
  1300  	BestBlock          string             `json:"bestblock"`          // Current best block height
  1301  	NumOfEligibleVotes int                `json:"numofeligiblevotes"` // Total number of eligible votes
  1302  	QuorumPercentage   uint32             `json:"quorumpercentage"`   // Percent of eligible votes required for quorum
  1303  	PassPercentage     uint32             `json:"passpercentage"`     // Percent of total votes required to pass
  1304  }
  1305  
  1306  // GetAllVoteStatus attempts to fetch the vote status of all public propsals
  1307  //
  1308  // This request is DEPRECATED.
  1309  type GetAllVoteStatus struct{}
  1310  
  1311  // GetAllVoteStatusReply returns the vote status of all public proposals
  1312  //
  1313  // This request is DEPRECATED.
  1314  type GetAllVoteStatusReply struct {
  1315  	VotesStatus []VoteStatusReply `json:"votesstatus"` // Vote status of all public proposals
  1316  }
  1317  
  1318  // UserDetails fetches a user's details by their id.
  1319  type UserDetails struct {
  1320  	UserID string `json:"userid"` // User id
  1321  }
  1322  
  1323  // UserDetailsReply returns a user's details.
  1324  type UserDetailsReply struct {
  1325  	User User `json:"user"`
  1326  }
  1327  
  1328  // ManageUser performs the given action on a user.
  1329  type ManageUser struct {
  1330  	UserID string            `json:"userid"` // User id
  1331  	Action UserManageActionT `json:"action"` // Action
  1332  	Reason string            `json:"reason"` // Admin reason for action
  1333  }
  1334  
  1335  // ManageUserReply is the reply for the ManageUserReply command.
  1336  type ManageUserReply struct{}
  1337  
  1338  // EditUser edits a user's preferences.
  1339  type EditUser struct {
  1340  	EmailNotifications *uint64 `json:"emailnotifications"` // Notify the user via emails
  1341  }
  1342  
  1343  // EditUserReply is the reply for the EditUser command.
  1344  type EditUserReply struct{}
  1345  
  1346  // User represents an individual user.
  1347  type User struct {
  1348  	ID                              string         `json:"id"`
  1349  	Email                           string         `json:"email"`
  1350  	Username                        string         `json:"username"`
  1351  	Admin                           bool           `json:"isadmin"`
  1352  	NewUserPaywallAddress           string         `json:"newuserpaywalladdress"`
  1353  	NewUserPaywallAmount            uint64         `json:"newuserpaywallamount"`
  1354  	NewUserPaywallTx                string         `json:"newuserpaywalltx"`
  1355  	NewUserPaywallTxNotBefore       int64          `json:"newuserpaywalltxnotbefore"`
  1356  	NewUserPaywallPollExpiry        int64          `json:"newuserpaywallpollexpiry"`
  1357  	NewUserVerificationToken        []byte         `json:"newuserverificationtoken"`
  1358  	NewUserVerificationExpiry       int64          `json:"newuserverificationexpiry"`
  1359  	UpdateKeyVerificationToken      []byte         `json:"updatekeyverificationtoken"`
  1360  	UpdateKeyVerificationExpiry     int64          `json:"updatekeyverificationexpiry"`
  1361  	ResetPasswordVerificationToken  []byte         `json:"resetpasswordverificationtoken"`
  1362  	ResetPasswordVerificationExpiry int64          `json:"resetpasswordverificationexpiry"`
  1363  	LastLoginTime                   int64          `json:"lastlogintime"`
  1364  	FailedLoginAttempts             uint64         `json:"failedloginattempts"`
  1365  	Deactivated                     bool           `json:"isdeactivated"`
  1366  	Locked                          bool           `json:"islocked"`
  1367  	Identities                      []UserIdentity `json:"identities"`
  1368  	ProposalCredits                 uint64         `json:"proposalcredits"`
  1369  	EmailNotifications              uint64         `json:"emailnotifications"` // Notify the user via emails
  1370  }
  1371  
  1372  // UserIdentity represents a user's unique identity.
  1373  type UserIdentity struct {
  1374  	Pubkey string `json:"pubkey"`
  1375  	Active bool   `json:"isactive"`
  1376  }
  1377  
  1378  // EditProposal attempts to edit a proposal
  1379  //
  1380  // Metadata is required to include a ProposalMetadata for all proposal
  1381  // submissions.
  1382  //
  1383  // Signature is the signature of the proposal merkle root. The merkle root
  1384  // contains the ordered files and metadata digests. The file digests are first
  1385  // in the ordering.
  1386  //
  1387  // This request is NO LONGER SUPPORTED.
  1388  type EditProposal struct {
  1389  	Token     string     `json:"token"`
  1390  	Files     []File     `json:"files"`
  1391  	Metadata  []Metadata `json:"metadata"`
  1392  	PublicKey string     `json:"publickey"`
  1393  	Signature string     `json:"signature"`
  1394  }
  1395  
  1396  // EditProposalReply is used to reply to the EditProposal command
  1397  //
  1398  // This request is NO LONGER SUPPORTED.
  1399  type EditProposalReply struct {
  1400  	Proposal ProposalRecord `json:"proposal"`
  1401  }
  1402  
  1403  // TokenInventory retrieves the censorship record tokens of all proposals in
  1404  // the inventory, categorized by stage of the voting process.
  1405  //
  1406  // This request has been DEPRECATED.
  1407  type TokenInventory struct{}
  1408  
  1409  // TokenInventoryReply is used to reply to the TokenInventory command and
  1410  // returns the tokens of all proposals in the inventory. The tokens are
  1411  // categorized by stage of the voting process and sorted according to the
  1412  // rules listed below. Unvetted proposal tokens are only returned to admins.
  1413  //
  1414  // Sorted by record timestamp in descending order:
  1415  // Pre, Abandonded, Unreviewed, Censored
  1416  //
  1417  // Sorted by voting period end block height in descending order:
  1418  // Active, Approved, Rejected
  1419  //
  1420  // This request has been DEPRECATED.
  1421  type TokenInventoryReply struct {
  1422  	// Vetted
  1423  	Pre       []string `json:"pre"`       // Tokens of all props that are pre-vote
  1424  	Active    []string `json:"active"`    // Tokens of all props with an active voting period
  1425  	Approved  []string `json:"approved"`  // Tokens of all props that have been approved by a vote
  1426  	Rejected  []string `json:"rejected"`  // Tokens of all props that have been rejected by a vote
  1427  	Abandoned []string `json:"abandoned"` // Tokens of all props that have been abandoned
  1428  
  1429  	// Unvetted
  1430  	Unreviewed []string `json:"unreviewed"` // Tokens of all unreviewed props
  1431  	Censored   []string `json:"censored"`   // Tokens of all censored props
  1432  }
  1433  
  1434  // Websocket commands
  1435  const (
  1436  	WSCError     = "error"
  1437  	WSCPing      = "ping"
  1438  	WSCSubscribe = "subscribe"
  1439  )
  1440  
  1441  // WSHeader is required to be sent before any other command. The point is to
  1442  // make decoding easier without too much magic. E.g. a ping command
  1443  // WSHeader<ping>WSPing<timestamp>
  1444  type WSHeader struct {
  1445  	Command string `json:"command"`      // Following command
  1446  	ID      string `json:"id,omitempty"` // Client setable client id
  1447  }
  1448  
  1449  // WSError is a generic websocket error. It returns in ID the client side id
  1450  // and all errors it encountered in Errors.
  1451  type WSError struct {
  1452  	Command string   `json:"command,omitempty"` // Command from client
  1453  	ID      string   `json:"id,omitempty"`      // Client set client id
  1454  	Errors  []string `json:"errors"`            // Errors returned by server
  1455  }
  1456  
  1457  // WSSubscribe is a client side push to tell the server what RPCs it wishes to
  1458  // subscribe to.
  1459  type WSSubscribe struct {
  1460  	RPCS []string `json:"rpcs"` // Commands that the client wants to subscribe to
  1461  }
  1462  
  1463  // WSPing is a server side push to the client to see if it is still alive.
  1464  type WSPing struct {
  1465  	Timestamp int64 `json:"timestamp"` // Server side timestamp
  1466  }
  1467  
  1468  // SetTOTP attempts to set a TOTP key for the chosen TOTP type (Basic/UFI2 etc).
  1469  // When the user issues this request, the server generates a new key pair for
  1470  // them and returns the key/image that will allow them to save it to their
  1471  // TOTP app of choice.  The server saves the generated TOTP secret in the
  1472  // userdb user information blob.
  1473  // If the user already has a TOTP set, they must also add a code generated from
  1474  // the currently set secret.
  1475  type SetTOTP struct {
  1476  	Type TOTPMethodT `json:"type"`
  1477  	Code string      `json:"code"`
  1478  }
  1479  
  1480  // SetTOTPReply returns the generated key and image that are used to add
  1481  // the key pair to the TOTP app of choice.
  1482  type SetTOTPReply struct {
  1483  	Key   string `json:"key"`
  1484  	Image string `json:"image"` // Base64 encoded PNG
  1485  }
  1486  
  1487  // VerifyTOTP must be used by a user before their TOTP is ready to use.  Once
  1488  // receiving the key/image from SetTOTP they can add it to their TOTP app.
  1489  // Upon adding it to their TOTP app, they can generate new TOTP codes at will.
  1490  type VerifyTOTP struct {
  1491  	Code string `json:"code"`
  1492  }
  1493  
  1494  // VerifyTOTPReply will return an empty reply if it was successfully confirmed
  1495  // with no errors.
  1496  type VerifyTOTPReply struct {
  1497  }