<commit_before>// +build !windows

package daemon

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/daemon/execdriver"
	derr "github.com/docker/docker/errors"
	"github.com/docker/docker/pkg/system"
	"github.com/docker/docker/runconfig"
	"github.com/docker/docker/volume"
	volumedrivers "github.com/docker/docker/volume/drivers"
	"github.com/docker/docker/volume/local"
	"github.com/opencontainers/runc/libcontainer/label"
)

// copyOwnership copies the permissions and uid:gid of the source file
// to the destination file
func copyOwnership(source, destination string) error {
	stat, err := system.Stat(source)
	if err != nil {
		return err
	}

	if err := os.Chown(destination, int(stat.UID()), int(stat.GID())); err != nil {
		return err
	}

	return os.Chmod(destination, os.FileMode(stat.Mode()))
}

// setupMounts iterates through each of the mount points for a container and
// calls Setup() on each. It also looks to see if is a network mount such as
// /etc/resolv.conf, and if it is not, appends it to the array of mounts.
func (container *Container) setupMounts() ([]execdriver.Mount, error) {
	var mounts []execdriver.Mount
	for _, m := range container.MountPoints {
		path, err := m.Setup()
		if err != nil {
			return nil, err
		}
		if !container.trySetNetworkMount(m.Destination, path) {
			mounts = append(mounts, execdriver.Mount{
				Source:      path,
				Destination: m.Destination,
				Writable:    m.RW,
			})
		}
	}

	mounts = sortMounts(mounts)
	netMounts := container.networkMounts()
	// if we are going to mount any of the network files from container
	// metadata, the ownership must be set properly for potential container
	// remapped root (user namespaces)
	rootUID, rootGID := container.daemon.GetRemappedUIDGID()
	for _, mount := range netMounts {
		if err := os.Chown(mount.Source, rootUID, rootGID); err != nil {
			return nil, err
		}
	}
	return append(mounts, netMounts...), nil
}

// parseBindMount validates the configuration of mount information in runconfig is valid.
func parseBindMount(spec, volumeDriver string) (*mountPoint, error) {
	bind := &mountPoint{
		RW: true,
	}
	arr := strings.Split(spec, ":")

	switch len(arr) {
	case 2:
		bind.Destination = arr[1]
	case 3:
		bind.Destination = arr[1]
		mode := arr[2]
		if !volume.ValidMountMode(mode) {
			return nil, derr.ErrorCodeVolumeInvalidMode.WithArgs(mode)
		}
		bind.RW = volume.ReadWrite(mode)
		// Mode field is used by SELinux to decide whether to apply label
		bind.Mode = mode
	default:
		return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec)
	}

	//validate the volumes destination path
	if !filepath.IsAbs(bind.Destination) {
		return nil, derr.ErrorCodeVolumeAbs.WithArgs(bind.Destination)
	}

	name, source, err := parseVolumeSource(arr[0])
	if err != nil {
		return nil, err
	}

	if len(source) == 0 {
		bind.Driver = volumeDriver
		if len(bind.Driver) == 0 {
			bind.Driver = volume.DefaultDriverName
		}
	} else {
		bind.Source = filepath.Clean(source)
	}

	bind.Name = name
	bind.Destination = filepath.Clean(bind.Destination)
	return bind, nil
}

// sortMounts sorts an array of mounts in lexicographic order. This ensure that
// when mounting, the mounts don't shadow other mounts. For example, if mounting
// /etc and /etc/resolv.conf, /etc/resolv.conf must not be mounted first.
func sortMounts(m []execdriver.Mount) []execdriver.Mount {
	sort.Sort(mounts(m))
	return m
}

type mounts []execdriver.Mount

// Len returns the number of mounts
func (m mounts) Len() int {
	return len(m)
}

// Less returns true if the number of parts (a/b/c would be 3 parts) in the
// mount indexed by parameter 1 is less than that of the mount indexed by
// parameter 2.
func (m mounts) Less(i, j int) bool {
	return m.parts(i) < m.parts(j)
}

// Swap swaps two items in an array of mounts.
func (m mounts) Swap(i, j int) {
	m[i], m[j] = m[j], m[i]
}

// parts returns the number of parts in the destination of a mount.
func (m mounts) parts(i int) int {
	return len(strings.Split(filepath.Clean(m[i].Destination), string(os.PathSeparator)))
}

// migrateVolume links the contents of a volume created pre Docker 1.7
// into the location expected by the local driver.
// It creates a symlink from DOCKER_ROOT/vfs/dir/VOLUME_ID to DOCKER_ROOT/volumes/VOLUME_ID/_container_data.
// It preserves the volume json configuration generated pre Docker 1.7 to be able to
// downgrade from Docker 1.7 to Docker 1.6 without losing volume compatibility.
func migrateVolume(id, vfs string) error {
	l, err := volumedrivers.Lookup(volume.DefaultDriverName)
	if err != nil {
		return err
	}

	newDataPath := l.(*local.Root).DataPath(id)
	fi, err := os.Stat(newDataPath)
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	if fi != nil && fi.IsDir() {
		return nil
	}

	return os.Symlink(vfs, newDataPath)
}

// validVolumeLayout checks whether the volume directory layout
// is valid to work with Docker post 1.7 or not.
func validVolumeLayout(files []os.FileInfo) bool {
	if len(files) == 1 && files[0].Name() == local.VolumeDataPathName && files[0].IsDir() {
		return true
	}

	if len(files) != 2 {
		return false
	}

	for _, f := range files {
		if f.Name() == "config.json" ||
			(f.Name() == local.VolumeDataPathName && f.Mode()&os.ModeSymlink == os.ModeSymlink) {
			// Old volume configuration, we ignore it
			continue
		}
		return false
	}

	return true
}

// verifyVolumesInfo ports volumes configured for the containers pre docker 1.7.
// It reads the container configuration and creates valid mount points for the old volumes.
func (daemon *Daemon) verifyVolumesInfo(container *Container) error {
	// Inspect old structures only when we're upgrading from old versions
	// to versions >= 1.7 and the MountPoints has not been populated with volumes data.
	if len(container.MountPoints) == 0 && len(container.Volumes) > 0 {
		for destination, hostPath := range container.Volumes {
			vfsPath := filepath.Join(daemon.root, "vfs", "dir")
			rw := container.VolumesRW != nil && container.VolumesRW[destination]

			if strings.HasPrefix(hostPath, vfsPath) {
				id := filepath.Base(hostPath)
				if err := migrateVolume(id, hostPath); err != nil {
					return err
				}
				container.addLocalMountPoint(id, destination, rw)
			} else { // Bind mount
				id, source, err := parseVolumeSource(hostPath)
				// We should not find an error here coming
				// from the old configuration, but who knows.
				if err != nil {
					return err
				}
				container.addBindMountPoint(id, source, destination, rw)
			}
		}
	} else if len(container.MountPoints) > 0 {
		// Volumes created with a Docker version >= 1.7. We verify integrity in case of data created
		// with Docker 1.7 RC versions that put the information in
		// DOCKER_ROOT/volumes/VOLUME_ID rather than DOCKER_ROOT/volumes/VOLUME_ID/_container_data.
		l, err := volumedrivers.Lookup(volume.DefaultDriverName)
		if err != nil {
			return err
		}

		for _, m := range container.MountPoints {
			if m.Driver != volume.DefaultDriverName {
				continue
			}
			dataPath := l.(*local.Root).DataPath(m.Name)
			volumePath := filepath.Dir(dataPath)

			d, err := ioutil.ReadDir(volumePath)
			if err != nil {
				// If the volume directory doesn't exist yet it will be recreated,
				// so we only return the error when there is a different issue.
				if !os.IsNotExist(err) {
					return err
				}
				// Do not check when the volume directory does not exist.
				continue
			}
			if validVolumeLayout(d) {
				continue
			}

			if err := os.Mkdir(dataPath, 0755); err != nil {
				return err
			}

			// Move data inside the data directory
			for _, f := range d {
				oldp := filepath.Join(volumePath, f.Name())
				newp := filepath.Join(dataPath, f.Name())
				if err := os.Rename(oldp, newp); err != nil {
					logrus.Errorf("Unable to move %s to %s\n", oldp, newp)
				}
			}
		}

		return container.toDiskLocking()
	}

	return nil
}

// parseVolumesFrom ensure that the supplied volumes-from is valid.
func parseVolumesFrom(spec string) (string, string, error) {
	if len(spec) == 0 {
		return "", "", derr.ErrorCodeVolumeFromBlank.WithArgs(spec)
	}

	specParts := strings.SplitN(spec, ":", 2)
	id := specParts[0]
	mode := "rw"

	if len(specParts) == 2 {
		mode = specParts[1]
		if !volume.ValidMountMode(mode) {
			return "", "", derr.ErrorCodeVolumeMode.WithArgs(mode)
		}
	}
	return id, mode, nil
}

// registerMountPoints initializes the container mount points with the configured volumes and bind mounts.
// It follows the next sequence to decide what to mount in each final destination:
//
// 1. Select the previously configured mount points for the containers, if any.
// 2. Select the volumes mounted from another containers. Overrides previously configured mount point destination.
// 3. Select the bind mounts set by the client. Overrides previously configured mount point destinations.
func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runconfig.HostConfig) error {
	binds := map[string]bool{}
	mountPoints := map[string]*mountPoint{}

	// 1. Read already configured mount points.
	for name, point := range container.MountPoints {
		mountPoints[name] = point
	}

	// 2. Read volumes from other containers.
	for _, v := range hostConfig.VolumesFrom {
		containerID, mode, err := parseVolumesFrom(v)
		if err != nil {
			return err
		}

		c, err := daemon.Get(containerID)
		if err != nil {
			return err
		}

		for _, m := range c.MountPoints {
			cp := &mountPoint{
				Name:        m.Name,
				Source:      m.Source,
				RW:          m.RW && volume.ReadWrite(mode),
				Driver:      m.Driver,
				Destination: m.Destination,
			}

			if len(cp.Source) == 0 {
				v, err := daemon.createVolume(cp.Name, cp.Driver, nil)
				if err != nil {
					return err
				}
				cp.Volume = v
			}

			mountPoints[cp.Destination] = cp
		}
	}

	// 3. Read bind mounts
	for _, b := range hostConfig.Binds {
		// #10618
		bind, err := parseBindMount(b, hostConfig.VolumeDriver)
		if err != nil {
			return err
		}

		if binds[bind.Destination] {
			return derr.ErrorCodeVolumeDup.WithArgs(bind.Destination)
		}

		if len(bind.Name) > 0 && len(bind.Driver) > 0 {
			// create the volume
			v, err := daemon.createVolume(bind.Name, bind.Driver, nil)
			if err != nil {
				return err
			}
			bind.Volume = v
			bind.Source = v.Path()
			// bind.Name is an already existing volume, we need to use that here
			bind.Driver = v.DriverName()
			// Since this is just a named volume and not a typical bind, set to shared mode `z`
			if bind.Mode == "" {
				bind.Mode = "z"
			}
		}

		shared := label.IsShared(bind.Mode)
		if err := label.Relabel(bind.Source, container.MountLabel, shared); err != nil {
			return err
		}
		binds[bind.Destination] = true
		mountPoints[bind.Destination] = bind
	}

	// Keep backwards compatible structures
	bcVolumes := map[string]string{}
	bcVolumesRW := map[string]bool{}
	for _, m := range mountPoints {
		if m.BackwardsCompatible() {
			bcVolumes[m.Destination] = m.Path()
			bcVolumesRW[m.Destination] = m.RW

			// This mountpoint is replacing an existing one, so the count needs to be decremented
			if mp, exists := container.MountPoints[m.Destination]; exists && mp.Volume != nil {
				daemon.volumes.Decrement(mp.Volume)
			}
		}
	}

	container.Lock()
	container.MountPoints = mountPoints
	container.Volumes = bcVolumes
	container.VolumesRW = bcVolumesRW
	container.Unlock()

	return nil
}

// createVolume creates a volume.
func (daemon *Daemon) createVolume(name, driverName string, opts map[string]string) (volume.Volume, error) {
	v, err := daemon.volumes.Create(name, driverName, opts)
	if err != nil {
		return nil, err
	}
	daemon.volumes.Increment(v)
	return v, nil
}

// parseVolumeSource parses the origin sources that's mounted into the container.
func parseVolumeSource(spec string) (string, string, error) {
	if !filepath.IsAbs(spec) {
		return spec, "", nil
	}

	return "", spec, nil
}

// BackwardsCompatible decides whether this mount point can be
// used in old versions of Docker or not.
// Only bind mounts and local volumes can be used in old versions of Docker.
func (m *mountPoint) BackwardsCompatible() bool {
	return len(m.Source) > 0 || m.Driver == volume.DefaultDriverName
}
<commit_msg>Fix relabel for SELinux<commit_after>// +build !windows

package daemon

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/daemon/execdriver"
	derr "github.com/docker/docker/errors"
	"github.com/docker/docker/pkg/system"
	"github.com/docker/docker/runconfig"
	"github.com/docker/docker/volume"
	volumedrivers "github.com/docker/docker/volume/drivers"
	"github.com/docker/docker/volume/local"
	"github.com/opencontainers/runc/libcontainer/label"
)

// copyOwnership copies the permissions and uid:gid of the source file
// to the destination file
func copyOwnership(source, destination string) error {
	stat, err := system.Stat(source)
	if err != nil {
		return err
	}

	if err := os.Chown(destination, int(stat.UID()), int(stat.GID())); err != nil {
		return err
	}

	return os.Chmod(destination, os.FileMode(stat.Mode()))
}

// setupMounts iterates through each of the mount points for a container and
// calls Setup() on each. It also looks to see if is a network mount such as
// /etc/resolv.conf, and if it is not, appends it to the array of mounts.
func (container *Container) setupMounts() ([]execdriver.Mount, error) {
	var mounts []execdriver.Mount
	for _, m := range container.MountPoints {
		path, err := m.Setup()
		if err != nil {
			return nil, err
		}
		if !container.trySetNetworkMount(m.Destination, path) {
			mounts = append(mounts, execdriver.Mount{
				Source:      path,
				Destination: m.Destination,
				Writable:    m.RW,
			})
		}
	}

	mounts = sortMounts(mounts)
	netMounts := container.networkMounts()
	// if we are going to mount any of the network files from container
	// metadata, the ownership must be set properly for potential container
	// remapped root (user namespaces)
	rootUID, rootGID := container.daemon.GetRemappedUIDGID()
	for _, mount := range netMounts {
		if err := os.Chown(mount.Source, rootUID, rootGID); err != nil {
			return nil, err
		}
	}
	return append(mounts, netMounts...), nil
}

// parseBindMount validates the configuration of mount information in runconfig is valid.
func parseBindMount(spec, volumeDriver string) (*mountPoint, error) {
	bind := &mountPoint{
		RW: true,
	}
	arr := strings.Split(spec, ":")

	switch len(arr) {
	case 2:
		bind.Destination = arr[1]
	case 3:
		bind.Destination = arr[1]
		mode := arr[2]
		if !volume.ValidMountMode(mode) {
			return nil, derr.ErrorCodeVolumeInvalidMode.WithArgs(mode)
		}
		bind.RW = volume.ReadWrite(mode)
		// Mode field is used by SELinux to decide whether to apply label
		bind.Mode = mode
	default:
		return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec)
	}

	//validate the volumes destination path
	if !filepath.IsAbs(bind.Destination) {
		return nil, derr.ErrorCodeVolumeAbs.WithArgs(bind.Destination)
	}

	name, source, err := parseVolumeSource(arr[0])
	if err != nil {
		return nil, err
	}

	if len(source) == 0 {
		bind.Driver = volumeDriver
		if len(bind.Driver) == 0 {
			bind.Driver = volume.DefaultDriverName
		}
	} else {
		bind.Source = filepath.Clean(source)
	}

	bind.Name = name
	bind.Destination = filepath.Clean(bind.Destination)
	return bind, nil
}

// sortMounts sorts an array of mounts in lexicographic order. This ensure that
// when mounting, the mounts don't shadow other mounts. For example, if mounting
// /etc and /etc/resolv.conf, /etc/resolv.conf must not be mounted first.
func sortMounts(m []execdriver.Mount) []execdriver.Mount {
	sort.Sort(mounts(m))
	return m
}

type mounts []execdriver.Mount

// Len returns the number of mounts
func (m mounts) Len() int {
	return len(m)
}

// Less returns true if the number of parts (a/b/c would be 3 parts) in the
// mount indexed by parameter 1 is less than that of the mount indexed by
// parameter 2.
func (m mounts) Less(i, j int) bool {
	return m.parts(i) < m.parts(j)
}

// Swap swaps two items in an array of mounts.
func (m mounts) Swap(i, j int) {
	m[i], m[j] = m[j], m[i]
}

// parts returns the number of parts in the destination of a mount.
func (m mounts) parts(i int) int {
	return len(strings.Split(filepath.Clean(m[i].Destination), string(os.PathSeparator)))
}

// migrateVolume links the contents of a volume created pre Docker 1.7
// into the location expected by the local driver.
// It creates a symlink from DOCKER_ROOT/vfs/dir/VOLUME_ID to DOCKER_ROOT/volumes/VOLUME_ID/_container_data.
// It preserves the volume json configuration generated pre Docker 1.7 to be able to
// downgrade from Docker 1.7 to Docker 1.6 without losing volume compatibility.
func migrateVolume(id, vfs string) error {
	l, err := volumedrivers.Lookup(volume.DefaultDriverName)
	if err != nil {
		return err
	}

	newDataPath := l.(*local.Root).DataPath(id)
	fi, err := os.Stat(newDataPath)
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	if fi != nil && fi.IsDir() {
		return nil
	}

	return os.Symlink(vfs, newDataPath)
}

// validVolumeLayout checks whether the volume directory layout
// is valid to work with Docker post 1.7 or not.
func validVolumeLayout(files []os.FileInfo) bool {
	if len(files) == 1 && files[0].Name() == local.VolumeDataPathName && files[0].IsDir() {
		return true
	}

	if len(files) != 2 {
		return false
	}

	for _, f := range files {
		if f.Name() == "config.json" ||
			(f.Name() == local.VolumeDataPathName && f.Mode()&os.ModeSymlink == os.ModeSymlink) {
			// Old volume configuration, we ignore it
			continue
		}
		return false
	}

	return true
}

// verifyVolumesInfo ports volumes configured for the containers pre docker 1.7.
// It reads the container configuration and creates valid mount points for the old volumes.
func (daemon *Daemon) verifyVolumesInfo(container *Container) error {
	// Inspect old structures only when we're upgrading from old versions
	// to versions >= 1.7 and the MountPoints has not been populated with volumes data.
	if len(container.MountPoints) == 0 && len(container.Volumes) > 0 {
		for destination, hostPath := range container.Volumes {
			vfsPath := filepath.Join(daemon.root, "vfs", "dir")
			rw := container.VolumesRW != nil && container.VolumesRW[destination]

			if strings.HasPrefix(hostPath, vfsPath) {
				id := filepath.Base(hostPath)
				if err := migrateVolume(id, hostPath); err != nil {
					return err
				}
				container.addLocalMountPoint(id, destination, rw)
			} else { // Bind mount
				id, source, err := parseVolumeSource(hostPath)
				// We should not find an error here coming
				// from the old configuration, but who knows.
				if err != nil {
					return err
				}
				container.addBindMountPoint(id, source, destination, rw)
			}
		}
	} else if len(container.MountPoints) > 0 {
		// Volumes created with a Docker version >= 1.7. We verify integrity in case of data created
		// with Docker 1.7 RC versions that put the information in
		// DOCKER_ROOT/volumes/VOLUME_ID rather than DOCKER_ROOT/volumes/VOLUME_ID/_container_data.
		l, err := volumedrivers.Lookup(volume.DefaultDriverName)
		if err != nil {
			return err
		}

		for _, m := range container.MountPoints {
			if m.Driver != volume.DefaultDriverName {
				continue
			}
			dataPath := l.(*local.Root).DataPath(m.Name)
			volumePath := filepath.Dir(dataPath)

			d, err := ioutil.ReadDir(volumePath)
			if err != nil {
				// If the volume directory doesn't exist yet it will be recreated,
				// so we only return the error when there is a different issue.
				if !os.IsNotExist(err) {
					return err
				}
				// Do not check when the volume directory does not exist.
				continue
			}
			if validVolumeLayout(d) {
				continue
			}

			if err := os.Mkdir(dataPath, 0755); err != nil {
				return err
			}

			// Move data inside the data directory
			for _, f := range d {
				oldp := filepath.Join(volumePath, f.Name())
				newp := filepath.Join(dataPath, f.Name())
				if err := os.Rename(oldp, newp); err != nil {
					logrus.Errorf("Unable to move %s to %s\n", oldp, newp)
				}
			}
		}

		return container.toDiskLocking()
	}

	return nil
}

// parseVolumesFrom ensure that the supplied volumes-from is valid.
func parseVolumesFrom(spec string) (string, string, error) {
	if len(spec) == 0 {
		return "", "", derr.ErrorCodeVolumeFromBlank.WithArgs(spec)
	}

	specParts := strings.SplitN(spec, ":", 2)
	id := specParts[0]
	mode := "rw"

	if len(specParts) == 2 {
		mode = specParts[1]
		if !volume.ValidMountMode(mode) {
			return "", "", derr.ErrorCodeVolumeMode.WithArgs(mode)
		}
	}
	return id, mode, nil
}

// registerMountPoints initializes the container mount points with the configured volumes and bind mounts.
// It follows the next sequence to decide what to mount in each final destination:
//
// 1. Select the previously configured mount points for the containers, if any.
// 2. Select the volumes mounted from another containers. Overrides previously configured mount point destination.
// 3. Select the bind mounts set by the client. Overrides previously configured mount point destinations.
func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runconfig.HostConfig) error {
	binds := map[string]bool{}
	mountPoints := map[string]*mountPoint{}

	// 1. Read already configured mount points.
	for name, point := range container.MountPoints {
		mountPoints[name] = point
	}

	// 2. Read volumes from other containers.
	for _, v := range hostConfig.VolumesFrom {
		containerID, mode, err := parseVolumesFrom(v)
		if err != nil {
			return err
		}

		c, err := daemon.Get(containerID)
		if err != nil {
			return err
		}

		for _, m := range c.MountPoints {
			cp := &mountPoint{
				Name:        m.Name,
				Source:      m.Source,
				RW:          m.RW && volume.ReadWrite(mode),
				Driver:      m.Driver,
				Destination: m.Destination,
			}

			if len(cp.Source) == 0 {
				v, err := daemon.createVolume(cp.Name, cp.Driver, nil)
				if err != nil {
					return err
				}
				cp.Volume = v
			}

			mountPoints[cp.Destination] = cp
		}
	}

	// 3. Read bind mounts
	for _, b := range hostConfig.Binds {
		// #10618
		bind, err := parseBindMount(b, hostConfig.VolumeDriver)
		if err != nil {
			return err
		}

		if binds[bind.Destination] {
			return derr.ErrorCodeVolumeDup.WithArgs(bind.Destination)
		}

		if len(bind.Name) > 0 && len(bind.Driver) > 0 {
			// create the volume
			v, err := daemon.createVolume(bind.Name, bind.Driver, nil)
			if err != nil {
				return err
			}
			bind.Volume = v
			bind.Source = v.Path()
			// bind.Name is an already existing volume, we need to use that here
			bind.Driver = v.DriverName()
			// Since this is just a named volume and not a typical bind, set to shared mode `z`
			if bind.Mode == "" {
				bind.Mode = "z"
			}
		}

		if label.RelabelNeeded(bind.Mode) {
			if err := label.Relabel(bind.Source, container.MountLabel, label.IsShared(bind.Mode)); err != nil {
				return err
			}
		}
		binds[bind.Destination] = true
		mountPoints[bind.Destination] = bind
	}

	// Keep backwards compatible structures
	bcVolumes := map[string]string{}
	bcVolumesRW := map[string]bool{}
	for _, m := range mountPoints {
		if m.BackwardsCompatible() {
			bcVolumes[m.Destination] = m.Path()
			bcVolumesRW[m.Destination] = m.RW

			// This mountpoint is replacing an existing one, so the count needs to be decremented
			if mp, exists := container.MountPoints[m.Destination]; exists && mp.Volume != nil {
				daemon.volumes.Decrement(mp.Volume)
			}
		}
	}

	container.Lock()
	container.MountPoints = mountPoints
	container.Volumes = bcVolumes
	container.VolumesRW = bcVolumesRW
	container.Unlock()

	return nil
}

// createVolume creates a volume.
func (daemon *Daemon) createVolume(name, driverName string, opts map[string]string) (volume.Volume, error) {
	v, err := daemon.volumes.Create(name, driverName, opts)
	if err != nil {
		return nil, err
	}
	daemon.volumes.Increment(v)
	return v, nil
}

// parseVolumeSource parses the origin sources that's mounted into the container.
func parseVolumeSource(spec string) (string, string, error) {
	if !filepath.IsAbs(spec) {
		return spec, "", nil
	}

	return "", spec, nil
}

// BackwardsCompatible decides whether this mount point can be
// used in old versions of Docker or not.
// Only bind mounts and local volumes can be used in old versions of Docker.
func (m *mountPoint) BackwardsCompatible() bool {
	return len(m.Source) > 0 || m.Driver == volume.DefaultDriverName
}
<|endoftext|>


<commit_before>// +build !windows

package metrics

import (
	"regexp"
	"strings"

	"github.com/mackerelio/mackerel-agent/util"
)

// FilesystemGenerator is common filesystem metrics generator on unix os.
type FilesystemGenerator struct {
	IgnoreRegexp *regexp.Regexp
}

var sanitizerReg = regexp.MustCompile(`[^A-Za-z0-9_-]`)

// Generate the metrics of filesystems
func (g *FilesystemGenerator) Generate() (Values, error) {
	filesystems, err := util.CollectDfValues()
	if err != nil {
		return nil, err
	}
	ret := Values{}
	for _, dfs := range filesystems {
		name := dfs.Name
		// https://github.com/docker/docker/blob/v1.5.0/daemon/graphdriver/devmapper/deviceset.go#L981
		if strings.HasPrefix(name, "/dev/mapper/docker-") ||
			(g.IgnoreRegexp != nil && g.IgnoreRegexp.MatchString(name)) {
			continue
		}
		if device := strings.TrimPrefix(name, "/dev/"); name != device {
			device = sanitizerReg.ReplaceAllString(device, "_")
			// kilo bytes -> bytes
			ret["filesystem."+device+".size"] = float64(dfs.Blocks) * 1024
			ret["filesystem."+device+".used"] = float64(dfs.Used) * 1024
		}
	}
	return ret, nil
}
<commit_msg>[incompatible] consider df used + available size of filesystem<commit_after>// +build !windows

package metrics

import (
	"regexp"
	"strings"

	"github.com/mackerelio/mackerel-agent/util"
)

// FilesystemGenerator is common filesystem metrics generator on unix os.
type FilesystemGenerator struct {
	IgnoreRegexp *regexp.Regexp
}

var sanitizerReg = regexp.MustCompile(`[^A-Za-z0-9_-]`)

// Generate the metrics of filesystems
func (g *FilesystemGenerator) Generate() (Values, error) {
	filesystems, err := util.CollectDfValues()
	if err != nil {
		return nil, err
	}
	ret := Values{}
	for _, dfs := range filesystems {
		name := dfs.Name
		// https://github.com/docker/docker/blob/v1.5.0/daemon/graphdriver/devmapper/deviceset.go#L981
		if strings.HasPrefix(name, "/dev/mapper/docker-") ||
			(g.IgnoreRegexp != nil && g.IgnoreRegexp.MatchString(name)) {
			continue
		}
		if device := strings.TrimPrefix(name, "/dev/"); name != device {
			device = sanitizerReg.ReplaceAllString(device, "_")
			// kilo bytes -> bytes
			ret["filesystem."+device+".size"] = float64(dfs.Used+dfs.Available) * 1024
			ret["filesystem."+device+".used"] = float64(dfs.Used) * 1024
		}
	}
	return ret, nil
}
<|endoftext|>


<commit_before>// Package jwt implements a Hook that fails an Announce if the client's request
// is missing a valid JSON Web Token.
//
// JWTs are validated against the standard claims in RFC7519 along with an
// extra "infohash" claim that verifies the client has access to the Swarm.
// RS256 keys are asychronously rotated from a provided JWK Set HTTP endpoint.
package jwt

import (
	"context"
	"crypto"
	"encoding/json"
	"errors"
	"net/http"
	"net/url"
	"time"

	jc "github.com/SermoDigital/jose/crypto"
	"github.com/SermoDigital/jose/jws"
	"github.com/SermoDigital/jose/jwt"
	log "github.com/Sirupsen/logrus"
	"github.com/mendsley/gojwk"

	"github.com/chihaya/chihaya/bittorrent"
	"github.com/chihaya/chihaya/middleware"
	"github.com/chihaya/chihaya/pkg/stop"
)

var (
	// ErrMissingJWT is returned when a JWT is missing from a request.
	ErrMissingJWT = bittorrent.ClientError("unapproved request: missing jwt")

	// ErrInvalidJWT is returned when a JWT fails to verify.
	ErrInvalidJWT = bittorrent.ClientError("unapproved request: invalid jwt")
)

// Config represents all the values required by this middleware to fetch JWKs
// and verify JWTs.
type Config struct {
	Issuer            string        `yaml:"issuer"`
	Audience          string        `yaml:"audience"`
	JWKSetURL         string        `yaml:"jwk_set_url"`
	JWKUpdateInterval time.Duration `yaml:"jwk_set_update_interval"`
}

type hook struct {
	cfg        Config
	publicKeys map[string]crypto.PublicKey
	closing    chan struct{}
}

// NewHook returns an instance of the JWT middleware.
func NewHook(cfg Config) (middleware.Hook, error) {
	log.Debugf("creating new JWT middleware with config: %#v", cfg)
	h := &hook{
		cfg:        cfg,
		publicKeys: map[string]crypto.PublicKey{},
		closing:    make(chan struct{}),
	}

	log.Debug("performing initial fetch of JWKs")
	err := h.updateKeys()
	if err != nil {
		return nil, errors.New("failed to fetch initial JWK Set: " + err.Error())
	}

	go func() {
		for {
			select {
			case <-h.closing:
				return
			case <-time.After(cfg.JWKUpdateInterval):
				log.Debug("performing fetch of JWKs")
				h.updateKeys()
			}
		}
	}()

	return h, nil
}

func (h *hook) updateKeys() error {
	resp, err := http.Get(h.cfg.JWKSetURL)
	if err != nil {
		log.Errorln("failed to fetch JWK Set: " + err.Error())
		return err
	}

	var parsedJWKs gojwk.Key
	err = json.NewDecoder(resp.Body).Decode(&parsedJWKs)
	if err != nil {
		resp.Body.Close()
		log.Errorln("failed to decode JWK JSON: " + err.Error())
		return err
	}
	resp.Body.Close()

	keys := map[string]crypto.PublicKey{}
	for _, parsedJWK := range parsedJWKs.Keys {
		publicKey, err := parsedJWK.DecodePublicKey()
		if err != nil {
			log.Errorln("failed to decode JWK into public key: " + err.Error())
			return err
		}
		keys[parsedJWK.Kid] = publicKey
	}
	h.publicKeys = keys

	log.Debug("successfully fetched JWK Set")
	return nil
}

func (h *hook) Stop() <-chan error {
	log.Debug("attempting to shutdown JWT middleware")
	select {
	case <-h.closing:
		return stop.AlreadyStopped
	default:
	}
	c := make(chan error)
	go func() {
		close(h.closing)
		close(c)
	}()
	return c
}

func (h *hook) HandleAnnounce(ctx context.Context, req *bittorrent.AnnounceRequest, resp *bittorrent.AnnounceResponse) (context.Context, error) {
	if req.Params == nil {
		return ctx, ErrMissingJWT
	}

	jwtParam, ok := req.Params.String("jwt")
	if !ok {
		return ctx, ErrMissingJWT
	}

	if err := validateJWT(req.InfoHash, []byte(jwtParam), h.cfg.Issuer, h.cfg.Audience, h.publicKeys); err != nil {
		return ctx, ErrInvalidJWT
	}

	return ctx, nil
}

func (h *hook) HandleScrape(ctx context.Context, req *bittorrent.ScrapeRequest, resp *bittorrent.ScrapeResponse) (context.Context, error) {
	// Scrapes don't require any protection.
	return ctx, nil
}

func validateJWT(ih bittorrent.InfoHash, jwtBytes []byte, cfgIss, cfgAud string, publicKeys map[string]crypto.PublicKey) error {
	parsedJWT, err := jws.ParseJWT(jwtBytes)
	if err != nil {
		return err
	}

	claims := parsedJWT.Claims()
	if iss, ok := claims.Issuer(); !ok || iss != cfgIss {
		return jwt.ErrInvalidISSClaim
	}

	if aud, ok := claims.Audience(); !ok || !validAudience(aud, cfgAud) {
		return jwt.ErrInvalidAUDClaim
	}

	if ihClaim, ok := claims.Get("infohash").(string); !ok || !validInfoHash(ihClaim, ih) {
		return errors.New("claim \"infohash\" is invalid")
	}

	parsedJWS := parsedJWT.(jws.JWS)
	kid, ok := parsedJWS.Protected().Get("kid").(string)
	if !ok {
		return errors.New("invalid kid")
	}
	publicKey, ok := publicKeys[kid]
	if !ok {
		return errors.New("signed by unknown kid")
	}

	return parsedJWS.Verify(publicKey, jc.SigningMethodRS256)
}

func validAudience(aud []string, cfgAud string) bool {
	for _, a := range aud {
		if a == cfgAud {
			return true
		}
	}
	return false
}

func validInfoHash(claim string, ih bittorrent.InfoHash) bool {
	if len(claim) == 20 && bittorrent.InfoHashFromString(claim) == ih {
		return true
	}

	unescapedClaim, err := url.QueryUnescape(claim)
	if err != nil {
		return false
	}

	if len(unescapedClaim) == 20 && bittorrent.InfoHashFromString(unescapedClaim) == ih {
		return true
	}

	return false
}
<commit_msg>middleware/jwt: add debug logs for JWT failures<commit_after>// Package jwt implements a Hook that fails an Announce if the client's request
// is missing a valid JSON Web Token.
//
// JWTs are validated against the standard claims in RFC7519 along with an
// extra "infohash" claim that verifies the client has access to the Swarm.
// RS256 keys are asychronously rotated from a provided JWK Set HTTP endpoint.
package jwt

import (
	"context"
	"crypto"
	"encoding/json"
	"errors"
	"net/http"
	"net/url"
	"time"

	jc "github.com/SermoDigital/jose/crypto"
	"github.com/SermoDigital/jose/jws"
	"github.com/SermoDigital/jose/jwt"
	log "github.com/Sirupsen/logrus"
	"github.com/mendsley/gojwk"

	"github.com/chihaya/chihaya/bittorrent"
	"github.com/chihaya/chihaya/middleware"
	"github.com/chihaya/chihaya/pkg/stop"
)

var (
	// ErrMissingJWT is returned when a JWT is missing from a request.
	ErrMissingJWT = bittorrent.ClientError("unapproved request: missing jwt")

	// ErrInvalidJWT is returned when a JWT fails to verify.
	ErrInvalidJWT = bittorrent.ClientError("unapproved request: invalid jwt")
)

// Config represents all the values required by this middleware to fetch JWKs
// and verify JWTs.
type Config struct {
	Issuer            string        `yaml:"issuer"`
	Audience          string        `yaml:"audience"`
	JWKSetURL         string        `yaml:"jwk_set_url"`
	JWKUpdateInterval time.Duration `yaml:"jwk_set_update_interval"`
}

type hook struct {
	cfg        Config
	publicKeys map[string]crypto.PublicKey
	closing    chan struct{}
}

// NewHook returns an instance of the JWT middleware.
func NewHook(cfg Config) (middleware.Hook, error) {
	log.Debugf("creating new JWT middleware with config: %#v", cfg)
	h := &hook{
		cfg:        cfg,
		publicKeys: map[string]crypto.PublicKey{},
		closing:    make(chan struct{}),
	}

	log.Debug("performing initial fetch of JWKs")
	err := h.updateKeys()
	if err != nil {
		return nil, errors.New("failed to fetch initial JWK Set: " + err.Error())
	}

	go func() {
		for {
			select {
			case <-h.closing:
				return
			case <-time.After(cfg.JWKUpdateInterval):
				log.Debug("performing fetch of JWKs")
				h.updateKeys()
			}
		}
	}()

	return h, nil
}

func (h *hook) updateKeys() error {
	resp, err := http.Get(h.cfg.JWKSetURL)
	if err != nil {
		log.Errorln("failed to fetch JWK Set: " + err.Error())
		return err
	}

	var parsedJWKs gojwk.Key
	err = json.NewDecoder(resp.Body).Decode(&parsedJWKs)
	if err != nil {
		resp.Body.Close()
		log.Errorln("failed to decode JWK JSON: " + err.Error())
		return err
	}
	resp.Body.Close()

	keys := map[string]crypto.PublicKey{}
	for _, parsedJWK := range parsedJWKs.Keys {
		publicKey, err := parsedJWK.DecodePublicKey()
		if err != nil {
			log.Errorln("failed to decode JWK into public key: " + err.Error())
			return err
		}
		keys[parsedJWK.Kid] = publicKey
	}
	h.publicKeys = keys

	log.Debug("successfully fetched JWK Set")
	return nil
}

func (h *hook) Stop() <-chan error {
	log.Debug("attempting to shutdown JWT middleware")
	select {
	case <-h.closing:
		return stop.AlreadyStopped
	default:
	}
	c := make(chan error)
	go func() {
		close(h.closing)
		close(c)
	}()
	return c
}

func (h *hook) HandleAnnounce(ctx context.Context, req *bittorrent.AnnounceRequest, resp *bittorrent.AnnounceResponse) (context.Context, error) {
	if req.Params == nil {
		return ctx, ErrMissingJWT
	}

	jwtParam, ok := req.Params.String("jwt")
	if !ok {
		return ctx, ErrMissingJWT
	}

	if err := validateJWT(req.InfoHash, []byte(jwtParam), h.cfg.Issuer, h.cfg.Audience, h.publicKeys); err != nil {
		return ctx, ErrInvalidJWT
	}

	return ctx, nil
}

func (h *hook) HandleScrape(ctx context.Context, req *bittorrent.ScrapeRequest, resp *bittorrent.ScrapeResponse) (context.Context, error) {
	// Scrapes don't require any protection.
	return ctx, nil
}

func validateJWT(ih bittorrent.InfoHash, jwtBytes []byte, cfgIss, cfgAud string, publicKeys map[string]crypto.PublicKey) error {
	parsedJWT, err := jws.ParseJWT(jwtBytes)
	if err != nil {
		return err
	}

	claims := parsedJWT.Claims()
	if iss, ok := claims.Issuer(); !ok || iss != cfgIss {
		log.WithFields(log.Fields{
			"exists": ok,
			"claim":  iss,
			"config": cfgIss,
		}).Debugln("unequal or missing issuer when validating JWT")
		return jwt.ErrInvalidISSClaim
	}

	if aud, ok := claims.Audience(); !ok || !validAudience(aud, cfgAud) {
		log.WithFields(log.Fields{
			"exists": ok,
			"claim":  aud,
			"config": cfgAud,
		}).Debugln("unequal or missing audience when validating JWT")
		return jwt.ErrInvalidAUDClaim
	}

	if ihClaim, ok := claims.Get("infohash").(string); !ok || !validInfoHash(ihClaim, ih) {
		log.WithFields(log.Fields{
			"exists":  ok,
			"request": ih,
			"claim":   ihClaim,
		}).Debugln("unequal or missing infohash when validating JWT")
		return errors.New("claim \"infohash\" is invalid")
	}

	parsedJWS := parsedJWT.(jws.JWS)
	kid, ok := parsedJWS.Protected().Get("kid").(string)
	if !ok {
		log.WithFields(log.Fields{
			"exists": ok,
			"claim":  kid,
		}).Debugln("missing kid when validating JWT")
		return errors.New("invalid kid")
	}
	publicKey, ok := publicKeys[kid]
	if !ok {
		log.WithFields(log.Fields{
			"kid": kid,
		}).Debugln("missing public key for kid when validating JWT")
		return errors.New("signed by unknown kid")
	}

	err = parsedJWS.Verify(publicKey, jc.SigningMethodRS256)
	if err != nil {
		log.WithFields(log.Fields{
			"err": err,
		}).Debugln("failed to verify signature of JWT")
		return err
	}

	return nil
}

func validAudience(aud []string, cfgAud string) bool {
	for _, a := range aud {
		if a == cfgAud {
			return true
		}
	}
	return false
}

// validInfoHash attempts to match the claim for the Infohash field of a JWT by
// checking both the raw and unescaped forms of the contents of the field.
func validInfoHash(claim string, ih bittorrent.InfoHash) bool {
	if len(claim) == 20 && bittorrent.InfoHashFromString(claim) == ih {
		return true
	}

	unescapedClaim, err := url.QueryUnescape(claim)
	if err != nil {
		return false
	}

	if len(unescapedClaim) == 20 && bittorrent.InfoHashFromString(unescapedClaim) == ih {
		return true
	}

	return false
}
<|endoftext|>


<commit_before>// Copyright 2016 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package badges

import (
	"bytes"
	"encoding/json"
	"sync"

	"github.com/keybase/client/go/gregor"
	"github.com/keybase/client/go/logger"
	"github.com/keybase/client/go/protocol/chat1"
	"github.com/keybase/client/go/protocol/gregor1"
	"github.com/keybase/client/go/protocol/keybase1"
	jsonw "github.com/keybase/go-jsonw"
)

// BadgeState represents the number of badges on the app. It's threadsafe.
// Useable from both the client service and gregor server.
// See service:Badger for the service part that owns this.
type BadgeState struct {
	sync.Mutex

	log   logger.Logger
	state keybase1.BadgeState

	inboxVers chat1.InboxVers
	// Map from ConversationID.String to BadgeConversationInfo.
	chatUnreadMap map[string]keybase1.BadgeConversationInfo
}

// NewBadgeState creates a new empty BadgeState.
func NewBadgeState(log logger.Logger) *BadgeState {
	return &BadgeState{
		log:           log,
		inboxVers:     chat1.InboxVers(0),
		chatUnreadMap: make(map[string]keybase1.BadgeConversationInfo),
	}
}

// Exports the state summary
func (b *BadgeState) Export() (keybase1.BadgeState, error) {
	b.Lock()
	defer b.Unlock()

	b.state.Conversations = []keybase1.BadgeConversationInfo{}
	for _, info := range b.chatUnreadMap {
		b.state.Conversations = append(b.state.Conversations, info)
	}
	b.state.InboxVers = int(b.inboxVers)

	return b.state, nil
}

type problemSetBody struct {
	Count int `json:"count"`
}

type newTeamBody struct {
	TeamID   string `json:"id"`
	TeamName string `json:"name"`
	Implicit bool   `json:"implicit_team"`
}

type memberOutBody struct {
	TeamName  string `json:"team_name"`
	ResetUser struct {
		UID      string `json:"uid"`
		Username string `json:"username"`
	} `json:"reset_user"`
}

type homeStateBody struct {
	Version    int `json:"version"`
	BadgeCount int `json:"badge_count"`
}

// UpdateWithGregor updates the badge state from a gregor state.
func (b *BadgeState) UpdateWithGregor(gstate gregor.State) error {
	b.Lock()
	defer b.Unlock()

	b.state.NewTlfs = 0
	b.state.NewFollowers = 0
	b.state.RekeysNeeded = 0
	b.state.NewGitRepoGlobalUniqueIDs = []string{}
	b.state.NewTeamNames = nil
	b.state.NewTeamAccessRequests = nil
	b.state.HomeTodoItems = 0

	var hsb *homeStateBody

	items, err := gstate.Items()
	if err != nil {
		return err
	}
	for _, item := range items {
		categoryObj := item.Category()
		if categoryObj == nil {
			continue
		}
		category := categoryObj.String()
		switch category {
		case "home.state":
			var tmp homeStateBody
			byt := item.Body().Bytes()
			dec := json.NewDecoder(bytes.NewReader(byt))
			if err := dec.Decode(&tmp); err != nil {
				b.log.Warning("BadgeState got bad home.state object; error: %v; on %q", err, string(byt))
				continue
			}
			if hsb == nil || hsb.Version < tmp.Version {
				hsb = &tmp
				b.state.HomeTodoItems = hsb.BadgeCount
			}
		case "tlf":
			jsw, err := jsonw.Unmarshal(item.Body().Bytes())
			if err != nil {
				b.log.Warning("BadgeState encountered non-json 'tlf' item: %v", err)
				continue
			}
			itemType, err := jsw.AtKey("type").GetString()
			if err != nil {
				b.log.Warning("BadgeState encountered gregor 'tlf' item without 'type': %v", err)
				continue
			}
			if itemType != "created" {
				continue
			}
			b.state.NewTlfs++
		case "kbfs_tlf_problem_set_count", "kbfs_tlf_sbs_problem_set_count":
			var body problemSetBody
			if err := json.Unmarshal(item.Body().Bytes(), &body); err != nil {
				b.log.Warning("BadgeState encountered non-json 'problem set' item: %v", err)
				continue
			}
			b.state.RekeysNeeded += body.Count
		case "follow":
			b.state.NewFollowers++
		case "new_git_repo":
			jsw, err := jsonw.Unmarshal(item.Body().Bytes())
			if err != nil {
				b.log.Warning("BadgeState encountered non-json 'new_git_repo' item: %v", err)
				continue
			}
			globalUniqueID, err := jsw.AtKey("global_unique_id").GetString()
			if err != nil {
				b.log.Warning("BadgeState encountered gregor 'new_git_repo' item without 'global_unique_id': %v", err)
				continue
			}
			b.state.NewGitRepoGlobalUniqueIDs = append(b.state.NewGitRepoGlobalUniqueIDs, globalUniqueID)
		case "team.newly_added_to_team":
			var body []newTeamBody
			if err := json.Unmarshal(item.Body().Bytes(), &body); err != nil {
				b.log.Warning("BadgeState unmarshal error for team.newly_added_to_team item: %v", err)
				continue
			}
			for _, x := range body {
				if x.TeamName == "" {
					continue
				}
				if x.Implicit {
					continue
				}
				b.state.NewTeamNames = append(b.state.NewTeamNames, x.TeamName)
			}
		case "team.request_access":
			var body []newTeamBody
			if err := json.Unmarshal(item.Body().Bytes(), &body); err != nil {
				b.log.Warning("BadgeState unmarshal error for team.request_access item: %v", err)
				continue
			}
			for _, x := range body {
				if x.TeamName == "" {
					continue
				}
				b.state.NewTeamAccessRequests = append(b.state.NewTeamAccessRequests, x.TeamName)
			}
		case "team.member_out_from_reset":
			var body keybase1.TeamMemberOutFromReset
			if err := json.Unmarshal(item.Body().Bytes(), &body); err != nil {
				b.log.Warning("BadgeState unmarshal error for team.member_out_from_reset item: %v", err)
				continue
			}

			msgID := item.Metadata().MsgID().(gregor1.MsgID)
			m := keybase1.TeamMemberOutReset{
				Teamname: body.TeamName,
				Username: body.ResetUser.Username,
				Id:       msgID,
			}
			b.state.TeamsWithResetUsers = append(b.state.TeamsWithResetUsers, m)
		}
	}

	return nil
}

func (b *BadgeState) UpdateWithChat(update chat1.UnreadUpdate, inboxVers chat1.InboxVers) {
	b.Lock()
	defer b.Unlock()

	// Skip stale updates
	if inboxVers < b.inboxVers {
		return
	}

	b.inboxVers = inboxVers
	b.updateWithChat(update)
}

func (b *BadgeState) UpdateWithChatFull(update chat1.UnreadUpdateFull) {
	b.Lock()
	defer b.Unlock()

	if update.Ignore {
		return
	}

	// Skip stale updates
	if update.InboxVers < b.inboxVers {
		return
	}

	switch update.InboxSyncStatus {
	case chat1.SyncInboxResType_CURRENT:
	case chat1.SyncInboxResType_INCREMENTAL:
	case chat1.SyncInboxResType_CLEAR:
		b.chatUnreadMap = make(map[string]keybase1.BadgeConversationInfo)
	}

	for _, upd := range update.Updates {
		b.updateWithChat(upd)
	}

	b.inboxVers = update.InboxVers
}

func (b *BadgeState) Clear() {
	b.Lock()
	defer b.Unlock()

	b.state = keybase1.BadgeState{}
	b.inboxVers = chat1.InboxVers(0)
	b.chatUnreadMap = make(map[string]keybase1.BadgeConversationInfo)
}

func (b *BadgeState) updateWithChat(update chat1.UnreadUpdate) {
	b.chatUnreadMap[update.ConvID.String()] = keybase1.BadgeConversationInfo{
		ConvID:         keybase1.ChatConversationID(update.ConvID),
		UnreadMessages: update.UnreadMessages,
		BadgeCounts:    update.UnreadNotifyingMessages,
	}
}
<commit_msg>Revert "Don't add implicit teams to NewTeamNames"<commit_after>// Copyright 2016 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package badges

import (
	"bytes"
	"encoding/json"
	"sync"

	"github.com/keybase/client/go/gregor"
	"github.com/keybase/client/go/logger"
	"github.com/keybase/client/go/protocol/chat1"
	"github.com/keybase/client/go/protocol/gregor1"
	"github.com/keybase/client/go/protocol/keybase1"
	jsonw "github.com/keybase/go-jsonw"
)

// BadgeState represents the number of badges on the app. It's threadsafe.
// Useable from both the client service and gregor server.
// See service:Badger for the service part that owns this.
type BadgeState struct {
	sync.Mutex

	log   logger.Logger
	state keybase1.BadgeState

	inboxVers chat1.InboxVers
	// Map from ConversationID.String to BadgeConversationInfo.
	chatUnreadMap map[string]keybase1.BadgeConversationInfo
}

// NewBadgeState creates a new empty BadgeState.
func NewBadgeState(log logger.Logger) *BadgeState {
	return &BadgeState{
		log:           log,
		inboxVers:     chat1.InboxVers(0),
		chatUnreadMap: make(map[string]keybase1.BadgeConversationInfo),
	}
}

// Exports the state summary
func (b *BadgeState) Export() (keybase1.BadgeState, error) {
	b.Lock()
	defer b.Unlock()

	b.state.Conversations = []keybase1.BadgeConversationInfo{}
	for _, info := range b.chatUnreadMap {
		b.state.Conversations = append(b.state.Conversations, info)
	}
	b.state.InboxVers = int(b.inboxVers)

	return b.state, nil
}

type problemSetBody struct {
	Count int `json:"count"`
}

type newTeamBody struct {
	TeamID   string `json:"id"`
	TeamName string `json:"name"`
}

type memberOutBody struct {
	TeamName  string `json:"team_name"`
	ResetUser struct {
		UID      string `json:"uid"`
		Username string `json:"username"`
	} `json:"reset_user"`
}

type homeStateBody struct {
	Version    int `json:"version"`
	BadgeCount int `json:"badge_count"`
}

// UpdateWithGregor updates the badge state from a gregor state.
func (b *BadgeState) UpdateWithGregor(gstate gregor.State) error {
	b.Lock()
	defer b.Unlock()

	b.state.NewTlfs = 0
	b.state.NewFollowers = 0
	b.state.RekeysNeeded = 0
	b.state.NewGitRepoGlobalUniqueIDs = []string{}
	b.state.NewTeamNames = nil
	b.state.NewTeamAccessRequests = nil
	b.state.HomeTodoItems = 0

	var hsb *homeStateBody

	items, err := gstate.Items()
	if err != nil {
		return err
	}
	for _, item := range items {
		categoryObj := item.Category()
		if categoryObj == nil {
			continue
		}
		category := categoryObj.String()
		switch category {
		case "home.state":
			var tmp homeStateBody
			byt := item.Body().Bytes()
			dec := json.NewDecoder(bytes.NewReader(byt))
			if err := dec.Decode(&tmp); err != nil {
				b.log.Warning("BadgeState got bad home.state object; error: %v; on %q", err, string(byt))
				continue
			}
			if hsb == nil || hsb.Version < tmp.Version {
				hsb = &tmp
				b.state.HomeTodoItems = hsb.BadgeCount
			}
		case "tlf":
			jsw, err := jsonw.Unmarshal(item.Body().Bytes())
			if err != nil {
				b.log.Warning("BadgeState encountered non-json 'tlf' item: %v", err)
				continue
			}
			itemType, err := jsw.AtKey("type").GetString()
			if err != nil {
				b.log.Warning("BadgeState encountered gregor 'tlf' item without 'type': %v", err)
				continue
			}
			if itemType != "created" {
				continue
			}
			b.state.NewTlfs++
		case "kbfs_tlf_problem_set_count", "kbfs_tlf_sbs_problem_set_count":
			var body problemSetBody
			if err := json.Unmarshal(item.Body().Bytes(), &body); err != nil {
				b.log.Warning("BadgeState encountered non-json 'problem set' item: %v", err)
				continue
			}
			b.state.RekeysNeeded += body.Count
		case "follow":
			b.state.NewFollowers++
		case "new_git_repo":
			jsw, err := jsonw.Unmarshal(item.Body().Bytes())
			if err != nil {
				b.log.Warning("BadgeState encountered non-json 'new_git_repo' item: %v", err)
				continue
			}
			globalUniqueID, err := jsw.AtKey("global_unique_id").GetString()
			if err != nil {
				b.log.Warning("BadgeState encountered gregor 'new_git_repo' item without 'global_unique_id': %v", err)
				continue
			}
			b.state.NewGitRepoGlobalUniqueIDs = append(b.state.NewGitRepoGlobalUniqueIDs, globalUniqueID)
		case "team.newly_added_to_team":
			var body []newTeamBody
			if err := json.Unmarshal(item.Body().Bytes(), &body); err != nil {
				b.log.Warning("BadgeState unmarshal error for team.newly_added_to_team item: %v", err)
				continue
			}
			for _, x := range body {
				if x.TeamName == "" {
					continue
				}
				b.state.NewTeamNames = append(b.state.NewTeamNames, x.TeamName)
			}
		case "team.request_access":
			var body []newTeamBody
			if err := json.Unmarshal(item.Body().Bytes(), &body); err != nil {
				b.log.Warning("BadgeState unmarshal error for team.request_access item: %v", err)
				continue
			}
			for _, x := range body {
				if x.TeamName == "" {
					continue
				}
				b.state.NewTeamAccessRequests = append(b.state.NewTeamAccessRequests, x.TeamName)
			}
		case "team.member_out_from_reset":
			var body keybase1.TeamMemberOutFromReset
			if err := json.Unmarshal(item.Body().Bytes(), &body); err != nil {
				b.log.Warning("BadgeState unmarshal error for team.member_out_from_reset item: %v", err)
				continue
			}

			msgID := item.Metadata().MsgID().(gregor1.MsgID)
			m := keybase1.TeamMemberOutReset{
				Teamname: body.TeamName,
				Username: body.ResetUser.Username,
				Id:       msgID,
			}
			b.state.TeamsWithResetUsers = append(b.state.TeamsWithResetUsers, m)
		}
	}

	return nil
}

func (b *BadgeState) UpdateWithChat(update chat1.UnreadUpdate, inboxVers chat1.InboxVers) {
	b.Lock()
	defer b.Unlock()

	// Skip stale updates
	if inboxVers < b.inboxVers {
		return
	}

	b.inboxVers = inboxVers
	b.updateWithChat(update)
}

func (b *BadgeState) UpdateWithChatFull(update chat1.UnreadUpdateFull) {
	b.Lock()
	defer b.Unlock()

	if update.Ignore {
		return
	}

	// Skip stale updates
	if update.InboxVers < b.inboxVers {
		return
	}

	switch update.InboxSyncStatus {
	case chat1.SyncInboxResType_CURRENT:
	case chat1.SyncInboxResType_INCREMENTAL:
	case chat1.SyncInboxResType_CLEAR:
		b.chatUnreadMap = make(map[string]keybase1.BadgeConversationInfo)
	}

	for _, upd := range update.Updates {
		b.updateWithChat(upd)
	}

	b.inboxVers = update.InboxVers
}

func (b *BadgeState) Clear() {
	b.Lock()
	defer b.Unlock()

	b.state = keybase1.BadgeState{}
	b.inboxVers = chat1.InboxVers(0)
	b.chatUnreadMap = make(map[string]keybase1.BadgeConversationInfo)
}

func (b *BadgeState) updateWithChat(update chat1.UnreadUpdate) {
	b.chatUnreadMap[update.ConvID.String()] = keybase1.BadgeConversationInfo{
		ConvID:         keybase1.ChatConversationID(update.ConvID),
		UnreadMessages: update.UnreadMessages,
		BadgeCounts:    update.UnreadNotifyingMessages,
	}
}
<|endoftext|>


<commit_before>package metadata

import (
	"fmt"
	"io/ioutil"
	"net/http"

	"github.com/golang/glog"

	"skia.googlesource.com/buildbot.git/go/util"
)

// Get retrieves the named value from the Metadata server. See
// https://developers.google.com/compute/docs/metadata
//
// level should be either "instance" or "project" for the kind of
// metadata to retrieve.
func get(name string, level string) (string, error) {
	req, err := http.NewRequest("GET", "http://metadata/computeMetadata/v1/"+level+"/attributes/"+name, nil)
	if err != nil {
		return "", fmt.Errorf("metadata.Get() failed to build request: %s", err)
	}
	c := util.NewTimeoutClient()
	req.Header.Add("Metadata-Flavor", "Google")
	resp, err := c.Do(req)
	if err != nil {
		return "", fmt.Errorf("metadata.Get() failed to make HTTP request for %s: %s", name, err)
	}
	defer resp.Body.Close()
	value, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("Failed to read %s from metadata server: %s", name, err)
	}
	return string(value), nil
}

// Get retrieves the named value from the instance Metadata server. See
// https://developers.google.com/compute/docs/metadata
func Get(name string) (string, error) {
	return get(name, "instance")
}

// Get retrieves the named value from the project Metadata server. See
// https://developers.google.com/compute/docs/metadata
func ProjectGet(name string) (string, error) {
	return get(name, "project")
}

// MustGet is Get() that panics on error.
func MustGet(keyname string) string {
	value, err := Get(keyname)
	if err != nil {
		glog.Fatalf("Unable to obtain %q from metadata server: %s.", keyname, err)
	}
	return value
}

func Must(s string, err error) string {
	if err != nil {
		glog.Fatalf("Failed to read metadata: %s.", err)
	}
	return s
}
<commit_msg>Fix doc typos in metadata package.<commit_after>package metadata

import (
	"fmt"
	"io/ioutil"
	"net/http"

	"github.com/golang/glog"
	"skia.googlesource.com/buildbot.git/go/util"
)

// get retrieves the named value from the Metadata server. See
// https://developers.google.com/compute/docs/metadata
//
// level should be either "instance" or "project" for the kind of
// metadata to retrieve.
func get(name string, level string) (string, error) {
	req, err := http.NewRequest("GET", "http://metadata/computeMetadata/v1/"+level+"/attributes/"+name, nil)
	if err != nil {
		return "", fmt.Errorf("metadata.Get() failed to build request: %s", err)
	}
	c := util.NewTimeoutClient()
	req.Header.Add("Metadata-Flavor", "Google")
	resp, err := c.Do(req)
	if err != nil {
		return "", fmt.Errorf("metadata.Get() failed to make HTTP request for %s: %s", name, err)
	}
	defer resp.Body.Close()
	value, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("Failed to read %s from metadata server: %s", name, err)
	}
	return string(value), nil
}

// Get retrieves the named value from the instance Metadata server. See
// https://developers.google.com/compute/docs/metadata
func Get(name string) (string, error) {
	return get(name, "instance")
}

// ProjectGet retrieves the named value from the project Metadata server. See
// https://developers.google.com/compute/docs/metadata
func ProjectGet(name string) (string, error) {
	return get(name, "project")
}

// MustGet is Get() that panics on error.
func MustGet(keyname string) string {
	value, err := Get(keyname)
	if err != nil {
		glog.Fatalf("Unable to obtain %q from metadata server: %s.", keyname, err)
	}
	return value
}

func Must(s string, err error) string {
	if err != nil {
		glog.Fatalf("Failed to read metadata: %s.", err)
	}
	return s
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All rights reserved.
//
// 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
//
//     http://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 main

import (
	"bytes"
	"encoding/json"
	"flag"
	"io/ioutil"
	"log"
	"log/syslog"
	"syscall"

	"github.com/google/testimony/go/testimonyd/internal/socket"
)

var (
	confFilename = flag.String("config", "/etc/testimony.conf", "Testimony config")
	logToSyslog  = flag.Bool("syslog", true, "log messages to syslog")
)

func main() {
	flag.Parse()
	if *logToSyslog {
		s, err := syslog.New(syslog.LOG_USER|syslog.LOG_INFO, "testimonyd")
		if err != nil {
			log.Fatalf("could not set up syslog logging: %v", err)
		}
		log.SetOutput(s)
	}
	log.Printf("Starting testimonyd...")
	confdata, err := ioutil.ReadFile(*confFilename)
	if err != nil {
		log.Fatalf("could not read configuration %q: %v", *confFilename, err)
	}
	// Set umask which will affect all of the sockets we create:
	syscall.Umask(0177)
	var t socket.Testimony
	if err := json.NewDecoder(bytes.NewBuffer(confdata)).Decode(&t); err != nil {
		log.Fatalf("could not parse configuration %q: %v", *confFilename, err)
	}
	socket.RunTestimony(t)
}
<commit_msg>Fix crash on first connection when FanoutSize is zero or unspecified<commit_after>// Copyright 2015 Google Inc. All rights reserved.
//
// 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
//
//     http://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 main

import (
	"bytes"
	"encoding/json"
	"flag"
	"io/ioutil"
	"log"
	"log/syslog"
	"syscall"

	"github.com/google/testimony/go/testimonyd/internal/socket"
)

var (
	confFilename = flag.String("config", "/etc/testimony.conf", "Testimony config")
	logToSyslog  = flag.Bool("syslog", true, "log messages to syslog")
)

func main() {
	flag.Parse()
	if *logToSyslog {
		s, err := syslog.New(syslog.LOG_USER|syslog.LOG_INFO, "testimonyd")
		if err != nil {
			log.Fatalf("could not set up syslog logging: %v", err)
		}
		log.SetOutput(s)
	}
	log.Printf("Starting testimonyd...")
	confdata, err := ioutil.ReadFile(*confFilename)
	if err != nil {
		log.Fatalf("could not read configuration %q: %v", *confFilename, err)
	}
	// Set umask which will affect all of the sockets we create:
	syscall.Umask(0177)
	var t socket.Testimony
	if err := json.NewDecoder(bytes.NewBuffer(confdata)).Decode(&t); err != nil {
		log.Fatalf("could not parse configuration %q: %v", *confFilename, err)
	}
	for i, _ := range t {
		if t[i].FanoutSize == 0 {
			t[i].FanoutSize = 1
		}
	}
	socket.RunTestimony(t)
}
<|endoftext|>


<commit_before>package goat

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"sync/atomic"
)

// HTTPConnHandler handles incoming HTTP (TCP) network connections
type HTTPConnHandler struct {
}

// Handle incoming HTTP connections and serve
func (h HTTPConnHandler) Handle(l net.Listener, httpDoneChan chan bool) {
	// Create shutdown function
	go func(l net.Listener, httpDoneChan chan bool) {
		// Wait for done signal
		Static.ShutdownChan <- <-Static.ShutdownChan

		// Close listener
		l.Close()
		httpDoneChan <- true
	}(l, httpDoneChan)

	// Log API configuration
	if Static.Config.API {
		log.Println("API functionality enabled")
	}

	// Set up HTTP routes for handling functions
	http.HandleFunc("/", parseHTTP)

	// Serve HTTP requests
	http.Serve(l, nil)
}

// Parse incoming HTTP connections before making tracker calls
func parseHTTP(w http.ResponseWriter, r *http.Request) {
	// Count incoming connections
	atomic.AddInt64(&Static.HTTP.Current, 1)
	atomic.AddInt64(&Static.HTTP.Total, 1)

	// Parse querystring
	querystring := r.URL.Query()

	// Flatten arrays into single values
	query := map[string]string{}
	for k, v := range querystring {
		query[k] = v[0]
	}

	// Check if IP was previously set
	if _, ok := query["ip"]; !ok {
		// If no IP set, detect and store it in query map
		query["ip"] = strings.Split(r.RemoteAddr, ":")[0]
	}

	// Add header to identify goat
	w.Header().Add("Server", fmt.Sprintf("%s/%s", App, Version))

	// Store current URL path
	url := r.URL.Path

	// Split URL into segments
	urlArr := strings.Split(url, "/")

	// If configured, Detect if client is making an API call
	url = urlArr[1]
	if url == "api" {
		// Output JSON
		w.Header().Add("Content-Type", "application/json")

		// API enabled
		if Static.Config.API {
			// Log API calls
			log.Printf("API: %s\n", r.URL.Path)

			// Handle API calls, output JSON
			APIRouter(w, r)
			return
		} else {
			http.Error(w, string(APIErrorResponse("API is currently disabled")), 503)
			return
		}
	}

	// Detect if passkey present in URL
	var passkey string
	if len(urlArr) == 3 {
		passkey = urlArr[1]
		url = urlArr[2]
	}

	// Verify that torrent client is advertising its User-Agent, so we can use a whitelist
	if _, ok := r.Header["User-Agent"]; !ok {
		w.Write(HTTPTrackerError("Your client is not identifying itself"))
		return
	}

	client := r.Header["User-Agent"][0]

	// If configured, verify that torrent client is on whitelist
	if Static.Config.Whitelist {
		whitelist := new(WhitelistRecord).Load(client, "client")
		if whitelist == (WhitelistRecord{}) || !whitelist.Approved {
			w.Write(HTTPTrackerError("Your client is not whitelisted"))

			// Block things like browsers and web crawlers, because they will just clutter up the table
			if strings.Contains(client, "Mozilla") || strings.Contains(client, "Opera") {
				return
			}

			// Insert unknown clients into list for later approval
			if whitelist == (WhitelistRecord{}) {
				whitelist.Client = client
				whitelist.Approved = false

				log.Printf("whitelist: detected new client '%s', awaiting manual approval", client)

				go whitelist.Save()
			}

			return
		}
	}

	// Put client in query map
	query["client"] = client

	// Check if server is configured for passkey announce
	if Static.Config.Passkey && passkey == "" {
		w.Write(HTTPTrackerError("No passkey found in announce URL"))
		return
	}

	// Validate passkey if needed
	user := new(UserRecord).Load(passkey, "passkey")
	if Static.Config.Passkey && user == (UserRecord{}) {
		w.Write(HTTPTrackerError("Invalid passkey"))
		return
	}

	// Put passkey in query map
	query["passkey"] = user.Passkey

	// Mark client as HTTP
	query["udp"] = "0"

	// Create channel to return response to client
	resChan := make(chan []byte)

	// Handle tracker functions via different URLs
	switch url {
	// Tracker announce
	case "announce":
		// Validate required parameter input
		required := []string{"info_hash", "ip", "port", "uploaded", "downloaded", "left"}
		// Validate required integer input
		reqInt := []string{"port", "uploaded", "downloaded", "left"}

		// Check for required parameters
		for _, r := range required {
			if _, ok := query[r]; !ok {
				w.Write(HTTPTrackerError("Missing required parameter: " + r))
				close(resChan)
				return
			}
		}

		// Check for all valid integers
		for _, r := range reqInt {
			if _, ok := query[r]; ok {
				_, err := strconv.Atoi(query[r])
				if err != nil {
					w.Write(HTTPTrackerError("Invalid integer parameter: " + r))
					close(resChan)
					return
				}
			}
		}

		// Only allow compact announce
		if _, ok := query["compact"]; !ok || query["compact"] != "1" {
			w.Write(HTTPTrackerError("Your client does not support compact announce"))
			close(resChan)
			return
		}

		// Perform tracker announce
		go TrackerAnnounce(user, query, nil, resChan)
	// Tracker scrape
	case "scrape":
		go TrackerScrape(user, query, resChan)
	// Any undefined handlers
	default:
		w.Write(HTTPTrackerError("Malformed announce"))
		close(resChan)
		return
	}

	// Wait for response, and send it when ready
	w.Write(<-resChan)
	close(resChan)
	return
}
<commit_msg>Add IP to API logging<commit_after>package goat

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"sync/atomic"
)

// HTTPConnHandler handles incoming HTTP (TCP) network connections
type HTTPConnHandler struct {
}

// Handle incoming HTTP connections and serve
func (h HTTPConnHandler) Handle(l net.Listener, httpDoneChan chan bool) {
	// Create shutdown function
	go func(l net.Listener, httpDoneChan chan bool) {
		// Wait for done signal
		Static.ShutdownChan <- <-Static.ShutdownChan

		// Close listener
		l.Close()
		httpDoneChan <- true
	}(l, httpDoneChan)

	// Log API configuration
	if Static.Config.API {
		log.Println("API functionality enabled")
	}

	// Set up HTTP routes for handling functions
	http.HandleFunc("/", parseHTTP)

	// Serve HTTP requests
	http.Serve(l, nil)
}

// Parse incoming HTTP connections before making tracker calls
func parseHTTP(w http.ResponseWriter, r *http.Request) {
	// Count incoming connections
	atomic.AddInt64(&Static.HTTP.Current, 1)
	atomic.AddInt64(&Static.HTTP.Total, 1)

	// Parse querystring
	querystring := r.URL.Query()

	// Flatten arrays into single values
	query := map[string]string{}
	for k, v := range querystring {
		query[k] = v[0]
	}

	// Check if IP was previously set
	if _, ok := query["ip"]; !ok {
		// If no IP set, detect and store it in query map
		query["ip"] = strings.Split(r.RemoteAddr, ":")[0]
	}

	// Add header to identify goat
	w.Header().Add("Server", fmt.Sprintf("%s/%s", App, Version))

	// Store current URL path
	url := r.URL.Path

	// Split URL into segments
	urlArr := strings.Split(url, "/")

	// If configured, Detect if client is making an API call
	url = urlArr[1]
	if url == "api" {
		// Output JSON
		w.Header().Add("Content-Type", "application/json")

		// API enabled
		if Static.Config.API {
			// Log API calls
			log.Printf("API: [http %s] %s\n", r.RemoteAddr, r.URL.Path)

			// Handle API calls, output JSON
			APIRouter(w, r)
			return
		} else {
			http.Error(w, string(APIErrorResponse("API is currently disabled")), 503)
			return
		}
	}

	// Detect if passkey present in URL
	var passkey string
	if len(urlArr) == 3 {
		passkey = urlArr[1]
		url = urlArr[2]
	}

	// Verify that torrent client is advertising its User-Agent, so we can use a whitelist
	if _, ok := r.Header["User-Agent"]; !ok {
		w.Write(HTTPTrackerError("Your client is not identifying itself"))
		return
	}

	client := r.Header["User-Agent"][0]

	// If configured, verify that torrent client is on whitelist
	if Static.Config.Whitelist {
		whitelist := new(WhitelistRecord).Load(client, "client")
		if whitelist == (WhitelistRecord{}) || !whitelist.Approved {
			w.Write(HTTPTrackerError("Your client is not whitelisted"))

			// Block things like browsers and web crawlers, because they will just clutter up the table
			if strings.Contains(client, "Mozilla") || strings.Contains(client, "Opera") {
				return
			}

			// Insert unknown clients into list for later approval
			if whitelist == (WhitelistRecord{}) {
				whitelist.Client = client
				whitelist.Approved = false

				log.Printf("whitelist: detected new client '%s', awaiting manual approval", client)

				go whitelist.Save()
			}

			return
		}
	}

	// Put client in query map
	query["client"] = client

	// Check if server is configured for passkey announce
	if Static.Config.Passkey && passkey == "" {
		w.Write(HTTPTrackerError("No passkey found in announce URL"))
		return
	}

	// Validate passkey if needed
	user := new(UserRecord).Load(passkey, "passkey")
	if Static.Config.Passkey && user == (UserRecord{}) {
		w.Write(HTTPTrackerError("Invalid passkey"))
		return
	}

	// Put passkey in query map
	query["passkey"] = user.Passkey

	// Mark client as HTTP
	query["udp"] = "0"

	// Create channel to return response to client
	resChan := make(chan []byte)

	// Handle tracker functions via different URLs
	switch url {
	// Tracker announce
	case "announce":
		// Validate required parameter input
		required := []string{"info_hash", "ip", "port", "uploaded", "downloaded", "left"}
		// Validate required integer input
		reqInt := []string{"port", "uploaded", "downloaded", "left"}

		// Check for required parameters
		for _, r := range required {
			if _, ok := query[r]; !ok {
				w.Write(HTTPTrackerError("Missing required parameter: " + r))
				close(resChan)
				return
			}
		}

		// Check for all valid integers
		for _, r := range reqInt {
			if _, ok := query[r]; ok {
				_, err := strconv.Atoi(query[r])
				if err != nil {
					w.Write(HTTPTrackerError("Invalid integer parameter: " + r))
					close(resChan)
					return
				}
			}
		}

		// Only allow compact announce
		if _, ok := query["compact"]; !ok || query["compact"] != "1" {
			w.Write(HTTPTrackerError("Your client does not support compact announce"))
			close(resChan)
			return
		}

		// Perform tracker announce
		go TrackerAnnounce(user, query, nil, resChan)
	// Tracker scrape
	case "scrape":
		go TrackerScrape(user, query, resChan)
	// Any undefined handlers
	default:
		w.Write(HTTPTrackerError("Malformed announce"))
		close(resChan)
		return
	}

	// Wait for response, and send it when ready
	w.Write(<-resChan)
	close(resChan)
	return
}
<|endoftext|>


<commit_before>// Copyright 2011 Rodrigo Moraes. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package gorilla/sessions provides cookie sessions and infrastructure for
custom session backends.

The key features are:

* Dead simple basic API: use it as an easy way to set signed (and optionally
encrypted) cookies.

* Advanced API for custom backends: built-in support for custom storage
systems; session store interface and helper functions; encoder interface
and default implementation with customizable cryptography methods (thanks to
Go interfaces).

* Conveniences: flash messages (session values that last until read);
built-in mechanism to rotate authentication and encryption keys;
multiple sessions per request, even using different backends; easy way to
switch session persistency (aka "remember me") and set other attributes.

The most basic example to retrieve a session is to call sessions.Session()
passing the current request. For example, in a handler:

	func MyHandler(w http.ResponseWriter, r *http.Request) {
		if session, err := sessions.Session(r); err == nil {
			session["foo"] = "bar"
			session["baz"] = 128
			sessions.Save(r, w)
		}
	}

The above snippet is "gorilla/sessions in a nutshell": a session is a simple
map[string]interface{} returned from sessions.Session(). It stores any values
that can be encoded using gob. After we set some values, we call
sessions.Save() passing the current request and response.

Side note about "any values that can be encoded using gob": to store special
structures in a session, we must register them using gob.Register() first.
For basic types this is not needed; it works out of the box.

Is it that simple? Well, almost. Before we can use sessions, we must define
a secret key to be used for authentication, and optionally an encryption key.
They are both set calling SetStoreKeys() and should be done at initialization
time:

	func init() {
		sessions.SetStoreKeys("cookie",
							  []byte("my-hmac-key"),
							  []byte("my-aes-key"))
	}

The first argument is the name used to register the session store. By default
a "cookie" store is registered and available for use, so we use that name.

The second argument is the secret key used to authenticate the session cookie
using HMAC. It is required; if no authentication key is set sessions can't be
read or written (and a call to sessions.Session() will return an error).

The third argument is the encryption key; it is optional and can be omitted.
For the cookie store, setting this will encrypt the contents stored in the
cookie; otherwise the contents can be read, although not forged.

Side note about the encryption key: if set, must be either 16, 24, or 32 bytes
to select AES-128, AES-192, or AES-256 modes. Otherwise a block can't be
created and sessions won't work.

Exposing the contents of a session is not a big deal in many cases, like when
we store a simple username or user id, but to to store sensitive information
using the cookie store, we must set an encryption key. For custom stores that
only set a random session id in the cookie, encryption is not needed.

And this is all you need to know about the basic usage. More advanced options
are explained below.

Sometimes we may want to change authentication and/or encryption keys without
breaking existing sessions. We can do this setting multiple authentication and
encryption keys, in pairs, to be tested in order:

	sessions.SetStoreKeys("cookie",
						  []byte("my-hmac-key"),
						  []byte("my-aes-key"),
						  []byte("my-previous-hmac-key"),
						  []byte("my-previous-aes-key"))

New sessions will be saved using the first pair. Old sessions can still be
read because the first pair will fail, and the second will be tested. This
makes it easy to "rotate" secret keys and still be able to validate existing
sessions. Note: for all pairs the encryption key is optional; set it
to nil and encryption won't be used.

Back to how sessions are retrieved.

Sessions are named. When we get a session calling sessions.Session(request),
we are implicitly requesting a session using the default key ("s") and store
(the CookieSessionStore). This is just a convenience; we can have as many
sessions as needed, just passing different session keys. For example:

	if authSession, err := sessions.Session(r, "auth"); err == nil {
		userId = authSession["userId"]
		// ...
	}

Here we requested a session explicitly naming it "auth". It will be saved
separately. This can be used as a convenient way to save signed cookies, and
is also how we access multiple sessions per request.

Session stores also have a name, and need to be registered to be available.
The default session store uses authenticated (and optionally encrypted)
cookies, and is registered with the name "cookie". To use a custom
session backend, we first register it in the SessionFactory, then pass its
name as the third argument to sessions.Session().

For the sake of demonstration, let's pretend that we defined a store called
MemcacheSessionStore. First we register it using the "memcache" key. This
should be done at initialization time:

	func init() {
		sessions.SetStore("memcache", new(MemcacheSessionStore))
	}

Then to get a session using memcached, we pass a third argument to
sessions.Session(), the store key:

	session, err := sessions.Session(r, "mysession", "memcache")

...and it will use the custom backend we defined, instead of the default
"cookie" one. This means that we can use multiple sessions in the same
request even using different backends.

And how to configure session expiration time, path or other cookie attributes?

By default, session cookies last for a month. This is probably too long for a
lot of cases, but it is easy to change this and other attributes during
runtime. Just request the session configuration struct and change the variables
as needed. The fields are basically a subset of http.Cookie fields.
To change MaxAge, we would do:

	if config, err = sessions.Config(r); err == nil {
		// Change max-age to 1 week.
		config.MaxAge = 86400 * 7
	}

After this, cookies will last for a week only. The Config() function
accepts an optional argument besides the request: the session key. If not
defined, the configuration for the default session key is returned.

Bonus: flash messages. What are they? It basically means "session values that
last until read". The term was popularized by Ruby On Rails a few years back.
When we request a flash message, it is removed from the session. We have two
convenience functions to read and set them: Flashes() and AddFlash(). Here is
an example:

	func MyHandler(w http.ResponseWriter, r *http.Request) {
		// Get the previously set flashes, if any.
		if flashes, _ := sessions.Flashes(r); flashes != nil {
			// Just print the flash values.
			fmt.Fprint(w, "%v", flashes)
		} else {
			fmt.Fprint(w, "No flashes found.")
			// Set a new flash.
			sessions.AddFlash(r, "Hello, flash messages world!")
		}
		sessions.Save(r, w)
	}

Flash messages are useful to set information to be read after a redirection,
usually after form submissions.

And that's it. There's probably a little more to cover, but the API is ready
to be explored. If you have any issues or want to suggest a feature or API
improvement, please post it to our issue tracker. Thanks!
*/
package sessions
<commit_msg>Removed last paragraph from sessions doc.<commit_after>// Copyright 2011 Rodrigo Moraes. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package gorilla/sessions provides cookie sessions and infrastructure for
custom session backends.

The key features are:

* Dead simple basic API: use it as an easy way to set signed (and optionally
encrypted) cookies.

* Advanced API for custom backends: built-in support for custom storage
systems; session store interface and helper functions; encoder interface
and default implementation with customizable cryptography methods (thanks to
Go interfaces).

* Conveniences: flash messages (session values that last until read);
built-in mechanism to rotate authentication and encryption keys;
multiple sessions per request, even using different backends; easy way to
switch session persistency (aka "remember me") and set other attributes.

The most basic example to retrieve a session is to call sessions.Session()
passing the current request. For example, in a handler:

	func MyHandler(w http.ResponseWriter, r *http.Request) {
		if session, err := sessions.Session(r); err == nil {
			session["foo"] = "bar"
			session["baz"] = 128
			sessions.Save(r, w)
		}
	}

The above snippet is "gorilla/sessions in a nutshell": a session is a simple
map[string]interface{} returned from sessions.Session(). It stores any values
that can be encoded using gob. After we set some values, we call
sessions.Save() passing the current request and response.

Side note about "any values that can be encoded using gob": to store special
structures in a session, we must register them using gob.Register() first.
For basic types this is not needed; it works out of the box.

Is it that simple? Well, almost. Before we can use sessions, we must define
a secret key to be used for authentication, and optionally an encryption key.
They are both set calling SetStoreKeys() and should be done at initialization
time:

	func init() {
		sessions.SetStoreKeys("cookie",
							  []byte("my-hmac-key"),
							  []byte("my-aes-key"))
	}

The first argument is the name used to register the session store. By default
a "cookie" store is registered and available for use, so we use that name.

The second argument is the secret key used to authenticate the session cookie
using HMAC. It is required; if no authentication key is set sessions can't be
read or written (and a call to sessions.Session() will return an error).

The third argument is the encryption key; it is optional and can be omitted.
For the cookie store, setting this will encrypt the contents stored in the
cookie; otherwise the contents can be read, although not forged.

Side note about the encryption key: if set, must be either 16, 24, or 32 bytes
to select AES-128, AES-192, or AES-256 modes. Otherwise a block can't be
created and sessions won't work.

Exposing the contents of a session is not a big deal in many cases, like when
we store a simple username or user id, but to to store sensitive information
using the cookie store, we must set an encryption key. For custom stores that
only set a random session id in the cookie, encryption is not needed.

And this is all you need to know about the basic usage. More advanced options
are explained below.

Sometimes we may want to change authentication and/or encryption keys without
breaking existing sessions. We can do this setting multiple authentication and
encryption keys, in pairs, to be tested in order:

	sessions.SetStoreKeys("cookie",
						  []byte("my-hmac-key"),
						  []byte("my-aes-key"),
						  []byte("my-previous-hmac-key"),
						  []byte("my-previous-aes-key"))

New sessions will be saved using the first pair. Old sessions can still be
read because the first pair will fail, and the second will be tested. This
makes it easy to "rotate" secret keys and still be able to validate existing
sessions. Note: for all pairs the encryption key is optional; set it
to nil and encryption won't be used.

Back to how sessions are retrieved.

Sessions are named. When we get a session calling sessions.Session(request),
we are implicitly requesting a session using the default key ("s") and store
(the CookieSessionStore). This is just a convenience; we can have as many
sessions as needed, just passing different session keys. For example:

	if authSession, err := sessions.Session(r, "auth"); err == nil {
		userId = authSession["userId"]
		// ...
	}

Here we requested a session explicitly naming it "auth". It will be saved
separately. This can be used as a convenient way to save signed cookies, and
is also how we access multiple sessions per request.

Session stores also have a name, and need to be registered to be available.
The default session store uses authenticated (and optionally encrypted)
cookies, and is registered with the name "cookie". To use a custom
session backend, we first register it in the SessionFactory, then pass its
name as the third argument to sessions.Session().

For the sake of demonstration, let's pretend that we defined a store called
MemcacheSessionStore. First we register it using the "memcache" key. This
should be done at initialization time:

	func init() {
		sessions.SetStore("memcache", new(MemcacheSessionStore))
	}

Then to get a session using memcached, we pass a third argument to
sessions.Session(), the store key:

	session, err := sessions.Session(r, "mysession", "memcache")

...and it will use the custom backend we defined, instead of the default
"cookie" one. This means that we can use multiple sessions in the same
request even using different backends.

And how to configure session expiration time, path or other cookie attributes?

By default, session cookies last for a month. This is probably too long for a
lot of cases, but it is easy to change this and other attributes during
runtime. Just request the session configuration struct and change the variables
as needed. The fields are basically a subset of http.Cookie fields.
To change MaxAge, we would do:

	if config, err = sessions.Config(r); err == nil {
		// Change max-age to 1 week.
		config.MaxAge = 86400 * 7
	}

After this, cookies will last for a week only. The Config() function
accepts an optional argument besides the request: the session key. If not
defined, the configuration for the default session key is returned.

Bonus: flash messages. What are they? It basically means "session values that
last until read". The term was popularized by Ruby On Rails a few years back.
When we request a flash message, it is removed from the session. We have two
convenience functions to read and set them: Flashes() and AddFlash(). Here is
an example:

	func MyHandler(w http.ResponseWriter, r *http.Request) {
		// Get the previously set flashes, if any.
		if flashes, _ := sessions.Flashes(r); flashes != nil {
			// Just print the flash values.
			fmt.Fprint(w, "%v", flashes)
		} else {
			fmt.Fprint(w, "No flashes found.")
			// Set a new flash.
			sessions.AddFlash(r, "Hello, flash messages world!")
		}
		sessions.Save(r, w)
	}

Flash messages are useful to set information to be read after a redirection,
usually after form submissions.
*/
package sessions
<|endoftext|>


<commit_before>package app

import (
	"net/http"
)

type Route struct {
	Name        string
	Method      string
	Pattern     string
	HandlerFunc http.HandlerFunc
}

type Routes []Route

func AttachHttpHandlers() {
	Info.Println("Attaching HTTP handler for route: [GET] /ping")
	Info.Println("Attaching HTTP handler for route: [GET] /api/v1/layers")
	Info.Println("Attaching HTTP handler for route: [GET] /api/v1/layer/{ds}")
	Info.Println("Attaching HTTP handler for route: [POST] /api/v1/layer")
	Info.Println("Attaching HTTP handler for route: [DELETE] /api/v1/layer/{ds}")
	Info.Println("Attaching HTTP handler for route: [PUT] /api/v1/layer/{ds}")
	Info.Println("Attaching HTTP handler for route: [POST] /api/v1/layer/{ds}/feature")
	Info.Println("Attaching HTTP handler for route: [GET] /api/v1/layer/{ds}/feature/{k}")
	Info.Println("Attaching HTTP handler for route: [POST] /api/v1/customer")
	Info.Println("Attaching HTTP handler for route: [GET] /")
	Info.Println("Attaching HTTP handler for route: [GET] /map/{ds}")
	Info.Println("Attaching HTTP handler for route: [GET] /management")
	Info.Println("Attaching HTTP handler for route: [GET] /ws/{ds}")
	Info.Println("Attaching HTTP handler for route: [GET] /management/unload/{ds}")
	Info.Println("Attaching HTTP handler for route: [GET] /management/loaded")
	Info.Println("Attaching HTTP handler for route: [GET] /management/profile")
}

var routes = Routes{
	// General
	Route{"Ping", "GET", "/ping", PingHandler},

	// Layers
	Route{"ViewLayers", "GET", "/api/v1/layers", ViewLayersHandler},
	Route{"ViewLayer", "GET", "/api/v1/layer/{ds}", ViewLayerHandler},
	Route{"NewLayer", "POST", "/api/v1/layer", NewLayerHandler},
	Route{"DeleteLayer", "DELETE", "/api/v1/layer/{ds}", DeleteLayerHandler},
	Route{"ShareLayerHandler", "PUT", "/api/v1/layer/{ds}", ShareLayerHandler},

	//
	Route{"NewFeature", "POST", "/api/v1/layer/{ds}/feature", NewFeatureHandler},
	Route{"ViewFeature", "GET", "/api/v1/layer/{ds}/feature/{k}", ViewFeatureHandler},

	// Superuser Routes
	Route{"NewCustomerHandler", "POST", "/api/v1/customer", NewCustomerHandler},

	// Web Client Routes
	Route{"Index", "GET", "/", IndexHandler},
	Route{"MapNew", "GET", "/map", MapHandler},
	Route{"CustomerManagement", "GET", "/management", CustomerManagementHandler},

	// Web Socket Route
	Route{"Socket", "GET", "/ws/{ds}", serveWs},

	// Experimental
	Route{"UnloadLayer", "GET", "/management/unload/{ds}", UnloadLayer},
	Route{"LoadedLayers", "GET", "/management/loaded", LoadedLayers},
	Route{"LoadedLayers", "GET", "/management/profile", server_profile},
}
<commit_msg>goreport fixes<commit_after>package app

import (
	"net/http"
)

type Route struct {
	Name        string
	Method      string
	Pattern     string
	HandlerFunc http.HandlerFunc
}

type Routes []Route

func AttachHttpHandlers() {
	Info.Println("Attaching HTTP handler for route: [GET] /ping")
	Info.Println("Attaching HTTP handler for route: [GET] /api/v1/layers")
	Info.Println("Attaching HTTP handler for route: [GET] /api/v1/layer/{ds}")
	Info.Println("Attaching HTTP handler for route: [POST] /api/v1/layer")
	Info.Println("Attaching HTTP handler for route: [DELETE] /api/v1/layer/{ds}")
	Info.Println("Attaching HTTP handler for route: [PUT] /api/v1/layer/{ds}")
	Info.Println("Attaching HTTP handler for route: [POST] /api/v1/layer/{ds}/feature")
	Info.Println("Attaching HTTP handler for route: [GET] /api/v1/layer/{ds}/feature/{k}")
	Info.Println("Attaching HTTP handler for route: [POST] /api/v1/customer")
	Info.Println("Attaching HTTP handler for route: [GET] /")
	Info.Println("Attaching HTTP handler for route: [GET] /map/{ds}")
	Info.Println("Attaching HTTP handler for route: [GET] /management")
	Info.Println("Attaching HTTP handler for route: [GET] /ws/{ds}")
	Info.Println("Attaching HTTP handler for route: [GET] /management/unload/{ds}")
	Info.Println("Attaching HTTP handler for route: [GET] /management/loaded")
	Info.Println("Attaching HTTP handler for route: [GET] /management/profile")
}

var routes = Routes{
	// General
	Route{"Ping", "GET", "/ping", PingHandler},

	// Layers
	Route{"ViewLayers", "GET", "/api/v1/layers", ViewLayersHandler},
	Route{"ViewLayer", "GET", "/api/v1/layer/{ds}", ViewLayerHandler},
	Route{"NewLayer", "POST", "/api/v1/layer", NewLayerHandler},
	Route{"DeleteLayer", "DELETE", "/api/v1/layer/{ds}", DeleteLayerHandler},
	Route{"ShareLayerHandler", "PUT", "/api/v1/layer/{ds}", ShareLayerHandler},

	//
	Route{"NewFeature", "POST", "/api/v1/layer/{ds}/feature", NewFeatureHandler},
	Route{"ViewFeature", "GET", "/api/v1/layer/{ds}/feature/{k}", ViewFeatureHandler},

	// Superuser Routes
	Route{"NewCustomerHandler", "POST", "/api/v1/customer", NewCustomerHandler},

	// Web Client Routes
	Route{"Index", "GET", "/", IndexHandler},
	Route{"MapNew", "GET", "/map", MapHandler},
	Route{"CustomerManagement", "GET", "/management", CustomerManagementHandler},

	// Web Socket Route
	Route{"Socket", "GET", "/ws/{ds}", serveWs},

	// Experimental
	Route{"UnloadLayer", "GET", "/management/unload/{ds}", UnloadLayer},
	Route{"LoadedLayers", "GET", "/management/loaded", LoadedLayers},
	Route{"LoadedLayers", "GET", "/management/profile", server_profile},
}
<|endoftext|>


<commit_before>package model

import (
	"github.com/af83/edwig/siri"
)

type SIRIPartner struct {
	MessageIdentifierConsumer

	partner *Partner
}

func NewSIRIPartner(partner *Partner) *SIRIPartner {
	return &SIRIPartner{partner: partner}
}

func (connector *SIRIPartner) SOAPClient() *siri.SOAPClient {
	return nil
}

func (connector *SIRIPartner) RequestorRef() string {
	return ""
}
<commit_msg>Use Partner.settings in SIRIPartner. Refs #1943<commit_after>package model

import (
	"github.com/af83/edwig/logger"
	"github.com/af83/edwig/siri"
)

type SIRIPartner struct {
	MessageIdentifierConsumer

	partner *Partner

	soapClient *siri.SOAPClient
}

func NewSIRIPartner(partner *Partner) *SIRIPartner {
	return &SIRIPartner{partner: partner}
}

func (connector *SIRIPartner) SOAPClient() *siri.SOAPClient {
	if connector.soapClient == nil {
		siriUrl := connector.partner.Setting("remote_url")
		logger.Log.Debugf("Create SIRI SOAPClient to %s", siriUrl)
		connector.soapClient = siri.NewSOAPClient(siriUrl)
	}
	return connector.soapClient
}

func (connector *SIRIPartner) RequestorRef() string {
	return connector.partner.Setting("remote_credential")
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tls

import (
	"crypto/x509"
	"encoding/pem"
)

// A CASet is a set of certificates.
type CASet struct {
	bySubjectKeyId map[string]*x509.Certificate
	byName         map[string]*x509.Certificate
}

func NewCASet() *CASet {
	return &CASet{
		make(map[string]*x509.Certificate),
		make(map[string]*x509.Certificate),
	}
}

func nameToKey(name *x509.Name) string {
	return name.Country + "/" + name.OrganizationalUnit + "/" + name.OrganizationalUnit + "/" + name.CommonName
}

// FindParent attempts to find the certificate in s which signs the given
// certificate. If no such certificate can be found, it returns nil.
func (s *CASet) FindParent(cert *x509.Certificate) (parent *x509.Certificate) {
	var ok bool

	if len(cert.AuthorityKeyId) > 0 {
		parent, ok = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
	} else {
		parent, ok = s.byName[nameToKey(&cert.Issuer)]
	}

	if !ok {
		return nil
	}
	return parent
}

// SetFromPEM attempts to parse a series of PEM encoded root certificates. It
// appends any certificates found to s and returns true if any certificates
// were successfully parsed. On many Linux systems, /etc/ssl/cert.pem will
// contains the system wide set of root CAs in a format suitable for this
// function.
func (s *CASet) SetFromPEM(pemCerts []byte) (ok bool) {
	for len(pemCerts) > 0 {
		var block *pem.Block
		block, pemCerts = pem.Decode(pemCerts)
		if block == nil {
			break
		}
		if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
			continue
		}

		cert, err := x509.ParseCertificate(block.Bytes)
		if err != nil {
			continue
		}

		if len(cert.SubjectKeyId) > 0 {
			s.bySubjectKeyId[string(cert.SubjectKeyId)] = cert
		}
		s.byName[nameToKey(&cert.Subject)] = cert
		ok = true
	}

	return
}
<commit_msg>crypto/tls: typo fix<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tls

import (
	"crypto/x509"
	"encoding/pem"
)

// A CASet is a set of certificates.
type CASet struct {
	bySubjectKeyId map[string]*x509.Certificate
	byName         map[string]*x509.Certificate
}

func NewCASet() *CASet {
	return &CASet{
		make(map[string]*x509.Certificate),
		make(map[string]*x509.Certificate),
	}
}

func nameToKey(name *x509.Name) string {
	return name.Country + "/" + name.Organization + "/" + name.OrganizationalUnit + "/" + name.CommonName
}

// FindParent attempts to find the certificate in s which signs the given
// certificate. If no such certificate can be found, it returns nil.
func (s *CASet) FindParent(cert *x509.Certificate) (parent *x509.Certificate) {
	var ok bool

	if len(cert.AuthorityKeyId) > 0 {
		parent, ok = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
	} else {
		parent, ok = s.byName[nameToKey(&cert.Issuer)]
	}

	if !ok {
		return nil
	}
	return parent
}

// SetFromPEM attempts to parse a series of PEM encoded root certificates. It
// appends any certificates found to s and returns true if any certificates
// were successfully parsed. On many Linux systems, /etc/ssl/cert.pem will
// contains the system wide set of root CAs in a format suitable for this
// function.
func (s *CASet) SetFromPEM(pemCerts []byte) (ok bool) {
	for len(pemCerts) > 0 {
		var block *pem.Block
		block, pemCerts = pem.Decode(pemCerts)
		if block == nil {
			break
		}
		if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
			continue
		}

		cert, err := x509.ParseCertificate(block.Bytes)
		if err != nil {
			continue
		}

		if len(cert.SubjectKeyId) > 0 {
			s.bySubjectKeyId[string(cert.SubjectKeyId)] = cert
		}
		s.byName[nameToKey(&cert.Subject)] = cert
		ok = true
	}

	return
}
<|endoftext|>