package api import ( "bytes" "crypto/sha256" "encoding/binary" "encoding/json" "errors" "io" "log" "math/rand" mathrand "math/rand" "net/http" ) type Object = map[string]interface{} // options are the things that we may need to know about a request to fulfill it properly type options struct { Key string `json:"key"` KeyType string `json:"kty"` Seed int64 `json:"-"` SeedStr string `json:"seed"` Claims Object `json:"claims"` Header Object `json:"header"` } // this shananigans is only for testing and debug API stuff func (o *options) nextReader() io.Reader { if 0 == o.Seed { return RandomReader } return rand.New(rand.NewSource(o.Seed)) } func getOpts(r *http.Request) (*options, error) { tok := make(map[string]interface{}) decoder := json.NewDecoder(r.Body) err := decoder.Decode(&tok) if nil != err && io.EOF != err { log.Printf("json decode error: %s", err) return nil, errors.New("Bad Request: invalid json body") } defer r.Body.Close() var seed int64 seedStr, _ := tok["seed"].(string) if "" != seedStr { if len(seedStr) > 256 { return nil, errors.New("Bad Request: base64 seed should be <256 characters (and is truncated to 64-bits anyway)") } b := sha256.Sum256([]byte(seedStr)) seed, _ = binary.ReadVarint(bytes.NewReader(b[0:8])) } key, _ := tok["key"].(string) opts := &options{ Seed: seed, Key: key, } opts.Claims, _ = tok["claims"].(Object) opts.Header, _ = tok["header"].(Object) var n int if 0 != seed { n = opts.nextReader().(*mathrand.Rand).Intn(2) } else { n = rand.Intn(2) } opts.KeyType, _ = tok["kty"].(string) if "" == opts.KeyType { if 0 == n { opts.KeyType = "RSA" } else { opts.KeyType = "EC" } } return opts, nil }