Compare commits
	
		
			No commits in common. "557f9085f68ca0ecdd696bdd9cc3484b2727f490" and "a8f1a9966762bab2b838940a396c0bd9c3083c22" have entirely different histories.
		
	
	
		
			557f9085f6
			...
			a8f1a99667
		
	
		
							
								
								
									
										131
									
								
								kvdb/kvdb.go
									
									
									
									
									
								
							
							
						
						
									
										131
									
								
								kvdb/kvdb.go
									
									
									
									
									
								
							| @ -1,131 +0,0 @@ | |||||||
| package kvdb |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"errors" |  | ||||||
| 	"fmt" |  | ||||||
| 	"io/ioutil" |  | ||||||
| 	"os" |  | ||||||
| 	"path/filepath" |  | ||||||
| 	"strconv" |  | ||||||
| 	"strings" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| type KVDB struct { |  | ||||||
| 	Prefix string |  | ||||||
| 	Ext    string |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (kv *KVDB) Load( |  | ||||||
| 	keyif interface{}, |  | ||||||
| 	typ ...interface{}, |  | ||||||
| ) (value interface{}, ok bool, err error) { |  | ||||||
| 	key, _ := keyif.(string) |  | ||||||
| 	if "" == key || strings.Contains(key, "..") || strings.ContainsAny(key, "$#!:| \n") { |  | ||||||
| 		return nil, false, nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	userFile := filepath.Join(kv.Prefix, key+"."+kv.Ext) |  | ||||||
| 	fmt.Println("Debug user file:", userFile) |  | ||||||
| 	b, err := ioutil.ReadFile(userFile) |  | ||||||
| 	if nil != err { |  | ||||||
| 		if os.IsNotExist(err) { |  | ||||||
| 			return nil, false, nil |  | ||||||
| 		} |  | ||||||
| 		fmt.Println("kvdb debug read:", err) |  | ||||||
| 		return nil, false, errors.New("database read failed") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	ok = true |  | ||||||
| 	value = b |  | ||||||
| 	if 1 == len(typ) { |  | ||||||
| 		err := json.Unmarshal(b, typ[0]) |  | ||||||
| 		if nil != err { |  | ||||||
| 			return nil, false, err |  | ||||||
| 		} |  | ||||||
| 		value = typ[0] |  | ||||||
| 	} else if len(b) > 0 && '"' == b[0] { |  | ||||||
| 		var str string |  | ||||||
| 		err := json.Unmarshal(b, &str) |  | ||||||
| 		if nil == err { |  | ||||||
| 			value = str |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return value, ok, nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (kv *KVDB) Store(keyif interface{}, value interface{}) (err error) { |  | ||||||
| 	key, _ := keyif.(string) |  | ||||||
| 	if "" == key || strings.Contains(key, "..") || strings.ContainsAny(key, "$#! \n") { |  | ||||||
| 		return errors.New("invalid key name") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	keypath := filepath.Join(kv.Prefix, key+"."+kv.Ext) |  | ||||||
| 	f, err := os.Open(keypath) |  | ||||||
| 	if nil == err { |  | ||||||
| 		s, err := f.Stat() |  | ||||||
| 		if nil != err { |  | ||||||
| 			// if we can open, we should be able to stat |  | ||||||
| 			return errors.New("database connection failure") |  | ||||||
| 		} |  | ||||||
| 		ts := strconv.FormatInt(s.ModTime().Unix(), 10) |  | ||||||
| 		bakpath := filepath.Join(kv.Prefix, key+"."+ts+"."+kv.Ext) |  | ||||||
| 		if err := os.Rename(keypath, bakpath); nil != err { |  | ||||||
| 			// keep the old record as a backup |  | ||||||
| 			return errors.New("database write failure") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	var b []byte |  | ||||||
| 	switch v := value.(type) { |  | ||||||
| 	case []byte: |  | ||||||
| 		b = v |  | ||||||
| 	case string: |  | ||||||
| 		b, _ = json.Marshal(v) |  | ||||||
| 	default: |  | ||||||
| 		fmt.Println("kvdb: not []byte or string:", v) |  | ||||||
| 		jsonb, err := json.Marshal(v) |  | ||||||
| 		if nil != err { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 		b = jsonb |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if err := ioutil.WriteFile( |  | ||||||
| 		keypath, |  | ||||||
| 		b, |  | ||||||
| 		os.FileMode(0600), |  | ||||||
| 	); nil != err { |  | ||||||
| 		fmt.Println("write failure:", err) |  | ||||||
| 		return errors.New("database write failed") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (kv *KVDB) Delete(keyif interface{}) (err error) { |  | ||||||
| 	key, _ := keyif.(string) |  | ||||||
| 	if "" == key || strings.Contains(key, "..") || strings.ContainsAny(key, "$#! \n") { |  | ||||||
| 		return errors.New("invalid key name") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	keypath := filepath.Join(kv.Prefix, key+"."+kv.Ext) |  | ||||||
| 	f, err := os.Open(keypath) |  | ||||||
| 	if nil == err { |  | ||||||
| 		s, err := f.Stat() |  | ||||||
| 		if nil != err { |  | ||||||
| 			return errors.New("database connection failure") |  | ||||||
| 		} |  | ||||||
| 		ts := strconv.FormatInt(s.ModTime().Unix(), 64) |  | ||||||
| 		if err := os.Rename(keypath, filepath.Join(kv.Prefix, key+"."+ts+"."+kv.Ext)); nil != err { |  | ||||||
| 			return errors.New("database connection failure") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (kv *KVDB) Vacuum() (err error) { |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @ -1,63 +0,0 @@ | |||||||
| package kvdb |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"strings" |  | ||||||
| 	"testing" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| type TestEntry struct { |  | ||||||
| 	Email    string   `json:"email"` |  | ||||||
| 	Subjects []string `json:"subjects"` |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| var email = "john@example.com" |  | ||||||
| var sub = "id123" |  | ||||||
| var dbPrefix = "../testdb" |  | ||||||
| var testKV = &KVDB{ |  | ||||||
| 	Prefix: dbPrefix + "/test-entries", |  | ||||||
| 	Ext:    "eml.json", |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestStore(t *testing.T) { |  | ||||||
| 	entry := &TestEntry{ |  | ||||||
| 		Email:    email, |  | ||||||
| 		Subjects: []string{sub}, |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if err := testKV.Store(email, entry); nil != err { |  | ||||||
| 		t.Fatal(err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	value, ok, err := testKV.Load(email, &(TestEntry{})) |  | ||||||
| 	if nil != err { |  | ||||||
| 		t.Fatal(err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if !ok { |  | ||||||
| 		t.Fatal("test entry not found") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	v, ok := value.(*TestEntry) |  | ||||||
| 	if !ok { |  | ||||||
| 		t.Fatal("test entry not of type TestEntry") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if email != v.Email || sub != strings.Join(v.Subjects, ",") { |  | ||||||
| 		t.Fatalf("value: %#v", v) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestNoExist(t *testing.T) { |  | ||||||
| 	value, ok, err := testKV.Load("not"+email, &(TestEntry{})) |  | ||||||
| 	if nil != err { |  | ||||||
| 		t.Fatal(err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if ok { |  | ||||||
| 		t.Fatal("found entry that doesn't exist") |  | ||||||
| 	} |  | ||||||
| 	if value != nil { |  | ||||||
| 		t.Fatal("had value for entry that doesn't exist") |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @ -11,17 +11,35 @@ import ( | |||||||
| 	"math/rand" | 	"math/rand" | ||||||
| 	mathrand "math/rand" | 	mathrand "math/rand" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 
 |  | ||||||
| 	"git.coolaj86.com/coolaj86/go-mockid/xkeypairs" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | 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 getJWS(r *http.Request) (*xkeypairs.KeyOptions, error) { | func getJWS(r *http.Request) (*options, error) { | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| func getOpts(r *http.Request) (*xkeypairs.KeyOptions, error) { | func getOpts(r *http.Request) (*options, error) { | ||||||
| 	tok := make(map[string]interface{}) | 	tok := make(map[string]interface{}) | ||||||
| 	decoder := json.NewDecoder(r.Body) | 	decoder := json.NewDecoder(r.Body) | ||||||
| 	err := decoder.Decode(&tok) | 	err := decoder.Decode(&tok) | ||||||
| @ -42,17 +60,17 @@ func getOpts(r *http.Request) (*xkeypairs.KeyOptions, error) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	key, _ := tok["key"].(string) | 	key, _ := tok["key"].(string) | ||||||
| 	opts := &xkeypairs.KeyOptions{ | 	opts := &options{ | ||||||
| 		Seed: seed, | 		Seed: seed, | ||||||
| 		Key:  key, | 		Key:  key, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	opts.Claims, _ = tok["claims"].(xkeypairs.Object) | 	opts.Claims, _ = tok["claims"].(Object) | ||||||
| 	opts.Header, _ = tok["header"].(xkeypairs.Object) | 	opts.Header, _ = tok["header"].(Object) | ||||||
| 
 | 
 | ||||||
| 	var n int | 	var n int | ||||||
| 	if 0 != seed { | 	if 0 != seed { | ||||||
| 		n = opts.MyFooNextReader().(*mathrand.Rand).Intn(2) | 		n = opts.nextReader().(*mathrand.Rand).Intn(2) | ||||||
| 	} else { | 	} else { | ||||||
| 		n = rand.Intn(2) | 		n = rand.Intn(2) | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -1,12 +1,21 @@ | |||||||
| package api | package api | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"crypto/ecdsa" | ||||||
|  | 	"crypto/elliptic" | ||||||
|  | 	"crypto/rand" | ||||||
|  | 	"crypto/rsa" | ||||||
|  | 	"io" | ||||||
|  | 	"log" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 
 | 
 | ||||||
| 	"git.coolaj86.com/coolaj86/go-mockid/xkeypairs" | 	"git.coolaj86.com/coolaj86/go-mockid/xkeypairs" | ||||||
| 	"git.rootprojects.org/root/keypairs" | 	"git.rootprojects.org/root/keypairs" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | // RandomReader may be overwritten for testing | ||||||
|  | var RandomReader io.Reader = rand.Reader | ||||||
|  | 
 | ||||||
| // GeneratePublicJWK will create a new private key in JWK format | // GeneratePublicJWK will create a new private key in JWK format | ||||||
| func GeneratePublicJWK(w http.ResponseWriter, r *http.Request) { | func GeneratePublicJWK(w http.ResponseWriter, r *http.Request) { | ||||||
| 	if "POST" != r.Method { | 	if "POST" != r.Method { | ||||||
| @ -43,7 +52,7 @@ func GeneratePrivateJWK(w http.ResponseWriter, r *http.Request) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	privkey := xkeypairs.GenPrivKey(opts) | 	privkey := genPrivKey(opts) | ||||||
| 
 | 
 | ||||||
| 	jwk := xkeypairs.MarshalJWKPrivateKey(privkey) | 	jwk := xkeypairs.MarshalJWKPrivateKey(privkey) | ||||||
| 	w.Write(append(jwk, '\n')) | 	w.Write(append(jwk, '\n')) | ||||||
| @ -86,7 +95,7 @@ func GeneratePrivateDER(w http.ResponseWriter, r *http.Request) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	privkey := xkeypairs.GenPrivKey(opts) | 	privkey := genPrivKey(opts) | ||||||
| 
 | 
 | ||||||
| 	der, _ := xkeypairs.MarshalDERPrivateKey(privkey) | 	der, _ := xkeypairs.MarshalDERPrivateKey(privkey) | ||||||
| 	w.Write(der) | 	w.Write(der) | ||||||
| @ -129,7 +138,7 @@ func GeneratePrivatePEM(w http.ResponseWriter, r *http.Request) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	privkey := xkeypairs.GenPrivKey(opts) | 	privkey := genPrivKey(opts) | ||||||
| 
 | 
 | ||||||
| 	privpem, _ := xkeypairs.MarshalPEMPrivateKey(privkey) | 	privpem, _ := xkeypairs.MarshalPEMPrivateKey(privkey) | ||||||
| 	w.Write(privpem) | 	w.Write(privpem) | ||||||
| @ -137,9 +146,39 @@ func GeneratePrivatePEM(w http.ResponseWriter, r *http.Request) { | |||||||
| 
 | 
 | ||||||
| const maxRetry = 16 | const maxRetry = 16 | ||||||
| 
 | 
 | ||||||
| func getPrivKey(opts *xkeypairs.KeyOptions) (keypairs.PrivateKey, error) { | func getPrivKey(opts *options) (keypairs.PrivateKey, error) { | ||||||
| 	if "" != opts.Key { | 	if "" != opts.Key { | ||||||
| 		return keypairs.ParsePrivateKey([]byte(opts.Key)) | 		return keypairs.ParsePrivateKey([]byte(opts.Key)) | ||||||
| 	} | 	} | ||||||
| 	return xkeypairs.GenPrivKey(opts), nil | 	return genPrivKey(opts), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func genPrivKey(opts *options) keypairs.PrivateKey { | ||||||
|  | 	var privkey keypairs.PrivateKey | ||||||
|  | 
 | ||||||
|  | 	if "RSA" == opts.KeyType { | ||||||
|  | 		keylen := 2048 | ||||||
|  | 		privkey, _ = rsa.GenerateKey(opts.nextReader(), keylen) | ||||||
|  | 		if 0 != opts.Seed { | ||||||
|  | 			for i := 0; i < maxRetry; i++ { | ||||||
|  | 				otherkey, _ := rsa.GenerateKey(opts.nextReader(), keylen) | ||||||
|  | 				otherCmp := otherkey.D.Cmp(privkey.(*rsa.PrivateKey).D) | ||||||
|  | 				if 0 != otherCmp { | ||||||
|  | 					// There are two possible keys, choose the lesser D value | ||||||
|  | 					// See https://github.com/square/go-jose/issues/189 | ||||||
|  | 					if otherCmp < 0 { | ||||||
|  | 						privkey = otherkey | ||||||
|  | 					} | ||||||
|  | 					break | ||||||
|  | 				} | ||||||
|  | 				if maxRetry == i-1 { | ||||||
|  | 					log.Printf("error: coinflip landed on heads %d times", maxRetry) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		// TODO: EC keys may also suffer the same random problems in the future | ||||||
|  | 		privkey, _ = ecdsa.GenerateKey(elliptic.P256(), opts.nextReader()) | ||||||
|  | 	} | ||||||
|  | 	return privkey | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,61 +0,0 @@ | |||||||
| package xkeypairs |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"crypto/ecdsa" |  | ||||||
| 	"crypto/elliptic" |  | ||||||
| 	"crypto/rsa" |  | ||||||
| 	"io" |  | ||||||
| 	"log" |  | ||||||
| 	"math/rand" |  | ||||||
| 
 |  | ||||||
| 	"git.rootprojects.org/root/keypairs" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // KeyOptions are the things that we may need to know about a request to fulfill it properly |  | ||||||
| type KeyOptions 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 *KeyOptions) MyFooNextReader() io.Reader { |  | ||||||
| 	if 0 == o.Seed { |  | ||||||
| 		return RandomReader |  | ||||||
| 	} |  | ||||||
| 	return rand.New(rand.NewSource(o.Seed)) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // GenPrivKey generates a 256-bit entropy RSA or ECDSA private key |  | ||||||
| func GenPrivKey(opts *KeyOptions) keypairs.PrivateKey { |  | ||||||
| 	var privkey keypairs.PrivateKey |  | ||||||
| 
 |  | ||||||
| 	if "RSA" == opts.KeyType { |  | ||||||
| 		keylen := 2048 |  | ||||||
| 		privkey, _ = rsa.GenerateKey(opts.MyFooNextReader(), keylen) |  | ||||||
| 		if 0 != opts.Seed { |  | ||||||
| 			for i := 0; i < maxRetry; i++ { |  | ||||||
| 				otherkey, _ := rsa.GenerateKey(opts.MyFooNextReader(), keylen) |  | ||||||
| 				otherCmp := otherkey.D.Cmp(privkey.(*rsa.PrivateKey).D) |  | ||||||
| 				if 0 != otherCmp { |  | ||||||
| 					// There are two possible keys, choose the lesser D value |  | ||||||
| 					// See https://github.com/square/go-jose/issues/189 |  | ||||||
| 					if otherCmp < 0 { |  | ||||||
| 						privkey = otherkey |  | ||||||
| 					} |  | ||||||
| 					break |  | ||||||
| 				} |  | ||||||
| 				if maxRetry == i-1 { |  | ||||||
| 					log.Printf("error: coinflip landed on heads %d times", maxRetry) |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		// TODO: EC keys may also suffer the same random problems in the future |  | ||||||
| 		privkey, _ = ecdsa.GenerateKey(elliptic.P256(), opts.MyFooNextReader()) |  | ||||||
| 	} |  | ||||||
| 	return privkey |  | ||||||
| } |  | ||||||
| @ -1,7 +1,7 @@ | |||||||
| package xkeypairs | package xkeypairs | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"io/ioutil" | 	"strconv" | ||||||
| 
 | 
 | ||||||
| 	"git.rootprojects.org/root/keypairs" | 	"git.rootprojects.org/root/keypairs" | ||||||
| ) | ) | ||||||
| @ -12,11 +12,37 @@ func ParsePEMPrivateKey(block []byte) (keypairs.PrivateKey, error) { | |||||||
| 	return keypairs.ParsePrivateKey(block) | 	return keypairs.ParsePrivateKey(block) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ParsePrivateKeyFile returns the private key from the given file path, if available | func ParseDuration(exp string) (int, error) { | ||||||
| func ParsePrivateKeyFile(pathname string) (keypairs.PrivateKey, error) { | 	if "" == exp { | ||||||
| 	block, err := ioutil.ReadFile(pathname) | 		exp = "15m" | ||||||
| 	if nil != err { |  | ||||||
| 		return nil, err |  | ||||||
| 	} | 	} | ||||||
| 	return keypairs.ParsePrivateKey(block) | 
 | ||||||
|  | 	mult := 1 | ||||||
|  | 	switch exp[len(exp)-1] { | ||||||
|  | 	case 'w': | ||||||
|  | 		mult *= 7 | ||||||
|  | 		fallthrough | ||||||
|  | 	case 'd': | ||||||
|  | 		mult *= 24 | ||||||
|  | 		fallthrough | ||||||
|  | 	case 'h': | ||||||
|  | 		mult *= 60 | ||||||
|  | 		fallthrough | ||||||
|  | 	case 'm': | ||||||
|  | 		mult *= 60 | ||||||
|  | 		fallthrough | ||||||
|  | 	case 's': | ||||||
|  | 		// no fallthrough | ||||||
|  | 	default: | ||||||
|  | 		// could be 'k' or 'z', but we assume its empty | ||||||
|  | 		exp += "s" | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// 15m => num=15, mult=1*60 | ||||||
|  | 	num, err := strconv.Atoi(exp[:len(exp)-1]) | ||||||
|  | 	if nil != err { | ||||||
|  | 		return 0, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return num * mult, nil | ||||||
| } | } | ||||||
|  | |||||||
| @ -17,10 +17,7 @@ import ( | |||||||
| 	"git.rootprojects.org/root/keypairs" | 	"git.rootprojects.org/root/keypairs" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // RandomReader may be overwritten for testing | var RandomReader = rand.Reader | ||||||
| var RandomReader io.Reader = rand.Reader |  | ||||||
| 
 |  | ||||||
| //var RandomReader = rand.Reader |  | ||||||
| 
 | 
 | ||||||
| type JWS struct { | type JWS struct { | ||||||
| 	Header    Object `json:"header"`    // JSON | 	Header    Object `json:"header"`    // JSON | ||||||
| @ -32,7 +29,6 @@ type JWS struct { | |||||||
| 
 | 
 | ||||||
| type Object = map[string]interface{} | type Object = map[string]interface{} | ||||||
| 
 | 
 | ||||||
| // SignClaims adds `typ`, `kid` (or `jwk`), and `alg` in the header and expects claims for `jti`, `exp`, `iss`, and `iat` |  | ||||||
| func SignClaims(privkey keypairs.PrivateKey, header Object, claims Object) (*JWS, error) { | func SignClaims(privkey keypairs.PrivateKey, header Object, claims Object) (*JWS, error) { | ||||||
| 	var randsrc io.Reader = RandomReader | 	var randsrc io.Reader = RandomReader | ||||||
| 	seed, _ := header["_seed"].(int64) | 	seed, _ := header["_seed"].(int64) | ||||||
| @ -123,12 +119,11 @@ func claimsToPayload(claims Object) ([]byte, error) { | |||||||
| 
 | 
 | ||||||
| 	// parse if exp is actually a duration, such as "15m" | 	// parse if exp is actually a duration, such as "15m" | ||||||
| 	if 0 == exp && "" != dur { | 	if 0 == exp && "" != dur { | ||||||
| 		s, err := time.ParseDuration(dur) | 		s, err := ParseDuration(dur) | ||||||
| 		// TODO s, err := time.ParseDuration(dur) |  | ||||||
| 		if nil != err { | 		if nil != err { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
| 		exp = time.Now().Add(s * time.Second).Unix() | 		exp = time.Now().Add(time.Duration(s) * time.Second).Unix() | ||||||
| 		claims["exp"] = exp | 		claims["exp"] = exp | ||||||
| 	} | 	} | ||||||
| 	if "" == jti && 0 == exp && !insecure { | 	if "" == jti && 0 == exp && !insecure { | ||||||
| @ -160,6 +155,8 @@ func Sign(rand io.Reader, privkey keypairs.PrivateKey, hash []byte) []byte { | |||||||
| 	case *ecdsa.PrivateKey: | 	case *ecdsa.PrivateKey: | ||||||
| 		r, s, _ := ecdsa.Sign(rand, k, hash[:]) | 		r, s, _ := ecdsa.Sign(rand, k, hash[:]) | ||||||
| 		rb := r.Bytes() | 		rb := r.Bytes() | ||||||
|  | 		fmt.Println("debug:") | ||||||
|  | 		fmt.Println(r, s) | ||||||
| 		for len(rb) < 32 { | 		for len(rb) < 32 { | ||||||
| 			rb = append([]byte{0}, rb...) | 			rb = append([]byte{0}, rb...) | ||||||
| 		} | 		} | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user