changed public id format to be 128 bit length.
This commit is contained in:
1 parent
78d50d9a6d
commit
d2cf9d7498
11 files changed
+187
-22
No files matched your search
+2
-2
@@ -6,13 +6,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func GetAllDoormen(w http.ResponseWriter, request *http.Request) {
|
func GetAllDoormen(w http.ResponseWriter, request *http.Request) {
|
||||||
fmt.Fprint(w, `{"doormen" :[`)
|
|
||||||
doormenIds := conn.GetAllDoormen()
|
doormenIds := conn.GetAllDoormen()
|
||||||
buff := <-doormenIds
|
buff := <-doormenIds
|
||||||
if buff == nil {
|
if buff == nil {
|
||||||
fmt.Fprint(w, "]}")
|
fmt.Fprint(w, `{"doormen" :[]}`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
fmt.Fprint(w, `{"doormen" :[`)
|
||||||
for doormanId := range doormenIds {
|
for doormanId := range doormenIds {
|
||||||
fmt.Fprint(w, getDoormenIdsAsJson(buff)+`,`)
|
fmt.Fprint(w, getDoormenIdsAsJson(buff)+`,`)
|
||||||
buff = doormanId
|
buff = doormanId
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func TestGetAllDoormen(t *testing.T) {
|
|||||||
GetAllDoormen(w, req)
|
GetAllDoormen(w, req)
|
||||||
|
|
||||||
d := json.NewDecoder(w.Body)
|
d := json.NewDecoder(w.Body)
|
||||||
m := make(map[string][]*doormen.DoormanDefinition)
|
m := make(map[string][]*doormen.DoormanId)
|
||||||
|
|
||||||
if err := d.Decode(&m); err != nil {
|
if err := d.Decode(&m); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/didiercrunch/doormanserver/doormen"
|
"github.com/didiercrunch/doormanserver/doormen"
|
||||||
|
"github.com/didiercrunch/doormanserver/shared"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
@@ -30,6 +31,6 @@ func CreateDoorman(w http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
go publisher.Emit(wdef.Id, wdef)
|
go publisher.Emit(wdef.Id, wdef)
|
||||||
w.Header().Set("location", "/api/doormen/"+wdef.Id.Hex())
|
w.Header().Set("location", "/api/doormen/"+shared.ObjectIdToPublicId(wdef.Id))
|
||||||
w.WriteHeader(201)
|
w.WriteHeader(201)
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ package api
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"github.com/didiercrunch/doormanserver/inmemoryconnector"
|
"github.com/didiercrunch/doormanserver/inmemoryconnector"
|
||||||
|
"github.com/didiercrunch/doormanserver/shared"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
@@ -11,7 +12,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func GetIdFromLocation(p string) bson.ObjectId {
|
func GetIdFromLocation(p string) bson.ObjectId {
|
||||||
return bson.ObjectIdHex(path.Base(p))
|
if id, err := shared.PublicIdToObjectId(path.Base(p)); err != nil {
|
||||||
|
panic(err)
|
||||||
|
} else {
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateDoorman(t *testing.T) {
|
func TestCreateDoorman(t *testing.T) {
|
||||||
|
|||||||
+5
-3
@@ -3,6 +3,7 @@ package api
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/didiercrunch/doormanserver/doormen"
|
"github.com/didiercrunch/doormanserver/doormen"
|
||||||
|
"github.com/didiercrunch/doormanserver/shared"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"log"
|
"log"
|
||||||
@@ -10,15 +11,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func getDoormenIdsAsJson(id *doormen.DoormanId) string {
|
func getDoormenIdsAsJson(id *doormen.DoormanId) string {
|
||||||
return fmt.Sprintf(`{"name": "%v", "id": "%v", "url": "/api/doormen/%v"}`, id.Name, id.Id.Hex(), id.Id.Hex())
|
publicId := shared.ObjectIdToPublicId(id.Id)
|
||||||
|
return fmt.Sprintf(`{"name": "%v", "id": "%v", "url": "/api/doormen/%v"}`, id.Name, publicId, publicId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDoormanIdFromRequest(w http.ResponseWriter, request *http.Request) bson.ObjectId {
|
func getDoormanIdFromRequest(w http.ResponseWriter, request *http.Request) bson.ObjectId {
|
||||||
id := mux.Vars(request)["id"]
|
id := mux.Vars(request)["id"]
|
||||||
if !bson.IsObjectIdHex(id) {
|
if id, err := shared.PublicIdToObjectId(id); err != nil {
|
||||||
return ""
|
return ""
|
||||||
} else {
|
} else {
|
||||||
return bson.ObjectIdHex(id)
|
return id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-9
@@ -17,11 +17,6 @@ type DoormanValue struct {
|
|||||||
Probability *big.Rat `json:"probability"`
|
Probability *big.Rat `json:"probability"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type doormanValue struct {
|
|
||||||
Name string
|
|
||||||
Probability string
|
|
||||||
}
|
|
||||||
|
|
||||||
type DoormanId struct {
|
type DoormanId struct {
|
||||||
Id bson.ObjectId `json:"id,omitempty" bson:"_id"`
|
Id bson.ObjectId `json:"id,omitempty" bson:"_id"`
|
||||||
Name string `json:"name" bson:"name"`
|
Name string `json:"name" bson:"name"`
|
||||||
@@ -35,10 +30,10 @@ func (wId *DoormanId) AsJson() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DoormanDefinition struct {
|
type DoormanDefinition struct {
|
||||||
Id bson.ObjectId `json:"id,omitempty" bson:"_id"`
|
Id bson.ObjectId `bson:"_id"`
|
||||||
Name string `json:"name" bson:"name"`
|
Name string `bson:"name"`
|
||||||
Values []*DoormanValue `json:"values" bson:"values"`
|
Values []*DoormanValue `bson:"values"`
|
||||||
OwnerEmails []string `json:"emails" bson:"emails"`
|
OwnerEmails []string `bson:"emails"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDoormanDefinition(name string, ownerEmails ...string) *DoormanDefinition {
|
func NewDoormanDefinition(name string, ownerEmails ...string) *DoormanDefinition {
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
package doormen
|
package doormen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/didiercrunch/doormanserver/shared"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"math/big"
|
"math/big"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type doormanValue struct {
|
||||||
|
Name string
|
||||||
|
Probability string
|
||||||
|
}
|
||||||
|
|
||||||
func (val *DoormanValue) GetBSON() (interface{}, error) {
|
func (val *DoormanValue) GetBSON() (interface{}, error) {
|
||||||
ret := &doormanValue{val.Name, ""}
|
ret := &doormanValue{val.Name, ""}
|
||||||
txt, err := val.Probability.MarshalText()
|
txt, err := val.Probability.MarshalText()
|
||||||
@@ -24,3 +31,60 @@ func (val *DoormanValue) SetBSON(raw bson.Raw) error {
|
|||||||
val.Probability = new(big.Rat)
|
val.Probability = new(big.Rat)
|
||||||
return val.Probability.UnmarshalText([]byte(v.Probability))
|
return val.Probability.UnmarshalText([]byte(v.Probability))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type jsonDoormanDefinition struct {
|
||||||
|
Id string `json:"id,omitempty"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Values []*DoormanValue `json:"values"`
|
||||||
|
OwnerEmails []string `json:"emails"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dm *DoormanDefinition) MarshalJSON() ([]byte, error) {
|
||||||
|
jdm := new(jsonDoormanDefinition)
|
||||||
|
jdm.Name = dm.Name
|
||||||
|
jdm.OwnerEmails = dm.OwnerEmails
|
||||||
|
jdm.Values = dm.Values
|
||||||
|
jdm.Id = shared.ObjectIdToPublicId(dm.Id)
|
||||||
|
return json.Marshal(jdm)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dm *DoormanDefinition) UnmarshalJSON(data []byte) error {
|
||||||
|
jsm := new(jsonDoormanDefinition)
|
||||||
|
var err error
|
||||||
|
if err = json.Unmarshal(data, jsm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if dm.Id, err = shared.PublicIdToObjectId(jsm.Id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dm.Name = jsm.Name
|
||||||
|
dm.Values = jsm.Values
|
||||||
|
dm.OwnerEmails = jsm.OwnerEmails
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type jsonDoormanId struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Id string `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (did *DoormanId) MarshalJSON() ([]byte, error) {
|
||||||
|
jdid := new(jsonDoormanId)
|
||||||
|
jdid.Name = did.Name
|
||||||
|
jdid.Id = shared.ObjectIdToPublicId(did.Id)
|
||||||
|
return json.Marshal(jdid)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (did *DoormanId) UnmarshalJSON(data []byte) error {
|
||||||
|
jdid := new(jsonDoormanId)
|
||||||
|
if err := json.Unmarshal(data, jdid); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
if did.Id, err = shared.PublicIdToObjectId(jdid.Id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
did.Name = jdid.Name
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package doormen
|
package doormen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -22,6 +23,42 @@ func TestJsonEncoding(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestJsonEncodingWithEmptyIds(t *testing.T) {
|
||||||
|
dmd := QuickNewDoormanDefinition("test json", "1/4", "3/4")
|
||||||
|
dmd.Id = ""
|
||||||
|
data, err := json.Marshal(dmd)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
dmd2 := new(DoormanDefinition)
|
||||||
|
if err = json.Unmarshal(data, dmd2); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(dmd2, dmd) {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJsonIdFormatToBeCompatibleWithSiphashKey(t *testing.T) {
|
||||||
|
dmd := QuickNewDoormanDefinition("test json", "1/4", "3/4")
|
||||||
|
data, err := json.Marshal(dmd)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m := make(map[string]interface{})
|
||||||
|
if err = json.Unmarshal(data, &m); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if b, err := base64.URLEncoding.DecodeString(m["id"].(string)); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
} else if len(b) != 16 {
|
||||||
|
t.Error("siphash requires a 16 bytes (128 bits) key not ", len(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBsonEncoding(t *testing.T) {
|
func TestBsonEncoding(t *testing.T) {
|
||||||
dmd := QuickNewDoormanDefinition("test bson", "1/4", "3/4")
|
dmd := QuickNewDoormanDefinition("test bson", "1/4", "3/4")
|
||||||
data, err := bson.Marshal(dmd)
|
data, err := bson.Marshal(dmd)
|
||||||
@@ -36,3 +73,19 @@ func TestBsonEncoding(t *testing.T) {
|
|||||||
t.Error()
|
t.Error()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDoormanIdJsonEncoding(t *testing.T) {
|
||||||
|
did := &DoormanId{bson.NewObjectId(), "hahaha"}
|
||||||
|
data, err := json.Marshal(did)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
did2 := new(DoormanId)
|
||||||
|
if err = json.Unmarshal(data, did2); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(did2, did) {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ func GetAddressToServe() string {
|
|||||||
return params.Host + ":" + strconv.Itoa(params.Port)
|
return params.Host + ":" + strconv.Itoa(params.Port)
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveStatic2(w http.ResponseWriter, request *http.Request) {
|
func serveStatic(w http.ResponseWriter, request *http.Request) {
|
||||||
filepath := request.URL.Path
|
filepath := request.URL.Path
|
||||||
w.Header().Set("Cache-Control", "private, max-age=0, no-cache")
|
w.Header().Set("Cache-Control", "private, max-age=0, no-cache")
|
||||||
http.ServeFile(w, request, path.Join(STATIC_DIR_PATH, filepath))
|
http.ServeFile(w, request, path.Join(STATIC_DIR_PATH, filepath))
|
||||||
@@ -26,7 +26,7 @@ func serveStatic2(w http.ResponseWriter, request *http.Request) {
|
|||||||
func main() {
|
func main() {
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.Handle("/api/", api.Create("/api"))
|
mux.Handle("/api/", api.Create("/api"))
|
||||||
mux.HandleFunc("/", serveStatic2)
|
mux.HandleFunc("/", serveStatic)
|
||||||
|
|
||||||
address := GetAddressToServe()
|
address := GetAddressToServe()
|
||||||
fmt.Println("server running at", address)
|
fmt.Println("server running at", address)
|
||||||
|
|||||||
+1
-1
@@ -69,7 +69,7 @@ func (p *Params) InsertDefaultValues() *Params {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LoadFromYamlFile(fileName string) (*Params, error) {
|
func LoadFromYamlFile(fileName string) (*Params, error) {
|
||||||
if !Exists(fileName) {
|
if !exists(fileName) {
|
||||||
return new(Params).InsertDefaultValues(), nil
|
return new(Params).InsertDefaultValues(), nil
|
||||||
}
|
}
|
||||||
data, err := ioutil.ReadFile(fileName)
|
data, err := ioutil.ReadFile(fileName)
|
||||||
|
|||||||
+46
-2
@@ -1,8 +1,17 @@
|
|||||||
package shared
|
package shared
|
||||||
|
|
||||||
import "os"
|
import (
|
||||||
|
"crypto/subtle"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"github.com/dchest/siphash"
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
func Exists(name string) bool {
|
var idHashKey []byte = []byte("semi-private-key")
|
||||||
|
|
||||||
|
func exists(name string) bool {
|
||||||
if _, err := os.Stat(name); err != nil {
|
if _, err := os.Stat(name); err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return false
|
return false
|
||||||
@@ -10,3 +19,38 @@ func Exists(name string) bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateId(id []byte) error {
|
||||||
|
if len(id) != 16 {
|
||||||
|
return errors.New("valid ids are 16 bytes (126 bit) long.")
|
||||||
|
}
|
||||||
|
h := siphash.New(idHashKey)
|
||||||
|
h.Write(id[4:16])
|
||||||
|
if subtle.ConstantTimeCompare(h.Sum(nil)[0:4], id[0:4]) != 1 {
|
||||||
|
return errors.New("invalid id checksum")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ObjectIdToPublicId(id bson.ObjectId) string {
|
||||||
|
if id == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
h := siphash.New(idHashKey)
|
||||||
|
h.Write([]byte(id))
|
||||||
|
return base64.URLEncoding.EncodeToString(append(h.Sum(nil)[0:4], []byte(id)...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func PublicIdToObjectId(id string) (bson.ObjectId, error) {
|
||||||
|
if id == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
cypher, err := base64.URLEncoding.DecodeString(id)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err := validateId(cypher); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return bson.ObjectId(cypher[4:16]), nil
|
||||||
|
}
|
||||||
Reference in new issue
Block a user