Commit f1a6eb37 authored by Loïck Bonniot's avatar Loïck Bonniot
Browse files

[p/contract] Add route and DFSS file generation

- Enhance package structure
- Improve platform tests
parent 20a9ed21
Pipeline #225 passed with stage
......@@ -19,6 +19,7 @@ Unit tests:
script:
- "ln -s $(pwd) $GOPATH/src/dfss"
- "./build/deps.sh"
- "cd $GOPATH/src/dfss && go install ./..."
- "go test -coverprofile auth.part -v dfss/auth"
- "go test -coverprofile mgdb.part -v dfss/mgdb"
- "go test -coverprofile mails.part -v dfss/mails"
......@@ -37,6 +38,7 @@ ARM tests:
script:
- "ln -s -f $(pwd) $GOPATH/src/dfss"
- "./build/deps.sh"
- "cd $GOPATH/src/dfss && go install ./..."
- "go test -cover -short -v dfss/auth"
- "go test -cover -short -v dfss/mgdb"
- "go test -cover -short -v dfss/net"
......
......@@ -84,9 +84,10 @@ func GetSelfSignedCertificate(days int, serial uint64, country, organization, un
OrganizationalUnit: []string{unit},
CommonName: cn,
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(0, 0, days),
IsCA: true,
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(0, 0, days),
BasicConstraintsValid: true,
IsCA: true,
}
der, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
......
......@@ -5,3 +5,4 @@ go get -u github.com/golang/protobuf/proto
go get -u github.com/golang/protobuf/protoc-gen-go
go get -u google.golang.org/grpc
go get -u github.com/pborman/uuid
go get -u github.com/bmizerany/assert
package api
const (
// INTERR is the error code for an internal server error
INTERR = -1
// SUCCESS is the error code for a successful requeset
SUCCESS = 0
// INVARG is the error code for an invalid argument
INVARG = 1
)
......@@ -38,6 +38,41 @@ var _ = math.Inf
// is compatible with the proto package it is being compiled against.
const _ = proto.ProtoPackageIsVersion1
type ErrorCode_Code int32
const (
// SUCCESS is the error code for a successful request
ErrorCode_SUCCESS ErrorCode_Code = 0
// INVARG is the error code for an invalid argument
ErrorCode_INVARG ErrorCode_Code = 1
// BADAUTH is the error code for a bad authentication
ErrorCode_BADAUTH ErrorCode_Code = 2
// WARNING is the error code for a success state containing a specific warning message
ErrorCode_WARNING ErrorCode_Code = 3
// INTERR is the error code for an internal server error
ErrorCode_INTERR ErrorCode_Code = -1
)
var ErrorCode_Code_name = map[int32]string{
0: "SUCCESS",
1: "INVARG",
2: "BADAUTH",
3: "WARNING",
-1: "INTERR",
}
var ErrorCode_Code_value = map[string]int32{
"SUCCESS": 0,
"INVARG": 1,
"BADAUTH": 2,
"WARNING": 3,
"INTERR": -1,
}
func (x ErrorCode_Code) String() string {
return proto.EnumName(ErrorCode_Code_name, int32(x))
}
func (ErrorCode_Code) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1, 0} }
// RegisterRequest message contains the client's email adress and his
// public key
type RegisterRequest struct {
......@@ -53,8 +88,8 @@ func (*RegisterRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, [
// ErrorCode message contains an error code (see dffs/dfssp/api/errorCodes.go)
// and a message
type ErrorCode struct {
Code int32 `protobuf:"varint,1,opt,name=code" json:"code,omitempty"`
Message string `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"`
Code ErrorCode_Code `protobuf:"varint,1,opt,name=code,enum=api.ErrorCode_Code" json:"code,omitempty"`
Message string `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"`
}
func (m *ErrorCode) Reset() { *m = ErrorCode{} }
......@@ -95,12 +130,13 @@ func (m *Empty) String() string { return proto.CompactTextString(m) }
func (*Empty) ProtoMessage() {}
func (*Empty) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
// PostContractRequest message contains the contract as SHA-512 hash, the list of signers
// as an array of string, and a comment
// PostContractRequest message contains the contract as SHA-512 hash, its filename,
// the list of signers as an array of strings, and a comment
type PostContractRequest struct {
Contract string `protobuf:"bytes,1,opt,name=contract" json:"contract,omitempty"`
Signer []string `protobuf:"bytes,2,rep,name=signer" json:"signer,omitempty"`
Comment string `protobuf:"bytes,3,opt,name=comment" json:"comment,omitempty"`
Hash string `protobuf:"bytes,1,opt,name=hash" json:"hash,omitempty"`
Filename string `protobuf:"bytes,2,opt,name=filename" json:"filename,omitempty"`
Signer []string `protobuf:"bytes,3,rep,name=signer" json:"signer,omitempty"`
Comment string `protobuf:"bytes,4,opt,name=comment" json:"comment,omitempty"`
}
func (m *PostContractRequest) Reset() { *m = PostContractRequest{} }
......@@ -139,6 +175,7 @@ func init() {
proto.RegisterType((*PostContractRequest)(nil), "api.PostContractRequest")
proto.RegisterType((*JoinSignatureRequest)(nil), "api.JoinSignatureRequest")
proto.RegisterType((*ReadySignRequest)(nil), "api.ReadySignRequest")
proto.RegisterEnum("api.ErrorCode_Code", ErrorCode_Code_name, ErrorCode_Code_value)
}
// Reference imports to suppress errors if they are not otherwise used.
......@@ -338,31 +375,37 @@ var _Platform_serviceDesc = grpc.ServiceDesc{
}
var fileDescriptor0 = []byte{
// 416 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x94, 0x53, 0xd1, 0xaa, 0xd3, 0x40,
0x10, 0xf5, 0x36, 0xb7, 0xf7, 0xb6, 0x63, 0xef, 0xb5, 0x4c, 0xab, 0xc4, 0x3e, 0x88, 0xec, 0x93,
0xf8, 0x50, 0xa1, 0x8a, 0xa0, 0xf8, 0x22, 0xa1, 0x2f, 0x22, 0x52, 0xb6, 0xf4, 0x03, 0x62, 0x32,
0xc6, 0xa5, 0x4d, 0x36, 0xee, 0x6e, 0x84, 0x7e, 0xa3, 0x3f, 0xe5, 0x66, 0xb3, 0x09, 0x8d, 0x06,
0xc1, 0xa7, 0xec, 0x99, 0xd9, 0x73, 0x66, 0xe6, 0xcc, 0x06, 0x30, 0xe3, 0xbb, 0x68, 0x4f, 0xea,
0xa7, 0x48, 0x48, 0xaf, 0x4b, 0x25, 0x8d, 0xc4, 0x20, 0x2e, 0x05, 0x7b, 0x07, 0x8f, 0x38, 0x65,
0x42, 0x1b, 0x52, 0x9c, 0x7e, 0x54, 0xa4, 0x0d, 0x2e, 0x61, 0x4c, 0x79, 0x2c, 0x4e, 0xe1, 0xd5,
0xf3, 0xab, 0x17, 0x53, 0xde, 0x00, 0x9c, 0x43, 0x70, 0xa4, 0x73, 0x38, 0x72, 0xb1, 0xfa, 0x68,
0xa9, 0xd3, 0xad, 0x52, 0x52, 0x45, 0x32, 0x25, 0x44, 0xb8, 0x4e, 0xec, 0xd7, 0x71, 0xc6, 0xdc,
0x9d, 0x31, 0x84, 0xdb, 0x9c, 0xb4, 0x8e, 0x33, 0xf2, 0xb4, 0x16, 0x5a, 0xea, 0xc3, 0x8f, 0x95,
0xf9, 0xfe, 0xef, 0x8a, 0x36, 0x6a, 0xe4, 0x91, 0x0a, 0x4f, 0x6e, 0x00, 0xfb, 0x0c, 0xf7, 0x6d,
0xc3, 0x94, 0x1e, 0x34, 0x29, 0x5c, 0xc1, 0x44, 0x49, 0x69, 0x22, 0x52, 0xc6, 0x09, 0xcc, 0x78,
0x87, 0xf1, 0x19, 0x40, 0x72, 0x12, 0x54, 0x34, 0xd9, 0x91, 0xcb, 0x5e, 0x44, 0xd8, 0x2d, 0x8c,
0xb7, 0x79, 0x69, 0xce, 0x2c, 0x81, 0xc5, 0x4e, 0x6a, 0x13, 0xc9, 0xc2, 0xa8, 0x38, 0x31, 0x6d,
0x67, 0x56, 0x3b, 0xf1, 0x21, 0xdf, 0x5c, 0x87, 0xf1, 0x09, 0xdc, 0x68, 0x91, 0x15, 0xa4, 0xac,
0x6e, 0x60, 0x33, 0x1e, 0xd5, 0x63, 0x27, 0x32, 0xcf, 0x6d, 0x89, 0x30, 0x68, 0xc6, 0xf6, 0x90,
0x7d, 0x81, 0xe5, 0x27, 0x29, 0x8a, 0xbd, 0xbd, 0x17, 0x9b, 0x4a, 0x51, 0x5b, 0x85, 0xc1, 0xac,
0x55, 0x3d, 0x54, 0x22, 0xf5, 0x95, 0x7a, 0xb1, 0xda, 0xe0, 0x52, 0xfa, 0x19, 0xee, 0xb8, 0x3b,
0xb3, 0xb7, 0x30, 0xe7, 0x14, 0xa7, 0xe7, 0x5a, 0xf0, 0x3f, 0xb4, 0x36, 0xbf, 0x46, 0x30, 0xd9,
0x9d, 0x62, 0xf3, 0x4d, 0xaa, 0x1c, 0x37, 0x30, 0x69, 0x0d, 0xc5, 0xe5, 0xda, 0xbe, 0x89, 0xf5,
0x1f, 0x0f, 0x62, 0x75, 0xef, 0xa2, 0xdd, 0xae, 0xd9, 0x03, 0x7c, 0x05, 0xd7, 0xf5, 0xfe, 0x70,
0xee, 0x32, 0x17, 0xab, 0x5c, 0x2d, 0x7a, 0x0a, 0xcd, 0x86, 0x2c, 0xe1, 0x25, 0xc0, 0xa1, 0x50,
0x6d, 0x19, 0x68, 0x04, 0x6b, 0xe3, 0x07, 0xc4, 0xdf, 0xc3, 0xec, 0x72, 0x15, 0x18, 0xba, 0x1b,
0x03, 0xdb, 0x19, 0xe0, 0x7e, 0x80, 0xbb, 0x9e, 0xc3, 0xf8, 0xd4, 0x5d, 0x19, 0x72, 0x7d, 0x80,
0xfd, 0x06, 0xa6, 0x9d, 0x9f, 0xf8, 0xd8, 0x4f, 0xd2, 0xf7, 0xf7, 0x6f, 0xd6, 0xd7, 0x1b, 0xf7,
0x3b, 0xbd, 0xfe, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x17, 0x95, 0x89, 0x4a, 0x64, 0x03, 0x00, 0x00,
// 501 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x94, 0x53, 0x5f, 0x8f, 0x93, 0x40,
0x10, 0xbf, 0x16, 0xee, 0xda, 0xce, 0xf5, 0x2a, 0x99, 0x56, 0x83, 0x7d, 0x30, 0x17, 0x5e, 0x34,
0x3e, 0xd4, 0xa4, 0x1a, 0x13, 0x8d, 0x2f, 0x88, 0xcd, 0x79, 0xc6, 0x34, 0xcd, 0x72, 0xe8, 0x33,
0xd2, 0xb9, 0x96, 0x5c, 0x61, 0xeb, 0xb2, 0xd5, 0xf4, 0xcb, 0xf8, 0x85, 0xfc, 0x50, 0xca, 0x2e,
0xd0, 0x14, 0x25, 0x26, 0xf2, 0x00, 0xfb, 0x9b, 0x3f, 0xbf, 0x99, 0xf9, 0xcd, 0x02, 0xb8, 0x62,
0x0b, 0xcf, 0x27, 0xf1, 0x2d, 0x8e, 0x28, 0x9b, 0x6c, 0x05, 0x97, 0x1c, 0x8d, 0x70, 0x1b, 0x3b,
0xaf, 0xe0, 0x1e, 0xa3, 0x55, 0x9c, 0x49, 0x12, 0x8c, 0xbe, 0xee, 0x28, 0x93, 0x38, 0x82, 0x53,
0x4a, 0xc2, 0x78, 0x63, 0xb7, 0x2e, 0x5b, 0x4f, 0x7a, 0xac, 0x00, 0x68, 0x81, 0x71, 0x47, 0x7b,
0xbb, 0xad, 0x6d, 0xea, 0xe8, 0xfc, 0x68, 0x41, 0x6f, 0x26, 0x04, 0x17, 0x1e, 0x5f, 0x12, 0x3e,
0x06, 0x33, 0xca, 0xbf, 0x3a, 0x69, 0x30, 0x1d, 0x4e, 0x72, 0xf2, 0xc9, 0xc1, 0x3b, 0x51, 0x2f,
0xa6, 0x03, 0xd0, 0x86, 0x4e, 0x42, 0x59, 0x16, 0xae, 0xa8, 0x24, 0xab, 0xa0, 0x33, 0x07, 0x53,
0x53, 0x9d, 0x43, 0xc7, 0x0f, 0x3c, 0x6f, 0xe6, 0xfb, 0xd6, 0x09, 0x02, 0x9c, 0x5d, 0xcf, 0x3f,
0xb9, 0xec, 0xca, 0x6a, 0x29, 0xc7, 0x5b, 0xf7, 0x9d, 0x1b, 0xdc, 0xbc, 0xb7, 0xda, 0x0a, 0x7c,
0x76, 0xd9, 0xfc, 0x7a, 0x7e, 0x65, 0x19, 0x38, 0x54, 0x51, 0x37, 0x33, 0xc6, 0xac, 0x5f, 0xd5,
0xd3, 0xca, 0x67, 0x3b, 0x77, 0x77, 0x72, 0xfd, 0xef, 0xb9, 0x72, 0xab, 0xe4, 0x77, 0x94, 0x96,
0xcd, 0x14, 0xc0, 0xf9, 0x08, 0x83, 0x4a, 0x16, 0x5a, 0x06, 0x19, 0x09, 0x1c, 0x43, 0x57, 0x70,
0x2e, 0x3d, 0x12, 0x52, 0x13, 0xf4, 0xd9, 0x01, 0xe3, 0x23, 0x80, 0x68, 0x13, 0x53, 0x5a, 0x78,
0xdb, 0xda, 0x7b, 0x64, 0x71, 0x3a, 0x70, 0x3a, 0x4b, 0xb6, 0x72, 0xef, 0x7c, 0x87, 0xe1, 0x82,
0x67, 0xd2, 0xe3, 0xa9, 0x14, 0x61, 0x24, 0xab, 0xce, 0x10, 0xcc, 0x75, 0x98, 0xad, 0xcb, 0xc6,
0xf4, 0x59, 0xd5, 0xbb, 0x8d, 0x37, 0x94, 0x86, 0x49, 0xa5, 0xd3, 0x01, 0xe3, 0x03, 0x38, 0xcb,
0xe2, 0x55, 0x4a, 0xc2, 0x36, 0x2e, 0x8d, 0xdc, 0x53, 0x22, 0x25, 0x6d, 0xc4, 0x93, 0x24, 0x2f,
0x6b, 0x9b, 0x85, 0xb4, 0x25, 0xcc, 0xa5, 0x1d, 0x7d, 0xe0, 0x71, 0xea, 0xe7, 0x71, 0xa1, 0xdc,
0x09, 0xaa, 0x2a, 0x3b, 0xd0, 0x8f, 0xca, 0x66, 0x82, 0x5d, 0xbc, 0x2c, 0x3b, 0xa8, 0xd9, 0x54,
0x77, 0x5b, 0x5e, 0xce, 0x75, 0xc1, 0xf4, 0xd9, 0x79, 0x09, 0x16, 0xa3, 0x70, 0xb9, 0x57, 0x84,
0xff, 0xc1, 0x35, 0xfd, 0xd9, 0x86, 0xee, 0x62, 0x13, 0xca, 0x5b, 0x2e, 0x12, 0x9c, 0x42, 0xb7,
0x12, 0x19, 0x47, 0xfa, 0xc2, 0xfc, 0x71, 0x15, 0xc7, 0x83, 0xfa, 0x35, 0x72, 0x4e, 0xf0, 0x19,
0x98, 0x6a, 0xa7, 0x68, 0x69, 0xcf, 0xd1, 0x7a, 0xc7, 0xc3, 0x1a, 0x43, 0xb1, 0xb5, 0x3c, 0xe1,
0x29, 0x40, 0x90, 0x8a, 0xaa, 0x0c, 0x14, 0x84, 0x6a, 0x19, 0x0d, 0xe4, 0xaf, 0xa1, 0x7f, 0xbc,
0x1e, 0xb4, 0x75, 0x44, 0xc3, 0xc6, 0x1a, 0x72, 0xdf, 0xc0, 0x45, 0x4d, 0x61, 0x7c, 0xa8, 0x43,
0x9a, 0x54, 0x6f, 0xc8, 0x7e, 0x01, 0xbd, 0x83, 0x9e, 0x78, 0xbf, 0x9c, 0xa4, 0xae, 0xef, 0xdf,
0x59, 0x5f, 0xce, 0xf4, 0x8f, 0xfc, 0xfc, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8b, 0x69, 0xb3,
0x9e, 0xde, 0x03, 0x00, 0x00,
}
......@@ -21,7 +21,19 @@ message RegisterRequest {
// ErrorCode message contains an error code (see dffs/dfssp/api/errorCodes.go)
// and a message
message ErrorCode {
int32 code = 1;
enum Code {
// SUCCESS is the error code for a successful request
SUCCESS = 0;
// INVARG is the error code for an invalid argument
INVARG = 1;
// BADAUTH is the error code for a bad authentication
BADAUTH = 2;
// WARNING is the error code for a success state containing a specific warning message
WARNING = 3;
// INTERR is the error code for an internal server error
INTERR = -1;
}
Code code = 1;
string message = 2;
}
......@@ -43,19 +55,20 @@ message RegisteredUser {
message Empty {
}
// PostContractRequest message contains the contract as SHA-512 hash, the list of signers
// as an array of string, and a comment
// PostContractRequest message contains the contract as SHA-512 hash, its filename,
// the list of signers as an array of strings, and a comment
message PostContractRequest {
string contract = 1;
repeated string signer = 2;
string comment = 3;
string hash = 1;
string filename = 2;
repeated string signer = 3;
string comment = 4;
}
// JoinSignatureRequest message contains the contract to join unique identifier
// and the port the client will be listening at
message JoinSignatureRequest {
string contractUuid = 1;
uint32 port =2;
uint32 port = 2;
}
// ReadySignRequest contains the contract unique identitier that is ready to be signed
......
package contract_test // Using another package to avoid import cycles
import (
"fmt"
"os"
"path/filepath"
"testing"
"dfss/dfssp/entities"
"dfss/dfssp/server"
"dfss/mgdb"
"dfss/net"
"github.com/bmizerany/assert"
"gopkg.in/mgo.v2/bson"
)
var err error
var collection *mgdb.MongoCollection
var manager *mgdb.MongoManager
var dbURI string
var repository *entities.ContractRepository
func TestMain(m *testing.M) {
dbURI = os.Getenv("DFSS_MONGO_URI")
if dbURI == "" {
dbURI = "mongodb://localhost/dfss-test"
}
manager, err = mgdb.NewManager(dbURI)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
collection = manager.Get("demo")
repository = entities.NewContractRepository(collection)
// Start platform server
keyPath := filepath.Join(os.Getenv("GOPATH"), "src", "dfss", "dfssp", "testdata")
srv := server.GetServer(keyPath, dbURI, true)
go func() { _ = net.Listen("localhost:9090", srv) }()
// Run
code := m.Run()
dropDataset()
manager.Close()
os.Exit(code)
}
func TestAddSigner(t *testing.T) {
c := entities.NewContract()
id := bson.NewObjectId()
c.AddSigner(nil, "mail1", "hash1")
c.AddSigner(&id, "mail2", "hash2")
signers := c.Signers
if len(signers) != 2 {
t.Fatal("Signers are not inserted correctly")
}
assert.Equal(t, signers[0].Email, "mail1")
assert.Equal(t, signers[0].Hash, "hash1")
assert.Equal(t, signers[0].UserID.Hex(), "000000000000000000000000")
assert.Equal(t, signers[1].Email, "mail2")
assert.Equal(t, signers[1].Hash, "hash2")
assert.Equal(t, signers[1].UserID.Hex(), id.Hex())
}
func assertContractEqual(t *testing.T, contract, fetched entities.Contract) {
assert.Equal(t, contract.File, fetched.File)
assert.Equal(t, contract.Date.Unix(), fetched.Date.Unix())
assert.Equal(t, contract.Comment, fetched.Comment)
assert.Equal(t, contract.Ready, fetched.Ready)
assert.Equal(t, contract.Signers, fetched.Signers)
}
// Insert a contract with 2 users and check the fields are correctly persisted
func TestInsertContract(t *testing.T) {
c := entities.NewContract()
c.AddSigner(nil, "mail1", "hash1")
c.AddSigner(nil, "mail1", "hash1")
c.File.Name = "file"
c.File.Hash = "hashFile"
c.File.Hosted = false
c.Comment = "comment"
c.Ready = true
_, err := repository.Collection.Insert(c)
if err != nil {
t.Fatal("Contract not inserted successfully in the database:", err)
}
fetched := entities.Contract{}
selector := entities.Contract{
ID: c.ID,
}
err = repository.Collection.FindByID(selector, &fetched)
if err != nil {
t.Fatal("Contract could not be successfully retrieved:", err)
}
assertContractEqual(t, *c, fetched)
}
package contract
import (
"crypto/sha512"
"log"
"time"
"dfss/dfssp/api"
"dfss/dfssp/entities"
"dfss/mgdb"
"gopkg.in/mgo.v2/bson"
)
// PostRoute is the GRPC route designed to create a contract.
func PostRoute(m *mgdb.MongoManager, in *api.PostContractRequest) *api.ErrorCode {
inputError := checkInput(in)
if inputError != nil {
return inputError
}
signers, missingSigners, err := fetchSigners(m, in.Signer)
if err != nil {
log.Println(err)
return &api.ErrorCode{Code: api.ErrorCode_INTERR, Message: "Database error"}
}
err = addContract(m, in, signers, missingSigners)
if err != nil {
log.Println(err)
return &api.ErrorCode{Code: api.ErrorCode_INTERR}
}
if len(missingSigners) > 0 {
return &api.ErrorCode{Code: api.ErrorCode_WARNING, Message: "Some users are not ready yet"}
}
return &api.ErrorCode{Code: api.ErrorCode_SUCCESS}
}
func checkInput(in *api.PostContractRequest) *api.ErrorCode {
if len(in.Signer) == 0 {
return &api.ErrorCode{Code: api.ErrorCode_INVARG, Message: "Expecting at least one signer"}
}
if len(in.Filename) == 0 {
return &api.ErrorCode{Code: api.ErrorCode_INVARG, Message: "Expecting a valid filename"}
}
if len(in.Hash) != sha512.Size {
return &api.ErrorCode{Code: api.ErrorCode_INVARG, Message: "Expecting a valid sha512 hash"}
}
return nil
}
func fetchSigners(m *mgdb.MongoManager, signers []string) ([]entities.User, []string, error) {
var users []entities.User
err := m.Get("users").FindAll(bson.M{
"expiration": bson.M{"$gt": time.Now()},
"email": bson.M{"$in": signers},
}, &users)
if err != nil {
return nil, nil, err
}
// Locate missing users
var missing []string
for _, s := range signers {
found := false
for _, u := range users {
if s == u.Email {
found = true
break
}
}
if !found {
missing = append(missing, s)
}
}
return users, missing, nil
}
func addContract(m *mgdb.MongoManager, in *api.PostContractRequest, signers []entities.User, missingSigners []string) error {
contract := entities.NewContract()
for _, s := range signers {
contract.AddSigner(&s.ID, s.Email, s.CertHash)
}
for _, s := range missingSigners {
contract.AddSigner(nil, s, "")
}
contract.Comment = in.Comment
contract.Ready = len(missingSigners) == 0
contract.File.Name = in.Filename
contract.File.Hash = in.Hash
contract.File.Hosted = false
_, err := m.Get("contracts").Insert(contract)
return err
}
package contract_test
import (
"crypto/sha512"
"io/ioutil"
"os"
"path/filepath"
"testing"
"time"
"dfss/auth"
"dfss/dfssp/api"
"dfss/dfssp/entities"
"dfss/net"
"github.com/bmizerany/assert"
"golang.org/x/net/context"
)
var user1, user2, user3 *entities.User
var defaultHash = sha512.Sum512([]byte{0})
var defaultHashStr = string(defaultHash[:sha512.Size])
func createDataset() {
user1 = entities.NewUser() // Regular user
user2 = entities.NewUser() // Regular user
user3 = entities.NewUser() // Non-auth user
user1.Email = "user1@example.com"
user1.Expiration = time.Now().AddDate(1, 0, 0)
user1.Certificate = "Certificate1"
user1.CertHash = "Hash1"
user2.Email = "user2@example.com"
user2.Expiration = time.Now().AddDate(1, 0, 0)
user2.Certificate = "Certificate2"
user2.CertHash = "Hash2"
user3.Email = "user3@example.com"
user3.Expiration = time.Now().AddDate(0, 0, -1)
user3.Certificate = "Certificate3"
user3.CertHash = "Hash3"
_, _ = manager.Get("users").Insert(user1)
_, _ = manager.Get("users").Insert(user2)
_, _ = manager.Get("users").Insert(user3)
}
func dropDataset() {
_ = manager.Get("users").Drop()
_ = manager.Get("contracts").Drop()
}
func clientTest(t *testing.T) api.PlatformClient {
path := filepath.Join(os.Getenv("GOPATH"), "src", "dfss", "dfssp", "testdata", "dfssp_rootCA.pem")
CAData, err := ioutil.ReadFile(path)
if err != nil {
t.Fatal("Unable to load CA file:", err)
}
CA, err := auth.PEMToCertificate(CAData)
conn, err := net.Connect("localhost:9090", nil, nil, CA)
if err != nil {
t.Fatal("Unable to connect:", err)
}
return api.NewPlatformClient(conn)
}
func TestAddContract(t *testing.T) {
dropDataset()
createDataset()
client := clientTest(t)
errorCode, err := client.PostContract(context.Background(), &api.PostContractRequest{
Hash: defaultHashStr,
Filename: "ContractFilename",
Signer: []string{user1.Email, user2.Email},
Comment: "ContractComment",
})
if err != nil {
t.Fatal(err)
}
if errorCode.Code != api.ErrorCode_SUCCESS {
t.Fatal("Unexpected errorCode:", errorCode)
}
// Check database content
var contracts []entities.Contract
err = manager.Get("contracts").FindAll(nil, &contracts)
if err != nil {
t.Fatal("Unexpected db error:", err)
}
assert.Equal(t, 1, len(contracts))
assert.Equal(t, defaultHashStr, contracts[0].File.Hash)
assert.Equal(t, "ContractFilename", contracts[0].File.Name)
assert.Equal(t, "ContractComment", contracts[0].Comment)
assert.T(t, contracts[0].Ready)
assert.Equal(t, user1.ID, contracts[0].Signers[0].UserID)
assert.Equal(t, user1.CertHash, contracts[0].Signers[0].Hash)
assert.Equal(t, user1.Email, contracts[0].Signers[0].Email)
assert.Equal(t, user2.ID, contracts[0].Signers[1].UserID)
assert.Equal(t, user2.CertHash, contracts[0].Signers[1].Hash)
assert.Equal(t, user2.Email, contracts[0].Signers[1].Email)
}
func TestAddContractMissingUser(t *testing.T) {
dropDataset()
createDataset()
client := clientTest(t)
errorCode, err := client.PostContract(context.Background(), &api.PostContractRequest{
Hash: defaultHashStr,
Filename: "ContractFilename",
Signer: []string{user1.Email, user3.Email},
})
assert.Equal(t, nil, err)
assert.Equal(t, api.ErrorCode_WARNING, errorCode.Code)
// Check database content
</