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) {
|
||||
fmt.Fprint(w, `{"doormen" :[`)
|
||||
doormenIds := conn.GetAllDoormen()
|
||||
buff := <-doormenIds
|
||||
if buff == nil {
|
||||
fmt.Fprint(w, "]}")
|
||||
fmt.Fprint(w, `{"doormen" :[]}`)
|
||||
return
|
||||
}
|
||||
fmt.Fprint(w, `{"doormen" :[`)
|
||||
for doormanId := range doormenIds {
|
||||
fmt.Fprint(w, getDoormenIdsAsJson(buff)+`,`)
|
||||
buff = doormanId
|
||||
|
||||
@@ -29,7 +29,7 @@ func TestGetAllDoormen(t *testing.T) {
|
||||
GetAllDoormen(w, req)
|
||||
|
||||
d := json.NewDecoder(w.Body)
|
||||
m := make(map[string][]*doormen.DoormanDefinition)
|
||||
m := make(map[string][]*doormen.DoormanId)
|
||||
|
||||
if err := d.Decode(&m); err != nil {
|
||||
t.Error(err)
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/didiercrunch/doormanserver/doormen"
|
||||
"github.com/didiercrunch/doormanserver/shared"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"net/http"
|
||||
)
|
||||
@@ -30,6 +31,6 @@ func CreateDoorman(w http.ResponseWriter, request *http.Request) {
|
||||
return
|
||||
}
|
||||
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)
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package api
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/didiercrunch/doormanserver/inmemoryconnector"
|
||||
"github.com/didiercrunch/doormanserver/shared"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -11,7 +12,12 @@ import (
|
||||
)
|
||||
|
||||
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) {
|
||||
|
||||
+5
-3
@@ -3,6 +3,7 @@ package api
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/didiercrunch/doormanserver/doormen"
|
||||
"github.com/didiercrunch/doormanserver/shared"
|
||||
"github.com/gorilla/mux"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"log"
|
||||
@@ -10,15 +11,16 @@ import (
|
||||
)
|
||||
|
||||
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 {
|
||||
id := mux.Vars(request)["id"]
|
||||
if !bson.IsObjectIdHex(id) {
|
||||
if id, err := shared.PublicIdToObjectId(id); err != nil {
|
||||
return ""
|
||||
} else {
|
||||
return bson.ObjectIdHex(id)
|
||||
return id
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-9
@@ -17,11 +17,6 @@ type DoormanValue struct {
|
||||
Probability *big.Rat `json:"probability"`
|
||||
}
|
||||
|
||||
type doormanValue struct {
|
||||
Name string
|
||||
Probability string
|
||||
}
|
||||
|
||||
type DoormanId struct {
|
||||
Id bson.ObjectId `json:"id,omitempty" bson:"_id"`
|
||||
Name string `json:"name" bson:"name"`
|
||||
@@ -35,10 +30,10 @@ func (wId *DoormanId) AsJson() string {
|
||||
}
|
||||
|
||||
type DoormanDefinition struct {
|
||||
Id bson.ObjectId `json:"id,omitempty" bson:"_id"`
|
||||
Name string `json:"name" bson:"name"`
|
||||
Values []*DoormanValue `json:"values" bson:"values"`
|
||||
OwnerEmails []string `json:"emails" bson:"emails"`
|
||||
Id bson.ObjectId `bson:"_id"`
|
||||
Name string `bson:"name"`
|
||||
Values []*DoormanValue `bson:"values"`
|
||||
OwnerEmails []string `bson:"emails"`
|
||||
}
|
||||
|
||||
func NewDoormanDefinition(name string, ownerEmails ...string) *DoormanDefinition {
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
package doormen
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/didiercrunch/doormanserver/shared"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type doormanValue struct {
|
||||
Name string
|
||||
Probability string
|
||||
}
|
||||
|
||||
func (val *DoormanValue) GetBSON() (interface{}, error) {
|
||||
ret := &doormanValue{val.Name, ""}
|
||||
txt, err := val.Probability.MarshalText()
|
||||
@@ -24,3 +31,60 @@ func (val *DoormanValue) SetBSON(raw bson.Raw) error {
|
||||
val.Probability = new(big.Rat)
|
||||
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
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"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) {
|
||||
dmd := QuickNewDoormanDefinition("test bson", "1/4", "3/4")
|
||||
data, err := bson.Marshal(dmd)
|
||||
@@ -36,3 +73,19 @@ func TestBsonEncoding(t *testing.T) {
|
||||
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)
|
||||
}
|
||||
|
||||
func serveStatic2(w http.ResponseWriter, request *http.Request) {
|
||||
func serveStatic(w http.ResponseWriter, request *http.Request) {
|
||||
filepath := request.URL.Path
|
||||
w.Header().Set("Cache-Control", "private, max-age=0, no-cache")
|
||||
http.ServeFile(w, request, path.Join(STATIC_DIR_PATH, filepath))
|
||||
@@ -26,7 +26,7 @@ func serveStatic2(w http.ResponseWriter, request *http.Request) {
|
||||
func main() {
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/api/", api.Create("/api"))
|
||||
mux.HandleFunc("/", serveStatic2)
|
||||
mux.HandleFunc("/", serveStatic)
|
||||
|
||||
address := GetAddressToServe()
|
||||
fmt.Println("server running at", address)
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@ func (p *Params) InsertDefaultValues() *Params {
|
||||
}
|
||||
|
||||
func LoadFromYamlFile(fileName string) (*Params, error) {
|
||||
if !Exists(fileName) {
|
||||
if !exists(fileName) {
|
||||
return new(Params).InsertDefaultValues(), nil
|
||||
}
|
||||
data, err := ioutil.ReadFile(fileName)
|
||||
|
||||
+46
-2
@@ -1,8 +1,17 @@
|
||||
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 os.IsNotExist(err) {
|
||||
return false
|
||||
@@ -10,3 +19,38 @@ func Exists(name string) bool {
|
||||
}
|
||||
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