<commit_before>package main

import (
	"fmt"
	"testing"

	"github.com/UniversityRadioYork/baps3-go"
)

// TestHasFeature tests whether serviceState.hasFeature seems to work.
func TestHasFeature(t *testing.T) {
	cases := []struct {
		feat    Feature
		present bool
	}{
		// We check the presence of some features and the absence of
		// others.  This is a shuffled, but even distribution of both.
		{FtFileLoad, true},
		{FtPlayStop, true},
		{FtSeek, false},
		{FtEnd, true},
		{FtTimeReport, false},
		{FtPlaylist, true},
		{FtPlaylistAutoAdvance, false},
		{FtPlaylistTextItems, false},
	}

	// This is for collecting the features we do want to enable.
	presents := []Feature{}

	// All features should be absent on a new serviceState.
	srv := initServiceState()

	for _, c := range cases {
		if srv.hasFeature(c.feat) {
			t.Errorf("initial serviceState shouldn't have feature %q", c.feat)
		}
		if c.present {
			presents = append(presents, c.feat)
		}
	}

	// Now set the features we want.
	msg := baps3.NewMessage(baps3.RsFeatures)
	for _, p := range presents {
		msg.AddArg(p.String())
	}

	if err := srv.update(*msg); err != nil {
		t.Errorf("error when setting features: %s", err)
	}

	// Now check if hasFeature works (!)
	for _, d := range cases {
		has := srv.hasFeature(d.feat)
		if has && !d.present {
			t.Errorf("service should not have feature %q, but does", d.feat)
		} else if !has && d.present {
			t.Errorf("service should have feature %q, but does not", d.feat)
		}
	}
}

// TestServiceStateUpdateFail tests the behaviour of a serviceState when it
// receives a malformed message.
func TestServiceStateUpdateFail(t *testing.T) {
	// TODO(CaptainHayashi): maybe test what the error actually is
	cases := []struct {
		msg    *baps3.Message
		hasErr bool
	}{
		// Request where response was expected
		{
			baps3.NewMessage(baps3.RqLoad).AddArg("/quux"),
			false, // TODO(CaptainHayashi): error on requests?
		},
		// Too few arguments
		{
			baps3.NewMessage(baps3.RsFile),
			true,
		},
		// Too many arguments
		{
			baps3.NewMessage(baps3.RsTime).AddArg("3003").AddArg("lol"),
			true,
		},
		// Unknown request (should be ignored)
		{
			baps3.NewMessage(baps3.RsUnknown).AddArg("heh"),
			false,
		},
	}

	for _, c := range cases {
		err := initServiceState().update(*c.msg)
		if c.hasErr && (err == nil) {
			t.Errorf("expected %q to produce error, none produced", c.msg)
		} else if !c.hasErr && (err != nil) {
			t.Errorf("expected %q not to produce error, one produced", c.msg)
		}
	}
}

// TestServiceStateUpdate tests the updating of a serviceState by messages.
func TestServiceStateUpdate(t *testing.T) {
	// TODO(CaptainHayashi): test failure states as well as successes

	cases := []struct {
		msg *baps3.Message
		cmp func(*serviceState) error
	}{
		{
			baps3.NewMessage(baps3.RsFeatures).AddArg("End").AddArg("FileLoad"),
			func(s *serviceState) (err error) {
				_, endIn := s.features[FtEnd]
				_, flIn := s.features[FtFileLoad]

				if !endIn || !flIn {
					err = fmt.Errorf(
						"features should contain End and Fileload, got %d",
						s.features,
					)
				}

				return
			},
		},
		{
			baps3.NewMessage(baps3.RsFile).AddArg("/home/foo/bar.mp3"),
			func(s *serviceState) (err error) {
				if s.file != "/home/foo/bar.mp3" {
					err = fmt.Errorf(
						"file should be %d, got %d",
						"/home/foo/bar.mp3",
						s.file,
					)
				}

				return
			},
		},
		{
			baps3.NewMessage(baps3.RsState).AddArg("Ejected"),
			func(s *serviceState) (err error) {
				if s.state != "Ejected" {
					err = fmt.Errorf(
						"state should be %d, got %d",
						"Ejected",
						s.state,
					)
				}

				return
			},
		},
		{
			baps3.NewMessage(baps3.RsTime).AddArg("1337000000"),
			func(s *serviceState) (err error) {
				if s.time.Seconds() != 1337 {
					err = fmt.Errorf(
						"time should be %i secs, got %i",
						1337,
						s.time,
					)
				}

				return
			},
		},
	}

	for _, c := range cases {
		st := initServiceState()
		if err := st.update(*c.msg); err != nil {
			t.Errorf("error when sending %d: %s", c.msg, err)
		}
		if err := c.cmp(st); err != nil {
			t.Errorf("sent %d, but got error: %s", c.msg, err)
		}
	}

}
<commit_msg>Fix test for moved features stuff<commit_after>package main

import (
	"fmt"
	"testing"

	"github.com/UniversityRadioYork/baps3-go"
)

// TestHasFeature tests whether serviceState.hasFeature seems to work.
func TestHasFeature(t *testing.T) {
	cases := []struct {
		feat    baps3.Feature
		present bool
	}{
		// We check the presence of some features and the absence of
		// others.  This is a shuffled, but even distribution of both.
		{baps3.FtFileLoad, true},
		{baps3.FtPlayStop, true},
		{baps3.FtSeek, false},
		{baps3.FtEnd, true},
		{baps3.FtTimeReport, false},
		{baps3.FtPlaylist, true},
		{baps3.FtPlaylistAutoAdvance, false},
		{baps3.FtPlaylistTextItems, false},
	}

	// This is for collecting the features we do want to enable.
	presents := []baps3.Feature{}

	// All features should be absent on a new serviceState.
	srv := initServiceState()

	for _, c := range cases {
		if srv.hasFeature(c.feat) {
			t.Errorf("initial serviceState shouldn't have feature %q", c.feat)
		}
		if c.present {
			presents = append(presents, c.feat)
		}
	}

	// Now set the features we want.
	msg := baps3.NewMessage(baps3.RsFeatures)
	for _, p := range presents {
		msg.AddArg(p.String())
	}

	if err := srv.update(*msg); err != nil {
		t.Errorf("error when setting features: %s", err)
	}

	// Now check if hasFeature works (!)
	for _, d := range cases {
		has := srv.hasFeature(d.feat)
		if has && !d.present {
			t.Errorf("service should not have feature %q, but does", d.feat)
		} else if !has && d.present {
			t.Errorf("service should have feature %q, but does not", d.feat)
		}
	}
}

// TestServiceStateUpdateFail tests the behaviour of a serviceState when it
// receives a malformed message.
func TestServiceStateUpdateFail(t *testing.T) {
	// TODO(CaptainHayashi): maybe test what the error actually is
	cases := []struct {
		msg    *baps3.Message
		hasErr bool
	}{
		// Request where response was expected
		{
			baps3.NewMessage(baps3.RqLoad).AddArg("/quux"),
			false, // TODO(CaptainHayashi): error on requests?
		},
		// Too few arguments
		{
			baps3.NewMessage(baps3.RsFile),
			true,
		},
		// Too many arguments
		{
			baps3.NewMessage(baps3.RsTime).AddArg("3003").AddArg("lol"),
			true,
		},
		// Unknown request (should be ignored)
		{
			baps3.NewMessage(baps3.RsUnknown).AddArg("heh"),
			false,
		},
	}

	for _, c := range cases {
		err := initServiceState().update(*c.msg)
		if c.hasErr && (err == nil) {
			t.Errorf("expected %q to produce error, none produced", c.msg)
		} else if !c.hasErr && (err != nil) {
			t.Errorf("expected %q not to produce error, one produced", c.msg)
		}
	}
}

// TestServiceStateUpdate tests the updating of a serviceState by messages.
func TestServiceStateUpdate(t *testing.T) {
	// TODO(CaptainHayashi): test failure states as well as successes

	cases := []struct {
		msg *baps3.Message
		cmp func(*serviceState) error
	}{
		{
			baps3.NewMessage(baps3.RsFeatures).AddArg("End").AddArg("FileLoad"),
			func(s *serviceState) (err error) {
				_, endIn := s.features[baps3.FtEnd]
				_, flIn := s.features[baps3.FtFileLoad]

				if !endIn || !flIn {
					err = fmt.Errorf(
						"features should contain End and Fileload, got %d",
						s.features,
					)
				}

				return
			},
		},
		{
			baps3.NewMessage(baps3.RsFile).AddArg("/home/foo/bar.mp3"),
			func(s *serviceState) (err error) {
				if s.file != "/home/foo/bar.mp3" {
					err = fmt.Errorf(
						"file should be %d, got %d",
						"/home/foo/bar.mp3",
						s.file,
					)
				}

				return
			},
		},
		{
			baps3.NewMessage(baps3.RsState).AddArg("Ejected"),
			func(s *serviceState) (err error) {
				if s.state != "Ejected" {
					err = fmt.Errorf(
						"state should be %d, got %d",
						"Ejected",
						s.state,
					)
				}

				return
			},
		},
		{
			baps3.NewMessage(baps3.RsTime).AddArg("1337000000"),
			func(s *serviceState) (err error) {
				if s.time.Seconds() != 1337 {
					err = fmt.Errorf(
						"time should be %i secs, got %i",
						1337,
						s.time,
					)
				}

				return
			},
		},
	}

	for _, c := range cases {
		st := initServiceState()
		if err := st.update(*c.msg); err != nil {
			t.Errorf("error when sending %d: %s", c.msg, err)
		}
		if err := c.cmp(st); err != nil {
			t.Errorf("sent %d, but got error: %s", c.msg, err)
		}
	}

}
<|endoftext|>


<commit_before>package asm

import (
	"io"
	"io/ioutil"

	"github.com/vbatts/tar-split/archive/tar"
	"github.com/vbatts/tar-split/tar/storage"
)

// NewInputTarStream wraps the Reader stream of a tar archive and provides a
// Reader stream of the same.
//
// In the middle it will pack the segments and file metadata to storage.Packer
// `p`.
//
// The the storage.FilePutter is where payload of files in the stream are
// stashed. If this stashing is not needed, you can provide a nil
// storage.FilePutter. Since the checksumming is still needed, then a default
// of NewDiscardFilePutter will be used internally
func NewInputTarStream(r io.Reader, p storage.Packer, fp storage.FilePutter) (io.Reader, error) {
	// What to do here... folks will want their own access to the Reader that is
	// their tar archive stream, but we'll need that same stream to use our
	// forked 'archive/tar'.
	// Perhaps do an io.TeeReader that hands back an io.Reader for them to read
	// from, and we'll MITM the stream to store metadata.
	// We'll need a storage.FilePutter too ...

	// Another concern, whether to do any storage.FilePutter operations, such that we
	// don't extract any amount of the archive. But then again, we're not making
	// files/directories, hardlinks, etc. Just writing the io to the storage.FilePutter.
	// Perhaps we have a DiscardFilePutter that is a bit bucket.

	// we'll return the pipe reader, since TeeReader does not buffer and will
	// only read what the outputRdr Read's. Since Tar archives have padding on
	// the end, we want to be the one reading the padding, even if the user's
	// `archive/tar` doesn't care.
	pR, pW := io.Pipe()
	outputRdr := io.TeeReader(r, pW)

	// we need a putter that will generate the crc64 sums of file payloads
	if fp == nil {
		fp = storage.NewDiscardFilePutter()
	}

	go func() {
		tr := tar.NewReader(outputRdr)
		tr.RawAccounting = true
		for {
			hdr, err := tr.Next()
			if err != nil {
				if err != io.EOF {
					pW.CloseWithError(err)
					return
				}
				// even when an EOF is reached, there is often 1024 null bytes on
				// the end of an archive. Collect them too.
				_, err := p.AddEntry(storage.Entry{
					Type:    storage.SegmentType,
					Payload: tr.RawBytes(),
				})
				if err != nil {
					pW.CloseWithError(err)
					return
				}
				break // not return. We need the end of the reader.
			}
			if hdr == nil {
				break // not return. We need the end of the reader.
			}

			if _, err := p.AddEntry(storage.Entry{
				Type:    storage.SegmentType,
				Payload: tr.RawBytes(),
			}); err != nil {
				pW.CloseWithError(err)
				return
			}

			var csum []byte
			if hdr.Size > 0 {
				var err error
				_, csum, err = fp.Put(hdr.Name, tr)
				if err != nil {
					pW.CloseWithError(err)
					return
				}
			}

			// File entries added, regardless of size
			_, err = p.AddEntry(storage.Entry{
				Type:    storage.FileType,
				Name:    hdr.Name,
				Size:    hdr.Size,
				Payload: csum,
			})
			if err != nil {
				pW.CloseWithError(err)
				return
			}

			if b := tr.RawBytes(); len(b) > 0 {
				_, err = p.AddEntry(storage.Entry{
					Type:    storage.SegmentType,
					Payload: b,
				})
				if err != nil {
					pW.CloseWithError(err)
					return
				}
			}
		}

		// it is allowable, and not uncommon that there is further padding on the
		// end of an archive, apart from the expected 1024 null bytes.
		remainder, err := ioutil.ReadAll(outputRdr)
		if err != nil && err != io.EOF {
			pW.CloseWithError(err)
			return
		}
		_, err = p.AddEntry(storage.Entry{
			Type:    storage.SegmentType,
			Payload: remainder,
		})
		if err != nil {
			pW.CloseWithError(err)
			return
		}
		pW.Close()
	}()

	return pR, nil
}
<commit_msg>tar/asm: check length before adding an entry<commit_after>package asm

import (
	"io"
	"io/ioutil"

	"github.com/vbatts/tar-split/archive/tar"
	"github.com/vbatts/tar-split/tar/storage"
)

// NewInputTarStream wraps the Reader stream of a tar archive and provides a
// Reader stream of the same.
//
// In the middle it will pack the segments and file metadata to storage.Packer
// `p`.
//
// The the storage.FilePutter is where payload of files in the stream are
// stashed. If this stashing is not needed, you can provide a nil
// storage.FilePutter. Since the checksumming is still needed, then a default
// of NewDiscardFilePutter will be used internally
func NewInputTarStream(r io.Reader, p storage.Packer, fp storage.FilePutter) (io.Reader, error) {
	// What to do here... folks will want their own access to the Reader that is
	// their tar archive stream, but we'll need that same stream to use our
	// forked 'archive/tar'.
	// Perhaps do an io.TeeReader that hands back an io.Reader for them to read
	// from, and we'll MITM the stream to store metadata.
	// We'll need a storage.FilePutter too ...

	// Another concern, whether to do any storage.FilePutter operations, such that we
	// don't extract any amount of the archive. But then again, we're not making
	// files/directories, hardlinks, etc. Just writing the io to the storage.FilePutter.
	// Perhaps we have a DiscardFilePutter that is a bit bucket.

	// we'll return the pipe reader, since TeeReader does not buffer and will
	// only read what the outputRdr Read's. Since Tar archives have padding on
	// the end, we want to be the one reading the padding, even if the user's
	// `archive/tar` doesn't care.
	pR, pW := io.Pipe()
	outputRdr := io.TeeReader(r, pW)

	// we need a putter that will generate the crc64 sums of file payloads
	if fp == nil {
		fp = storage.NewDiscardFilePutter()
	}

	go func() {
		tr := tar.NewReader(outputRdr)
		tr.RawAccounting = true
		for {
			hdr, err := tr.Next()
			if err != nil {
				if err != io.EOF {
					pW.CloseWithError(err)
					return
				}
				// even when an EOF is reached, there is often 1024 null bytes on
				// the end of an archive. Collect them too.
				if b := tr.RawBytes(); len(b) > 0 {
					_, err := p.AddEntry(storage.Entry{
						Type:    storage.SegmentType,
						Payload: b,
					})
					if err != nil {
						pW.CloseWithError(err)
						return
					}
				}
				break // not return. We need the end of the reader.
			}
			if hdr == nil {
				break // not return. We need the end of the reader.
			}

			if b := tr.RawBytes(); len(b) > 0 {
				_, err := p.AddEntry(storage.Entry{
					Type:    storage.SegmentType,
					Payload: b,
				})
				if err != nil {
					pW.CloseWithError(err)
					return
				}
			}

			var csum []byte
			if hdr.Size > 0 {
				var err error
				_, csum, err = fp.Put(hdr.Name, tr)
				if err != nil {
					pW.CloseWithError(err)
					return
				}
			}

			// File entries added, regardless of size
			_, err = p.AddEntry(storage.Entry{
				Type:    storage.FileType,
				Name:    hdr.Name,
				Size:    hdr.Size,
				Payload: csum,
			})
			if err != nil {
				pW.CloseWithError(err)
				return
			}

			if b := tr.RawBytes(); len(b) > 0 {
				_, err = p.AddEntry(storage.Entry{
					Type:    storage.SegmentType,
					Payload: b,
				})
				if err != nil {
					pW.CloseWithError(err)
					return
				}
			}
		}

		// it is allowable, and not uncommon that there is further padding on the
		// end of an archive, apart from the expected 1024 null bytes.
		remainder, err := ioutil.ReadAll(outputRdr)
		if err != nil && err != io.EOF {
			pW.CloseWithError(err)
			return
		}
		_, err = p.AddEntry(storage.Entry{
			Type:    storage.SegmentType,
			Payload: remainder,
		})
		if err != nil {
			pW.CloseWithError(err)
			return
		}
		pW.Close()
	}()

	return pR, nil
}
<|endoftext|>


<commit_before>package main

import (
	zmq "github.com/pebbe/zmq4"
	"flag"
	"os"
	"fmt"
)

func Exitf(code int, format string, v... interface{}) {
	fmt.Fprintf(os.Stderr, "Fatal: ")
	fmt.Fprintf(os.Stderr, format, v...)
	os.Exit(code)
}

func main() {
	block := flag.Bool("block", true, "Use a blocking zmq_recv.")
	text := flag.Bool("text", false, "Read messages as strings.")
	multipart := flag.Bool("multipart", false, "Read multipart messages and print the parts individually.")
	flag.Usage = func() {
		Exitf(2, "Usage of %s:\n", os.Args[0])
		Exitf(2, "%s <zmq_endpoint> [opts]\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()
	if flag.NArg() < 1 {
		flag.Usage()
	}
	uri := flag.Arg(0)
	sock, err := zmq.NewSocket(zmq.SUB)
	if err != nil {
		Exitf(2, "Could not create ZMQ socket: %v", err)
	}
	err = sock.Connect(uri)
	if err != nil {
		Exitf(2, "Could not connect to endpoint %s: %v", uri, err)
	}
	err = sock.SetSubscribe("")
	if err != nil {
		Exitf(2, "Could not subscribe: %v", err)
	}
	var recvFlag zmq.Flag
	if *block {
		recvFlag = 0
	} else {
		recvFlag = zmq.DONTWAIT
	}
	for {
		if *multipart && *text {
			msg, err := sock.RecvMessage(recvFlag)
			if err != nil {
				Exitf(2, "Could not receive bytes: %v", err)
			}
			for _, part := range msg {
				fmt.Println(part)
			}
		} else if *multipart {
			msg, err := sock.RecvMessageBytes(recvFlag)
			if err != nil {
				Exitf(2, "Could not receive bytes: %v", err)
			}
			for _, part := range msg {
				os.Stdout.Write(part)
			}
		} else if *text {
			msg, err := sock.Recv(recvFlag)
			if err != nil {
				Exitf(2, "Could not receive bytes: %v", err)
			}
			fmt.Println(msg)
		}
	}
}
<commit_msg>Refactor<commit_after>package main

import (
	zmq "github.com/pebbe/zmq4"
	"flag"
	"os"
	"fmt"
)

func Exitf(code int, format string, v... interface{}) {
	fmt.Fprintf(os.Stderr, "Fatal: ")
	fmt.Fprintf(os.Stderr, format, v...)
	os.Exit(code)
}

func main() {
	block := flag.Bool("block", true, "Use a blocking zmq_recv.")
	text := flag.Bool("text", false, "Read messages as strings.")
	multipart := flag.Bool("multipart", false, "Read multipart messages and print the parts individually.")
	flag.Usage = func() {
		Exitf(2, "Usage of %s:\n", os.Args[0])
		Exitf(2, "%s <zmq_endpoint> [opts]\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()
	if flag.NArg() < 1 {
		flag.Usage()
	}
	uri := flag.Arg(0)
	sock, err := zmq.NewSocket(zmq.SUB)
	if err != nil {
		Exitf(2, "Could not create ZMQ socket: %v", err)
	}
	err = sock.Connect(uri)
	if err != nil {
		Exitf(2, "Could not connect to endpoint %s: %v", uri, err)
	}
	err = sock.SetSubscribe("")
	if err != nil {
		Exitf(2, "Could not subscribe: %v", err)
	}
	var recvFlag zmq.Flag
	if *block {
		recvFlag = 0
	} else {
		recvFlag = zmq.DONTWAIT
	}
	var strMsg string
	var strMsgMulti []string
	var rawMsg []byte
	var rawMsgMulti [][]byte
	for {
		switch {
		case *multipart && *text:
			strMsgMulti, err = sock.RecvMessage(recvFlag)
		case *multipart:
			rawMsgMulti, err = sock.RecvMessageBytes(recvFlag)
		case *text:
			strMsg, err = sock.Recv(recvFlag)
		default:
			rawMsg, err = sock.RecvBytes(recvFlag)
		}
		if err != nil {
			Exitf(2, "Could not receive bytes: %v", err)
		}
		switch {
		case *multipart && *text:
			for _, part := range strMsgMulti {
				fmt.Println(part)
			}
		case *multipart:
			for _, part := range rawMsgMulti {
				os.Stdout.Write(part)
			}
		case *text:
			fmt.Println(strMsg)
		default:
			os.Stdout.Write(rawMsg)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"runtime"
	"time"

	"github.com/Sirupsen/logrus"

	"github.com/mozilla/tls-observatory/config"
	"github.com/mozilla/tls-observatory/connection"
	pg "github.com/mozilla/tls-observatory/database"
	"github.com/mozilla/tls-observatory/logger"
	"github.com/mozilla/tls-observatory/worker"
)

var db *pg.DB
var log = logger.GetLogger()

var activeScanners int = 0

func main() {
	var (
		cfgFile, cipherscan string
		debug               bool
	)
	flag.StringVar(&cfgFile, "c", "/etc/tls-observatory/scanner.cfg", "Configuration file")
	flag.StringVar(&cipherscan, "b", "/opt/cipherscan/cipherscan", "Cipherscan binary location")
	flag.BoolVar(&debug, "debug", false, "Set debug logging")
	flag.Parse()

	if debug {
		logger.SetLevelToDebug()
	}

	conf, err := config.Load(cfgFile)
	if err != nil {
		log.Fatal(fmt.Sprintf("Failed to load configuration: %v", err))
	}
	if !conf.General.Enable && os.Getenv("TLSOBS_SCANNER_ENABLE") != "on" {
		log.Fatal("Scanner is disabled in configuration")
	}

	_, err = os.Stat(cipherscan)
	if err != nil {
		log.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Error("Could not locate cipherscan executable. TLS connection capabilities will not be available.")
	}

	// increase the n
	runtime.GOMAXPROCS(conf.General.MaxProc)

	dbtls := "disable"
	if conf.General.PostgresUseTLS {
		dbtls = "verify-full"
	}
	db, err = pg.RegisterConnection(
		conf.General.PostgresDB,
		conf.General.PostgresUser,
		conf.General.PostgresPass,
		conf.General.Postgres,
		dbtls)
	defer db.Close()
	if err != nil {
		log.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Fatal("Failed to connect to database")
	}
	db.SetMaxOpenConns(conf.General.MaxProc)
	db.SetMaxIdleConns(10)
	incomingScans := db.RegisterScanListener(conf.General.PostgresDB, conf.General.PostgresUser, conf.General.PostgresPass, conf.General.Postgres, "disable")
	Setup(conf)

	for scanID := range incomingScans {
		// wait until we have an available scanner
		for {
			if activeScanners >= conf.General.MaxProc {
				time.Sleep(time.Second)
			} else {
				break
			}
		}
		go scan(scanID, cipherscan)
	}
}

func scan(scanID int64, cipherscan string) {
	activeScanners++
	defer func() {
		activeScanners--
	}()
	log.WithFields(logrus.Fields{
		"scan_id": scanID,
	}).Info("Received new scan")

	db.Exec("UPDATE scans SET attempts = attempts + 1 WHERE id=$1", scanID)

	scan, err := db.GetScanByID(scanID)
	if err != nil {
		log.WithFields(logrus.Fields{
			"scan_id": scanID,
			"error":   err.Error(),
		}).Error("Could not find/decode scan")
		return
	}
	var completion int

	// Retrieve the certificate from the target
	certID, trustID, err := handleCert(scan.Target)
	if err != nil {
		db.Exec("UPDATE scans SET has_tls=FALSE, completion_perc=100 WHERE id=$1", scanID)
		log.WithFields(logrus.Fields{
			"scan_id":     scanID,
			"scan_Target": scan.Target,
			"error":       err.Error(),
		}).Error("Could not get certificate info")
		return
	}
	log.WithFields(logrus.Fields{
		"scan_id":  scanID,
		"cert_id":  certID,
		"trust_id": trustID,
	}).Debug("Retrieved certs")

	isTrustValid, err := db.IsTrustValid(trustID)
	if err != nil {
		log.WithFields(logrus.Fields{
			"scan_id": scanID,
			"cert_id": certID,
			"error":   err.Error(),
		}).Error("Could not get if trust is valid")
		return
	}
	completion += 20
	_, err = db.Exec(`UPDATE scans
			SET cert_id=$1, trust_id=$2, has_tls=TRUE, is_valid=$3, completion_perc=$4
			WHERE id=$5`, certID, trustID, isTrustValid, completion, scanID)
	if err != nil {
		log.WithFields(logrus.Fields{
			"scan_id": scanID,
			"cert_id": certID,
			"error":   err.Error(),
		}).Error("Could not update scans for cert")
		return
	}

	// Cipherscan the target
	js, err := connection.Connect(scan.Target, cipherscan)
	if err != nil {
		err, ok := err.(connection.NoTLSConnErr)
		if ok {
			//does not implement TLS
			db.Exec("UPDATE scans SET has_tls=FALSE, completion_perc=100 WHERE id=$1", scanID)
		} else {
			log.WithFields(logrus.Fields{
				"scan_id": scanID,
				"error":   err.Error(),
			}).Error("Could not get TLS connection info")
		}
		return
	}
	completion += 20
	_, err = db.Exec("UPDATE scans SET conn_info=$1, completion_perc=$2 WHERE id=$3",
		js, completion, scanID)
	if err != nil {
		log.WithFields(logrus.Fields{
			"scan_id": scanID,
			"error":   err.Error(),
		}).Error("Could not update connection information for scan")
	}

	// Prepare worker input
	cert, err := db.GetCertByID(certID)
	if err != nil {
		log.WithFields(logrus.Fields{
			"scan_id": scanID,
			"cert_id": certID,
		}).Error("Could not get certificate from db to pass to workers")
		return
	}
	var conn_info connection.Stored
	err = json.Unmarshal(js, &conn_info)
	if err != nil {
		log.WithFields(logrus.Fields{
			"scan_id": scanID,
		}).Error("Could not parse connection info to pass to workers")
		return
	}
	workerInput := worker.Input{
		DBHandle:    db,
		Scanid:      scanID,
		Certificate: *cert,
		Connection:  conn_info,
	}
	// launch workers that evaluate the results
	resChan := make(chan worker.Result)
	totalWorkers := 0
	for _, wrkInfo := range worker.AvailableWorkers {
		go wrkInfo.Runner.(worker.Worker).Run(workerInput, resChan)
		totalWorkers++
	}
	log.WithFields(logrus.Fields{
		"scan_id": scanID,
		"count":   totalWorkers,
	}).Info("Running workers")

	// read the results from the results chan in a loop until all workers have ran or expired
	for endedWorkers := 0; endedWorkers < totalWorkers; endedWorkers++ {
		select {
		case <-time.After(30 * time.Second):
			log.WithFields(logrus.Fields{
				"scan_id": scanID,
			}).Error("Analysis workers timed out after 30 seconds")
			return
		case res := <-resChan:
			endedWorkers += endedWorkers
			completion = ((endedWorkers/totalWorkers)*60 + completion)
			log.WithFields(logrus.Fields{
				"scan_id":     scanID,
				"worker_name": res.WorkerName,
				"success":     res.Success,
				"result":      string(res.Result),
			}).Debug("Received results from worker")

			err = db.UpdateScanCompletionPercentage(scanID, completion)
			if err != nil {
				log.WithFields(logrus.Fields{
					"scan_id": scanID,
					"error":   err.Error(),
				}).Error("Could not update completion percentage")
				continue
			}
			if !res.Success {
				log.WithFields(logrus.Fields{
					"worker_name": res.WorkerName,
					"errors":      res.Errors,
				}).Error("Worker returned with errors")
				continue
			}
			_, err = db.Exec("INSERT INTO analysis(scan_id,worker_name,output) VALUES($1,$2,$3)",
				scanID, res.WorkerName, res.Result)
			if err != nil {
				log.WithFields(logrus.Fields{
					"scan_id": scanID,
					"error":   err.Error(),
				}).Error("Could not insert worker results in database")
				continue
			}
			log.WithFields(logrus.Fields{
				"scan_id":     scanID,
				"worker_name": res.WorkerName,
			}).Info("Results from worker stored in database")
		}
	}
	err = db.UpdateScanCompletionPercentage(scanID, 100)
	if err != nil {
		log.WithFields(logrus.Fields{
			"scan_id": scanID,
			"error":   err.Error(),
		}).Error("Could not update completion percentage")
	}
	return
}
<commit_msg>minor tweak to handling of concurrent scanners<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"runtime"
	"time"

	"github.com/Sirupsen/logrus"

	"github.com/mozilla/tls-observatory/config"
	"github.com/mozilla/tls-observatory/connection"
	pg "github.com/mozilla/tls-observatory/database"
	"github.com/mozilla/tls-observatory/logger"
	"github.com/mozilla/tls-observatory/worker"
)

var db *pg.DB
var log = logger.GetLogger()

func main() {
	var (
		cfgFile, cipherscan string
		debug               bool
	)
	flag.StringVar(&cfgFile, "c", "/etc/tls-observatory/scanner.cfg", "Configuration file")
	flag.StringVar(&cipherscan, "b", "/opt/cipherscan/cipherscan", "Cipherscan binary location")
	flag.BoolVar(&debug, "debug", false, "Set debug logging")
	flag.Parse()

	if debug {
		logger.SetLevelToDebug()
	}

	conf, err := config.Load(cfgFile)
	if err != nil {
		log.Fatal(fmt.Sprintf("Failed to load configuration: %v", err))
	}
	if !conf.General.Enable && os.Getenv("TLSOBS_SCANNER_ENABLE") != "on" {
		log.Fatal("Scanner is disabled in configuration")
	}

	_, err = os.Stat(cipherscan)
	if err != nil {
		log.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Error("Could not locate cipherscan executable. TLS connection capabilities will not be available.")
	}

	// increase the n
	runtime.GOMAXPROCS(conf.General.MaxProc)

	dbtls := "disable"
	if conf.General.PostgresUseTLS {
		dbtls = "verify-full"
	}
	db, err = pg.RegisterConnection(
		conf.General.PostgresDB,
		conf.General.PostgresUser,
		conf.General.PostgresPass,
		conf.General.Postgres,
		dbtls)
	defer db.Close()
	if err != nil {
		log.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Fatal("Failed to connect to database")
	}
	db.SetMaxOpenConns(conf.General.MaxProc)
	db.SetMaxIdleConns(10)
	incomingScans := db.RegisterScanListener(
		conf.General.PostgresDB,
		conf.General.PostgresUser,
		conf.General.PostgresPass,
		conf.General.Postgres,
		"disable")
	Setup(conf)

	activeScanners := 0
	for scanID := range incomingScans {
		// wait until we have an available scanner
		for {
			if activeScanners >= conf.General.MaxProc {
				time.Sleep(time.Second)
			} else {
				break
			}
		}
		go func() {
			activeScanners++
			scan(scanID, cipherscan)
			activeScanners--
		}()
	}
}

func scan(scanID int64, cipherscan string) {
	log.WithFields(logrus.Fields{
		"scan_id": scanID,
	}).Info("Received new scan")

	db.Exec("UPDATE scans SET attempts = attempts + 1 WHERE id=$1", scanID)

	scan, err := db.GetScanByID(scanID)
	if err != nil {
		log.WithFields(logrus.Fields{
			"scan_id": scanID,
			"error":   err.Error(),
		}).Error("Could not find/decode scan")
		return
	}
	var completion int

	// Retrieve the certificate from the target
	certID, trustID, err := handleCert(scan.Target)
	if err != nil {
		db.Exec("UPDATE scans SET has_tls=FALSE, completion_perc=100 WHERE id=$1", scanID)
		log.WithFields(logrus.Fields{
			"scan_id":     scanID,
			"scan_Target": scan.Target,
			"error":       err.Error(),
		}).Error("Could not get certificate info")
		return
	}
	log.WithFields(logrus.Fields{
		"scan_id":  scanID,
		"cert_id":  certID,
		"trust_id": trustID,
	}).Debug("Retrieved certs")

	isTrustValid, err := db.IsTrustValid(trustID)
	if err != nil {
		log.WithFields(logrus.Fields{
			"scan_id": scanID,
			"cert_id": certID,
			"error":   err.Error(),
		}).Error("Could not get if trust is valid")
		return
	}
	completion += 20
	_, err = db.Exec(`UPDATE scans
			SET cert_id=$1, trust_id=$2, has_tls=TRUE, is_valid=$3, completion_perc=$4
			WHERE id=$5`, certID, trustID, isTrustValid, completion, scanID)
	if err != nil {
		log.WithFields(logrus.Fields{
			"scan_id": scanID,
			"cert_id": certID,
			"error":   err.Error(),
		}).Error("Could not update scans for cert")
		return
	}

	// Cipherscan the target
	js, err := connection.Connect(scan.Target, cipherscan)
	if err != nil {
		err, ok := err.(connection.NoTLSConnErr)
		if ok {
			//does not implement TLS
			db.Exec("UPDATE scans SET has_tls=FALSE, completion_perc=100 WHERE id=$1", scanID)
		} else {
			log.WithFields(logrus.Fields{
				"scan_id": scanID,
				"error":   err.Error(),
			}).Error("Could not get TLS connection info")
		}
		return
	}
	completion += 20
	_, err = db.Exec("UPDATE scans SET conn_info=$1, completion_perc=$2 WHERE id=$3",
		js, completion, scanID)
	if err != nil {
		log.WithFields(logrus.Fields{
			"scan_id": scanID,
			"error":   err.Error(),
		}).Error("Could not update connection information for scan")
	}

	// Prepare worker input
	cert, err := db.GetCertByID(certID)
	if err != nil {
		log.WithFields(logrus.Fields{
			"scan_id": scanID,
			"cert_id": certID,
		}).Error("Could not get certificate from db to pass to workers")
		return
	}
	var conn_info connection.Stored
	err = json.Unmarshal(js, &conn_info)
	if err != nil {
		log.WithFields(logrus.Fields{
			"scan_id": scanID,
		}).Error("Could not parse connection info to pass to workers")
		return
	}
	workerInput := worker.Input{
		DBHandle:    db,
		Scanid:      scanID,
		Certificate: *cert,
		Connection:  conn_info,
	}
	// launch workers that evaluate the results
	resChan := make(chan worker.Result)
	totalWorkers := 0
	for _, wrkInfo := range worker.AvailableWorkers {
		go wrkInfo.Runner.(worker.Worker).Run(workerInput, resChan)
		totalWorkers++
	}
	log.WithFields(logrus.Fields{
		"scan_id": scanID,
		"count":   totalWorkers,
	}).Info("Running workers")

	// read the results from the results chan in a loop until all workers have ran or expired
	for endedWorkers := 0; endedWorkers < totalWorkers; endedWorkers++ {
		select {
		case <-time.After(30 * time.Second):
			log.WithFields(logrus.Fields{
				"scan_id": scanID,
			}).Error("Analysis workers timed out after 30 seconds")
			return
		case res := <-resChan:
			endedWorkers += endedWorkers
			completion = ((endedWorkers/totalWorkers)*60 + completion)
			log.WithFields(logrus.Fields{
				"scan_id":     scanID,
				"worker_name": res.WorkerName,
				"success":     res.Success,
				"result":      string(res.Result),
			}).Debug("Received results from worker")

			err = db.UpdateScanCompletionPercentage(scanID, completion)
			if err != nil {
				log.WithFields(logrus.Fields{
					"scan_id": scanID,
					"error":   err.Error(),
				}).Error("Could not update completion percentage")
				continue
			}
			if !res.Success {
				log.WithFields(logrus.Fields{
					"worker_name": res.WorkerName,
					"errors":      res.Errors,
				}).Error("Worker returned with errors")
				continue
			}
			_, err = db.Exec("INSERT INTO analysis(scan_id,worker_name,output) VALUES($1,$2,$3)",
				scanID, res.WorkerName, res.Result)
			if err != nil {
				log.WithFields(logrus.Fields{
					"scan_id": scanID,
					"error":   err.Error(),
				}).Error("Could not insert worker results in database")
				continue
			}
			log.WithFields(logrus.Fields{
				"scan_id":     scanID,
				"worker_name": res.WorkerName,
			}).Info("Results from worker stored in database")
		}
	}
	err = db.UpdateScanCompletionPercentage(scanID, 100)
	if err != nil {
		log.WithFields(logrus.Fields{
			"scan_id": scanID,
			"error":   err.Error(),
		}).Error("Could not update completion percentage")
	}
	return
}
<|endoftext|>


<commit_before>package util

import (
	"errors"
	"fmt"
	"os"
	"path"

	"github.com/codegangsta/cli"
	"github.com/rackspace/gophercloud"
)

// Name is the name of the CLI
var name = "rack"

// Version is the current CLI version
var Version = "0.0.0-dev"

// Usage return a string that specifies how to call a particular command.
func Usage(commandPrefix, action, mandatoryFlags string) string {
	return fmt.Sprintf("%s [GLOBALS] %s %s %s [OPTIONS]", name, commandPrefix, action, mandatoryFlags)
}

// Contains checks whether a given string is in a provided slice of strings.
func Contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}

// RackDir returns the location of the `rack` directory. This directory is for
// storing `rack`-specific information such as the cache or a config file.
func RackDir() (string, error) {
	homeDir := os.Getenv("HOME") // *nix
	if homeDir == "" {           // Windows
		homeDir = os.Getenv("USERPROFILE")
	}
	if homeDir == "" {
		return "", errors.New("User home directory not found.")
	}
	dirpath := path.Join(homeDir, ".rack")
	err := os.MkdirAll(dirpath, 0644)
	return dirpath, err
}

// CheckArgNum checks that the provided number of arguments has the same
// cardinality as the expected number of arguments.
func CheckArgNum(c *cli.Context, expected int) error {
	argsLen := len(c.Args())
	if argsLen != expected {
		return fmt.Errorf("Expected %d args but got %d\nUsage: %s", expected, argsLen, c.Command.Usage)
	}
	return nil
}

// CheckFlagsSet checks that the given flag names are set for the command.
func CheckFlagsSet(c *cli.Context, flagNames []string) error {
	for _, flagName := range flagNames {
		if !c.IsSet(flagName) {
			return Error(c, ErrMissingFlag{
				Msg: fmt.Sprintf("--%s is required.", flagName),
			})
		}
	}
	return nil
}

// IDOrName is a function for retrieving a resources unique identifier based on
// whether he or she passed an `id` or a `name` flag.
func IDOrName(c *cli.Context, client *gophercloud.ServiceClient, idFromName func(*gophercloud.ServiceClient, string) (string, error)) (string, error) {
	if c.IsSet("id") {
		return c.String("id"), nil
	} else if c.IsSet("name") {
		name := c.String("name")
		id, err := idFromName(client, name)
		if err != nil {
			return "", fmt.Errorf("Error converting name [%s] to ID: %s", name, err)
		}
		return id, nil
	} else {
		return "", Error(c, ErrMissingFlag{
			Msg: "One of either --id or --name must be provided.",
		})
	}
}

// IDAndNameFlags are flags for commands that allow either an ID or a name.
var IDAndNameFlags = []cli.Flag{
	cli.StringFlag{
		Name:  "id",
		Usage: "[optional; required if 'name' is not provided] The ID of the resource",
	},
	cli.StringFlag{
		Name:  "name",
		Usage: "[optional; required if 'id' is not provided] The name of the resource",
	},
}

// IDOrNameUsage returns flag usage information for resources that allow either
// an ID or a name.
func IDOrNameUsage(resource string) string {
	return fmt.Sprintf("[--id <%sID> | --name <%sName>]", resource, resource)
}
<commit_msg>error if both id and name are provided<commit_after>package util

import (
	"errors"
	"fmt"
	"os"
	"path"

	"github.com/codegangsta/cli"
	"github.com/rackspace/gophercloud"
)

// Name is the name of the CLI
var name = "rack"

// Version is the current CLI version
var Version = "0.0.0-dev"

// Usage return a string that specifies how to call a particular command.
func Usage(commandPrefix, action, mandatoryFlags string) string {
	return fmt.Sprintf("%s [GLOBALS] %s %s %s [OPTIONS]", name, commandPrefix, action, mandatoryFlags)
}

// Contains checks whether a given string is in a provided slice of strings.
func Contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}

// RackDir returns the location of the `rack` directory. This directory is for
// storing `rack`-specific information such as the cache or a config file.
func RackDir() (string, error) {
	homeDir := os.Getenv("HOME") // *nix
	if homeDir == "" {           // Windows
		homeDir = os.Getenv("USERPROFILE")
	}
	if homeDir == "" {
		return "", errors.New("User home directory not found.")
	}
	dirpath := path.Join(homeDir, ".rack")
	err := os.MkdirAll(dirpath, 0644)
	return dirpath, err
}

// CheckArgNum checks that the provided number of arguments has the same
// cardinality as the expected number of arguments.
func CheckArgNum(c *cli.Context, expected int) error {
	argsLen := len(c.Args())
	if argsLen != expected {
		return fmt.Errorf("Expected %d args but got %d\nUsage: %s", expected, argsLen, c.Command.Usage)
	}
	return nil
}

// CheckFlagsSet checks that the given flag names are set for the command.
func CheckFlagsSet(c *cli.Context, flagNames []string) error {
	for _, flagName := range flagNames {
		if !c.IsSet(flagName) {
			return Error(c, ErrMissingFlag{
				Msg: fmt.Sprintf("--%s is required.", flagName),
			})
		}
	}
	return nil
}

// IDOrName is a function for retrieving a resources unique identifier based on
// whether he or she passed an `id` or a `name` flag.
func IDOrName(c *cli.Context, client *gophercloud.ServiceClient, idFromName func(*gophercloud.ServiceClient, string) (string, error)) (string, error) {
	if c.IsSet("id") {
		if c.IsSet("name") {
			return "", fmt.Errorf("Only one of either --id or --name may be provided.")
		}
		return c.String("id"), nil
	} else if c.IsSet("name") {
		name := c.String("name")
		id, err := idFromName(client, name)
		if err != nil {
			return "", fmt.Errorf("Error converting name [%s] to ID: %s", name, err)
		}
		return id, nil
	} else {
		return "", Error(c, ErrMissingFlag{
			Msg: "One of either --id or --name must be provided.",
		})
	}
}

// IDAndNameFlags are flags for commands that allow either an ID or a name.
var IDAndNameFlags = []cli.Flag{
	cli.StringFlag{
		Name:  "id",
		Usage: "[optional; required if 'name' is not provided] The ID of the resource",
	},
	cli.StringFlag{
		Name:  "name",
		Usage: "[optional; required if 'id' is not provided] The name of the resource",
	},
}

// IDOrNameUsage returns flag usage information for resources that allow either
// an ID or a name.
func IDOrNameUsage(resource string) string {
	return fmt.Sprintf("[--id <%sID> | --name <%sName>]", resource, resource)
}
<|endoftext|>


<commit_before>package iso

import (
	"fmt"
	"github.com/mitchellh/multistep"
	parallelscommon "github.com/mitchellh/packer/builder/parallels/common"
	"github.com/mitchellh/packer/packer"
	"log"
)

// This step attaches the ISO to the virtual machine.
//
// Uses:
//   driver Driver
//   isoPath string
//   ui packer.Ui
//   vmName string
//
// Produces:
type stepAttachISO struct {
	cdromDevice string
}

func (s *stepAttachISO) Run(state multistep.StateBag) multistep.StepAction {
	driver := state.Get("driver").(parallelscommon.Driver)
	isoPath := state.Get("iso_path").(string)
	ui := state.Get("ui").(packer.Ui)
	vmName := state.Get("vmName").(string)

	// Attach the disk to the controller
	ui.Say("Attaching ISO to the new CD/DVD drive...")
	cdrom, err := driver.DeviceAddCdRom(vmName, isoPath)

	if err != nil {
		err := fmt.Errorf("Error attaching ISO: %s", err)
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	// Set new boot order
	ui.Say("Setting the boot order...")
	command := []string{
		"set", vmName,
		"--device-bootorder", fmt.Sprintf("hdd0 %s cdrom0 net0", cdrom),
	}

	if err := driver.Prlctl(command...); err != nil {
		err := fmt.Errorf("Error setting the boot order: %s", err)
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	// Disable 'cdrom0' device
	ui.Say("Disabling default CD/DVD drive...")
	command = []string{
		"set", vmName,
		"--device-set", "cdrom0", "--disable",
	}

	if err := driver.Prlctl(command...); err != nil {
		err := fmt.Errorf("Error disabling default CD/DVD drive: %s", err)
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	// Track the device name so that we can can delete later
	s.cdromDevice = cdrom

	return multistep.ActionContinue
}

func (s *stepAttachISO) Cleanup(state multistep.StateBag) {
	driver := state.Get("driver").(parallelscommon.Driver)
	ui := state.Get("ui").(packer.Ui)
	vmName := state.Get("vmName").(string)

	// Enable 'cdrom0' device back
	log.Println("Enabling default CD/DVD drive...")
	command := []string{
		"set", vmName,
		"--device-set", "cdrom0", "--enable", "--disconnect",
	}

	if err := driver.Prlctl(command...); err != nil {
		ui.Error(fmt.Sprintf("Error enabling default CD/DVD drive: %s", err))
	}

	// Detach ISO
	if s.cdromDevice == "" {
		return
	}

	log.Println("Detaching ISO...")
	command = []string{
		"set", vmName,
		"--device-del", s.cdromDevice,
	}

	if err := driver.Prlctl(command...); err != nil {
		ui.Error(fmt.Sprintf("Error detaching ISO: %s", err))
	}
}
<commit_msg>builder/parallels: Attach bootable ISO exactly to cdrom0 [GH-1667]<commit_after>package iso

import (
	"fmt"
	"github.com/mitchellh/multistep"
	parallelscommon "github.com/mitchellh/packer/builder/parallels/common"
	"github.com/mitchellh/packer/packer"
	"log"
)

// This step attaches the ISO to the virtual machine.
//
// Uses:
//   driver Driver
//   isoPath string
//   ui packer.Ui
//   vmName string
//
// Produces:
//	 attachedIso bool
type stepAttachISO struct{}

func (s *stepAttachISO) Run(state multistep.StateBag) multistep.StepAction {
	driver := state.Get("driver").(parallelscommon.Driver)
	isoPath := state.Get("iso_path").(string)
	ui := state.Get("ui").(packer.Ui)
	vmName := state.Get("vmName").(string)

	// Set new boot order
	ui.Say("Setting the boot order...")
	command := []string{
		"set", vmName,
		"--device-bootorder", fmt.Sprintf("hdd0 cdrom0 net0"),
	}

	if err := driver.Prlctl(command...); err != nil {
		err := fmt.Errorf("Error setting the boot order: %s", err)
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	// Attach the disk to the cdrom0 device. We couldn't use a separated device because it is failed to boot in PD9 [GH-1667]
	ui.Say("Attaching ISO to the default CD/DVD ROM device...")
	command = []string{
		"set", vmName,
		"--device-set", "cdrom0",
		"--image", isoPath,
		"--enable", "--connect",
	}
	if err := driver.Prlctl(command...); err != nil {
		err := fmt.Errorf("Error attaching ISO: %s", err)
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	// Set some state so we know to remove
	state.Put("attachedIso", true)

	return multistep.ActionContinue
}

func (s *stepAttachISO) Cleanup(state multistep.StateBag) {
	if _, ok := state.GetOk("attachedIso"); !ok {
		return
	}

	driver := state.Get("driver").(parallelscommon.Driver)
	ui := state.Get("ui").(packer.Ui)
	vmName := state.Get("vmName").(string)

	// Detach ISO by setting an empty string image.
	log.Println("Detaching ISO from the default CD/DVD ROM device...")
	command := []string{
		"set", vmName,
		"--device-set", "cdrom0",
		"--image", "", "--disconnect", "--enable",
	}

	if err := driver.Prlctl(command...); err != nil {
		ui.Error(fmt.Sprintf("Error detaching ISO: %s", err))
	}
}
<|endoftext|>


<commit_before>// Copyright 2020 Jigsaw Operations LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package shadowsocks

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/sha1"
	"fmt"
	"io"
	"strings"

	"golang.org/x/crypto/chacha20poly1305"
	"golang.org/x/crypto/hkdf"
)

// SuportedCipherNames lists the names of the AEAD ciphers that are supported.
var SuportedCipherNames []string

func init() {
	SuportedCipherNames = make([]string, len(supportedAEADs))
	for i, spec := range supportedAEADs {
		SuportedCipherNames[i] = spec.name
	}
}

type aeadSpec struct {
	name        string
	newInstance func(key []byte) (cipher.AEAD, error)
	keySize     int
	tagSize     int
}

// List of supported AEAD ciphers, as specified at https://shadowsocks.org/en/spec/AEAD-Ciphers.html
var supportedAEADs = []aeadSpec{
	newAeadSpec("chacha20-ietf-poly1305", chacha20poly1305.New, chacha20poly1305.KeySize),
	newAeadSpec("aes-256-gcm", newAesGCM, 32),
	newAeadSpec("aes-192-gcm", newAesGCM, 24),
	newAeadSpec("aes-128-gcm", newAesGCM, 16),
}

func newAeadSpec(name string, newInstance func(key []byte) (cipher.AEAD, error), keySize int) aeadSpec {
	dummyAead, err := newInstance(make([]byte, keySize))
	if err != nil {
		panic(fmt.Sprintf("Failed to initialize AEAD %v", name))
	}
	return aeadSpec{name, newInstance, keySize, dummyAead.Overhead()}
}

func newAesGCM(key []byte) (cipher.AEAD, error) {
	blk, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	return cipher.NewGCM(blk)
}

// Cipher encapsulates a Shadowsocks AEAD spec and a secret
type Cipher struct {
	aead   aeadSpec
	secret []byte
}

// SaltSize is the size of the salt for this Cipher
func (c *Cipher) SaltSize() int {
	return c.aead.keySize
}

// TagSize is the size of the AEAD tag for this Cipher
func (c *Cipher) TagSize() int {
	return c.aead.tagSize
}

// NewAEAD creates the AEAD for this cipher
func (c *Cipher) NewAEAD(salt []byte) (cipher.AEAD, error) {
	sessionKey := make([]byte, c.aead.keySize)
	r := hkdf.New(sha1.New, c.secret, salt, []byte("ss-subkey"))
	if _, err := io.ReadFull(r, sessionKey); err != nil {
		return nil, err
	}
	return c.aead.newInstance(sessionKey)
}

func getAEADSpec(name string) (*aeadSpec, error) {
	name = strings.ToLower(name)
	for _, aeadSpec := range supportedAEADs {
		if aeadSpec.name == name {
			return &aeadSpec, nil
		}
	}
	return nil, fmt.Errorf("Unknown cipher %v", name)
}

// NewCipher creates a Cipher given a cipher name and a secret
func NewCipher(cipherName string, secretText string) (*Cipher, error) {
	secret := []byte(secretText)
	aeadSpec, err := getAEADSpec(cipherName)
	if err != nil {
		return nil, err
	}
	return &Cipher{*aeadSpec, secret}, nil
}

// Assumes all ciphers have NonceSize() <= 12.
var zeroNonce [12]byte

// DecryptOnce will decrypt the cipherText using the cipher and salt, appending the output to plainText.
func DecryptOnce(cipher *Cipher, salt []byte, plainText, cipherText []byte) ([]byte, error) {
	aead, err := cipher.NewAEAD(salt)
	if err != nil {
		return nil, err
	}
	if len(cipherText) < aead.Overhead() {
		return nil, io.ErrUnexpectedEOF
	}
	if cap(plainText)-len(plainText) < len(cipherText)-aead.Overhead() {
		return nil, io.ErrShortBuffer
	}
	return aead.Open(plainText, zeroNonce[:aead.NonceSize()], cipherText, nil)
}
<commit_msg>Update shadowsocks/cipher.go<commit_after>// Copyright 2020 Jigsaw Operations LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package shadowsocks

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/sha1"
	"fmt"
	"io"
	"strings"

	"golang.org/x/crypto/chacha20poly1305"
	"golang.org/x/crypto/hkdf"
)

// SuportedCipherNames lists the names of the AEAD ciphers that are supported.
var SuportedCipherNames []string

func init() {
	SuportedCipherNames = make([]string, len(supportedAEADs))
	for i, spec := range supportedAEADs {
		SuportedCipherNames[i] = spec.name
	}
}

type aeadSpec struct {
	name        string
	newInstance func(key []byte) (cipher.AEAD, error)
	keySize     int
	tagSize     int
}

// List of supported AEAD ciphers, as specified at https://shadowsocks.org/en/spec/AEAD-Ciphers.html
var supportedAEADs = [...]aeadSpec{
	newAeadSpec("chacha20-ietf-poly1305", chacha20poly1305.New, chacha20poly1305.KeySize),
	newAeadSpec("aes-256-gcm", newAesGCM, 32),
	newAeadSpec("aes-192-gcm", newAesGCM, 24),
	newAeadSpec("aes-128-gcm", newAesGCM, 16),
}

func newAeadSpec(name string, newInstance func(key []byte) (cipher.AEAD, error), keySize int) aeadSpec {
	dummyAead, err := newInstance(make([]byte, keySize))
	if err != nil {
		panic(fmt.Sprintf("Failed to initialize AEAD %v", name))
	}
	return aeadSpec{name, newInstance, keySize, dummyAead.Overhead()}
}

func newAesGCM(key []byte) (cipher.AEAD, error) {
	blk, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	return cipher.NewGCM(blk)
}

// Cipher encapsulates a Shadowsocks AEAD spec and a secret
type Cipher struct {
	aead   aeadSpec
	secret []byte
}

// SaltSize is the size of the salt for this Cipher
func (c *Cipher) SaltSize() int {
	return c.aead.keySize
}

// TagSize is the size of the AEAD tag for this Cipher
func (c *Cipher) TagSize() int {
	return c.aead.tagSize
}

// NewAEAD creates the AEAD for this cipher
func (c *Cipher) NewAEAD(salt []byte) (cipher.AEAD, error) {
	sessionKey := make([]byte, c.aead.keySize)
	r := hkdf.New(sha1.New, c.secret, salt, []byte("ss-subkey"))
	if _, err := io.ReadFull(r, sessionKey); err != nil {
		return nil, err
	}
	return c.aead.newInstance(sessionKey)
}

func getAEADSpec(name string) (*aeadSpec, error) {
	name = strings.ToLower(name)
	for _, aeadSpec := range supportedAEADs {
		if aeadSpec.name == name {
			return &aeadSpec, nil
		}
	}
	return nil, fmt.Errorf("Unknown cipher %v", name)
}

// NewCipher creates a Cipher given a cipher name and a secret
func NewCipher(cipherName string, secretText string) (*Cipher, error) {
	secret := []byte(secretText)
	aeadSpec, err := getAEADSpec(cipherName)
	if err != nil {
		return nil, err
	}
	return &Cipher{*aeadSpec, secret}, nil
}

// Assumes all ciphers have NonceSize() <= 12.
var zeroNonce [12]byte

// DecryptOnce will decrypt the cipherText using the cipher and salt, appending the output to plainText.
func DecryptOnce(cipher *Cipher, salt []byte, plainText, cipherText []byte) ([]byte, error) {
	aead, err := cipher.NewAEAD(salt)
	if err != nil {
		return nil, err
	}
	if len(cipherText) < aead.Overhead() {
		return nil, io.ErrUnexpectedEOF
	}
	if cap(plainText)-len(plainText) < len(cipherText)-aead.Overhead() {
		return nil, io.ErrShortBuffer
	}
	return aead.Open(plainText, zeroNonce[:aead.NonceSize()], cipherText, nil)
}
<|endoftext|>


<commit_before>package v8

/*
#include "v8_wrap.h"
#include <stdlib.h>
*/
import "C"
import "unsafe"
import "reflect"

type PropertyAttribute int

const (
	PA_None       PropertyAttribute = 0
	PA_ReadOnly                     = 1 << 0
	PA_DontEnum                     = 1 << 1
	PA_DontDelete                   = 1 << 2
)

type External struct {
	*Value
	data interface{}
}

func (e *Engine) NewExternal(value interface{}) *External {
	if value == nil {
		panic("value is nil")
	}

	external := &External{
		data: value,
	}

	external.Value = newValue(e, C.V8_NewExternal(
		e.self, unsafe.Pointer(&(external.data)),
	))

	external.setOwner(external)

	return external
}

func (ex *External) GetValue() interface{} {
	if ex.data == nil {
		ptr := C.V8_External_Value(ex.self)
		ex.data = *(*interface{})(ptr)
	}

	return ex.data
}

// A JavaScript object (ECMA-262, 4.3.3)
//
type Object struct {
	*Value
	internalFields []interface{}
	accessor       *accessorInfo
}

func (e *Engine) NewObject() *Value {
	return newValue(e, C.V8_NewObject(e.self))
}

func (o *Object) SetProperty(key string, value *Value) bool {
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&key)).Data)
	return C.V8_Object_SetProperty(
		o.self, (*C.char)(keyPtr), C.int(len(key)), value.self,
	) == 1
}

func (o *Object) GetProperty(key string) *Value {
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&key)).Data)
	return newValue(o.engine, C.V8_Object_GetProperty(
		o.self, (*C.char)(keyPtr), C.int(len(key)),
	))
}

func (o *Object) SetElement(index int, value *Value) bool {
	return C.V8_Object_SetElement(
		o.self, C.uint32_t(index), value.self,
	) == 1
}

func (o *Object) GetElement(index int) *Value {
	return newValue(o.engine, C.V8_Object_GetElement(o.self, C.uint32_t(index)))
}

func (o *Object) GetPropertyAttributes(key string) PropertyAttribute {
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&key)).Data)
	return PropertyAttribute(C.V8_Object_GetPropertyAttributes(
		o.self, (*C.char)(keyPtr), C.int(len(key)),
	))
}

func (o *Object) InternalFieldCount() int {
	return int(C.V8_Object_InternalFieldCount(o.self))
}

func (o *Object) GetInternalField(index int) interface{} {
	data := C.V8_Object_GetInternalField(o.self, C.int(index))
	if data == nil {
		return nil
	}
	return *(*interface{})(data)
}

func (o *Object) SetInternalField(index int, value interface{}) {
	C.V8_Object_SetInternalField(
		o.self,
		C.int(index),
		unsafe.Pointer(&value),
	)

	// the value reference by object so the value can't destory by GC
	o.internalFields = append(o.internalFields, value)
	o.setOwner(o)
}

func (o *Object) SetAccessor(
	key string,
	getter AccessorGetterCallback,
	setter AccessorSetterCallback,
	data interface{},
	attribs PropertyAttribute,
) {
	o.setAccessor(&accessorInfo{
		key:     key,
		getter:  getter,
		setter:  setter,
		data:    data,
		attribs: attribs,
	})
}

func (o *Object) setAccessor(info *accessorInfo) {
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&info.key)).Data)
	var getterPointer, setterPointer unsafe.Pointer
	if info.getter != nil {
		getterPointer = unsafe.Pointer(&info.getter)
	}

	if info.setter != nil {
		setterPointer = unsafe.Pointer(&info.setter)
	}

	o.accessor = info
	o.setOwner(o)

	C.V8_Object_SetAccessor(
		o.self,
		(*C.char)(keyPtr), C.int(len(info.key)),
		getterPointer,
		setterPointer,
		unsafe.Pointer(&info.data),
		C.int(info.attribs),
	)
}

// Sets a local property on this object bypassing interceptors and
// overriding accessors or read-only properties.
//
// Note that if the object has an interceptor the property will be set
// locally, but since the interceptor takes precedence the local property
// will only be returned if the interceptor doesn't return a value.
//
// Note also that this only works for named properties.
func (o *Object) ForceSetProperty(key string, value *Value, attribs PropertyAttribute) bool {
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&key)).Data)
	return C.V8_Object_ForceSetProperty(o.self,
		(*C.char)(keyPtr), C.int(len(key)), value.self, C.int(attribs),
	) == 1
}

func (o *Object) HasProperty(key string) bool {
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&key)).Data)
	return C.V8_Object_HasProperty(
		o.self, (*C.char)(keyPtr), C.int(len(key)),
	) == 1
}

func (o *Object) DeleteProperty(key string) bool {
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&key)).Data)
	return C.V8_Object_DeleteProperty(
		o.self, (*C.char)(keyPtr), C.int(len(key)),
	) == 1
}

// Delete a property on this object bypassing interceptors and
// ignoring dont-delete attributes.
func (o *Object) ForceDeleteProperty(key string) bool {
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&key)).Data)
	return C.V8_Object_ForceDeleteProperty(
		o.self, (*C.char)(keyPtr), C.int(len(key)),
	) == 1
}

func (o *Object) HasElement(index int) bool {
	return C.V8_Object_HasElement(
		o.self, C.uint32_t(index),
	) == 1
}

func (o *Object) DeleteElement(index int) bool {
	return C.V8_Object_DeleteElement(
		o.self, C.uint32_t(index),
	) == 1
}

// Returns an array containing the names of the enumerable properties
// of this object, including properties from prototype objects.  The
// array returned by this method contains the same values as would
// be enumerated by a for-in statement over this object.
//
func (o *Object) GetPropertyNames() *Array {
	return newValue(o.engine, C.V8_Object_GetPropertyNames(o.self)).ToArray()
}

// This function has the same functionality as GetPropertyNames but
// the returned array doesn't contain the names of properties from
// prototype objects.
//
func (o *Object) GetOwnPropertyNames() *Array {
	return newValue(o.engine, C.V8_Object_GetOwnPropertyNames(o.self)).ToArray()
}

// Get the prototype object.  This does not skip objects marked to
// be skipped by __proto__ and it does not consult the security
// handler.
//
func (o *Object) GetPrototype() *Object {
	return newValue(o.engine, C.V8_Object_GetPrototype(o.self)).ToObject()
}

// Set the prototype object.  This does not skip objects marked to
// be skipped by __proto__ and it does not consult the security
// handler.
//
func (o *Object) SetPrototype(proto *Object) bool {
	return C.V8_Object_SetPrototype(o.self, proto.self) == 1
}

func (o *Object) SetHiddenValue(key string, value *Value) bool{
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&key)).Data)
	return C.V8_Object_SetHiddenValue(o.self, (*C.char)(keyPtr), value.self) == 1
}

func (o *Object) DeleteHiddenValue(key string) bool{
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&key)).Data)
	return C.V8_Object_DeleteHiddenValue(o.self, (*C.char)(keyPtr)) == 1
}

func (o *Object) GetConstructorName() string{
	return newValue(o.engine, C.V8_Object_GetConstructorName(o.self)).ToString()
}

// An instance of the built-in array constructor (ECMA-262, 15.4.2).
//
type Array struct {
	*Object
}

func (e *Engine) NewArray(length int) *Value {
	return newValue(e, C.V8_NewArray(
		e.self, C.int(length),
	))
}

func (a *Array) Length() int {
	return int(C.V8_Array_Length(a.self))
}

type RegExpFlags int

// Regular expression flag bits. They can be or'ed to enable a set
// of flags.
//
const (
	RF_None       RegExpFlags = 0
	RF_Global                 = 1
	RF_IgnoreCase             = 2
	RF_Multiline              = 4
)

type RegExp struct {
	*Object
	pattern       string
	patternCached bool
	flags         RegExpFlags
	flagsCached   bool
}

// Creates a regular expression from the given pattern string and
// the flags bit field. May throw a JavaScript exception as
// described in ECMA-262, 15.10.4.1.
//
// For example,
//   NewRegExp("foo", RF_Global | RF_Multiline)
//
// is equivalent to evaluating "/foo/gm".
//
func (e *Engine) NewRegExp(pattern string, flags RegExpFlags) *Value {
	patternPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&pattern)).Data)

	return newValue(e, C.V8_NewRegExp(
		e.self, (*C.char)(patternPtr), C.int(len(pattern)), C.int(flags),
	))
}

// Returns the value of the source property: a string representing
// the regular expression.
func (r *RegExp) Pattern() string {
	if !r.patternCached {
		cstring := C.V8_RegExp_Pattern(r.self)
		r.pattern = C.GoString(cstring)
		r.patternCached = true
		C.free(unsafe.Pointer(cstring))
	}
	return r.pattern
}

// Returns the flags bit field.
//
func (r *RegExp) Flags() RegExpFlags {
	if !r.flagsCached {
		r.flags = RegExpFlags(C.V8_RegExp_Flags(r.self))
		r.flagsCached = true
	}
	return r.flags
}
<commit_msg>add functin <SetAlignedPointerInInternalField,GetAlignedPointerFromInternalField><commit_after>package v8

/*
#include "v8_wrap.h"
#include <stdlib.h>
*/
import "C"
import "unsafe"
import "reflect"

type PropertyAttribute int

const (
	PA_None       PropertyAttribute = 0
	PA_ReadOnly                     = 1 << 0
	PA_DontEnum                     = 1 << 1
	PA_DontDelete                   = 1 << 2
)

type External struct {
	*Value
	data interface{}
}

func (e *Engine) NewExternal(value interface{}) *External {
	if value == nil {
		panic("value is nil")
	}

	external := &External{
		data: value,
	}

	external.Value = newValue(e, C.V8_NewExternal(
		e.self, unsafe.Pointer(&(external.data)),
	))

	external.setOwner(external)

	return external
}

func (ex *External) GetValue() interface{} {
	if ex.data == nil {
		ptr := C.V8_External_Value(ex.self)
		ex.data = *(*interface{})(ptr)
	}

	return ex.data
}

// A JavaScript object (ECMA-262, 4.3.3)
//
type Object struct {
	*Value
	internalFields []interface{}
	accessor       *accessorInfo
}

func (e *Engine) NewObject() *Value {
	return newValue(e, C.V8_NewObject(e.self))
}

func (o *Object) SetProperty(key string, value *Value) bool {
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&key)).Data)
	return C.V8_Object_SetProperty(
		o.self, (*C.char)(keyPtr), C.int(len(key)), value.self,
	) == 1
}

func (o *Object) GetProperty(key string) *Value {
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&key)).Data)
	return newValue(o.engine, C.V8_Object_GetProperty(
		o.self, (*C.char)(keyPtr), C.int(len(key)),
	))
}

func (o *Object) SetElement(index int, value *Value) bool {
	return C.V8_Object_SetElement(
		o.self, C.uint32_t(index), value.self,
	) == 1
}

func (o *Object) GetElement(index int) *Value {
	return newValue(o.engine, C.V8_Object_GetElement(o.self, C.uint32_t(index)))
}

func (o *Object) GetPropertyAttributes(key string) PropertyAttribute {
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&key)).Data)
	return PropertyAttribute(C.V8_Object_GetPropertyAttributes(
		o.self, (*C.char)(keyPtr), C.int(len(key)),
	))
}

func (o *Object) InternalFieldCount() int {
	return int(C.V8_Object_InternalFieldCount(o.self))
}

func (o *Object) GetInternalField(index int) interface{} {
	data := C.V8_Object_GetInternalField(o.self, C.int(index))
	if data == nil {
		return nil
	}
	return *(*interface{})(data)
}

func (o *Object) SetInternalField(index int, value interface{}) {
	C.V8_Object_SetInternalField(
		o.self,
		C.int(index),
		unsafe.Pointer(&value),
	)

	// the value reference by object so the value can't destory by GC
	o.internalFields = append(o.internalFields, value)
	o.setOwner(o)
}

func (o *Object) SetAccessor(
	key string,
	getter AccessorGetterCallback,
	setter AccessorSetterCallback,
	data interface{},
	attribs PropertyAttribute,
) {
	o.setAccessor(&accessorInfo{
		key:     key,
		getter:  getter,
		setter:  setter,
		data:    data,
		attribs: attribs,
	})
}

func (o *Object) setAccessor(info *accessorInfo) {
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&info.key)).Data)
	var getterPointer, setterPointer unsafe.Pointer
	if info.getter != nil {
		getterPointer = unsafe.Pointer(&info.getter)
	}

	if info.setter != nil {
		setterPointer = unsafe.Pointer(&info.setter)
	}

	o.accessor = info
	o.setOwner(o)

	C.V8_Object_SetAccessor(
		o.self,
		(*C.char)(keyPtr), C.int(len(info.key)),
		getterPointer,
		setterPointer,
		unsafe.Pointer(&info.data),
		C.int(info.attribs),
	)
}

// Sets a local property on this object bypassing interceptors and
// overriding accessors or read-only properties.
//
// Note that if the object has an interceptor the property will be set
// locally, but since the interceptor takes precedence the local property
// will only be returned if the interceptor doesn't return a value.
//
// Note also that this only works for named properties.
func (o *Object) ForceSetProperty(key string, value *Value, attribs PropertyAttribute) bool {
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&key)).Data)
	return C.V8_Object_ForceSetProperty(o.self,
		(*C.char)(keyPtr), C.int(len(key)), value.self, C.int(attribs),
	) == 1
}

func (o *Object) HasProperty(key string) bool {
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&key)).Data)
	return C.V8_Object_HasProperty(
		o.self, (*C.char)(keyPtr), C.int(len(key)),
	) == 1
}

func (o *Object) DeleteProperty(key string) bool {
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&key)).Data)
	return C.V8_Object_DeleteProperty(
		o.self, (*C.char)(keyPtr), C.int(len(key)),
	) == 1
}

// Delete a property on this object bypassing interceptors and
// ignoring dont-delete attributes.
func (o *Object) ForceDeleteProperty(key string) bool {
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&key)).Data)
	return C.V8_Object_ForceDeleteProperty(
		o.self, (*C.char)(keyPtr), C.int(len(key)),
	) == 1
}

func (o *Object) HasElement(index int) bool {
	return C.V8_Object_HasElement(
		o.self, C.uint32_t(index),
	) == 1
}

func (o *Object) DeleteElement(index int) bool {
	return C.V8_Object_DeleteElement(
		o.self, C.uint32_t(index),
	) == 1
}

// Returns an array containing the names of the enumerable properties
// of this object, including properties from prototype objects.  The
// array returned by this method contains the same values as would
// be enumerated by a for-in statement over this object.
//
func (o *Object) GetPropertyNames() *Array {
	return newValue(o.engine, C.V8_Object_GetPropertyNames(o.self)).ToArray()
}

// This function has the same functionality as GetPropertyNames but
// the returned array doesn't contain the names of properties from
// prototype objects.
//
func (o *Object) GetOwnPropertyNames() *Array {
	return newValue(o.engine, C.V8_Object_GetOwnPropertyNames(o.self)).ToArray()
}

// Get the prototype object.  This does not skip objects marked to
// be skipped by __proto__ and it does not consult the security
// handler.
//
func (o *Object) GetPrototype() *Object {
	return newValue(o.engine, C.V8_Object_GetPrototype(o.self)).ToObject()
}

// Set the prototype object.  This does not skip objects marked to
// be skipped by __proto__ and it does not consult the security
// handler.
//
func (o *Object) SetPrototype(proto *Object) bool {
	return C.V8_Object_SetPrototype(o.self, proto.self) == 1
}

func (o *Object) SetHiddenValue(key string, value *Value) bool{
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&key)).Data)
	return C.V8_Object_SetHiddenValue(o.self, (*C.char)(keyPtr), value.self) == 1
}

func (o *Object) DeleteHiddenValue(key string) bool{
	keyPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&key)).Data)
	return C.V8_Object_DeleteHiddenValue(o.self, (*C.char)(keyPtr)) == 1
}

func (o *Object) GetConstructorName() string{
	return newValue(o.engine, C.V8_Object_GetConstructorName(o.self)).ToString()
}

func (o *Object) SetAlignedPointerInInternalField(index int, val_ptr unsafe.Pointer) {
	C.V8_Object_SetAlignedPointerInInternalField(o.self, C.int(index), val_ptr)
}

func (o *Object) GetAlignedPointerFromInternalField(index int) unsafe.Pointer{
	return C.V8_Object_GetAlignedPointerFromInternalField(o.self, C.int(index))
}
// An instance of the built-in array constructor (ECMA-262, 15.4.2).
//
type Array struct {
	*Object
}

func (e *Engine) NewArray(length int) *Value {
	return newValue(e, C.V8_NewArray(
		e.self, C.int(length),
	))
}

func (a *Array) Length() int {
	return int(C.V8_Array_Length(a.self))
}

type RegExpFlags int

// Regular expression flag bits. They can be or'ed to enable a set
// of flags.
//
const (
	RF_None       RegExpFlags = 0
	RF_Global                 = 1
	RF_IgnoreCase             = 2
	RF_Multiline              = 4
)

type RegExp struct {
	*Object
	pattern       string
	patternCached bool
	flags         RegExpFlags
	flagsCached   bool
}

// Creates a regular expression from the given pattern string and
// the flags bit field. May throw a JavaScript exception as
// described in ECMA-262, 15.10.4.1.
//
// For example,
//   NewRegExp("foo", RF_Global | RF_Multiline)
//
// is equivalent to evaluating "/foo/gm".
//
func (e *Engine) NewRegExp(pattern string, flags RegExpFlags) *Value {
	patternPtr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&pattern)).Data)

	return newValue(e, C.V8_NewRegExp(
		e.self, (*C.char)(patternPtr), C.int(len(pattern)), C.int(flags),
	))
}

// Returns the value of the source property: a string representing
// the regular expression.
func (r *RegExp) Pattern() string {
	if !r.patternCached {
		cstring := C.V8_RegExp_Pattern(r.self)
		r.pattern = C.GoString(cstring)
		r.patternCached = true
		C.free(unsafe.Pointer(cstring))
	}
	return r.pattern
}

// Returns the flags bit field.
//
func (r *RegExp) Flags() RegExpFlags {
	if !r.flagsCached {
		r.flags = RegExpFlags(C.V8_RegExp_Flags(r.self))
		r.flagsCached = true
	}
	return r.flags
}
<|endoftext|>


<commit_before>package cache

import (
	"gondola/log"
	"net/url"
)

type BackendInitializer func(*url.URL) Backend

var (
	defaultCacheUrl string
	backends        = map[string]BackendInitializer{}
	codecs          = map[string]*Codec{}
)

type Backend interface {
	Set(key string, b []byte, timeout int) error
	Get(key string) ([]byte, error)
	GetMulti(keys []string) (map[string][]byte, error)
	Delete(key string) error
	Close() error
}

type Codec struct {
	Encode func(v interface{}) ([]byte, error)
	Decode func(data []byte, v interface{}) error
}

type Cache struct {
	Prefix  string
	Backend Backend
	Codec   *Codec
}

func (c *Cache) manipulatesKeys() bool {
	return c.Prefix != ""
}

func (c *Cache) backendKey(key string) string {
	return c.Prefix + key
}

func (c *Cache) frontendKey(key string) string {
	if c.Prefix != "" {
		return key[len(c.Prefix):]
	}
	return key
}

// Set stores the given object in the cache associated with the
// given key. Timeout is the number of seconds until the item
// expires. If the timeout is 0, the item is never expired and
// might be only purged from cache when running out of space
func (c *Cache) Set(key string, object interface{}, timeout int) {
	b, err := c.Codec.Encode(&object)
	if err != nil {
		log.Errorf("Error encoding object for key %s: %s", key, err)
		return
	}
	c.SetBytes(key, b, timeout)
}

// Get returns the item assocciated with the given key
func (c *Cache) Get(key string) interface{} {
	b := c.GetBytes(key)
	if b != nil {
		var object interface{}
		err := c.Codec.Decode(b, &object)
		if err != nil {
			log.Errorf("Error decoding object for key %s: %s", key, err)
		}
		return object
	}
	return nil
}

// GetMulti returns several objects as a map[string]interface{}
// in only one roundtrip to the cache
func (c *Cache) GetMulti(keys []string) map[string]interface{} {
	if c.manipulatesKeys() {
		k := make([]string, len(keys))
		for ii, v := range keys {
			k[ii] = c.backendKey(v)
		}
		keys = k
	}
	data, err := c.Backend.GetMulti(keys)
	if err != nil {
		log.Errorf("Error querying cache for keys %v: %v", keys, err)
		return nil
	}
	objects := make(map[string]interface{}, len(data))
	if c.manipulatesKeys() {
		for k, v := range data {
			var object interface{}
			err := c.Codec.Decode(v, &object)
			if err != nil {
				log.Errorf("Error decoding object for key %s: %s", k, err)
				continue
			}
			objects[c.frontendKey(k)] = object
		}
	} else {
		for k, v := range data {
			var object interface{}
			err := c.Codec.Decode(v, &object)
			if err != nil {
				log.Errorf("Error decoding object for key %s: %s", k, err)
				continue
			}
			objects[k] = object
		}
	}
	return objects
}

// SetBytes stores the given byte array assocciated with
// the given key. See the documentation for Set for an
// explanation of the timeout parameter
func (c *Cache) SetBytes(key string, b []byte, timeout int) {
	log.Debugf("Setting key %s", c.backendKey(key))
	err := c.Backend.Set(c.backendKey(key), b, timeout)
	if err != nil {
		log.Errorf("Error setting cache key %s: %s", key, err)
	}
}

// GetBytes returns the byte array assocciated with the given key
func (c *Cache) GetBytes(key string) []byte {
	b, err := c.Backend.Get(c.backendKey(key))
	if err != nil {
		log.Errorf("Error getting cache key %s: %s", key, err)
		return nil
	}
	return b
}

func (c *Cache) Delete(key string) {
	err := c.Backend.Delete(c.backendKey(key))
	if err != nil {
		log.Errorf("Error deleting cache key %s: %s", key, err)
	}
}

func (c *Cache) Close() {
	c.Backend.Close()
}

func RegisterBackend(scheme string, f BackendInitializer) {
	backends[scheme] = f
}

func RegisterCodec(name string, codec *Codec) {
	codecs[name] = codec
}

func SetDefaultUrl(url string) {
	defaultCacheUrl = url
}

func DefaultUrl() string {
	return defaultCacheUrl
}

func New(cacheUrl string) *Cache {
	cache := &Cache{}
	var query url.Values
	u, err := url.Parse(cacheUrl)
	if err != nil {
		if err != nil && cacheUrl != "" {
			log.Errorf("Invalid cache URL '%s': %s\n", cacheUrl, err)
		}
	} else {
		query = u.Query()
	}
	var codec *Codec = nil
	if query != nil {
		codecName := query.Get("codec")
		if codecName != "" {
			if c, ok := codecs[codecName]; ok {
				codec = c
			} else {
				log.Errorf("Unknown cache codec name '%s'\n", codecName)
			}
		}
		cache.Prefix = query.Get("prefix")
	}
	if codec == nil {
		codec = &GobEncoder
	}
	cache.Codec = codec
	var backendInitializer BackendInitializer
	if u != nil {
		backendInitializer = backends[u.Scheme]
		if backendInitializer == nil {
			log.Errorf("Unknown cache backend type '%s'\n", u.Scheme)
		}
	}
	if backendInitializer == nil {
		backendInitializer = InitializeDummyBackend
	}
	cache.Backend = backendInitializer(u)
	return cache
}

func NewDefault() *Cache {
	return New(defaultCacheUrl)
}
<commit_msg>Better log messages<commit_after>package cache

import (
	"gondola/log"
	"net/url"
)

type BackendInitializer func(*url.URL) Backend

var (
	defaultCacheUrl string
	backends        = map[string]BackendInitializer{}
	codecs          = map[string]*Codec{}
)

type Backend interface {
	Set(key string, b []byte, timeout int) error
	Get(key string) ([]byte, error)
	GetMulti(keys []string) (map[string][]byte, error)
	Delete(key string) error
	Close() error
}

type Codec struct {
	Encode func(v interface{}) ([]byte, error)
	Decode func(data []byte, v interface{}) error
}

type Cache struct {
	Prefix  string
	Backend Backend
	Codec   *Codec
}

func (c *Cache) manipulatesKeys() bool {
	return c.Prefix != ""
}

func (c *Cache) backendKey(key string) string {
	return c.Prefix + key
}

func (c *Cache) frontendKey(key string) string {
	if c.Prefix != "" {
		return key[len(c.Prefix):]
	}
	return key
}

// Set stores the given object in the cache associated with the
// given key. Timeout is the number of seconds until the item
// expires. If the timeout is 0, the item is never expired and
// might be only purged from cache when running out of space
func (c *Cache) Set(key string, object interface{}, timeout int) {
	b, err := c.Codec.Encode(&object)
	if err != nil {
		log.Errorf("Error encoding object for key %s: %s", key, err)
		return
	}
	c.SetBytes(key, b, timeout)
}

// Get returns the item assocciated with the given key
func (c *Cache) Get(key string) interface{} {
	b := c.GetBytes(key)
	if b != nil {
		var object interface{}
		err := c.Codec.Decode(b, &object)
		if err != nil {
			log.Errorf("Error decoding object for key %s: %s", key, err)
		}
		return object
	}
	return nil
}

// GetMulti returns several objects as a map[string]interface{}
// in only one roundtrip to the cache
func (c *Cache) GetMulti(keys []string) map[string]interface{} {
	if c.manipulatesKeys() {
		k := make([]string, len(keys))
		for ii, v := range keys {
			k[ii] = c.backendKey(v)
		}
		keys = k
	}
	data, err := c.Backend.GetMulti(keys)
	if err != nil {
		log.Errorf("Error querying cache for keys %v: %v", keys, err)
		return nil
	}
	objects := make(map[string]interface{}, len(data))
	if c.manipulatesKeys() {
		for k, v := range data {
			var object interface{}
			err := c.Codec.Decode(v, &object)
			if err != nil {
				log.Errorf("Error decoding object for key %s: %s", k, err)
				continue
			}
			objects[c.frontendKey(k)] = object
		}
	} else {
		for k, v := range data {
			var object interface{}
			err := c.Codec.Decode(v, &object)
			if err != nil {
				log.Errorf("Error decoding object for key %s: %s", k, err)
				continue
			}
			objects[k] = object
		}
	}
	return objects
}

// SetBytes stores the given byte array assocciated with
// the given key. See the documentation for Set for an
// explanation of the timeout parameter
func (c *Cache) SetBytes(key string, b []byte, timeout int) {
	log.Debugf("Setting key %s", c.backendKey(key))
	err := c.Backend.Set(c.backendKey(key), b, timeout)
	if err != nil {
		log.Errorf("Error setting cache key %s: %s", key, err)
	}
}

// GetBytes returns the byte array assocciated with the given key
func (c *Cache) GetBytes(key string) []byte {
	b, err := c.Backend.Get(c.backendKey(key))
	if err != nil {
		log.Errorf("Error getting cache key %s: %s", key, err)
		return nil
	}
	return b
}

func (c *Cache) Delete(key string) {
	err := c.Backend.Delete(c.backendKey(key))
	if err != nil {
		log.Errorf("Error deleting cache key %s: %s", key, err)
	}
}

func (c *Cache) Close() {
	c.Backend.Close()
}

func RegisterBackend(scheme string, f BackendInitializer) {
	backends[scheme] = f
}

func RegisterCodec(name string, codec *Codec) {
	codecs[name] = codec
}

func SetDefaultUrl(url string) {
	defaultCacheUrl = url
}

func DefaultUrl() string {
	return defaultCacheUrl
}

func New(cacheUrl string) *Cache {
	cache := &Cache{}
	var query url.Values
	u, err := url.Parse(cacheUrl)
	if err != nil {
		if err != nil && cacheUrl != "" {
			log.Errorf("Invalid cache URL %q: %s\n", cacheUrl, err)
		}
	} else {
		query = u.Query()
	}
	var codec *Codec = nil
	if query != nil {
		codecName := query.Get("codec")
		if codecName != "" {
			if c, ok := codecs[codecName]; ok {
				codec = c
			} else {
				log.Errorf("Unknown cache codec name %q\n", codecName)
			}
		}
		cache.Prefix = query.Get("prefix")
	}
	if codec == nil {
		codec = &GobEncoder
	}
	cache.Codec = codec
	var backendInitializer BackendInitializer
	if u != nil {
		backendInitializer = backends[u.Scheme]
		if backendInitializer == nil && cacheUrl != "" {
			log.Errorf("Unknown cache backend type %q\n", u.Scheme)
		}
	}
	if backendInitializer == nil {
		backendInitializer = InitializeDummyBackend
	}
	cache.Backend = backendInitializer(u)
	return cache
}

func NewDefault() *Cache {
	return New(defaultCacheUrl)
}
<|endoftext|>


<commit_before>package cache

import (
	"fmt"
	"hash/fnv"
	"io/ioutil"
	"os"
)

// Hash returns the hash for an string
func Hash(input string) (hash string) {
	h := fnv.New32a()
	h.Write([]byte(input))
	return fmt.Sprint(h.Sum32())
}

// IsCached check if a hash is cached on a path
func IsCached(path string, hash string) bool {
	filename := path + "/" + hash
	if _, err := os.Stat(filename); err == nil {
		fmt.Println("Caché exists : " + filename)
		return true
	}
	fmt.Println("Not cached : " + filename)
	return false
}

// Save saves the content to the caché
func Save(path string, hash string, payload string) (err error) {
	filename := path + "/" + hash
	err = ioutil.WriteFile(filename, []byte(payload), 0644)
	if err != nil {
		return err
	}
	return nil
}

// Get gets the content from the caché
func Get(path string, hash string) (data []byte, err error) {
	filename := path + "/" + hash
	data, err = ioutil.ReadFile(filename)
	if err != nil {
		return data, err
	}
	return data, nil
}
<commit_msg>Using filepath package<commit_after>package cache

import (
	"fmt"
	"hash/fnv"
	"io/ioutil"
	"os"
	"path/filepath"
)

// Hash returns the hash for an string
func Hash(input string) (hash string) {
	h := fnv.New32a()
	h.Write([]byte(input))
	return fmt.Sprint(h.Sum32())
}

// IsCached check if a hash is cached on a path
func IsCached(path string, hash string) bool {
	filename := filepath.Join(path, hash)
	if _, err := os.Stat(filename); err == nil {
		fmt.Println("Caché exists : " + filename)
		return true
	}
	fmt.Println("Not cached : " + filename)
	return false
}

// Save saves the content to the caché
func Save(path string, hash string, payload string) (err error) {
	filename := filepath.Join(path, hash)
	err = ioutil.WriteFile(filename, []byte(payload), 0644)
	if err != nil {
		return err
	}
	return nil
}

// Get gets the content from the caché
func Get(path string, hash string) (data []byte, err error) {
	filename := filepath.Join(path, hash)
	data, err = ioutil.ReadFile(filename)
	if err != nil {
		return data, err
	}
	return data, nil
}
<|endoftext|>


<commit_before>package cache

import (
	"encoding/gob"
	"golang.org/x/net/context"
	"log"
	"time"

	"google.golang.org/appengine"
	"google.golang.org/appengine/memcache"
)

//http://www.funcmain.com/gob_encoding_an_interface
//http://stackoverflow.com/questions/13264555/store-an-object-in-memcache-of-gae-in-go

type SlowRetrieve func(ctx context.Context) (interface{}, error)

func Remember(ctx context.Context, key string, expiration time.Duration, p SlowRetrieve, disable ...bool) (interface{}, error) {

	//For debugging, you can disable cache
	if len(disable) != 0 && disable[0] == true {
		return p(ctx)
	}

	//Check if item exists
	var v interface{}
	if _, err := memcache.Gob.Get(ctx, key, &v); err == nil {
		//Item exists in cache
		if appengine.IsDevAppServer() {
			log.Println("\x1b[36mFound in Cache key:", key, "\x1b[39;49m")
		}
		return v, nil
	} else {
		if appengine.IsDevAppServer() {
			log.Println("\x1b[31mGrabbing from SlowRetrieve key:", key, err, "\x1b[39;49m")
		}
	}

	//Item does not exist in cache so grab it from the persistent store
	itemToStore, err := p(ctx)
	func(itemToStore interface{}) {
		defer func() {
			recover()
		}()
		gob.Register(itemToStore)
	}(itemToStore)
	if err != nil {
		return nil, err
	}

	//Store item in Cache
	item := &memcache.Item{
		Key:        key,
		Object:     &itemToStore,
		Expiration: expiration,
	}

	err = memcache.Gob.Set(ctx, item)
	if err != nil {
		//Memcache storage failed
		if appengine.IsDevAppServer() {
			log.Println("\x1b[31mCould not store item to memcache key:", key, err, itemToStore, "\x1b[39;49m")
		}
	}
	return itemToStore, nil
}

//Delete key from memcache
func Delete(ctx context.Context, key string) error {
	return memcache.Delete(ctx, key)
}

func DeleteMulti(ctx context.Context, keys []string) error {
	return memcache.DeleteMulti(ctx, keys)
}
<commit_msg>Added fresh parameter for caching.<commit_after>package cache

import (
	"encoding/gob"
	"golang.org/x/net/context"
	"log"
	"time"

	"google.golang.org/appengine"
	"google.golang.org/appengine/memcache"
)

//http://www.funcmain.com/gob_encoding_an_interface
//http://stackoverflow.com/questions/13264555/store-an-object-in-memcache-of-gae-in-go

type SlowRetrieve func(ctx context.Context) (interface{}, error)

//Options:
//param 1 (bool): disable caching. (Usually for debugging)
//Param 2 (bool): Obtain fresh copy. Ignore content in cache but store fresh copy in cache.
//NB: In order for Param 2 to be activated, param 1 must be false.
func Remember(ctx context.Context, key string, expiration time.Duration, p SlowRetrieve, options ...bool) (interface{}, error) {

	disableCache := false
	fresh := false

	if len(options) != 0 {
		disableCache = options[0]
		if len(options) >= 2 {
			fresh = options[1]
		}
	}

	//For debugging, you can disable cache
	if disableCache {
		return p(ctx)
	}

	var v interface{}

	if fresh {
		if appengine.IsDevAppServer() {
			log.Println("\x1b[31mGrabbing (fresh) from SlowRetrieve key:", key, "\x1b[39;49m")
		}
		goto fresh
	}

	//Check if item exists
	if _, err := memcache.Gob.Get(ctx, key, &v); err == nil {
		//Item exists in cache
		if appengine.IsDevAppServer() {
			log.Println("\x1b[36mFound in Cache key:", key, "\x1b[39;49m")
		}
		return v, nil
	} else {
		if appengine.IsDevAppServer() {
			log.Println("\x1b[31mGrabbing from SlowRetrieve key:", key, err, "\x1b[39;49m")
		}
	}

fresh:
	//Item does not exist in cache so grab it from the persistent store
	itemToStore, err := p(ctx)
	func(itemToStore interface{}) {
		defer func() {
			recover()
		}()
		gob.Register(itemToStore)
	}(itemToStore)
	if err != nil {
		return nil, err
	}

	//Store item in Cache
	item := &memcache.Item{
		Key:        key,
		Object:     &itemToStore,
		Expiration: expiration,
	}

	err = memcache.Gob.Set(ctx, item)
	if err != nil {
		//Memcache storage failed
		if appengine.IsDevAppServer() {
			log.Println("\x1b[31mCould not store item to memcache key:", key, err, itemToStore, "\x1b[39;49m")
		}
	}
	return itemToStore, nil
}

//Delete key from memcache
func Delete(ctx context.Context, key string) error {
	return memcache.Delete(ctx, key)
}

func DeleteMulti(ctx context.Context, keys []string) error {
	return memcache.DeleteMulti(ctx, keys)
}
<|endoftext|>