server.go 6.88 KB
Newer Older
1
// Package server provides the ttp server.
2 3 4
package server

import (
Caro Axel's avatar
Caro Axel committed
5
	"errors"
6 7 8
	"fmt"
	"os"

Caro Axel's avatar
Caro Axel committed
9
	cAPI "dfss/dfssc/api"
10
	"dfss/dfssc/security"
Caro Axel's avatar
Caro Axel committed
11 12 13
	tAPI "dfss/dfsst/api"
	"dfss/dfsst/entities"
	"dfss/dfsst/resolve"
14 15
	"dfss/mgdb"
	"dfss/net"
ElyKar's avatar
ElyKar committed
16
	"github.com/spf13/viper"
17 18 19 20
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

Caro Axel's avatar
Caro Axel committed
21 22 23
// InternalError : constant string used to return a generic error message through gRPC in case of an internal error.
const InternalError string = "Internal server error"

24
type ttpServer struct {
ElyKar's avatar
ElyKar committed
25
	DB *mgdb.MongoManager
26 27
}

Caro Axel's avatar
Caro Axel committed
28 29
// Alert route for the TTP.
func (server *ttpServer) Alert(ctx context.Context, in *tAPI.AlertRequest) (*tAPI.TTPResponse, error) {
30
	valid, signatureUUID, signers, senderIndex := entities.IsRequestValid(ctx, in)
Caro Axel's avatar
Caro Axel committed
31 32 33 34 35 36 37
	if !valid {
		return nil, errors.New(InternalError)
	}
	// Now we know that the request contains information correctly signed by the platform,
	// with the same signatureUUID (thus signed information) for all promises, and sent by a valid signer
	// wrt to the signed signers' hashes

38
	manager := entities.NewArchivesManager(server.DB)
Caro Axel's avatar
Caro Axel committed
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
	manager.InitializeArchives(in.Promises[0], signatureUUID, &signers)
	// Now archives contains the new or already present SignatureArchives

	// We check if we have already sent an abort token to the sender of the request
	stop, message, err := server.handleAbortedSender(manager, senderIndex)
	if stop {
		return message, err
	}

	// We check that the sender of the request sent valid and complete information
	stop, message, tmpPromises, err := server.handleInvalidPromises(manager, in.Promises, senderIndex)
	if stop {
		return message, err
	}
	// Now we are sure that the sender of the AlertRequest is not dishonest

	// We try to use the already generated contract if it exists
	generated, contract := manager.WasContractSigned()
	if generated {
		return &tAPI.TTPResponse{
			Abort:    false,
			Contract: contract,
		}, nil
	}

	// If we didn't already generate the signed contract, we take into account the new promises
	// Computing the dishonest signers wrt to the new evidence
	server.updateArchiveWithEvidence(manager, tmpPromises)
	// Try to generate the contract now
	message, err = server.handleContractGenerationTry(manager)
	// We manually update the database
	ok, _ := server.DB.Get("signatures").UpdateByID(manager.Archives)
	if !ok {
		return nil, errors.New(InternalError)
	}

	return message, err
}

// handleAbortedSender : if the specified signer has already recieved an abort token, adds him to the dishonest signers of the specified
// signatureArchives, and returns a boolean that states if we should stop the execution of the resolve protocol, and the response that should be sent back to him.
//
// Updates the database with the new aborted signers.
// If an error occurs during this process, it is returned.
83
func (server *ttpServer) handleAbortedSender(manager *entities.ArchivesManager, senderIndex uint32) (bool, *tAPI.TTPResponse, error) {
Caro Axel's avatar
Caro Axel committed
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
	if manager.HasReceivedAbortToken(senderIndex) {
		manager.AddToDishonest(senderIndex)

		ok, _ := manager.DB.Get("signatures").UpdateByID(manager.Archives)
		if !ok {
			return true, nil, errors.New(InternalError)
		}

		return true, &tAPI.TTPResponse{
			Abort:    true,
			Contract: nil,
		}, nil
	}

	return false, nil, nil
}

// handleInvalidPromises : if the specified signer has sent us a valid request, but with invalid promises, ie:
// - he sent us impossible information wrt the information signed by the platform
// OR
// - he sent not enough information wrt the information signed by the platform and the signing protocol
// then he is added to the dishonest signers.
//
// Returns a boolean that states if we should stop the execution of the resolve protocol, and the response that should be sent back to him.
// If the promises are valid, return them in the simplified form of an array of *entities.Promise
//
// Updates the database with the new aborted signer.
// If an error occurs during this process, it is returned.
112 113
func (server *ttpServer) handleInvalidPromises(manager *entities.ArchivesManager, promises []*cAPI.Promise, senderIndex uint32) (bool, *tAPI.TTPResponse, []*entities.Promise, error) {
	valid, tmpPromises := entities.ArePromisesValid(promises)
Caro Axel's avatar
Caro Axel committed
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
	complete := resolve.ArePromisesComplete(tmpPromises, promises[0])
	if !valid || !complete {
		manager.AddToAbort(senderIndex)
		manager.AddToDishonest(senderIndex)

		ok, _ := manager.DB.Get("signatures").UpdateByID(manager.Archives)
		if !ok {
			return true, nil, nil, errors.New(InternalError)
		}

		return true, &tAPI.TTPResponse{
			Abort:    true,
			Contract: nil,
		}, nil, nil
	}

	return false, nil, tmpPromises, nil
}

// updateArchiveWithEvidence : computes the dishonest signers from the new provided evidence, and updates the specified signatureArchives accordingly.
//
// DOES NOT UPDATE THE DATABASE (should be handled manually)
136
func (server *ttpServer) updateArchiveWithEvidence(manager *entities.ArchivesManager, tmpPromises []*entities.Promise) {
Caro Axel's avatar
Caro Axel committed
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
	computedDishonest := resolve.ComputeDishonestSigners(manager.Archives, tmpPromises)

	for _, di := range computedDishonest {
		manager.AddToDishonest(di)
	}

	for _, p := range tmpPromises {
		manager.AddPromise(p)
	}
}

// handleContractGenerationTry : tries to generate the signed contract from the specified signatureArchives.
// Returns the response to send back to the sender of the request.
//
// Does not take into account if the sender is dishonest.
//
// If the contract has been successfully generated, returns it. Otherwise, returns an abort token.
//
// DOES NOT UPDATE THE DATABASE (should be handled manually)
156
func (server *ttpServer) handleContractGenerationTry(manager *entities.ArchivesManager) (*tAPI.TTPResponse, error) {
Caro Axel's avatar
Caro Axel committed
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
	generated, contract := resolve.Solve(manager)
	if !generated {
		return &tAPI.TTPResponse{
			Abort:    true,
			Contract: nil,
		}, nil
	}

	// We add the generated contract to the signatureArchives
	manager.Archives.SignedContract = contract

	return &tAPI.TTPResponse{
		Abort:    false,
		Contract: contract,
	}, nil
172 173
}

Caro Axel's avatar
Caro Axel committed
174 175 176
// Recover route for the TTP.
func (server *ttpServer) Recover(ctx context.Context, in *tAPI.RecoverRequest) (*tAPI.TTPResponse, error) {
	// TODO
177 178 179
	return nil, nil
}

Caro Axel's avatar
Caro Axel committed
180
// GetServer returns the gRPC server.
ElyKar's avatar
ElyKar committed
181 182
func GetServer() *grpc.Server {
	// We can do that because NewAuthContainer is looking for "file_ca", "file_cert", and "file_key" in viper, which are set by the TTP
183 184
	entities.AuthContainer = security.NewAuthContainer(viper.GetString("password"))
	ca, cert, key, err := entities.AuthContainer.LoadFiles()
185
	if err != nil {
186
		fmt.Fprintln(os.Stderr, "An error occured during the private key and certificates retrieval:", err)
187 188 189
		os.Exit(1)
	}

ElyKar's avatar
ElyKar committed
190
	dbManager, err := mgdb.NewManager(viper.GetString("dbURI"))
191 192
	if err != nil {
		fmt.Fprintln(os.Stderr, "An error occured during the connection to MongoDB:", err)
193
		os.Exit(2)
194 195
	}

196
	server := &ttpServer{
ElyKar's avatar
ElyKar committed
197
		DB: dbManager,
198 199
	}
	netServer := net.NewServer(cert, key, ca)
Caro Axel's avatar
Caro Axel committed
200
	tAPI.RegisterTTPServer(netServer, server)
201 202
	return netServer
}