Commit d8ee0857 authored by Loïck Bonniot's avatar Loïck Bonniot

[p] Add JoinSignature API

parent 438c6a5f
......@@ -17,6 +17,7 @@ It has these top-level messages:
......@@ -161,6 +162,7 @@ func (*JoinSignatureRequest) Descriptor() ([]byte, []int) { return fileDescripto
type UserConnected struct {
ErrorCode *ErrorCode `protobuf:"bytes,1,opt,name=errorCode" json:"errorCode,omitempty"`
ContractUuid string `protobuf:"bytes,2,opt,name=contractUuid" json:"contractUuid,omitempty"`
User *User `protobuf:"bytes,3,opt,name=user" json:"user,omitempty"`
func (m *UserConnected) Reset() { *m = UserConnected{} }
......@@ -175,17 +177,24 @@ func (m *UserConnected) GetErrorCode() *ErrorCode {
return nil
type UserConnected_User struct {
KeyHash []byte `protobuf:"bytes,1,opt,name=KeyHash,proto3" json:"KeyHash,omitempty"`
func (m *UserConnected) GetUser() *User {
if m != nil {
return m.User
return nil
type User struct {
KeyHash []byte `protobuf:"bytes,1,opt,name=keyHash,proto3" json:"keyHash,omitempty"`
Email string `protobuf:"bytes,2,opt,name=email" json:"email,omitempty"`
Ip string `protobuf:"bytes,3,opt,name=ip" json:"ip,omitempty"`
Port uint32 `protobuf:"varint,4,opt,name=port" json:"port,omitempty"`
func (m *UserConnected_User) Reset() { *m = UserConnected_User{} }
func (m *UserConnected_User) String() string { return proto.CompactTextString(m) }
func (*UserConnected_User) ProtoMessage() {}
func (*UserConnected_User) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7, 0} }
func (m *User) Reset() { *m = User{} }
func (m *User) String() string { return proto.CompactTextString(m) }
func (*User) ProtoMessage() {}
func (*User) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
// ReadySignRequest contains the contract unique identitier that is ready to be signed
type ReadySignRequest struct {
......@@ -195,7 +204,7 @@ type ReadySignRequest struct {
func (m *ReadySignRequest) Reset() { *m = ReadySignRequest{} }
func (m *ReadySignRequest) String() string { return proto.CompactTextString(m) }
func (*ReadySignRequest) ProtoMessage() {}
func (*ReadySignRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
func (*ReadySignRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
// LaunchSignature is emitted by the platform when every signers are ready
type LaunchSignature struct {
......@@ -207,7 +216,7 @@ type LaunchSignature struct {
func (m *LaunchSignature) Reset() { *m = LaunchSignature{} }
func (m *LaunchSignature) String() string { return proto.CompactTextString(m) }
func (*LaunchSignature) ProtoMessage() {}
func (*LaunchSignature) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
func (*LaunchSignature) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} }
func (m *LaunchSignature) GetErrorCode() *ErrorCode {
if m != nil {
......@@ -225,7 +234,7 @@ func init() {
proto.RegisterType((*PostContractRequest)(nil), "api.PostContractRequest")
proto.RegisterType((*JoinSignatureRequest)(nil), "api.JoinSignatureRequest")
proto.RegisterType((*UserConnected)(nil), "api.UserConnected")
proto.RegisterType((*UserConnected_User)(nil), "api.UserConnected.User")
proto.RegisterType((*User)(nil), "api.User")
proto.RegisterType((*ReadySignRequest)(nil), "api.ReadySignRequest")
proto.RegisterType((*LaunchSignature)(nil), "api.LaunchSignature")
proto.RegisterEnum("api.ErrorCode_Code", ErrorCode_Code_name, ErrorCode_Code_value)
......@@ -462,43 +471,44 @@ var _Platform_serviceDesc = grpc.ServiceDesc{
var fileDescriptor0 = []byte{
// 605 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x94, 0x54, 0x6f, 0x6f, 0xd2, 0x40,
0x18, 0xa7, 0xa5, 0x1b, 0xe3, 0xd9, 0x60, 0xcd, 0x31, 0x4d, 0xed, 0x0b, 0xb3, 0x5c, 0x4c, 0x34,
0xc6, 0xe0, 0x82, 0x89, 0x89, 0xbe, 0xeb, 0x2a, 0xd9, 0xa6, 0x86, 0x90, 0x63, 0x68, 0xe2, 0xbb,
0x5a, 0x6e, 0xd0, 0x8c, 0xb6, 0x78, 0x3d, 0x34, 0xbc, 0xf2, 0x9b, 0xf8, 0x4d, 0xfc, 0x1c, 0x7e,
0x1c, 0xbd, 0xbb, 0xf6, 0xa0, 0x65, 0xc4, 0x64, 0xbc, 0x80, 0xfe, 0x9e, 0xff, 0xcf, 0xef, 0xf9,
0x15, 0x40, 0x53, 0x32, 0xf4, 0x47, 0x94, 0x7d, 0x8f, 0x42, 0x9a, 0x75, 0x17, 0x2c, 0xe5, 0x29,
0xaa, 0x07, 0x8b, 0x08, 0x7b, 0x70, 0x4c, 0xe8, 0x34, 0xca, 0x38, 0x65, 0x84, 0x7e, 0x5b, 0xd2,
0x8c, 0xa3, 0x13, 0xd8, 0xa3, 0x71, 0x10, 0xcd, 0x1d, 0xe3, 0xd4, 0x78, 0xd6, 0x24, 0x39, 0x40,
0x0e, 0x34, 0x58, 0x1e, 0xe0, 0x98, 0xca, 0xae, 0x21, 0xfe, 0x65, 0x40, 0xb3, 0xcf, 0x58, 0xca,
0xfc, 0x74, 0x42, 0xd1, 0x53, 0xb0, 0x42, 0xf1, 0xab, 0x92, 0xdb, 0xbd, 0x4e, 0x57, 0x34, 0xe9,
0xae, 0xbd, 0x5d, 0xf9, 0x45, 0x54, 0x80, 0x2c, 0x18, 0xd3, 0x2c, 0x0b, 0xa6, 0x54, 0x17, 0x2c,
0x20, 0x1e, 0x80, 0xa5, 0x4a, 0x1d, 0x42, 0x63, 0x34, 0xf6, 0xfd, 0xfe, 0x68, 0x64, 0xd7, 0x10,
0xc0, 0xfe, 0xd5, 0xe0, 0x93, 0x47, 0x2e, 0x6c, 0x43, 0x3a, 0xce, 0xbd, 0x77, 0xde, 0xf8, 0xfa,
0xd2, 0x36, 0x25, 0xf8, 0xec, 0x91, 0xc1, 0xd5, 0xe0, 0xc2, 0xae, 0xa3, 0x8e, 0x8c, 0xba, 0xee,
0x13, 0x62, 0xff, 0xd5, 0x1f, 0x03, 0xbf, 0x81, 0x43, 0x6f, 0xc9, 0x67, 0xff, 0xdf, 0x4f, 0x58,
0x79, 0x7a, 0x4b, 0x93, 0x62, 0x98, 0x1c, 0xe0, 0x33, 0x68, 0x6b, 0x7a, 0xe8, 0x64, 0x9c, 0x51,
0x86, 0x1e, 0x03, 0x84, 0xf3, 0x88, 0x26, 0xdc, 0xa7, 0x8c, 0x17, 0x25, 0x4a, 0x16, 0xdc, 0x80,
0xbd, 0x7e, 0xbc, 0xe0, 0x2b, 0xfc, 0x03, 0x3a, 0xc3, 0x34, 0xe3, 0x7e, 0x9a, 0x70, 0x16, 0x84,
0x5c, 0x77, 0x47, 0x60, 0xcd, 0x82, 0x6c, 0xa6, 0x32, 0x8f, 0x88, 0x7a, 0x46, 0x2e, 0x1c, 0xdc,
0x44, 0x73, 0x9a, 0x04, 0xb1, 0xe6, 0x62, 0x8d, 0xd1, 0x43, 0xd8, 0xcf, 0xa2, 0x69, 0x42, 0x99,
0x53, 0x3f, 0xad, 0x0b, 0x4f, 0x81, 0x24, 0x7d, 0x61, 0x1a, 0xc7, 0xa2, 0xad, 0x63, 0xe5, 0xf4,
0x15, 0x50, 0xd0, 0x77, 0xf2, 0x3e, 0x8d, 0x92, 0x91, 0x88, 0x0b, 0xf8, 0x92, 0x51, 0xdd, 0x19,
0xc3, 0x51, 0x58, 0x0c, 0x33, 0x5e, 0x46, 0x93, 0x62, 0xf6, 0x8a, 0x4d, 0x4e, 0xb7, 0x48, 0x59,
0x7e, 0xe2, 0x16, 0x51, 0xcf, 0xf8, 0xb7, 0x01, 0x2d, 0xb9, 0xba, 0xd8, 0x24, 0xa1, 0x21, 0xa7,
0x13, 0xf4, 0x02, 0x9a, 0x54, 0x9f, 0x54, 0x95, 0x39, 0xec, 0xb5, 0xab, 0x87, 0x26, 0x9b, 0x80,
0x3b, 0x7d, 0xcd, 0xbb, 0x7d, 0xdd, 0x2f, 0x60, 0x29, 0x76, 0xc5, 0x56, 0x1f, 0xe8, 0xea, 0x72,
0x43, 0x50, 0xe3, 0x36, 0x87, 0x9b, 0xab, 0x99, 0xe5, 0xab, 0xb5, 0xc1, 0x8c, 0x16, 0x82, 0x19,
0x69, 0x12, 0x4f, 0xeb, 0xf9, 0xad, 0xd2, 0xfc, 0xaf, 0xc1, 0x26, 0x34, 0x98, 0xac, 0x24, 0x21,
0xf7, 0xe0, 0x02, 0xff, 0x84, 0xe3, 0x8f, 0xc1, 0x32, 0x09, 0x67, 0x6b, 0x26, 0xef, 0xb9, 0xf8,
0x13, 0x68, 0x65, 0x3a, 0xb5, 0xb4, 0x79, 0xd5, 0x28, 0x57, 0x2e, 0x76, 0x2c, 0x2e, 0xac, 0x61,
0xef, 0x8f, 0x09, 0x07, 0xc3, 0x79, 0xc0, 0x6f, 0x52, 0x16, 0xa3, 0x1e, 0x1c, 0x68, 0x25, 0xa2,
0x13, 0xd5, 0x73, 0xeb, 0xbd, 0x75, 0xb7, 0x26, 0xc1, 0x35, 0xf4, 0x12, 0x2c, 0x29, 0x7c, 0x64,
0x2b, 0x4f, 0xe9, 0x1d, 0x70, 0x3b, 0x95, 0x0a, 0xb9, 0xb4, 0x45, 0xc2, 0x73, 0x80, 0x71, 0xc2,
0x74, 0x1b, 0xc8, 0x0b, 0x4a, 0x35, 0xef, 0x28, 0xfe, 0x16, 0x8e, 0xca, 0xfa, 0x46, 0x8e, 0x8a,
0xd8, 0x21, 0xf9, 0x1d, 0xb9, 0xe7, 0xd0, 0xaa, 0x48, 0x14, 0x3d, 0x52, 0x21, 0xbb, 0x64, 0xeb,
0x22, 0xe5, 0xaa, 0x08, 0x10, 0xd7, 0xce, 0x0c, 0xd1, 0xbf, 0xb9, 0x3e, 0x2b, 0x7a, 0x50, 0xec,
0x53, 0x3d, 0xb3, 0x9b, 0x13, 0xb5, 0x75, 0x45, 0x5c, 0xfb, 0xba, 0xaf, 0xfe, 0x01, 0x5f, 0xfd,
0x0b, 0x00, 0x00, 0xff, 0xff, 0x91, 0x07, 0xf4, 0xa6, 0x17, 0x05, 0x00, 0x00,
// 618 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x94, 0x54, 0x5f, 0x6f, 0xd3, 0x3e,
0x14, 0x6d, 0xd2, 0xec, 0x4f, 0xee, 0xd6, 0x2e, 0x72, 0xf7, 0xfb, 0x29, 0x54, 0x02, 0x4d, 0x16,
0x12, 0x08, 0xa1, 0x32, 0x15, 0x09, 0x09, 0xde, 0xb2, 0x50, 0x6d, 0x43, 0xa8, 0x9a, 0xdc, 0x15,
0x24, 0xde, 0x42, 0xea, 0xb5, 0xd1, 0x9a, 0xa4, 0x38, 0x0e, 0x68, 0x4f, 0xf0, 0x49, 0xf8, 0x5a,
0x7c, 0x1c, 0xb0, 0x9d, 0x38, 0x4d, 0x4a, 0x85, 0xb4, 0x3e, 0xb4, 0x3e, 0xd7, 0xd7, 0xe7, 0xf8,
0x9e, 0x7b, 0x5d, 0x40, 0x73, 0x72, 0xe5, 0x4f, 0x28, 0xfb, 0x1a, 0x85, 0x34, 0x1b, 0xac, 0x58,
0xca, 0x53, 0xd4, 0x0e, 0x56, 0x11, 0xf6, 0xe0, 0x88, 0xd0, 0x79, 0x94, 0x71, 0xca, 0x08, 0xfd,
0x92, 0xd3, 0x8c, 0xa3, 0x63, 0xd8, 0xa1, 0x71, 0x10, 0x2d, 0x5d, 0xe3, 0xc4, 0x78, 0x6a, 0x93,
0x02, 0x20, 0x17, 0xf6, 0x58, 0x91, 0xe0, 0x9a, 0x2a, 0xae, 0x21, 0xfe, 0x69, 0x80, 0x3d, 0x62,
0x2c, 0x65, 0x7e, 0x3a, 0xa3, 0xe8, 0x09, 0x58, 0xa1, 0xf8, 0x55, 0x87, 0xbb, 0xc3, 0xde, 0x40,
0x88, 0x0c, 0xaa, 0xdd, 0x81, 0xfc, 0x22, 0x2a, 0x41, 0x12, 0xc6, 0x34, 0xcb, 0x82, 0x39, 0xd5,
0x84, 0x25, 0xc4, 0x63, 0xb0, 0x14, 0xd5, 0x01, 0xec, 0x4d, 0xa6, 0xbe, 0x3f, 0x9a, 0x4c, 0x9c,
0x16, 0x02, 0xd8, 0xbd, 0x1c, 0x7f, 0xf0, 0xc8, 0xb9, 0x63, 0xc8, 0x8d, 0x33, 0xef, 0xad, 0x37,
0xbd, 0xbe, 0x70, 0x4c, 0x09, 0x3e, 0x7a, 0x64, 0x7c, 0x39, 0x3e, 0x77, 0xda, 0xa8, 0x27, 0xb3,
0xae, 0x47, 0x84, 0x38, 0xbf, 0xf5, 0xc7, 0xc0, 0xaf, 0xe1, 0xc0, 0xcb, 0xf9, 0xe2, 0xdf, 0xf5,
0x89, 0x28, 0x4f, 0x6f, 0x69, 0x52, 0x5e, 0xa6, 0x00, 0xf8, 0x14, 0xba, 0xda, 0x1e, 0x3a, 0x9b,
0x66, 0x94, 0xa1, 0x47, 0x00, 0xe1, 0x32, 0xa2, 0x09, 0xf7, 0x29, 0xe3, 0x25, 0x45, 0x2d, 0x82,
0xf7, 0x60, 0x67, 0x14, 0xaf, 0xf8, 0x1d, 0xfe, 0x06, 0xbd, 0xab, 0x34, 0xe3, 0x7e, 0x9a, 0x70,
0x16, 0x84, 0x5c, 0xab, 0x23, 0xb0, 0x16, 0x41, 0xb6, 0x50, 0x27, 0x0f, 0x89, 0x5a, 0xa3, 0x3e,
0xec, 0xdf, 0x44, 0x4b, 0x9a, 0x04, 0xb1, 0xf6, 0xa2, 0xc2, 0xe8, 0x7f, 0xd8, 0xcd, 0xa2, 0x79,
0x42, 0x99, 0xdb, 0x3e, 0x69, 0x8b, 0x9d, 0x12, 0x49, 0xfb, 0xc2, 0x34, 0x8e, 0x85, 0xac, 0x6b,
0x15, 0xf6, 0x95, 0x50, 0xd8, 0x77, 0xfc, 0x2e, 0x8d, 0x92, 0x89, 0xc8, 0x0b, 0x78, 0xce, 0xa8,
0x56, 0xc6, 0x70, 0x18, 0x96, 0x97, 0x99, 0xe6, 0xd1, 0xac, 0xbc, 0x7b, 0x23, 0x26, 0x6f, 0xb7,
0x4a, 0x59, 0xd1, 0xe2, 0x0e, 0x51, 0x6b, 0xfc, 0xc3, 0x80, 0x8e, 0x2c, 0x5d, 0x54, 0x92, 0xd0,
0x90, 0xd3, 0x19, 0x7a, 0x0e, 0x36, 0xd5, 0x2d, 0x55, 0x34, 0x07, 0xc3, 0x6e, 0xb3, 0xd1, 0x64,
0x9d, 0xf0, 0x97, 0xae, 0xb9, 0x45, 0xf7, 0x21, 0x58, 0x79, 0xa6, 0x6a, 0x94, 0x64, 0xb6, 0x22,
0x93, 0x9a, 0x44, 0x85, 0xf1, 0x27, 0xb0, 0x94, 0xf9, 0xa2, 0xe8, 0x5b, 0x7a, 0x77, 0xb1, 0xf6,
0x4f, 0xc3, 0x75, 0x53, 0xcd, 0x7a, 0x53, 0xbb, 0x60, 0x46, 0x2b, 0x45, 0x6a, 0x13, 0xb1, 0xaa,
0xca, 0xb3, 0x6a, 0xe5, 0xbd, 0x02, 0x87, 0xd0, 0x60, 0x76, 0x27, 0xfd, 0xba, 0x87, 0x55, 0xf8,
0x3b, 0x1c, 0xbd, 0x0f, 0xf2, 0x24, 0x5c, 0x54, 0x46, 0xdf, 0xd3, 0x97, 0xc7, 0xd0, 0xc9, 0xf4,
0xd1, 0x9a, 0x31, 0xcd, 0x60, 0xbd, 0xe4, 0x62, 0x00, 0x34, 0x1c, 0xfe, 0x32, 0x61, 0xff, 0x6a,
0x19, 0xf0, 0x9b, 0x94, 0xc5, 0x68, 0x08, 0xfb, 0x7a, 0x50, 0xd1, 0xb1, 0xd2, 0xdc, 0x78, 0xd6,
0xfd, 0x8d, 0x9b, 0xe0, 0x16, 0x7a, 0x01, 0x96, 0x7c, 0x17, 0xc8, 0x51, 0x3b, 0xb5, 0x27, 0xd2,
0xef, 0x35, 0x18, 0x8a, 0xc9, 0x17, 0x07, 0x9e, 0x01, 0x4c, 0x13, 0xa6, 0x65, 0xa0, 0x20, 0x94,
0xc3, 0xbe, 0x85, 0xfc, 0x0d, 0x1c, 0xd6, 0xc7, 0x1f, 0xb9, 0x2a, 0x63, 0xcb, 0x8b, 0xd8, 0x72,
0xf6, 0x0c, 0x3a, 0x8d, 0x09, 0x46, 0x0f, 0x54, 0xca, 0xb6, 0xa9, 0xee, 0xa3, 0x6a, 0x56, 0xaa,
0xf9, 0xc4, 0xad, 0x53, 0x43, 0xe8, 0xdb, 0x55, 0x5b, 0xd1, 0x7f, 0x65, 0x3d, 0xcd, 0x36, 0xf7,
0x0b, 0xa3, 0x36, 0xba, 0x88, 0x5b, 0x9f, 0x77, 0xd5, 0x1f, 0xe4, 0xcb, 0x3f, 0x01, 0x00, 0x00,
0xff, 0xff, 0xff, 0xc7, 0x56, 0xf4, 0x36, 0x05, 0x00, 0x00,
......@@ -74,14 +74,15 @@ message JoinSignatureRequest {
message UserConnected {
ErrorCode errorCode = 1;
string contractUuid = 2;
message User {
bytes KeyHash = 1;
string email = 2;
string ip = 3;
uint32 port = 4;
User user = 3;
message User {
bytes keyHash = 1;
string email = 2;
string ip = 3;
uint32 port = 4;
// ReadySignRequest contains the contract unique identitier that is ready to be signed
message ReadySignRequest {
string contractUuid = 1;
......@@ -113,10 +113,9 @@ func TestInsertContract(t *testing.T) {
// Insert some contracts with missing user and test waiting contracts for this user
func TestGetWaitingForUser(t *testing.T) {
knownID := bson.NewObjectId()
c1 := entities.NewContract()
c1.AddSigner(nil, "mail1", []byte{})
c1.Ready = false
......@@ -139,3 +138,22 @@ func TestGetWaitingForUser(t *testing.T) {
assert.Equal(t, nil, err)
assert.Equal(t, 2, len(contracts))
func TestCheckAuthorization(t *testing.T) {
id := addTestContract()
assert.T(t, repository.CheckAuthorization(user1.CertHash, id))
assert.T(t, !repository.CheckAuthorization(user1.CertHash, bson.NewObjectId()))
assert.T(t, !repository.CheckAuthorization(user2.CertHash, id))
assert.T(t, !repository.CheckAuthorization(user2.CertHash, bson.NewObjectId()))
contract := entities.Contract{}
_ = repository.Collection.FindByID(entities.Contract{ID: id}, &contract)
contract.Ready = false
_, _ = repository.Collection.UpdateByID(contract)
// Not valid if contract is not ready
assert.T(t, !repository.CheckAuthorization(user1.CertHash, id))
......@@ -2,6 +2,7 @@ package contract_test
import (
......@@ -27,7 +28,7 @@ func createDataset() {
user1.Email = ""
user1.Expiration = time.Now().AddDate(1, 0, 0)
user1.Certificate = "Certificate1"
user1.CertHash = []byte{0x01}
_, _ = fmt.Sscanf("23a012afa19d5892f66ae9681afb3bb010e61c8bb4afdedd6a407fa40dbb7d4d1ad94953ca25866b6b07e25f8bf604cc94b13fb9dc1e7fa53980040db2a7f787", "%x", &user1.CertHash)
user2.Email = ""
user2.Expiration = time.Now().AddDate(1, 0, 0)
package contract
import (
n "net"
// JoinSignature allows a client to wait for other clients connections on a specific contract.
// Firstly, every client present BEFORE the call of this function is sent to the stream.
// Then, client information is sent to the stream as it's available.
// Please note that the current user will also receive it's own information.
// There is no timeout, this function will shut down on stream disconnection or on error.
func JoinSignature(db *mgdb.MongoManager, rooms *common.WaitingGroupMap, in *api.JoinSignatureRequest, stream api.Platform_JoinSignatureServer) {
repository := entities.NewContractRepository(db.Get("contracts"))
ctx := stream.Context()
state, addr, _ := net.GetTLSState(&ctx)
hash := auth.GetCertificateHash(state.VerifiedChains[0][0])
if !bson.IsObjectIdHex(in.ContractUuid) {
_ = stream.Send(&api.UserConnected{
ErrorCode: &api.ErrorCode{
Code: api.ErrorCode_INVARG,
Message: "invalid contract uuid",
if !repository.CheckAuthorization(hash, bson.ObjectIdHex(in.ContractUuid)) {
_ = stream.Send(&api.UserConnected{
ErrorCode: &api.ErrorCode{
Code: api.ErrorCode_INVARG,
Message: "unauthorized signature",
// Join room
roomID := "contract_" + in.ContractUuid
channel, pendingSigners := rooms.Join(roomID)
// Send pendingSigners
for _, p := range pendingSigners {
err := sendUserToStream(&stream, in.ContractUuid, p.(*api.User))
if err != nil {
rooms.Unjoin(roomID, channel)
// Broadcast self identity
host, _, _ := n.SplitHostPort(addr.String())
rooms.Broadcast(roomID, &api.User{
KeyHash: hash,
Email: net.GetCN(&ctx),
Ip: host,
Port: in.Port,
// Listen for others
for {
select {
case user, ok := <-channel:
if !ok { // channel is closed, means that the room is closed
err := sendUserToStream(&stream, in.ContractUuid, user.(*api.User))
if err != nil {
rooms.Unjoin(roomID, channel)
case <-ctx.Done():
rooms.Unjoin(roomID, channel)
func sendUserToStream(stream *api.Platform_JoinSignatureServer, contractUUID string, user *api.User) error {
return (*stream).Send(&api.UserConnected{
ErrorCode: &api.ErrorCode{Code: api.ErrorCode_SUCCESS},
ContractUuid: contractUUID,
User: user,
package contract_test
import (
func addTestContract() bson.ObjectId {
contract := entities.NewContract()
contract.AddSigner(&user1.ID, user1.Email, user1.CertHash)
contract.Ready = true
_, _ = manager.Get("contracts").Insert(contract)
return contract.ID
func TestJoinSignature(t *testing.T) {
contractID := addTestContract()
client := clientTest(t)
stream, err := client.JoinSignature(context.Background(), &api.JoinSignatureRequest{
ContractUuid: contractID.Hex(),
Port: 5050,
assert.Equal(t, nil, err)
user, err := stream.Recv()
assert.Equal(t, nil, err)
assert.Equal(t, "", user.ErrorCode.Message)
assert.Equal(t, api.ErrorCode_SUCCESS, user.ErrorCode.Code)
assert.Equal(t, contractID.Hex(), user.ContractUuid)
assert.Equal(t, "", user.User.Email)
assert.Equal(t, "", user.User.Ip)
assert.Equal(t, uint32(5050), user.User.Port)
func TestJoinSignatureBadContract(t *testing.T) {
client := clientTest(t)
stream, err := client.JoinSignature(context.Background(), &api.JoinSignatureRequest{
ContractUuid: bson.NewObjectId().Hex(),
Port: 5050,
assert.Equal(t, nil, err)
user, err := stream.Recv()
assert.Equal(t, nil, err)
assert.Equal(t, "unauthorized signature", user.ErrorCode.Message)
assert.Equal(t, api.ErrorCode_INVARG, user.ErrorCode.Code)
......@@ -83,3 +83,17 @@ func (r *ContractRepository) GetWaitingForUser(email string) ([]Contract, error)
}, &res)
return res, err
// CheckAuthorization checks that a client is allowed to sign a specific contract
func (r *ContractRepository) CheckAuthorization(signerHash []byte, contractID bson.ObjectId) bool {
count, _ := r.Collection.Collection.Find(bson.M{
"_id": contractID,
"ready": true,
"signers": bson.M{
"$elemMatch": bson.M{"hash": signerHash},
return count == 1
......@@ -6,6 +6,7 @@ import (
......@@ -17,6 +18,7 @@ import (
type platformServer struct {
Pid *authority.PlatformID
DB *mgdb.MongoManager
Rooms *common.WaitingGroupMap
CertDuration int
Verbose bool
......@@ -61,7 +63,17 @@ func (s *platformServer) PostContract(ctx context.Context, in *api.PostContractR
// Handle incoming JoinSignatureRequest messages
func (s *platformServer) JoinSignature(in *api.JoinSignatureRequest, stream api.Platform_JoinSignatureServer) error {
ctx := stream.Context()
cn := net.GetCN(&ctx)
if len(cn) == 0 {
_ = stream.Send(&api.UserConnected{
ErrorCode: &api.ErrorCode{Code: api.ErrorCode_BADAUTH},
return nil
contract.JoinSignature(s.DB, s.Rooms, in, stream)
return nil
......@@ -91,6 +103,7 @@ func GetServer(keyPath, db string, certValidity int, verbose bool) *grpc.Server
api.RegisterPlatformServer(server, &platformServer{
Pid: pid,
DB: dbManager,
Rooms: common.NewWaitingGroupMap(),
CertDuration: certValidity,
Verbose: verbose,
......@@ -56,18 +56,18 @@ func Listen(addrPort string, grpcServer *grpc.Server) error {
// GetTLSState returns the current tls connection state from a grpc context.
// If you just need to check that the connected peer provides its certificate, use `GetCN`.
func GetTLSState(ctx *context.Context) (tls.ConnectionState, bool) {
func GetTLSState(ctx *context.Context) (tls.ConnectionState, net.Addr, bool) {
p, ok := peer.FromContext(*ctx)
if !ok {
return tls.ConnectionState{}, false
return tls.ConnectionState{}, nil, false
return p.AuthInfo.(credentials.TLSInfo).State, true
return p.AuthInfo.(credentials.TLSInfo).State, p.Addr, true
// GetCN returns the current common name of connected peer from grpc context.
// The returned string is empty if encountering a non-auth peer.
func GetCN(ctx *context.Context) string {
state, ok := GetTLSState(ctx)
state, _, ok := GetTLSState(ctx)
if !ok || len(state.VerifiedChains) == 0 {
return ""
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment