~welt/murse

ref: signing murse/quarantine.go -rw-r--r-- 1.5 KiB
408fd8d8welt Fix garbage JSON when wrapping revisions. 2 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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
package main

import (
	"crypto/ecdsa"
	"errors"
	"io"
	"os"
	"path/filepath"
)

func mkQuar() error {
	return os.MkdirAll(quarantineDir, 0777)
}

func rmQuar() error {
	return os.RemoveAll(quarantineDir)
}

// Does the whole read from a reader, quarantine, and move song and dance.
// We tee the reader to both the file and verifyReaderMD5 (which in turn
// does its own teeing with the SHA256 and MD5 hashes) and deletes it if
// there was some verification problem.

// This is complex, but is also extremely fast. Everything aside from
// actually writing to the file to the disk is all done in-memory with
// memory-efficient pipes. We aren't wasting our time re-reading the
// file from the disk like some other implementations.
func treadSave(key *ecdsa.PublicKey, r io.Reader, md5 string, sig []byte, path string, uniq string) error {
	tmpPath := filepath.Join(quarantineDir, uniq)

	file, err := os.Create(tmpPath)
	if err != nil {
		return err
	}
	defer file.Close()

	pr, pw := io.Pipe()
	tee := io.TeeReader(r, pw)

	var ferr error
	go func() {
		_, ferr = io.Copy(file, tee)
		pw.Close()
	}()

	oksig, okh, err := verifyReaderMD5(key, pr, sig, md5)
	if err != nil {
		return err
	}
	if !oksig {
		os.Remove(tmpPath)
		return errors.New("object failed signature check")
	}
	if !okh {
		os.Remove(tmpPath)
		return errors.New("object failed hash checks")
	}

	if ferr != nil {
		return ferr
	}

	file.Close()

	err = os.RemoveAll(path)
	if err != nil {
		return err
	}

	return os.Rename(tmpPath, path)
}