// Given a set of PEM Block bytes (for example from a file that contains user data in PEM format), get a UserSet of multiple users func NewUserSet(PEMBlockBytes []byte) (UserSet, error) { var userset UserSet for { var PEMBlock *pem.Block PEMBlock, PEMBlockBytes = pem.Decode(PEMBlockBytes) if PEMBlock == nil { PEMBlockBytes = []byte(strings.TrimSpace(string(PEMBlockBytes))) // Trim remaining whitespace if len(PEMBlockBytes) == 0 { break // We're done } else { // There's still data to be processed, but we can't make sense of it return nil, ErrUserExtraData } } if PEMBlock.Type != "PUBLIC KEY" { return nil, errors.New("Found unexpected " + PEMBlock.Type + " when processing PEM Blocks") } user, err := NewUserFromBlock(PEMBlock) if err != nil { return nil, err } err = userset.Add(user) if err != nil { return nil, err } } return userset, nil }
// The default URL Checker constrains the crawler to the domains of the seed URLs func defaultCheckURL(crawler *Crawler, checkurl string) error { parsedURL, err := url.Parse(checkurl) if err != nil { return err } for _, seedURL := range crawler.URLs { parsedSeed, err := url.Parse(seedURL) if err != nil { return err } if parsedSeed.Host == parsedURL.Host { return nil } } return errors.New("URL not in approved domain") }
func GetDBSize(dbname string) (size string, err error) { info, err := os.Stat(DataDir + "/" + dbname) if err != nil { return "", err } if !info.IsDir() { return "", ErrInvalidDir } cmd := exec.Command("du", DataDir+"/"+dbname, "-s", "-k") output, err := cmd.CombinedOutput() if err != nil { return "", errors.Append(err, errors.New(string(output))) } size = strings.TrimSpace(strings.Split(string(output), "\t")[0]) return size, nil }
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")
"crypto/x509" "encoding/pem" "github.com/phayes/errors" "strings" ) type User struct { PublicKey PublicKey // base64 encoded PEM formatted public-key Perms []string // List of permissions. @@TODO: Maybe this shouldn't be a string but should be an enumeration Properties map[string]string // List of all key->value properties } type UserSet []User var ( ErrUserInvalidPEM = errors.New("Could not decode PEM Block for user") ErrUserBlockNotFound = errors.New("Could not find PUBLIC KEY block for user") ErrUserPermsNotFound = errors.New("No permissions specified for user") ErrUserPermsInvalid = errors.New("Could not parse user permissions") ErrUserExtraData = errors.New("Could not parse PEM Blocks or extra data found that could not be parsed.") ErrUserSetUserExists = errors.New("Could not add User to UserSet. User already exists with the same public-key") ErrUserSetUserNotFound = errors.New("Could not find user") ) func NewUser(PEMBlockBytes []byte) (*User, error) { PEMBlock, _ := pem.Decode(PEMBlockBytes) if PEMBlock == nil { return nil, ErrUserInvalidPEM } return NewUserFromBlock(PEMBlock) }
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 PublicKey // The public key of the admin that created this election
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 } if len(parts[0]) > MaxTagKeySize { return Tag{}, ErrTagKeyTooBig
"crypto" "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" "encoding/hex" "encoding/pem" "fmt" "github.com/phayes/errors" ) // A DER encoded private key type PrivateKey []byte var ( ErrPrivatKeyInvalidPEM = errors.New("Could not decode Prviate Key PEM Block") ErrPrivatKeyWrongType = errors.New("Could not find RSA PRIVATE KEY block") ErrPrivatKeyGenerate = errors.New("Could not generate new PrivateKey") ErrPrivatKeyCryptoKey = errors.New("Could not create from rsa.CryptoKey from PrivateKey. Could not parse PrivateKey bytes") ErrPrivatKeySign = errors.New("PrivateKey could not sign bytes") ErrPrivateKeySHA256 = errors.New("Invalid SHA256 Hash checksum") ) // Create a new PrivateKey from a PEM Block bytes func NewPrivateKey(PEMBlockBytes []byte) (PrivateKey, error) { PEMBlock, _ := pem.Decode(PEMBlockBytes) if PEMBlock == nil { return nil, ErrPrivatKeyInvalidPEM } return NewPrivateKeyFromBlock(PEMBlock) }
import ( "flag" "fmt" "github.com/phayes/errors" "github.com/vaughan0/go-ini" "io/ioutil" "log" "os" "os/exec" "regexp" "strings" ) var ( ErrDataDir = errors.New("Could not determine mysql data directory") ErrInvalidDB = errors.New("Invalid database name") ErrInvalidDir = errors.New("Invalid database directory") ValidDBName = regexp.MustCompile("[0-9a-zA-Z$_]+") DataDir string ) func main() { flag.Parse() c, err := ini.LoadFile("/etc/my.cnf") if err != nil { // Syntax errors are OK because my.cnf contains weird syntax if _, ok := err.(ini.ErrSyntax); !ok { log.Fatal(err) }
package cryptoballot import ( "crypto" "crypto/rsa" "crypto/sha256" "encoding/base64" "github.com/phayes/errors" ) // An RSA signature. Raw bytes. type Signature []byte var ( ErrSignatureBase64 = errors.New("Invalid Signature. Could not read base64 encoded bytes") ErrSignatureTooShort = errors.New("Invalid Signature. Signature too short") ErrSignatureVerify = errors.New("Could not cryptographically verify signature") ) // Create a new signature from a base64 encoded item, as we would get in a PUT or POST request //@@TODO: Test to make sure "Signature too short" is working as expected func NewSignature(Base64Signature []byte) (Signature, error) { dbuf := make([]byte, base64.StdEncoding.DecodedLen(len(Base64Signature))) n, err := base64.StdEncoding.Decode(dbuf, Base64Signature) if err != nil { return nil, errors.Wrap(err, ErrSignatureBase64) } if n < 128 { return nil, ErrSignatureTooShort } sig := dbuf[:n]
) type State int // URL states. // You can query the current state of a url by calling Crawler.GetURL(url) const ( StateNotFound State = iota StatePending State = iota StateRunning State = iota StateRejected State = iota StateDone State = iota ) var ( ErrReqFailed = errors.New("HTTP request failed") ErrBodyRead = errors.New("Error reading HTTP response body") ErrAlreadyStarted = errors.New("Cannot start crawler that is already running") ErrHeaderRejected = errors.New("CheckHeader rejected URL") ErrURLRejected = errors.New("CheckURL rejected URL") ErrBadHttpCode = errors.New("Bad HTTP reponse code") ErrBadContentType = errors.New("Unsupported Content-Type") ) // When handling a crawled page a Response is passed to the Handler function. // A crawlbot.Response is an http.Response with a few extra fields. type Response struct { // The http.Reponse object *http.Response // The for this Response
"bytes" "crypto/sha256" "encoding/hex" "github.com/phayes/errors" ) type SignatureRequest struct { ElectionID string RequestID []byte // SHA256 (hex) of base64 encoded public-key PublicKey // base64 encoded PEM formatted public-key BallotHash []byte // SHA256 (hex-encoded) of the ballot. This would generally be blinded. Signature // Voter signature for the ballot request } var ( ErrSignatureRequestInvalid = errors.New("Cannot read Signature Request. Invalid format") ErrSignatureRequestPublicKey = errors.New("Cannot read Signature Request. Invalid Public Key") ErrSignatureRequestID = errors.New("Invalid SignatureRequest ID. A SignatureRequest ID must be the (hex encoded) SHA256 of the voters public key.") ErrSignatureRequestBallotHash = errors.New("Invalid Signature Request. Ballot hash must be hex encoded.") ErrSignatureRequestHashBits = errors.New("Invalid Signature Request. You must provide exactly 256 bits for the blinded SHA256 ballot hash") ErrSignatureRequestSigInvalid = errors.New("Invalid Signature Request. Could not parse voter signature") ErrSignatureRequestSigNotFoud = errors.New("Could not verify voter signature on Signature Request: voter-signature does not exist") ErrSignatureRequestSignBallot = errors.New("Could not sign ballot") ) // Given a raw Signature Request string (as a []byte -- see documentation for format), return a new SignatureRequest object. // Generally the Signature Request string is coming from a voter in a POST body. // This will also verify the signature on the SignatureRequest and return an error if the request does not pass crypto verification func NewSignatureRequest(rawSignatureRequest []byte) (*SignatureRequest, error) { var ( err error
"crypto/rsa" "crypto/sha256" "crypto/x509" "encoding/base64" "encoding/hex" "github.com/phayes/errors" ) const ( absoluteMinPublicKeySize = 2048 // We cannot go lower than this since it would hinder our ability to differentiate between public keys and tagsets on ballots ) var ( MinPublicKeySize = 4096 // Recommended minimum public key size -- this can be changed ErrPubicMinKeySize = errors.New("Invalid public key - too short") ErrPublicKeyBase64 = errors.New("Invalid Public Key. Could not read base64 encoded bytes") ErrPublicKeyLen = errors.New("Could not determine PublicKey key length") ErrPublicKeyCryptoKey = errors.New("Could not create from rsa.PublicKey from PublicKey. Could not parse PublicKey bytes") ) // A DER encoded public key type PublicKey []byte // Create a new PublicKey from a base64 encoded item, as we would get in a PUT or POST request // This function also performs error checking to make sure the key is valid. func NewPublicKey(base64PublicKey []byte) (PublicKey, error) { decodedLen := base64.StdEncoding.DecodedLen(len(base64PublicKey)) dbuf := make([]byte, decodedLen) n, err := base64.StdEncoding.Decode(dbuf, base64PublicKey) if err != nil {
"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) }
package cryptoballot import ( "bytes" "github.com/phayes/errors" ) type FulfilledSignatureRequest struct { SignatureRequest BallotSignature Signature // ElectionClerk signature signing off on the validity of the ballot } var ( ErrFulfilledSignatureRequestInvalid = errors.New("Cannot read Fulfilled Signature Request. Invalid format") ) // Given the raw bytes of a Fulfilled Signature Request, get a FulfilledSignatureRequest object func NewFulfilledSignatureRequest(rawBytes []byte) (*FulfilledSignatureRequest, error) { parts := bytes.Split(rawBytes, []byte("\n\n")) if len(parts) != 6 { return &FulfilledSignatureRequest{}, ErrFulfilledSignatureRequestInvalid } signatureRequest, err := NewSignatureRequest(bytes.Join(parts[:5], []byte("\n\n"))) if err != nil { return &FulfilledSignatureRequest{}, err } ballotSignature, err := NewSignature(parts[5]) if err != nil { return &FulfilledSignatureRequest{}, err