Example #1
0
func prefix(b []byte) []byte {
	sha256 := sha256.New()
	sha256.Write(b)
	h := sha256.Sum(nil)
	sha256.Reset()
	sha256.Write(h)
	cs := sha256.Sum(nil)
	return cs[:4]
}
Example #2
0
func IdForKey(pk rsa.PublicKey) Id {

	// Write the Rsa64 representation of public key into Sha256
	pk64 := []byte(rsa64.PubToBase64(&pk))
	sha256 := sha256.New()
	for {
		n, err := sha256.Write(pk64)
		if err != nil {
			panic("sha256 malfunction")
		}
		if n == len(pk64) {
			break
		}
		pk64 = pk64[n:]
	}

	// Compute and fold the Sha256 hash
	h := sha256.Sum()
	if len(h) != 32 {
		panic("expecting 32 bytes")
	}

	for i := 1; i < 4; i++ {
		for j := 0; j < 8; j++ {
			h[j] ^= h[8*i+j]
		}
	}
	id64, err := bytes.BytesToInt64(h[0:8])
	if err != nil {
		panic("logic")
	}

	return Id(id64)
}
Example #3
0
File: shax.go Project: ra/go-samp
func main() {
	fmt.Println("Start...")
	// String from:
	// http://en.wikipedia.org/wiki/WebSocket
	s := "x3JJHMbDL1EzLkh9GBhXDw==258EAFA5-E914-47DA-95CA-C5AB0DC85B11"

	// sha1 stuff ...
	sha1 := sha1.New()
	sha1.Write([]byte(s))
	ss := fmt.Sprintf("%x", sha1.Sum(nil))
	fmt.Printf("%s\n", ss)
	w := "1d29ab734b0c9585240069a6e4e3e91b61da1969"
	fmt.Printf("%s\n", w)
	if ss != w {
		panic("Uh oh, something is not right")
	}
	// ---------------------------------------------------------------------------
	// The base64 encoding part of that post is left as an exercise for now.
	// From the article the base64 result should be:
	// HSmrc0sMlYUkAGmm5OPpG2HaGWk=
	// *not tested*
	// ---------------------------------------------------------------------------
	// sha256 stuff ...
	sha256 := sha256.New()
	sha256.Write([]byte(s))
	ss = fmt.Sprintf("%x", sha256.Sum(nil))
	fmt.Printf("%s\n", ss)
	fmt.Println("End...")
}
Example #4
0
func (s *SimpleStreams) downloadFile(path string, hash string, target string, progress func(int)) error {
	download := func(url string, hash string, target string) error {
		out, err := os.Create(target)
		if err != nil {
			return err
		}
		defer out.Close()

		req, err := http.NewRequest("GET", url, nil)
		if err != nil {
			return err
		}
		req.Header.Set("User-Agent", UserAgent)

		resp, err := s.http.Do(req)
		if err != nil {
			return err
		}
		defer resp.Body.Close()

		if resp.StatusCode != http.StatusOK {
			return fmt.Errorf("invalid simplestreams source: got %d looking for %s", resp.StatusCode, path)
		}

		body := &TransferProgress{Reader: resp.Body, Length: resp.ContentLength, Handler: progress}

		sha256 := sha256.New()
		_, err = io.Copy(io.MultiWriter(out, sha256), body)
		if err != nil {
			return err
		}

		result := fmt.Sprintf("%x", sha256.Sum(nil))
		if result != hash {
			os.Remove(target)
			return fmt.Errorf("Hash mismatch for %s: %s != %s", path, result, hash)
		}

		return nil
	}

	// Try http first
	if strings.HasPrefix(s.url, "https://") {
		err := download(fmt.Sprintf("http://%s/%s", strings.TrimPrefix(s.url, "https://"), path), hash, target)
		if err == nil {
			return nil
		}
	}

	err := download(fmt.Sprintf("%s/%s", s.url, path), hash, target)
	if err != nil {
		return err
	}

	return nil
}
Example #5
0
File: core.go Project: misdep/azure
/*
params:
 HTTP Verb
 Content-Encoding
 Content-Language
 Content-Length
 Content-MD5
 Content-Type
 Date
 If-Modified-Since
 If-Match
 If-None-Match
 If-Unmodified-Since
 Range
*/
func (core Core) signature() string {
	signature := fmt.Sprintf("%s\n\n\n%s\n\n%s\n\n\n\n\n\n\n%s\n%s",
		strings.ToUpper(core.AzureRequest.Method),
		core.contentLength(),
		core.AzureRequest.Request.Header.Get("Content-Type"),
		core.canonicalizedHeaders(),
		core.canonicalizedResource())

	decodedKey, _ := base64.StdEncoding.DecodeString(core.Credentials.AccessKey)

	sha256 := hmac.New(sha256.New, []byte(decodedKey))
	sha256.Write([]byte(signature))

	return base64.StdEncoding.EncodeToString(sha256.Sum(nil))
}
Example #6
0
func (s *SimpleStreams) downloadFile(path string, hash string, target string, progress func(int)) error {
	download := func(url string, hash string, target string) error {
		out, err := os.Create(target)
		if err != nil {
			return err
		}
		defer out.Close()

		resp, err := s.http.Get(url)
		if err != nil {
		}
		defer resp.Body.Close()

		body := &TransferProgress{Reader: resp.Body, Length: resp.ContentLength, Handler: progress}

		sha256 := sha256.New()
		_, err = io.Copy(io.MultiWriter(out, sha256), body)
		if err != nil {
			return err
		}

		if fmt.Sprintf("%x", sha256.Sum(nil)) != hash {
			os.Remove(target)
			return fmt.Errorf("Hash mismatch")
		}

		return nil
	}

	// Try http first
	if strings.HasPrefix(s.url, "https://") {
		err := download(fmt.Sprintf("http://%s/%s", strings.TrimPrefix(s.url, "https://"), path), hash, target)
		if err == nil {
			return nil
		}
	}

	err := download(fmt.Sprintf("%s/%s", s.url, path), hash, target)
	if err != nil {
		return err
	}

	return nil
}
Example #7
0
// Calculate hashes
// FROM: http://marcio.io/2015/07/calculating-multiple-file-hashes-in-a-single-pass/
func CalculateBasicHashes(filename string) (info models.HashInfo, err error) {
	rd, err := os.OpenFile(filename, os.O_RDONLY, 0)
	if err != nil {
		return
	}
	defer rd.Close()

	md5 := md5.New()
	sha1 := sha1.New()
	sha256 := sha256.New()
	sha512 := sha512.New()

	// For optimum speed, Getpagesize returns the underlying system's memory page size.
	pagesize := os.Getpagesize()

	// wraps the Reader object into a new buffered reader to read the files in chunks
	// and buffering them for performance.
	reader := bufio.NewReaderSize(rd, pagesize)

	// creates a multiplexer Writer object that will duplicate all write
	// operations when copying data from source into all different hashing algorithms
	// at the same time
	multiWriter := io.MultiWriter(md5, sha1, sha256, sha512)

	// Using a buffered reader, this will write to the writer multiplexer
	// so we only traverse through the file once, and can calculate all hashes
	// in a single byte buffered scan pass.
	//
	_, err = io.Copy(multiWriter, reader)
	if err != nil {
		return
	}

	info.Md5 = hex.EncodeToString(md5.Sum(nil))
	info.Sha1 = hex.EncodeToString(sha1.Sum(nil))
	info.Sha256 = hex.EncodeToString(sha256.Sum(nil))
	info.Sha512 = hex.EncodeToString(sha512.Sum(nil))

	return info, nil
}
Example #8
0
File: images.go Project: djibi2/lxd
func getImgPostInfo(d *Daemon, r *http.Request,
	builddir string, post *os.File) (info shared.ImageInfo, err error) {

	var imageMeta *imageMetadata
	logger := logging.AddContext(shared.Log, log.Ctx{"function": "getImgPostInfo"})

	public, _ := strconv.Atoi(r.Header.Get("X-LXD-public"))
	info.Public = public == 1
	propHeaders := r.Header[http.CanonicalHeaderKey("X-LXD-properties")]
	ctype, ctypeParams, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
	if err != nil {
		ctype = "application/octet-stream"
	}

	sha256 := sha256.New()
	var size int64

	// Create a temporary file for the image tarball
	imageTarf, err := ioutil.TempFile(builddir, "lxd_tar_")
	if err != nil {
		return info, err
	}

	if ctype == "multipart/form-data" {
		// Parse the POST data
		post.Seek(0, 0)
		mr := multipart.NewReader(post, ctypeParams["boundary"])

		// Get the metadata tarball
		part, err := mr.NextPart()
		if err != nil {
			return info, err
		}

		if part.FormName() != "metadata" {
			return info, fmt.Errorf("Invalid multipart image")
		}

		size, err = io.Copy(io.MultiWriter(imageTarf, sha256), part)
		info.Size += size

		imageTarf.Close()
		if err != nil {
			logger.Error(
				"Failed to copy the image tarfile",
				log.Ctx{"err": err})
			return info, err
		}

		// Get the rootfs tarball
		part, err = mr.NextPart()
		if err != nil {
			logger.Error(
				"Failed to get the next part",
				log.Ctx{"err": err})
			return info, err
		}

		if part.FormName() != "rootfs" {
			logger.Error(
				"Invalid multipart image")

			return info, fmt.Errorf("Invalid multipart image")
		}

		// Create a temporary file for the rootfs tarball
		rootfsTarf, err := ioutil.TempFile(builddir, "lxd_tar_")
		if err != nil {
			return info, err
		}

		size, err = io.Copy(io.MultiWriter(rootfsTarf, sha256), part)
		info.Size += size

		rootfsTarf.Close()
		if err != nil {
			logger.Error(
				"Failed to copy the rootfs tarfile",
				log.Ctx{"err": err})
			return info, err
		}

		info.Filename = part.FileName()
		info.Fingerprint = fmt.Sprintf("%x", sha256.Sum(nil))

		expectedFingerprint := r.Header.Get("X-LXD-fingerprint")
		if expectedFingerprint != "" && info.Fingerprint != expectedFingerprint {
			err = fmt.Errorf("fingerprints don't match, got %s expected %s", info.Fingerprint, expectedFingerprint)
			return info, err
		}

		imgfname := shared.VarPath("images", info.Fingerprint)
		err = shared.FileMove(imageTarf.Name(), imgfname)
		if err != nil {
			logger.Error(
				"Failed to move the image tarfile",
				log.Ctx{
					"err":    err,
					"source": imageTarf.Name(),
					"dest":   imgfname})
			return info, err
		}

		rootfsfname := shared.VarPath("images", info.Fingerprint+".rootfs")
		err = shared.FileMove(rootfsTarf.Name(), rootfsfname)
		if err != nil {
			logger.Error(
				"Failed to move the rootfs tarfile",
				log.Ctx{
					"err":    err,
					"source": rootfsTarf.Name(),
					"dest":   imgfname})
			return info, err
		}

		imageMeta, err = getImageMetadata(imgfname)
		if err != nil {
			logger.Error(
				"Failed to get image metadata",
				log.Ctx{"err": err})
			return info, err
		}
	} else {
		post.Seek(0, 0)
		size, err = io.Copy(io.MultiWriter(imageTarf, sha256), post)
		info.Size = size
		imageTarf.Close()
		logger.Debug("Tar size", log.Ctx{"size": size})
		if err != nil {
			logger.Error(
				"Failed to copy the tarfile",
				log.Ctx{"err": err})
			return info, err
		}

		info.Filename = r.Header.Get("X-LXD-filename")
		info.Fingerprint = fmt.Sprintf("%x", sha256.Sum(nil))

		expectedFingerprint := r.Header.Get("X-LXD-fingerprint")
		if expectedFingerprint != "" && info.Fingerprint != expectedFingerprint {
			logger.Error(
				"Fingerprints don't match",
				log.Ctx{
					"got":      info.Fingerprint,
					"expected": expectedFingerprint})
			err = fmt.Errorf(
				"fingerprints don't match, got %s expected %s",
				info.Fingerprint,
				expectedFingerprint)
			return info, err
		}

		imgfname := shared.VarPath("images", info.Fingerprint)
		err = shared.FileMove(imageTarf.Name(), imgfname)
		if err != nil {
			logger.Error(
				"Failed to move the tarfile",
				log.Ctx{
					"err":    err,
					"source": imageTarf.Name(),
					"dest":   imgfname})
			return info, err
		}

		imageMeta, err = getImageMetadata(imgfname)
		if err != nil {
			logger.Error(
				"Failed to get image metadata",
				log.Ctx{"err": err})
			return info, err
		}
	}

	info.Architecture, _ = shared.ArchitectureId(imageMeta.Architecture)
	info.CreationDate = imageMeta.CreationDate
	info.ExpiryDate = imageMeta.ExpiryDate

	info.Properties = imageMeta.Properties
	if len(propHeaders) > 0 {
		for _, ph := range propHeaders {
			p, _ := url.ParseQuery(ph)
			for pkey, pval := range p {
				info.Properties[pkey] = pval[0]
			}
		}
	}

	return info, nil
}
Example #9
0
File: images.go Project: djibi2/lxd
/*
 * This function takes a container or snapshot from the local image server and
 * exports it as an image.
 */
func imgPostContInfo(d *Daemon, r *http.Request, req imagePostReq,
	builddir string) (info shared.ImageInfo, err error) {

	info.Properties = map[string]string{}
	name := req.Source["name"]
	ctype := req.Source["type"]
	if ctype == "" || name == "" {
		return info, fmt.Errorf("No source provided")
	}

	switch ctype {
	case "snapshot":
		if !shared.IsSnapshot(name) {
			return info, fmt.Errorf("Not a snapshot")
		}
	case "container":
		if shared.IsSnapshot(name) {
			return info, fmt.Errorf("This is a snapshot")
		}
	default:
		return info, fmt.Errorf("Bad type")
	}

	info.Filename = req.Filename
	switch req.Public {
	case true:
		info.Public = true
	case false:
		info.Public = false
	}

	c, err := containerLoadByName(d, name)
	if err != nil {
		return info, err
	}

	// Build the actual image file
	tarfile, err := ioutil.TempFile(builddir, "lxd_build_tar_")
	if err != nil {
		return info, err
	}
	defer os.Remove(tarfile.Name())

	if err := c.Export(tarfile); err != nil {
		tarfile.Close()
		return info, fmt.Errorf("imgPostContInfo: export failed: %s", err)
	}
	tarfile.Close()

	compress, err := d.ConfigValueGet("images.compression_algorithm")
	if err != nil {
		return info, err
	}

	// Default to gzip for this
	if compress == "" {
		compress = "gzip"
	}

	var compressedPath string
	if compress != "none" {
		compressedPath, err = compressFile(tarfile.Name(), compress)
		if err != nil {
			return info, err
		}
	} else {
		compressedPath = tarfile.Name()
	}
	defer os.Remove(compressedPath)

	sha256 := sha256.New()
	tarf, err := os.Open(compressedPath)
	if err != nil {
		return info, err
	}
	info.Size, err = io.Copy(sha256, tarf)
	tarf.Close()
	if err != nil {
		return info, err
	}
	info.Fingerprint = fmt.Sprintf("%x", sha256.Sum(nil))

	_, err = dbImageGet(d.db, info.Fingerprint, false, true)
	if err == nil {
		return info, fmt.Errorf("The image already exists: %s", info.Fingerprint)
	}

	/* rename the the file to the expected name so our caller can use it */
	finalName := shared.VarPath("images", info.Fingerprint)
	err = shared.FileMove(compressedPath, finalName)
	if err != nil {
		return info, err
	}

	info.Architecture = c.Architecture()
	info.Properties = req.Properties

	return info, nil
}
Example #10
0
File: images.go Project: Ramzec/lxd
func getImgPostInfo(d *Daemon, r *http.Request, builddir string) (public int,
	fingerprint string, arch int,
	filename string, size int64,
	properties map[string]string, err error) {

	// Is this a container request?
	decoder := json.NewDecoder(r.Body)
	req := imageFromContainerPostReq{}
	if err = decoder.Decode(&req); err == nil {
		return imgPostContInfo(d, r, req, builddir)
	}

	// ok we've got an image in the body
	public, _ = strconv.Atoi(r.Header.Get("X-LXD-public"))
	filename = r.Header.Get("X-LXD-filename")
	propHeaders := r.Header[http.CanonicalHeaderKey("X-LXD-properties")]

	properties = map[string]string{}
	if len(propHeaders) > 0 {
		for _, ph := range propHeaders {
			p, _ := url.ParseQuery(ph)
			for pkey, pval := range p {
				properties[pkey] = pval[0]
			}
		}
	}

	// Create a file for the tarball
	tarf, err := ioutil.TempFile(builddir, "lxd_tar_")
	if err != nil {
		return 0, "", 0, "", 0, properties, err
	}

	tarfname := tarf.Name()
	sha256 := sha256.New()

	var size1, size2 int64
	size1, err = io.Copy(io.MultiWriter(tarf, sha256), decoder.Buffered())
	if err == nil {
		size2, err = io.Copy(io.MultiWriter(tarf, sha256), r.Body)
	}
	size = size1 + size2
	tarf.Close()
	if err != nil {
		return 0, "", 0, "", 0, properties, err
	}

	fingerprint = fmt.Sprintf("%x", sha256.Sum(nil))
	expectedFingerprint := r.Header.Get("X-LXD-fingerprint")
	if expectedFingerprint != "" && fingerprint != expectedFingerprint {
		err = fmt.Errorf("fingerprints don't match, got %s expected %s", fingerprint, expectedFingerprint)
		return 0, "", 0, "", 0, properties, err
	}

	imagefname := filepath.Join(builddir, fingerprint)
	err = os.Rename(tarfname, imagefname)
	if err != nil {
		return 0, "", 0, "", 0, properties, err
	}

	var imageMeta *imageMetadata
	imageMeta, err = getImageMetadata(imagefname)
	if err != nil {
		return 0, "", 0, "", 0, properties, err
	}

	arch, _ = shared.ArchitectureId(imageMeta.Architecture)

	err = nil
	return
}
Example #11
0
File: images.go Project: Ramzec/lxd
/*
 * This function takes a container or snapshot from the local image server and
 * exports it as an image.
 */
func imgPostContInfo(d *Daemon, r *http.Request, req imageFromContainerPostReq,
	builddir string) (public int, fingerprint string, arch int,
	filename string, size int64, properties map[string]string, err error) {

	properties = map[string]string{}
	name := req.Source["name"]
	ctype := req.Source["type"]
	if ctype == "" || name == "" {
		return 0, "", 0, "", 0, properties, fmt.Errorf("No source provided")
	}

	switch ctype {
	case "snapshot":
		if !shared.IsSnapshot(name) {
			return 0, "", 0, "", 0, properties, fmt.Errorf("Not a snapshot")
		}
	case "container":
		if shared.IsSnapshot(name) {
			return 0, "", 0, "", 0, properties, fmt.Errorf("This is a snapshot")
		}
	default:
		return 0, "", 0, "", 0, properties, fmt.Errorf("Bad type")
	}

	filename = req.Filename
	switch req.Public {
	case true:
		public = 1
	case false:
		public = 0
	}

	snap := ""
	if ctype == "snapshot" {
		fields := strings.SplitN(name, "/", 2)
		if len(fields) != 2 {
			return 0, "", 0, "", 0, properties, fmt.Errorf("Not a snapshot")
		}
		name = fields[0]
		snap = fields[1]
	}

	c, err := newLxdContainer(name, d)
	if err != nil {
		return 0, "", 0, "", 0, properties, err
	}

	if err := c.exportToDir(snap, builddir); err != nil {
		return 0, "", 0, "", 0, properties, err
	}

	// Build the actual image file
	tarfname := fmt.Sprintf("%s.tar.xz", name)
	tarpath := filepath.Join(builddir, tarfname)
	args := []string{"-C", builddir, "--numeric-owner", "-Jcf", tarpath}
	if shared.PathExists(filepath.Join(builddir, "metadata.yaml")) {
		args = append(args, "metadata.yaml")
	}
	args = append(args, "rootfs")
	output, err := exec.Command("tar", args...).CombinedOutput()
	if err != nil {
		shared.Debugf("image packing failed\n")
		shared.Debugf("command was: tar %q\n", args)
		shared.Debugf(string(output))
		return 0, "", 0, "", 0, properties, err
	}

	// get the size and fingerprint
	sha256 := sha256.New()
	tarf, err := os.Open(tarpath)
	if err != nil {
		return 0, "", 0, "", 0, properties, err
	}
	size, err = io.Copy(sha256, tarf)
	tarf.Close()
	if err != nil {
		return 0, "", 0, "", 0, properties, err
	}
	fingerprint = fmt.Sprintf("%x", sha256.Sum(nil))

	/* rename the the file to the expected name so our caller can use it */
	imagefname := filepath.Join(builddir, fingerprint)
	err = os.Rename(tarpath, imagefname)
	if err != nil {
		return 0, "", 0, "", 0, properties, err
	}

	arch = c.architecture
	properties = req.Properties

	return
}
Example #12
0
File: images.go Project: RuneTM/lxd
/*
 * This function takes a container or snapshot from the local image server and
 * exports it as an image.
 */
func imgPostContInfo(d *Daemon, r *http.Request, req imagePostReq,
	builddir string) (info shared.ImageInfo, err error) {

	info.Properties = map[string]string{}
	name := req.Source["name"]
	ctype := req.Source["type"]
	if ctype == "" || name == "" {
		return info, fmt.Errorf("No source provided")
	}

	switch ctype {
	case "snapshot":
		if !shared.IsSnapshot(name) {
			return info, fmt.Errorf("Not a snapshot")
		}
	case "container":
		if shared.IsSnapshot(name) {
			return info, fmt.Errorf("This is a snapshot")
		}
	default:
		return info, fmt.Errorf("Bad type")
	}

	info.Filename = req.Filename
	switch req.Public {
	case true:
		info.Public = 1
	case false:
		info.Public = 0
	}

	snap := ""
	if ctype == "snapshot" {
		fields := strings.SplitN(name, "/", 2)
		if len(fields) != 2 {
			return info, fmt.Errorf("Not a snapshot")
		}
		name = fields[0]
		snap = fields[1]
	}

	c, err := newLxdContainer(name, d)
	if err != nil {
		return info, err
	}

	// Build the actual image file
	tarfile, err := ioutil.TempFile(builddir, "lxd_build_tar_")
	if err != nil {
		return info, err
	}

	if err := c.exportToTar(snap, tarfile); err != nil {
		tarfile.Close()
		return info, fmt.Errorf("imgPostContInfo: exportToTar failed: %s\n", err)
	}
	tarfile.Close()

	_, err = exec.Command("gzip", tarfile.Name()).CombinedOutput()
	if err != nil {
		shared.Debugf("image compression\n")
		return info, err
	}
	gztarpath := fmt.Sprintf("%s.gz", tarfile.Name())

	sha256 := sha256.New()
	tarf, err := os.Open(gztarpath)
	if err != nil {
		return info, err
	}
	info.Size, err = io.Copy(sha256, tarf)
	tarf.Close()
	if err != nil {
		return info, err
	}
	info.Fingerprint = fmt.Sprintf("%x", sha256.Sum(nil))

	/* rename the the file to the expected name so our caller can use it */
	finalName := shared.VarPath("images", info.Fingerprint)
	err = shared.FileMove(gztarpath, finalName)
	if err != nil {
		return info, err
	}

	info.Architecture = c.architecture
	info.Properties = req.Properties

	return info, nil
}
Example #13
0
func getImgPostInfo(d *Daemon, r *http.Request, builddir string) (info shared.ImageInfo, err error) {
	var imageMeta *imageMetadata

	// Store the post data to disk
	post, err := ioutil.TempFile(builddir, "lxd_post_")
	if err != nil {
		return info, err
	}
	defer os.Remove(post.Name())
	_, err = io.Copy(post, r.Body)
	if err != nil {
		return info, err
	}

	// Is this a container request?
	post.Seek(0, 0)
	decoder := json.NewDecoder(post)
	req := imageFromContainerPostReq{}
	if err = decoder.Decode(&req); err == nil {
		return imgPostContInfo(d, r, req, builddir)
	}

	// ok we've got an image in the body
	info.Public, _ = strconv.Atoi(r.Header.Get("X-LXD-public"))
	propHeaders := r.Header[http.CanonicalHeaderKey("X-LXD-properties")]
	ctype, ctypeParams, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
	if err != nil {
		ctype = "application/octet-stream"
	}

	sha256 := sha256.New()
	var size int64

	// Create a temporary file for the image tarball
	imageTarf, err := ioutil.TempFile(builddir, "lxd_tar_")
	if err != nil {
		return info, err
	}

	if ctype == "multipart/form-data" {
		// Create a temporary file for the rootfs tarball
		rootfsTarf, err := ioutil.TempFile(builddir, "lxd_tar_")
		if err != nil {
			return info, err
		}

		// Parse the POST data
		post.Seek(0, 0)
		mr := multipart.NewReader(post, ctypeParams["boundary"])

		// Get the metadata tarball
		part, err := mr.NextPart()
		if err != nil {
			return info, err
		}

		if part.FormName() != "metadata" {
			return info, fmt.Errorf("Invalid multipart image")
		}

		size, err = io.Copy(io.MultiWriter(imageTarf, sha256), part)
		info.Size += size

		imageTarf.Close()
		if err != nil {
			return info, err
		}

		// Get the rootfs tarball
		part, err = mr.NextPart()
		if err != nil {
			return info, err
		}

		if part.FormName() != "rootfs" {
			return info, fmt.Errorf("Invalid multipart image")
		}

		size, err = io.Copy(io.MultiWriter(rootfsTarf, sha256), part)
		info.Size += size

		rootfsTarf.Close()
		if err != nil {
			return info, err
		}

		info.Filename = part.FileName()
		info.Fingerprint = fmt.Sprintf("%x", sha256.Sum(nil))

		expectedFingerprint := r.Header.Get("X-LXD-fingerprint")
		if expectedFingerprint != "" && info.Fingerprint != expectedFingerprint {
			err = fmt.Errorf("fingerprints don't match, got %s expected %s", info.Fingerprint, expectedFingerprint)
			return info, err
		}

		imgfname := filepath.Join(builddir, info.Fingerprint)
		err = os.Rename(imageTarf.Name(), imgfname)
		if err != nil {
			return info, err
		}

		rootfsfname := filepath.Join(builddir, info.Fingerprint+".rootfs")
		err = os.Rename(rootfsTarf.Name(), rootfsfname)
		if err != nil {
			return info, err
		}

		imageMeta, err = getImageMetadata(imgfname)
		if err != nil {
			return info, err
		}
	} else {
		post.Seek(0, 0)
		size, err = io.Copy(io.MultiWriter(imageTarf, sha256), post)
		info.Size = size
		imageTarf.Close()
		if err != nil {
			return info, err
		}

		info.Filename = r.Header.Get("X-LXD-filename")
		info.Fingerprint = fmt.Sprintf("%x", sha256.Sum(nil))

		expectedFingerprint := r.Header.Get("X-LXD-fingerprint")
		if expectedFingerprint != "" && info.Fingerprint != expectedFingerprint {
			err = fmt.Errorf("fingerprints don't match, got %s expected %s", info.Fingerprint, expectedFingerprint)
			return info, err
		}

		imgfname := filepath.Join(builddir, info.Fingerprint)
		err = os.Rename(imageTarf.Name(), imgfname)
		if err != nil {
			return info, err
		}

		imageMeta, err = getImageMetadata(imgfname)
		if err != nil {
			return info, err
		}
	}

	info.Architecture, _ = shared.ArchitectureId(imageMeta.Architecture)
	info.CreationDate = imageMeta.CreationDate
	info.ExpiryDate = imageMeta.ExpiryDate

	info.Properties = imageMeta.Properties
	if len(propHeaders) > 0 {
		for _, ph := range propHeaders {
			p, _ := url.ParseQuery(ph)
			for pkey, pval := range p {
				info.Properties[pkey] = pval[0]
			}
		}
	}

	return info, nil
}
Example #14
0
// computes hexified hash over bytes from a Reader
// ... this is one place where I really miss exceptions
func computeHash(rdr io.Reader) string {
	sha256 := sha256.New()
	io.Copy(sha256, rdr)
	hash := sha256.Sum(make([]byte, 0))
	return hex.EncodeToString(hash)
}