Commit 075c808d authored by Richer Maximilien's avatar Richer Maximilien

Merge branch '415_contract_hash_verification' into 'master'

415 contract hash verification



See merge request !74
parents afe4329b 29f94ffc
Pipeline #1769 passed with stages
......@@ -26,6 +26,13 @@ var signCmd = &cobra.Command{
os.Exit(1)
}
var contractPath string
readStringParam("Local contract path [skip]", "", &contractPath)
if !checkContractHash(contractPath, contract.File.Hash) {
fmt.Fprintln(os.Stderr, "Invalid contract file! Aborting.")
os.Exit(1)
}
var passphrase string
_ = readPassword(&passphrase, false)
......@@ -33,7 +40,7 @@ var signCmd = &cobra.Command{
manager, err := sign.NewSignatureManager(passphrase, contract)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(2)
os.Exit(1)
}
fmt.Println("Waiting for peers...")
......@@ -41,7 +48,7 @@ var signCmd = &cobra.Command{
err = manager.ConnectToPeers()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(3)
os.Exit(1)
}
// Confirmation
......@@ -49,7 +56,7 @@ var signCmd = &cobra.Command{
readStringParam("Do you REALLY want to sign "+contract.File.Name+"? Type 'yes' to confirm", "", &ready)
if ready != "yes" {
fmt.Println("Signature aborted!")
os.Exit(4)
os.Exit(1)
}
// Ignition
......@@ -57,7 +64,7 @@ var signCmd = &cobra.Command{
signatureUUID, err := manager.SendReadySign()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(5)
os.Exit(1)
}
// TODO Warning, integration tests are checking Stdout
......@@ -68,20 +75,33 @@ var signCmd = &cobra.Command{
err = manager.Sign()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(5)
os.Exit(1)
}
// Persist evidencies, if any
err = manager.PersistSignaturesToFile()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(5)
os.Exit(1)
}
fmt.Println("Signature complete! See .proof file for evidences.")
},
}
func checkContractHash(filename string, expectedHash string) bool {
if filename == "" {
return true
}
ok, err := sign.CheckContractHash(filename, expectedHash)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
return ok
}
func signFeedbackFn(mail string, status sign.SignerStatus, data string) {
if status == sign.StatusConnecting {
fmt.Println("- Trying to connect with", mail, "/", data)
......
package sign
import (
"bytes"
"crypto/sha512"
"encoding/hex"
"io/ioutil"
)
// CheckContractHash computes the hash of the provided file and compares it to the expected one.
func CheckContractHash(filename string, expectedHash string) (ok bool, err error) {
data, err := ioutil.ReadFile(filename)
if err != nil {
return
}
expected, err := hex.DecodeString(expectedHash)
if err != nil {
return
}
hash := sha512.Sum512(data)
ok = bytes.Equal(expected, hash[:])
return
}
......@@ -5,12 +5,17 @@ import (
"io/ioutil"
"dfss/dfssc/common"
"dfss/dfssc/sign"
"dfss/dfssp/contract"
dialog "dfss/gui/common"
"github.com/spf13/viper"
"github.com/visualfc/goqt/ui"
)
type Widget struct {
*ui.QWidget
checked bool
}
func NewWidget(contract *contract.JSON, onSign func()) *Widget {
......@@ -23,17 +28,59 @@ func NewWidget(contract *contract.JSON, onSign func()) *Widget {
signersField := ui.NewLabelFromDriver(form.FindChild("signersField"))
informationField := ui.NewLabelFromDriver(form.FindChild("informationField"))
signButton := ui.NewPushButtonFromDriver(form.FindChild("signButton"))
fileButton := ui.NewPushButtonFromDriver(form.FindChild("fileButton"))
fileField.SetText(contract.File.Name)
commentField.SetText(contract.Comment)
signersField.SetText(getSignersString(contract))
informationField.SetText("Contract #" + contract.UUID + "\nCreated on " + contract.Date.Format("2006-01-02 15:04:05 MST") + ".")
signButton.OnClicked(onSign)
return &Widget{
w := &Widget{
QWidget: form,
checked: false,
}
fileButton.OnClicked(func() {
home := viper.GetString("home_dir")
filter := "Any (*.*)"
filename := ui.QFileDialogGetOpenFileNameWithParentCaptionDirFilterSelectedfilterOptions(nil, "Select the local contract to compare to "+contract.File.Name, home, filter, &filter, 0)
if filename == "" {
return
}
ok, err := sign.CheckContractHash(filename, contract.File.Hash)
if err != nil {
dialog.ShowMsgBox(err.Error(), true)
} else if !ok {
dialog.ShowMsgBox("The provided file is not the one hashed during contract creation, beware!", true)
} else {
dialog.ShowMsgBox("The provided file is correct for this contract!", false)
w.checked = true
}
})
signButton.OnClicked(func() {
if !w.checked { // If the contract file has not been checked locally
box := ui.NewMessageBox()
box.SetWindowTitle("Warning")
box.SetText("Do you want to check your local contract file before signing this DFSS contract?")
box.SetIcon(ui.QMessageBox_Question)
box.AddButton(ui.QMessageBox_Yes)
box.AddButton(ui.QMessageBox_No)
box.OnButtonClicked(func(b *ui.QAbstractButton) {
if box.ButtonRole(b) == ui.QMessageBox_YesRole {
fileButton.Click()
} else {
onSign()
}
})
box.Show()
} else {
onSign()
}
})
return w
}
func (w *Widget) Q() *ui.QWidget {
......
......@@ -106,9 +106,6 @@
</item>
<item>
<widget class="QToolButton" name="fileButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Check with local</string>
</property>
......
......@@ -56,9 +56,10 @@ func TestSignContract(t *testing.T) {
// Create contract
client1 = newClient(client1)
setLastArg(client1, "new", true)
contractFilePath := filepath.Join("testdata", "contract.txt")
client1.Stdin = strings.NewReader(
"password\n" +
filepath.Join("testdata", "contract.txt") + "\n" +
contractFilePath + "\n" +
"\n" +
"client1@example.com\n" +
"client2@example.com\n" +
......@@ -76,6 +77,14 @@ func TestSignContract(t *testing.T) {
err = ioutil.WriteFile(contractPath, contractData, os.ModePerm)
assert.Equal(t, nil, err)
// Test with wrong file, should abort
wrongFileClient := newClient(client1)
setLastArg(wrongFileClient, "sign", true)
setLastArg(wrongFileClient, contractPath, false)
wrongFileClient.Stdin = strings.NewReader("wrongfile.txt\npassword\nyes\n")
_, err = wrongFileClient.Output()
assert.NotNil(t, err)
// Sign!
clients[0] = newClient(client1)
clients[1] = newClient(client2)
......@@ -87,7 +96,7 @@ func TestSignContract(t *testing.T) {
setLastArg(clients[i], contractPath, false)
go func(c *exec.Cmd, i int) {
time.Sleep(time.Duration(i*2) * time.Second)
c.Stdin = strings.NewReader("password\nyes\n")
c.Stdin = strings.NewReader(contractFilePath + "\npassword\nyes\n")
c.Stderr = os.Stderr
output, err1 := c.Output()
if err1 != nil {
......
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