package errors_test import ( stderrors "errors" "github.com/phayes/errors" "testing" ) var ( Strger = stringer{} ErrFoo = errors.New("Fooey") ErrBar = errors.New("Barf") ErrStd = stderrors.New("This is a stanard error from the standard library.") ErrStd2 = stderrors.New("Another standard error from the standard library.") ErrFmt = errors.Newf("%s", Strger) ) type stringer struct{} func (s stringer) String() string { return "stringer out" } func TestFooWrappingStdError(t *testing.T) { err := FooWrappingStdError() if !errors.Equal(err, ErrFoo) || !errors.Equal(ErrFoo, err) { t.Error("Foo not determined to be equal to an errors.Error based on itself") return } if !errors.IsA(err, ErrStd) { t.Error("Error that wraps standard library not determined to contain the standard")
import ( "bytes" "github.com/phayes/errors" "regexp" "time" ) const ( MaxElectionIDSize = 32 // Votes are stored in a postgres table named votes_<electon-id> so we need to limit the election ID size. ) var ( ValidElectionID = regexp.MustCompile(`^[0-9a-z_]+$`) // Regex for valid characters. We use this ID to construct the name of a table, so we need to limit allowed characters. ErrElectionIDTooBig = errors.Newf("Invalid ElectionID. Too many characters. Maximum is %i characters", MaxElectionIDSize) ErrEelectionInvalid = errors.New("Cannot parse election. Invalid format") ErrElectionIDInvalid = errors.New("ElectionID contains illigal characters. Only lowercase alpha-numeric characters allowed") ErrElectionStartInvalid = errors.New("Invalid election start time") ErrElectionEndInvalid = errors.New("Invalid election end time") ErrElectionInvalidTagSet = errors.New("Cannot parse TagSet in election") ErrElectionInvalidKey = errors.New("Cannot parse PublicKey in election") ErrElectionInvalidSig = errors.New("Cannot parse Signature in election") ErrEletionSigNotFound = errors.New("Could not verify election signature: Signature does not exist") ) type Election struct { ElectionID string Start time.Time // Start date & time (RFC-1123 format with a numeric timezone) End time.Time // End date & time (RFC-1123 format with a numeric timezone) TagSet // Optional key-value tag-set
// Votes are an ordered list of choices. You may change MaxVoteOptions to set the maximum number of choices. // For a standard first-past-the-post election this would be set to 1 const MaxVoteOptions = 64 // You may set the maximum number of bytes per vote-option here. const MaxVoteBytes = 256 // The total maximum vote-size is options*chracters + seperator characters var maxVoteSize = (MaxVoteOptions * MaxVoteBytes) + MaxVoteOptions // A Vote is an ordered list of choices as strings // It's up to the counting / tallying applications to assign meaning to these strings type Vote []string var ( ErrVoteTooBig = errors.Newf("Vote has too many bytes. A vote may have a maximum of %i characters, including seperators", maxVoteSize) ErrVoteTooManyOptions = errors.Newf("Vote has too many options") ErrVoteOptionTooBig = errors.Newf("Vote option has too many characters") ) // Given a raw slice of bytes, construct a Vote // @@TODO: A custom splitter that checks for errors as it goes might be faster than splitting the whole thing and then looping the results to check for errors. func NewVote(rawVote []byte) (Vote, error) { if len(rawVote) > maxVoteSize { return Vote{}, ErrVoteTooBig } vote := Vote(strings.Split(string(rawVote), "\n")) if len(vote) > MaxVoteOptions { return Vote{}, errors.Wrapf(ErrVoteTooManyOptions, "A vote may have a maximum of %i option lines", MaxVoteOptions) } for i, voteItem := range vote {
) const ( MaxTagKeySize = 64 MaxTagValueSize = 256 ) type Tag struct { Key []byte Value []byte } type TagSet []Tag var ( ErrTagKeyTooBig = errors.Newf("Tag key too long. Maximum tag key size is $i characters", MaxTagKeySize) ErrTagValTooBig = errors.Newf("Tag value too long. Maximum tag value size is $i characters", MaxTagValueSize) ErrTagMalformed = errors.New("Malformed tag") ErrTagKeyMalformed = errors.New("Malformed tag key") //@@TODO: Actually put some limits around allowed-charcters for keys ErrTagKeyNotFound = errors.New("Missing tag key") ErrTagValNotFound = errors.New("Missing tag value") ) func NewTag(rawTag []byte) (Tag, error) { parts := bytes.SplitN(rawTag, []byte("="), 2) if len(parts) != 2 { return Tag{}, ErrTagMalformed } if len(parts[0]) == 0 { return Tag{}, ErrTagKeyNotFound }
"encoding/base64" "encoding/hex" "github.com/phayes/errors" "regexp" ) const ( MaxBallotIDSize = 128 ) var ( // maxBallotSize: election-id (max 128 bytes) + BallotID + Vote + (64 tags) + signature + line-seperators MaxBallotSize = MaxElectionIDSize + MaxBallotIDSize + (maxVoteSize) + (64 * (MaxTagKeySize + MaxTagValueSize + 1)) + base64.StdEncoding.EncodedLen(1024) + (4*2 + 64 + 64) ValidBallotID = regexp.MustCompile(`^[0-9a-zA-Z\-\.\[\]_~:/?#@!$&'()*+,;=]+$`) // Regex for valid characters. More or less the same as RFC 3986, sec 2. ErrBallotTooBig = errors.Newf("This ballot is too big. Maximum ballot size is %i bytes", MaxBallotSize) ErrBallotIDTooBig = errors.Newf("Ballot ID is too big. Maximum ballot-id size is %i characters", MaxBallotIDSize) ErrBallotInvalid = errors.New("Invalid ballot format") ErrBallotIDInvalid = errors.New("Ballot ID contains illigal characters. Valid characters are as per RFC 3986, sec 2: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=") ErrBallotInvalidVote = errors.New("Cannot parse Cote in ballot") ErrBallotInvalidTagSet = errors.New("Cannot parse TagSet in ballot") ErrBallotInvalidSig = errors.New("Cannot parse ballot Signature") ErrBallotSigNotFound = errors.New("Could not verify ballot signature: Signature does not exist") ) type Ballot struct { ElectionID string BallotID string // Random user-selected string. Valid characters are as per RFC 3986, sec 2: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;= Vote // Ordered list of choice TagSet // Arbitrary key-value store Signature // Crypto signature for the ballot (signed by ballot-clerk server)